Merge branch 'master' of https://github.com/zinnschlag/openmw into savedgame

Conflicts:
	apps/openmw/mwgui/referenceinterface.cpp
	apps/openmw/mwmechanics/actors.cpp
	apps/openmw/mwmechanics/mechanicsmanagerimp.cpp
	apps/openmw/mwmechanics/mechanicsmanagerimp.hpp
	apps/openmw/mwscript/cellextensions.cpp
	apps/openmw/mwworld/cells.cpp
	apps/openmw/mwworld/cells.hpp
	apps/openmw/mwworld/cellstore.cpp
	apps/openmw/mwworld/store.cpp
	apps/openmw/mwworld/worldimp.cpp
actorid
scrawl 11 years ago
commit 03cf383be7

@ -93,8 +93,6 @@ set(OENGINE_GUI
) )
set(OENGINE_BULLET set(OENGINE_BULLET
${LIBDIR}/openengine/bullet/btKinematicCharacterController.cpp
${LIBDIR}/openengine/bullet/btKinematicCharacterController.h
${LIBDIR}/openengine/bullet/BtOgre.cpp ${LIBDIR}/openengine/bullet/BtOgre.cpp
${LIBDIR}/openengine/bullet/BtOgreExtras.h ${LIBDIR}/openengine/bullet/BtOgreExtras.h
${LIBDIR}/openengine/bullet/BtOgreGP.h ${LIBDIR}/openengine/bullet/BtOgreGP.h
@ -183,10 +181,11 @@ if (WIN32)
set(Boost_USE_STATIC_LIBS ON) set(Boost_USE_STATIC_LIBS ON)
set(PLATFORM_INCLUDE_DIR "platform") set(PLATFORM_INCLUDE_DIR "platform")
add_definitions(-DBOOST_ALL_NO_LIB) add_definitions(-DBOOST_ALL_NO_LIB)
# Suppress WinMain(), provided by SDL
add_definitions(-DSDL_MAIN_HANDLED)
else (WIN32) else (WIN32)
set(PLATFORM_INCLUDE_DIR "") set(PLATFORM_INCLUDE_DIR "")
find_path (UUID_INCLUDE_DIR uuid/uuid.h)
include_directories(${UUID_INCLUDE_DIR})
endif (WIN32) endif (WIN32)
if (MSVC10) if (MSVC10)
set(PLATFORM_INCLUDE_DIR "") set(PLATFORM_INCLUDE_DIR "")
@ -238,7 +237,6 @@ include_directories("."
${MYGUI_INCLUDE_DIRS} ${MYGUI_INCLUDE_DIRS}
${MYGUI_PLATFORM_INCLUDE_DIRS} ${MYGUI_PLATFORM_INCLUDE_DIRS}
${OPENAL_INCLUDE_DIR} ${OPENAL_INCLUDE_DIR}
${UUID_INCLUDE_DIR}
${LIBDIR} ${LIBDIR}
) )
@ -408,46 +406,6 @@ IF(NOT WIN32 AND NOT APPLE)
# Install resources # Install resources
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${DATADIR}" FILE_PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT "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") 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) ENDIF(NOT WIN32 AND NOT APPLE)
if(WIN32) if(WIN32)

@ -680,7 +680,7 @@ std::string creatureFlags(int flags)
if (flags & ESM::Creature::Walks) properties += "Walks "; if (flags & ESM::Creature::Walks) properties += "Walks ";
if (flags & ESM::Creature::Swims) properties += "Swims "; if (flags & ESM::Creature::Swims) properties += "Swims ";
if (flags & ESM::Creature::Flies) properties += "Flies "; 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::Respawn) properties += "Respawn ";
if (flags & ESM::Creature::Weapon) properties += "Weapon "; if (flags & ESM::Creature::Weapon) properties += "Weapon ";
if (flags & ESM::Creature::Skeleton) properties += "Skeleton "; if (flags & ESM::Creature::Skeleton) properties += "Skeleton ";
@ -691,7 +691,7 @@ std::string creatureFlags(int flags)
ESM::Creature::Walks| ESM::Creature::Walks|
ESM::Creature::Swims| ESM::Creature::Swims|
ESM::Creature::Flies| ESM::Creature::Flies|
ESM::Creature::Biped| ESM::Creature::Bipedal|
ESM::Creature::Respawn| ESM::Creature::Respawn|
ESM::Creature::Weapon| ESM::Creature::Weapon|
ESM::Creature::Skeleton| ESM::Creature::Skeleton|
@ -717,16 +717,26 @@ std::string landFlags(int flags)
return properties; return properties;
} }
std::string leveledListFlags(int flags) std::string itemListFlags(int flags)
{ {
std::string properties = ""; std::string properties = "";
if (flags == 0) properties += "[None] "; if (flags == 0) properties += "[None] ";
if (flags & ESM::LeveledListBase::AllLevels) properties += "AllLevels "; if (flags & ESM::ItemLevList::AllLevels) properties += "AllLevels ";
// This flag apparently not present on creature lists... if (flags & ESM::ItemLevList::Each) properties += "Each ";
if (flags & ESM::LeveledListBase::Each) properties += "Each ";
int unused = (0xFFFFFFFF ^ int unused = (0xFFFFFFFF ^
(ESM::LeveledListBase::AllLevels| (ESM::ItemLevList::AllLevels|
ESM::LeveledListBase::Each)); 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 "; if (flags & unused) properties += "Invalid ";
properties += str(boost::format("(0x%08X)") % flags); properties += str(boost::format("(0x%08X)") % flags);
return properties; return properties;
@ -764,34 +774,19 @@ std::string magicEffectFlags(int flags)
{ {
std::string properties = ""; std::string properties = "";
if (flags == 0) properties += "[None] "; if (flags == 0) properties += "[None] ";
// Enchanting & SpellMaking occur on the same list of effects. if (flags & ESM::MagicEffect::TargetAttribute) properties += "TargetAttribute ";
// "EXTRA SPELL" appears in the construction set under both the if (flags & ESM::MagicEffect::TargetSkill) properties += "TargetSkill ";
// 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::NoDuration) properties += "NoDuration "; if (flags & ESM::MagicEffect::NoDuration) properties += "NoDuration ";
if (flags & 0x00000008) properties += "NoMagnitude "; if (flags & ESM::MagicEffect::NoMagnitude) properties += "NoMagnitude ";
if (flags & 0x00000010) properties += "Negative "; if (flags & ESM::MagicEffect::Harmful) properties += "Harmful ";
if (flags & 0x00000020) properties += "Unknown1 "; if (flags & ESM::MagicEffect::ContinuousVfx) properties += "ContinuousVFX ";
// ESM componet says 0x800 is negative, but none of the magic if (flags & ESM::MagicEffect::CastSelf) properties += "CastSelf ";
// effects have this flags set. if (flags & ESM::MagicEffect::CastTouch) properties += "CastTouch ";
if (flags & ESM::MagicEffect::Negative) properties += "Unused "; if (flags & ESM::MagicEffect::CastTarget) properties += "CastTarget ";
// Since only Chameleon has this flag it could be anything if (flags & ESM::MagicEffect::UncappedDamage) properties += "UncappedDamage ";
// that uniquely distinguishes Chameleon. if (flags & ESM::MagicEffect::NonRecastable) properties += "NonRecastable ";
if (flags & 0x00002000) properties += "Chameleon "; if (flags & ESM::MagicEffect::Unreflectable) properties += "Unreflectable ";
if (flags & 0x00004000) properties += "Bound "; if (flags & ESM::MagicEffect::CasterLinked) properties += "CasterLinked ";
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 & 0xFFFC0000) properties += "Invalid "; if (flags & 0xFFFC0000) properties += "Invalid ";
properties += str(boost::format("(0x%08X)") % flags); properties += str(boost::format("(0x%08X)") % flags);
return properties; return properties;

@ -50,7 +50,8 @@ std::string cellFlags(int flags);
std::string containerFlags(int flags); std::string containerFlags(int flags);
std::string creatureFlags(int flags); std::string creatureFlags(int flags);
std::string landFlags(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 lightFlags(int flags);
std::string magicEffectFlags(int flags); std::string magicEffectFlags(int flags);
std::string npcFlags(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 << " Distance: " << p.mWander.mDistance << std::endl;
std::cout << " Duration: " << p.mWander.mDuration << std::endl; std::cout << " Duration: " << p.mWander.mDuration << std::endl;
std::cout << " Time of Day: " << (int)p.mWander.mTimeOfDay << std::endl; std::cout << " Time of Day: " << (int)p.mWander.mTimeOfDay << std::endl;
if (p.mWander.mUnk != 1) if (p.mWander.mShouldRepeat != 1)
std::cout << " Unknown: " << (int)p.mWander.mUnk << std::endl; std::cout << " Should repeat: " << (bool)p.mWander.mShouldRepeat << std::endl;
std::cout << " Idle: "; std::cout << " Idle: ";
for (int i = 0; i != 8; i++) for (int i = 0; i != 8; i++)
@ -834,7 +834,7 @@ template<>
void Record<ESM::CreatureLevList>::print() void Record<ESM::CreatureLevList>::print()
{ {
std::cout << " Chance for None: " << (int)mData.mChanceNone << std::endl; 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::cout << " Number of items: " << mData.mList.size() << std::endl;
std::vector<ESM::LeveledListBase::LevelItem>::iterator iit; std::vector<ESM::LeveledListBase::LevelItem>::iterator iit;
for (iit = mData.mList.begin(); iit != mData.mList.end(); iit++) for (iit = mData.mList.begin(); iit != mData.mList.end(); iit++)
@ -846,11 +846,11 @@ template<>
void Record<ESM::ItemLevList>::print() void Record<ESM::ItemLevList>::print()
{ {
std::cout << " Chance for None: " << (int)mData.mChanceNone << std::endl; 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::cout << " Number of items: " << mData.mList.size() << std::endl;
std::vector<ESM::LeveledListBase::LevelItem>::iterator iit; std::vector<ESM::LeveledListBase::LevelItem>::iterator iit;
for (iit = mData.mList.begin(); iit != mData.mList.end(); 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; << " Item: " << iit->mId << std::endl;
} }
@ -958,7 +958,7 @@ void Record<ESM::MagicEffect>::print()
std::cout << " RGB Color: " << "(" std::cout << " RGB Color: " << "("
<< mData.mData.mRed << "," << mData.mData.mRed << ","
<< mData.mData.mGreen << "," << mData.mData.mGreen << ","
<< mData.mData.mGreen << ")" << std::endl; << mData.mData.mBlue << ")" << std::endl;
} }
template<> template<>

@ -16,6 +16,7 @@
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software"); SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software");
SDL_SetMainReady();
if (SDL_Init(SDL_INIT_VIDEO) != 0) if (SDL_Init(SDL_INIT_VIDEO) != 0)
{ {
qDebug() << "SDL_Init failed: " << QString::fromStdString(SDL_GetError()); qDebug() << "SDL_Init failed: " << QString::fromStdString(SDL_GetError());

@ -235,7 +235,7 @@ namespace
{ {
for ( bfs::recursive_directory_iterator end, dir(in); dir != end; ++dir ) 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(); return dir->path();
} }
} }
@ -243,7 +243,7 @@ namespace
{ {
for ( bfs::directory_iterator end, dir(in); dir != end; ++dir ) 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(); return dir->path();
} }
} }
@ -255,7 +255,7 @@ namespace
{ {
for(bfs::directory_iterator end, dir(in); dir != end; ++dir) 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; return true;
} }

@ -623,6 +623,17 @@ MwIniImporter::MwIniImporter()
"Moons:Masser Fade Out Finish", "Moons:Masser Fade Out Finish",
"Moons:Script Color", "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 0
}; };

@ -38,7 +38,7 @@ opencs_units (model/tools
opencs_units_noqt (model/tools opencs_units_noqt (model/tools
mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck
birthsigncheck spellcheck birthsigncheck spellcheck referenceablecheck
) )

File diff suppressed because it is too large Load Diff

@ -0,0 +1,78 @@
#ifndef REFERENCEABLECHECKSTAGE_H
#define REFERENCEABLECHECKSTAGE_H
#include "../world/universalid.hpp"
#include "../doc/stage.hpp"
#include "../world/data.hpp"
#include "../world/refiddata.hpp"
namespace CSMTools
{
class ReferenceableCheckStage : public CSMDoc::Stage
{
public:
ReferenceableCheckStage(const CSMWorld::RefIdData& referenceable,
const CSMWorld::IdCollection<ESM::Race>& races,
const CSMWorld::IdCollection<ESM::Class>& classes,
const CSMWorld::IdCollection<ESM::Faction>& factions);
virtual void perform(int stage, std::vector< std::string >& messages);
virtual int setup();
private:
//CONCRETE CHECKS
void bookCheck(int stage, const CSMWorld::RefIdDataContainer< ESM::Book >& records, std::vector< std::string >& messages);
void activatorCheck(int stage, const CSMWorld::RefIdDataContainer< ESM::Activator >& records, std::vector< std::string >& messages);
void potionCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Potion>& records, std::vector<std::string>& messages);
void apparatusCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Apparatus>& records, std::vector<std::string>& messages);
void armorCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Armor>& records, std::vector<std::string>& messages);
void clothingCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Clothing>& records, std::vector<std::string>& messages);
void containerCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Container>& records, std::vector<std::string>& messages);
void creatureCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Creature>& records, std::vector<std::string>& messages);
void doorCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Door>& records, std::vector<std::string>& messages);
void ingredientCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Ingredient>& records, std::vector<std::string>& messages);
void creaturesLevListCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::CreatureLevList>& records, std::vector<std::string>& messages);
void itemLevelledListCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::ItemLevList>& records, std::vector<std::string>& messages);
void lightCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Light>& records, std::vector<std::string>& messages);
void lockpickCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Lockpick>& records, std::vector<std::string>& messages);
void miscCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Miscellaneous>& records, std::vector<std::string>& messages);
void npcCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::NPC>& records, std::vector<std::string>& messages);
void weaponCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Weapon>& records, std::vector<std::string>& messages);
void probeCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Probe>& records, std::vector<std::string>& messages);
void repairCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Repair>& records, std::vector<std::string>& messages);
void staticCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Static>& records, std::vector<std::string>& messages);
//FINAL CHECK
void finalCheck(std::vector<std::string>& messages);
//TEMPLATE CHECKS
template<typename ITEM> void inventoryItemCheck(const ITEM& someItem,
std::vector<std::string>& messages,
const std::string& someID,
bool enchantable); //for all enchantable items.
template<typename ITEM> void inventoryItemCheck(const ITEM& someItem,
std::vector<std::string>& messages,
const std::string& someID); //for non-enchantable items.
template<typename TOOL> void toolCheck(const TOOL& someTool,
std::vector<std::string>& messages,
const std::string& someID,
bool canbebroken); //for tools with uses.
template<typename TOOL> void toolCheck(const TOOL& someTool,
std::vector<std::string>& messages,
const std::string& someID); //for tools without uses.
template<typename LIST> void listCheck(const LIST& someList,
std::vector< std::string >& messages,
const std::string& someID);
const CSMWorld::RefIdData& mReferencables;
const CSMWorld::IdCollection<ESM::Race>& mRaces;
const CSMWorld::IdCollection<ESM::Class>& mClasses;
const CSMWorld::IdCollection<ESM::Faction>& mFactions;
bool mPlayerPresent;
};
}
#endif // REFERENCEABLECHECKSTAGE_H

@ -68,4 +68,4 @@ void CSMTools::ReportModel::add (const std::string& row)
const CSMWorld::UniversalId& CSMTools::ReportModel::getUniversalId (int row) const const CSMWorld::UniversalId& CSMTools::ReportModel::getUniversalId (int row) const
{ {
return mRows.at (row).first; return mRows.at (row).first;
} }

@ -19,6 +19,7 @@
#include "regioncheck.hpp" #include "regioncheck.hpp"
#include "birthsigncheck.hpp" #include "birthsigncheck.hpp"
#include "spellcheck.hpp" #include "spellcheck.hpp"
#include "referenceablecheck.hpp"
CSMDoc::Operation *CSMTools::Tools::get (int type) 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 BirthsignCheckStage (mData.getBirthsigns()));
mVerifier->appendStage (new SpellCheckStage (mData.getSpells())); mVerifier->appendStage (new SpellCheckStage (mData.getSpells()));
mVerifier->appendStage (new ReferenceableCheckStage (mData.getReferenceables().getDataSet(), mData.getRaces(), mData.getClasses(), mData.getFactions()));
} }
return mVerifier; return mVerifier;
@ -138,4 +141,5 @@ void CSMTools::Tools::verifierMessage (const QString& message, int type)
if (iter!=mActiveReports.end()) if (iter!=mActiveReports.end())
mReports[iter->second]->add (message.toStdString()); 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); std::string name2 = Misc::StringUtils::lowerCase (name);
for (int i=0; sNames[i].mName; ++i) 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 sNames[i].mId;
return -1; return -1;

@ -67,7 +67,7 @@ int CSMWorld::InfoCollection::getIndex (const std::string& id, const std::string
std::pair<RecordConstIterator, RecordConstIterator> range = getTopicRange (topic); std::pair<RecordConstIterator, RecordConstIterator> range = getTopicRange (topic);
for (; range.first!=range.second; ++range.first) 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 std::distance (getRecords().begin(), range.first);
return -1; return -1;
@ -177,8 +177,8 @@ CSMWorld::InfoCollection::Range CSMWorld::InfoCollection::getTopicRange (const s
RecordConstIterator end = begin; RecordConstIterator end = begin;
for (; end!=getRecords().end(); ++end) for (; end!=getRecords().end(); ++end)
if (Misc::StringUtils::lowerCase (end->get().mTopicId)!=topic2) if (!Misc::StringUtils::ciEqual(end->get().mTopicId, topic2))
break; break;
return Range (begin, end); return Range (begin, end);
} }

@ -181,7 +181,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
unsigned int mFlag; unsigned int mFlag;
} sCreatureFlagTable[] = } sCreatureFlagTable[] =
{ {
{ Columns::ColumnId_Biped, ESM::Creature::Biped }, { Columns::ColumnId_Biped, ESM::Creature::Bipedal },
{ Columns::ColumnId_HasWeapon, ESM::Creature::Weapon }, { Columns::ColumnId_HasWeapon, ESM::Creature::Weapon },
{ Columns::ColumnId_NoMovement, ESM::Creature::None }, { Columns::ColumnId_NoMovement, ESM::Creature::None },
{ Columns::ColumnId_Swims, ESM::Creature::Swims }, { Columns::ColumnId_Swims, ESM::Creature::Swims },
@ -549,3 +549,9 @@ void CSMWorld::RefIdCollection::save (int index, ESM::ESMWriter& writer) const
{ {
mData.save (index, writer); mData.save (index, writer);
} }
const CSMWorld::RefIdData& CSMWorld::RefIdCollection::getDataSet() const
{
return mData;
}

@ -107,7 +107,10 @@ namespace CSMWorld
/// \return Success? /// \return Success?
void save (int index, ESM::ESMWriter& writer) const; void save (int index, ESM::ESMWriter& writer) const;
const RefIdData& getDataSet() const; //I can't figure out a better name for this one :(
}; };
} }
#endif #endif

@ -230,4 +230,104 @@ void CSMWorld::RefIdData::save (int index, ESM::ESMWriter& writer) const
throw std::logic_error ("invalid local index type"); throw std::logic_error ("invalid local index type");
iter->second->save (localIndex.first, writer); 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;
} }

@ -214,7 +214,33 @@ namespace CSMWorld
/// \param listDeleted include deleted record in the list /// \param listDeleted include deleted record in the list
void save (int index, ESM::ESMWriter& writer) const; 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 #endif

@ -19,8 +19,8 @@ source_group(game FILES ${GAME} ${GAME_HEADER})
add_openmw_dir (mwrender add_openmw_dir (mwrender
renderingmanager debugging sky camera animation npcanimation creatureanimation activatoranimation renderingmanager debugging sky camera animation npcanimation creatureanimation activatoranimation
actors objects renderinginterface localmap occlusionquery water shadows actors objects renderinginterface localmap occlusionquery water shadows
characterpreview externalrendering globalmap videoplayer ripplesimulation refraction characterpreview globalmap videoplayer ripplesimulation refraction
terrainstorage renderconst terrainstorage renderconst effectmanager
) )
add_openmw_dir (mwinput add_openmw_dir (mwinput
@ -74,7 +74,7 @@ add_openmw_dir (mwmechanics
mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects
drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow
aiescort aiactivate aicombat repair enchanting pathfinding security spellsuccess spellcasting aiescort aiactivate aicombat repair enchanting pathfinding security spellsuccess spellcasting
disease disease pickpocket levelledlist
) )
add_openmw_dir (mwstate add_openmw_dir (mwstate

@ -6,6 +6,7 @@
#include <sys/wait.h> #include <sys/wait.h>
#include <sys/param.h> #include <sys/param.h>
#include <sys/ucontext.h> #include <sys/ucontext.h>
#include <sys/utsname.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <limits.h> #include <limits.h>
@ -42,78 +43,78 @@ static char altstack[SIGSTKSZ];
static struct { static struct {
int signum; int signum;
pid_t pid; pid_t pid;
int has_siginfo; int has_siginfo;
siginfo_t siginfo; siginfo_t siginfo;
char buf[1024]; char buf[1024];
} crash_info; } crash_info;
static const struct { static const struct {
const char *name; const char *name;
int signum; int signum;
} signals[] = { } signals[] = {
{ "Segmentation fault", SIGSEGV }, { "Segmentation fault", SIGSEGV },
{ "Illegal instruction", SIGILL }, { "Illegal instruction", SIGILL },
{ "FPU exception", SIGFPE }, { "FPU exception", SIGFPE },
{ "System BUS error", SIGBUS }, { "System BUS error", SIGBUS },
{ NULL, 0 } { NULL, 0 }
}; };
static const struct { static const struct {
int code; int code;
const char *name; const char *name;
} sigill_codes[] = { } sigill_codes[] = {
#ifndef __FreeBSD__ #ifndef __FreeBSD__
{ ILL_ILLOPC, "Illegal opcode" }, { ILL_ILLOPC, "Illegal opcode" },
{ ILL_ILLOPN, "Illegal operand" }, { ILL_ILLOPN, "Illegal operand" },
{ ILL_ILLADR, "Illegal addressing mode" }, { ILL_ILLADR, "Illegal addressing mode" },
{ ILL_ILLTRP, "Illegal trap" }, { ILL_ILLTRP, "Illegal trap" },
{ ILL_PRVOPC, "Privileged opcode" }, { ILL_PRVOPC, "Privileged opcode" },
{ ILL_PRVREG, "Privileged register" }, { ILL_PRVREG, "Privileged register" },
{ ILL_COPROC, "Coprocessor error" }, { ILL_COPROC, "Coprocessor error" },
{ ILL_BADSTK, "Internal stack error" }, { ILL_BADSTK, "Internal stack error" },
#endif #endif
{ 0, NULL } { 0, NULL }
}; };
static const struct { static const struct {
int code; int code;
const char *name; const char *name;
} sigfpe_codes[] = { } sigfpe_codes[] = {
{ FPE_INTDIV, "Integer divide by zero" }, { FPE_INTDIV, "Integer divide by zero" },
{ FPE_INTOVF, "Integer overflow" }, { FPE_INTOVF, "Integer overflow" },
{ FPE_FLTDIV, "Floating point divide by zero" }, { FPE_FLTDIV, "Floating point divide by zero" },
{ FPE_FLTOVF, "Floating point overflow" }, { FPE_FLTOVF, "Floating point overflow" },
{ FPE_FLTUND, "Floating point underflow" }, { FPE_FLTUND, "Floating point underflow" },
{ FPE_FLTRES, "Floating point inexact result" }, { FPE_FLTRES, "Floating point inexact result" },
{ FPE_FLTINV, "Floating point invalid operation" }, { FPE_FLTINV, "Floating point invalid operation" },
{ FPE_FLTSUB, "Subscript out of range" }, { FPE_FLTSUB, "Subscript out of range" },
{ 0, NULL } { 0, NULL }
}; };
static const struct { static const struct {
int code; int code;
const char *name; const char *name;
} sigsegv_codes[] = { } sigsegv_codes[] = {
#ifndef __FreeBSD__ #ifndef __FreeBSD__
{ SEGV_MAPERR, "Address not mapped to object" }, { SEGV_MAPERR, "Address not mapped to object" },
{ SEGV_ACCERR, "Invalid permissions for mapped object" }, { SEGV_ACCERR, "Invalid permissions for mapped object" },
#endif #endif
{ 0, NULL } { 0, NULL }
}; };
static const struct { static const struct {
int code; int code;
const char *name; const char *name;
} sigbus_codes[] = { } sigbus_codes[] = {
#ifndef __FreeBSD__ #ifndef __FreeBSD__
{ BUS_ADRALN, "Invalid address alignment" }, { BUS_ADRALN, "Invalid address alignment" },
{ BUS_ADRERR, "Non-existent physical address" }, { BUS_ADRERR, "Non-existent physical address" },
{ BUS_OBJERR, "Object specific hardware error" }, { BUS_OBJERR, "Object specific hardware error" },
#endif #endif
{ 0, NULL } { 0, NULL }
}; };
static int (*cc_user_info)(char*, char*); static int (*cc_user_info)(char*, char*);
@ -121,314 +122,318 @@ static int (*cc_user_info)(char*, char*);
static void gdb_info(pid_t pid) static void gdb_info(pid_t pid)
{ {
char respfile[64]; char respfile[64];
char cmd_buf[128]; char cmd_buf[128];
FILE *f; FILE *f;
int fd; int fd;
/* Create a temp file to put gdb commands into */ /* Create a temp file to put gdb commands into */
strcpy(respfile, "gdb-respfile-XXXXXX"); strcpy(respfile, "gdb-respfile-XXXXXX");
if((fd=mkstemp(respfile)) >= 0 && (f=fdopen(fd, "w")) != NULL) if((fd=mkstemp(respfile)) >= 0 && (f=fdopen(fd, "w")) != NULL)
{ {
fprintf(f, "attach %d\n" fprintf(f, "attach %d\n"
"shell echo \"\"\n" "shell echo \"\"\n"
"shell echo \"* Loaded Libraries\"\n" "shell echo \"* Loaded Libraries\"\n"
"info sharedlibrary\n" "info sharedlibrary\n"
"shell echo \"\"\n" "shell echo \"\"\n"
"shell echo \"* Threads\"\n" "shell echo \"* Threads\"\n"
"info threads\n" "info threads\n"
"shell echo \"\"\n" "shell echo \"\"\n"
"shell echo \"* FPU Status\"\n" "shell echo \"* FPU Status\"\n"
"info float\n" "info float\n"
"shell echo \"\"\n" "shell echo \"\"\n"
"shell echo \"* Registers\"\n" "shell echo \"* Registers\"\n"
"info registers\n" "info registers\n"
"shell echo \"\"\n" "shell echo \"\"\n"
"shell echo \"* Backtrace\"\n" "shell echo \"* Backtrace\"\n"
"thread apply all backtrace full\n" "thread apply all backtrace full\n"
"detach\n" "detach\n"
"quit\n", pid); "quit\n", pid);
fclose(f); fclose(f);
/* Run gdb and print process info. */ /* Run gdb and print process info. */
snprintf(cmd_buf, sizeof(cmd_buf), "gdb --quiet --batch --command=%s", respfile); snprintf(cmd_buf, sizeof(cmd_buf), "gdb --quiet --batch --command=%s", respfile);
printf("Executing: %s\n", cmd_buf); printf("Executing: %s\n", cmd_buf);
fflush(stdout); fflush(stdout);
system(cmd_buf); system(cmd_buf);
/* Clean up */ /* Clean up */
remove(respfile); remove(respfile);
} }
else else
{ {
/* Error creating temp file */ /* Error creating temp file */
if(fd >= 0) if(fd >= 0)
{ {
close(fd); close(fd);
remove(respfile); remove(respfile);
} }
printf("!!! Could not create gdb command file\n"); printf("!!! Could not create gdb command file\n");
} }
fflush(stdout); fflush(stdout);
} }
static void sys_info(void) static void sys_info(void)
{ {
#ifdef __unix__ #ifdef __unix__
system("echo \"System: `uname -a`\""); struct utsname info;
putchar('\n'); if(uname(&info))
fflush(stdout); printf("!!! Failed to get system information\n");
else
printf("System: %s %s %s %s %s\n",
info.sysname, info.nodename, info.release, info.version, info.machine);
fflush(stdout);
#endif #endif
} }
static size_t safe_write(int fd, const void *buf, size_t len) static size_t safe_write(int fd, const void *buf, size_t len)
{ {
size_t ret = 0; size_t ret = 0;
while(ret < len) while(ret < len)
{ {
ssize_t rem; ssize_t rem;
if((rem=write(fd, (const char*)buf+ret, len-ret)) == -1) if((rem=write(fd, (const char*)buf+ret, len-ret)) == -1)
{ {
if(errno == EINTR) if(errno == EINTR)
continue; continue;
break; break;
} }
ret += rem; ret += rem;
} }
return ret; return ret;
} }
static void crash_catcher(int signum, siginfo_t *siginfo, void *context) static void crash_catcher(int signum, siginfo_t *siginfo, void *context)
{ {
//ucontext_t *ucontext = (ucontext_t*)context; //ucontext_t *ucontext = (ucontext_t*)context;
pid_t dbg_pid; pid_t dbg_pid;
int fd[2]; int fd[2];
/* Make sure the effective uid is the real uid */ /* Make sure the effective uid is the real uid */
if(getuid() != geteuid()) if(getuid() != geteuid())
{ {
raise(signum); raise(signum);
return; return;
} }
safe_write(STDERR_FILENO, fatal_err, sizeof(fatal_err)-1); safe_write(STDERR_FILENO, fatal_err, sizeof(fatal_err)-1);
if(pipe(fd) == -1) if(pipe(fd) == -1)
{ {
safe_write(STDERR_FILENO, pipe_err, sizeof(pipe_err)-1); safe_write(STDERR_FILENO, pipe_err, sizeof(pipe_err)-1);
raise(signum); raise(signum);
return; return;
} }
crash_info.signum = signum; crash_info.signum = signum;
crash_info.pid = getpid(); crash_info.pid = getpid();
crash_info.has_siginfo = !!siginfo; crash_info.has_siginfo = !!siginfo;
if(siginfo) if(siginfo)
crash_info.siginfo = *siginfo; crash_info.siginfo = *siginfo;
if(cc_user_info) if(cc_user_info)
cc_user_info(crash_info.buf, crash_info.buf+sizeof(crash_info.buf)); cc_user_info(crash_info.buf, crash_info.buf+sizeof(crash_info.buf));
/* Fork off to start a crash handler */ /* Fork off to start a crash handler */
switch((dbg_pid=fork())) switch((dbg_pid=fork()))
{ {
/* Error */ /* Error */
case -1: case -1:
safe_write(STDERR_FILENO, fork_err, sizeof(fork_err)-1); safe_write(STDERR_FILENO, fork_err, sizeof(fork_err)-1);
raise(signum); raise(signum);
return; return;
case 0: case 0:
dup2(fd[0], STDIN_FILENO); dup2(fd[0], STDIN_FILENO);
close(fd[0]); close(fd[0]);
close(fd[1]); close(fd[1]);
execl(argv0, argv0, crash_switch, NULL); execl(argv0, argv0, crash_switch, NULL);
safe_write(STDERR_FILENO, exec_err, sizeof(exec_err)-1); safe_write(STDERR_FILENO, exec_err, sizeof(exec_err)-1);
_exit(1); _exit(1);
default: default:
#ifdef __linux__ #ifdef __linux__
prctl(PR_SET_PTRACER, dbg_pid, 0, 0, 0); prctl(PR_SET_PTRACER, dbg_pid, 0, 0, 0);
#endif #endif
safe_write(fd[1], &crash_info, sizeof(crash_info)); safe_write(fd[1], &crash_info, sizeof(crash_info));
close(fd[0]); close(fd[0]);
close(fd[1]); close(fd[1]);
/* Wait; we'll be killed when gdb is done */ /* Wait; we'll be killed when gdb is done */
do { do {
int status; int status;
if(waitpid(dbg_pid, &status, 0) == dbg_pid && if(waitpid(dbg_pid, &status, 0) == dbg_pid &&
(WIFEXITED(status) || WIFSIGNALED(status))) (WIFEXITED(status) || WIFSIGNALED(status)))
{ {
/* The debug process died before it could kill us */ /* The debug process died before it could kill us */
raise(signum); raise(signum);
break; break;
} }
} while(1); } while(1);
} }
} }
static void crash_handler(const char *logfile) static void crash_handler(const char *logfile)
{ {
const char *sigdesc = ""; const char *sigdesc = "";
int i; int i;
if(fread(&crash_info, sizeof(crash_info), 1, stdin) != 1) if(fread(&crash_info, sizeof(crash_info), 1, stdin) != 1)
{ {
fprintf(stderr, "!!! Failed to retrieve info from crashed process\n"); fprintf(stderr, "!!! Failed to retrieve info from crashed process\n");
exit(1); exit(1);
} }
/* Get the signal description */ /* Get the signal description */
for(i = 0;signals[i].name;++i) for(i = 0;signals[i].name;++i)
{ {
if(signals[i].signum == crash_info.signum) if(signals[i].signum == crash_info.signum)
{ {
sigdesc = signals[i].name; sigdesc = signals[i].name;
break; break;
} }
} }
if(crash_info.has_siginfo) if(crash_info.has_siginfo)
{ {
switch(crash_info.signum) switch(crash_info.signum)
{ {
case SIGSEGV: case SIGSEGV:
for(i = 0;sigsegv_codes[i].name;++i) for(i = 0;sigsegv_codes[i].name;++i)
{ {
if(sigsegv_codes[i].code == crash_info.siginfo.si_code) if(sigsegv_codes[i].code == crash_info.siginfo.si_code)
{ {
sigdesc = sigsegv_codes[i].name; sigdesc = sigsegv_codes[i].name;
break; break;
} }
} }
break; break;
case SIGFPE: case SIGFPE:
for(i = 0;sigfpe_codes[i].name;++i) for(i = 0;sigfpe_codes[i].name;++i)
{ {
if(sigfpe_codes[i].code == crash_info.siginfo.si_code) if(sigfpe_codes[i].code == crash_info.siginfo.si_code)
{ {
sigdesc = sigfpe_codes[i].name; sigdesc = sigfpe_codes[i].name;
break; break;
} }
} }
break; break;
case SIGILL: case SIGILL:
for(i = 0;sigill_codes[i].name;++i) for(i = 0;sigill_codes[i].name;++i)
{ {
if(sigill_codes[i].code == crash_info.siginfo.si_code) if(sigill_codes[i].code == crash_info.siginfo.si_code)
{ {
sigdesc = sigill_codes[i].name; sigdesc = sigill_codes[i].name;
break; break;
} }
} }
break; break;
case SIGBUS: case SIGBUS:
for(i = 0;sigbus_codes[i].name;++i) for(i = 0;sigbus_codes[i].name;++i)
{ {
if(sigbus_codes[i].code == crash_info.siginfo.si_code) if(sigbus_codes[i].code == crash_info.siginfo.si_code)
{ {
sigdesc = sigbus_codes[i].name; sigdesc = sigbus_codes[i].name;
break; break;
} }
} }
break; break;
} }
} }
fprintf(stderr, "%s (signal %i)\n", sigdesc, crash_info.signum); fprintf(stderr, "%s (signal %i)\n", sigdesc, crash_info.signum);
if(crash_info.has_siginfo) if(crash_info.has_siginfo)
fprintf(stderr, "Address: %p\n", crash_info.siginfo.si_addr); fprintf(stderr, "Address: %p\n", crash_info.siginfo.si_addr);
fputc('\n', stderr); fputc('\n', stderr);
if(logfile) if(logfile)
{ {
/* Create crash log file and redirect shell output to it */ /* Create crash log file and redirect shell output to it */
if(freopen(logfile, "wa", stdout) != stdout) if(freopen(logfile, "wa", stdout) != stdout)
{ {
fprintf(stderr, "!!! Could not create %s following signal\n", logfile); fprintf(stderr, "!!! Could not create %s following signal\n", logfile);
exit(1); exit(1);
} }
fprintf(stderr, "Generating %s and killing process %d, please wait... ", logfile, crash_info.pid); fprintf(stderr, "Generating %s and killing process %d, please wait... ", logfile, crash_info.pid);
printf("*** Fatal Error ***\n" printf("*** Fatal Error ***\n"
"%s (signal %i)\n", sigdesc, crash_info.signum); "%s (signal %i)\n", sigdesc, crash_info.signum);
if(crash_info.has_siginfo) if(crash_info.has_siginfo)
printf("Address: %p\n", crash_info.siginfo.si_addr); printf("Address: %p\n", crash_info.siginfo.si_addr);
fputc('\n', stdout); fputc('\n', stdout);
fflush(stdout); fflush(stdout);
} }
sys_info(); sys_info();
crash_info.buf[sizeof(crash_info.buf)-1] = '\0'; crash_info.buf[sizeof(crash_info.buf)-1] = '\0';
printf("%s\n", crash_info.buf); printf("%s\n", crash_info.buf);
fflush(stdout); fflush(stdout);
if(crash_info.pid > 0) if(crash_info.pid > 0)
{ {
gdb_info(crash_info.pid); gdb_info(crash_info.pid);
kill(crash_info.pid, SIGKILL); kill(crash_info.pid, SIGKILL);
} }
if(logfile) if(logfile)
{ {
char cwd[MAXPATHLEN]; char cwd[MAXPATHLEN];
getcwd(cwd, MAXPATHLEN); getcwd(cwd, MAXPATHLEN);
std::string message = "OpenMW has encountered a fatal error.\nCrash log saved to '" + std::string(cwd) + "/" + std::string(logfile) + "'.\n Please report this to https://bugs.openmw.org !"; std::string message = "OpenMW has encountered a fatal error.\nCrash log saved to '" + std::string(cwd) + "/" + std::string(logfile) + "'.\n Please report this to https://bugs.openmw.org !";
SDL_ShowSimpleMessageBox(0, "Fatal Error", message.c_str(), NULL); SDL_ShowSimpleMessageBox(0, "Fatal Error", message.c_str(), NULL);
} }
exit(0); exit(0);
} }
int cc_install_handlers(int argc, char **argv, int num_signals, int *signals, const char *logfile, int (*user_info)(char*, char*)) int cc_install_handlers(int argc, char **argv, int num_signals, int *signals, const char *logfile, int (*user_info)(char*, char*))
{ {
struct sigaction sa; struct sigaction sa;
stack_t altss; stack_t altss;
int retval; int retval;
if(argc == 2 && strcmp(argv[1], crash_switch) == 0) if(argc == 2 && strcmp(argv[1], crash_switch) == 0)
crash_handler(logfile); crash_handler(logfile);
cc_user_info = user_info; cc_user_info = user_info;
if(argv[0][0] == '/') if(argv[0][0] == '/')
snprintf(argv0, sizeof(argv0), "%s", argv[0]); snprintf(argv0, sizeof(argv0), "%s", argv[0]);
else else
{ {
getcwd(argv0, sizeof(argv0)); getcwd(argv0, sizeof(argv0));
retval = strlen(argv0); retval = strlen(argv0);
snprintf(argv0+retval, sizeof(argv0)-retval, "/%s", argv[0]); snprintf(argv0+retval, sizeof(argv0)-retval, "/%s", argv[0]);
} }
/* Set an alternate signal stack so SIGSEGVs caused by stack overflows /* Set an alternate signal stack so SIGSEGVs caused by stack overflows
* still run */ * still run */
altss.ss_sp = altstack; altss.ss_sp = altstack;
altss.ss_flags = 0; altss.ss_flags = 0;
altss.ss_size = sizeof(altstack); altss.ss_size = sizeof(altstack);
sigaltstack(&altss, NULL); sigaltstack(&altss, NULL);
memset(&sa, 0, sizeof(sa)); memset(&sa, 0, sizeof(sa));
sa.sa_sigaction = crash_catcher; sa.sa_sigaction = crash_catcher;
sa.sa_flags = SA_RESETHAND | SA_NODEFER | SA_SIGINFO | SA_ONSTACK; sa.sa_flags = SA_RESETHAND | SA_NODEFER | SA_SIGINFO | SA_ONSTACK;
sigemptyset(&sa.sa_mask); sigemptyset(&sa.sa_mask);
retval = 0; retval = 0;
while(num_signals--) while(num_signals--)
{ {
if((*signals != SIGSEGV && *signals != SIGILL && *signals != SIGFPE && *signals != SIGABRT && if((*signals != SIGSEGV && *signals != SIGILL && *signals != SIGFPE && *signals != SIGABRT &&
*signals != SIGBUS) || sigaction(*signals, &sa, NULL) == -1) *signals != SIGBUS) || sigaction(*signals, &sa, NULL) == -1)
{ {
*signals = 0; *signals = 0;
retval = -1; retval = -1;
} }
++signals; ++signals;
} }
return retval; return retval;
} }

@ -172,6 +172,7 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager)
//kindly ask SDL not to trash our OGL context //kindly ask SDL not to trash our OGL context
//might this be related to http://bugzilla.libsdl.org/show_bug.cgi?id=748 ? //might this be related to http://bugzilla.libsdl.org/show_bug.cgi?id=748 ?
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software"); SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software");
SDL_SetMainReady();
if(SDL_Init(flags) != 0) if(SDL_Init(flags) != 0)
{ {
throw std::runtime_error("Could not initialize SDL! " + std::string(SDL_GetError())); throw std::runtime_error("Could not initialize SDL! " + std::string(SDL_GetError()));
@ -534,13 +535,13 @@ void OMW::Engine::activate()
MWScript::InterpreterContext interpreterContext (&ptr.getRefData().getLocals(), ptr); MWScript::InterpreterContext interpreterContext (&ptr.getRefData().getLocals(), ptr);
boost::shared_ptr<MWWorld::Action> action = boost::shared_ptr<MWWorld::Action> action =
MWWorld::Class::get (ptr).activate (ptr, MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); MWWorld::Class::get (ptr).activate (ptr, MWBase::Environment::get().getWorld()->getPlayerPtr());
interpreterContext.activate (ptr, action); interpreterContext.activate (ptr, action);
std::string script = MWWorld::Class::get (ptr).getScript (ptr); std::string script = MWWorld::Class::get (ptr).getScript (ptr);
MWBase::Environment::get().getWorld()->breakInvisibility(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); MWBase::Environment::get().getWorld()->breakInvisibility(MWBase::Environment::get().getWorld()->getPlayerPtr());
if (!script.empty()) if (!script.empty())
{ {

@ -11,6 +11,7 @@
#include <boost/iostreams/stream_buffer.hpp> #include <boost/iostreams/stream_buffer.hpp>
// For OutputDebugString // For OutputDebugString
#define WIN32_LEAN_AND_MEAN
#include <Windows.h> #include <Windows.h>
// makes __argc and __argv available on windows // makes __argc and __argv available on windows
#include <cstdlib> #include <cstdlib>

@ -51,7 +51,7 @@ namespace MWBase
virtual void persuade (int type) = 0; virtual void persuade (int type) = 0;
virtual int getTemporaryDispositionChange () const = 0; virtual int getTemporaryDispositionChange () const = 0;
virtual void applyTemporaryDispositionChange (int delta) = 0; virtual void applyDispositionChange (int delta) = 0;
}; };
} }

@ -76,8 +76,12 @@ namespace MWBase
virtual void setPlayerClass (const ESM::Class& class_) = 0; virtual void setPlayerClass (const ESM::Class& class_) = 0;
///< Set player class to custom class. ///< Set player class to custom class.
virtual void restoreDynamicStats() = 0; virtual void rest(bool sleep) = 0;
///< If the player is sleeping, this should be called every hour. ///< 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; 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. ///< This is used by every service to determine the price of objects given the trading skills of the player and NPC.
@ -88,6 +92,36 @@ namespace MWBase
virtual int countDeaths (const std::string& id) const = 0; virtual int countDeaths (const std::string& id) const = 0;
///< Return the number of deaths for actors with the given ID. ///< Return the number of deaths for actors with the given ID.
/// Check if \a observer is potentially aware of \a ptr. Does not do a line of sight check!
virtual bool awarenessCheck (const MWWorld::Ptr& ptr, const MWWorld::Ptr& observer) = 0;
enum OffenseType
{
OT_Theft, // Taking items owned by an NPC or a faction you are not a member of
OT_Assault, // Attacking a peaceful NPC
OT_Murder, // Murdering a peaceful NPC
OT_Trespassing, // Staying in a cell you are not allowed in (where is this defined?)
OT_SleepingInOwnedBed, // Sleeping in a bed owned by an NPC or a faction you are not a member of
OT_Pickpocket // Entering pickpocket mode, leaving it, and being detected. Any items stolen are a separate crime (Theft)
};
/**
* @brief Commit a crime. If any actors witness the crime and report it,
* reportCrime will be called automatically.
* @param arg Depends on \a type, e.g. for Theft, the value of the item that was stolen.
* @return was the crime reported?
*/
virtual bool commitCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim,
OffenseType type, int arg=0) = 0;
virtual void reportCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim,
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;
enum PersuasionType enum PersuasionType
{ {
PT_Admire, PT_Admire,

@ -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 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 staticMessageBox(const std::string& message) = 0;
virtual void removeStaticMessageBox() = 0; virtual void removeStaticMessageBox() = 0;
virtual void enterPressed () = 0;
virtual void activateKeyPressed () = 0;
virtual int readPressedButton() = 0; virtual int readPressedButton() = 0;
///< returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox) ///< returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox)

@ -42,7 +42,6 @@ namespace ESM
namespace MWRender namespace MWRender
{ {
class ExternalRendering;
class Animation; class Animation;
} }
@ -127,6 +126,7 @@ namespace MWBase
virtual const MWWorld::Fallback *getFallback () const = 0; virtual const MWWorld::Fallback *getFallback () const = 0;
virtual MWWorld::Player& getPlayer() = 0; virtual MWWorld::Player& getPlayer() = 0;
virtual MWWorld::Ptr getPlayerPtr() = 0;
virtual const MWWorld::ESMStore& getStore() const = 0; virtual const MWWorld::ESMStore& getStore() const = 0;
@ -181,6 +181,10 @@ namespace MWBase
///< Return a pointer to a liveCellRef with the given name. ///< Return a pointer to a liveCellRef with the given name.
/// \param activeOnly do non search inactive cells. /// \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; virtual MWWorld::Ptr getPtrViaHandle (const std::string& handle) = 0;
///< Return a pointer to a liveCellRef with the given Ogre handle. ///< Return a pointer to a liveCellRef with the given Ogre handle.
@ -396,8 +400,6 @@ namespace MWBase
virtual void enableActorCollision(const MWWorld::Ptr& actor, bool enable) = 0; virtual void enableActorCollision(const MWWorld::Ptr& actor, bool enable) = 0;
virtual void setupExternalRendering (MWRender::ExternalRendering& rendering) = 0;
virtual int canRest() = 0; virtual int canRest() = 0;
///< check if the player is allowed to rest \n ///< check if the player is allowed to rest \n
/// 0 - yes \n /// 0 - yes \n
@ -466,11 +468,10 @@ namespace MWBase
virtual bool findInteriorPositionInWorldSpace(MWWorld::CellStore* cell, Ogre::Vector3& result) = 0; virtual bool findInteriorPositionInWorldSpace(MWWorld::CellStore* cell, Ogre::Vector3& result) = 0;
/// Teleports \a ptr to the reference of \a id (e.g. DivineMarker, PrisonMarker, TempleMarker) /// Teleports \a ptr to the closest reference of \a id (e.g. DivineMarker, PrisonMarker, TempleMarker)
/// closest to \a worldPos.
/// @note id must be lower case /// @note id must be lower case
virtual void teleportToClosestMarker (const MWWorld::Ptr& ptr, virtual void teleportToClosestMarker (const MWWorld::Ptr& ptr,
const std::string& id, Ogre::Vector3 worldPos) = 0; const std::string& id) = 0;
enum DetectionType enum DetectionType
{ {
@ -483,6 +484,21 @@ namespace MWBase
/// @note This also works for references in containers. /// @note This also works for references in containers.
virtual void listDetectedReferences (const MWWorld::Ptr& ptr, std::vector<MWWorld::Ptr>& out, virtual void listDetectedReferences (const MWWorld::Ptr& ptr, std::vector<MWWorld::Ptr>& out,
DetectionType type) = 0; DetectionType type) = 0;
/// 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;
}; };
} }

@ -96,7 +96,11 @@ namespace MWClass
std::string text; std::string text;
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) if (MWBase::Environment::get().getWindowManager()->getFullHelp())
{
text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner");
text += MWGui::ToolTips::getMiscString(ref->mRef.mFaction, "Faction");
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
}
info.text = text; info.text = text;
return info; return info;

@ -128,6 +128,7 @@ namespace MWClass
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner");
text += MWGui::ToolTips::getMiscString(ref->mRef.mFaction, "Faction");
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
} }
info.text = text; info.text = text;

@ -17,7 +17,6 @@
#include "../mwworld/physicssystem.hpp" #include "../mwworld/physicssystem.hpp"
#include "../mwworld/nullaction.hpp" #include "../mwworld/nullaction.hpp"
#include "../mwworld/containerstore.hpp" #include "../mwworld/containerstore.hpp"
#include "../mwworld/player.hpp"
#include "../mwrender/objects.hpp" #include "../mwrender/objects.hpp"
#include "../mwrender/renderinginterface.hpp" #include "../mwrender/renderinginterface.hpp"
@ -252,6 +251,7 @@ namespace MWClass
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner");
text += MWGui::ToolTips::getMiscString(ref->mRef.mFaction, "Faction");
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
} }

@ -140,6 +140,7 @@ namespace MWClass
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner");
text += MWGui::ToolTips::getMiscString(ref->mRef.mFaction, "Faction");
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
} }

@ -14,7 +14,6 @@
#include "../mwworld/cellstore.hpp" #include "../mwworld/cellstore.hpp"
#include "../mwworld/physicssystem.hpp" #include "../mwworld/physicssystem.hpp"
#include "../mwworld/nullaction.hpp" #include "../mwworld/nullaction.hpp"
#include "../mwworld/player.hpp"
#include "../mwgui/tooltips.hpp" #include "../mwgui/tooltips.hpp"
@ -195,6 +194,7 @@ namespace MWClass
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner");
text += MWGui::ToolTips::getMiscString(ref->mRef.mFaction, "Faction");
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
} }

@ -16,7 +16,6 @@
#include "../mwworld/actionopen.hpp" #include "../mwworld/actionopen.hpp"
#include "../mwworld/actiontrap.hpp" #include "../mwworld/actiontrap.hpp"
#include "../mwworld/physicssystem.hpp" #include "../mwworld/physicssystem.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/inventorystore.hpp" #include "../mwworld/inventorystore.hpp"
#include "../mwgui/tooltips.hpp" #include "../mwgui/tooltips.hpp"
@ -53,7 +52,7 @@ namespace MWClass
ptr.get<ESM::Container>(); ptr.get<ESM::Container>();
data->mContainerStore.fill( data->mContainerStore.fill(
ref->mBase->mInventory, ptr.getCellRef().mOwner, MWBase::Environment::get().getWorld()->getStore()); ref->mBase->mInventory, ptr.getCellRef().mOwner, ptr.getCellRef().mFaction, MWBase::Environment::get().getWorld()->getStore());
// store // store
ptr.getRefData().setCustomData (data.release()); ptr.getRefData().setCustomData (data.release());
@ -108,7 +107,7 @@ namespace MWClass
const std::string lockedSound = "LockedChest"; const std::string lockedSound = "LockedChest";
const std::string trapActivationSound = "Disarm Trap Fail"; const std::string trapActivationSound = "Disarm Trap Fail";
MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayer().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr();
MWWorld::InventoryStore& invStore = MWWorld::Class::get(player).getInventoryStore(player); MWWorld::InventoryStore& invStore = MWWorld::Class::get(player).getInventoryStore(player);
bool needKey = ptr.getCellRef().mLockLevel>0; bool needKey = ptr.getCellRef().mLockLevel>0;
@ -216,6 +215,7 @@ namespace MWClass
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner");
text += MWGui::ToolTips::getMiscString(ref->mRef.mFaction, "Faction");
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
} }

@ -61,6 +61,17 @@ namespace MWClass
fMinWalkSpeedCreature = gmst.find("fMinWalkSpeedCreature"); fMinWalkSpeedCreature = gmst.find("fMinWalkSpeedCreature");
fMaxWalkSpeedCreature = gmst.find("fMaxWalkSpeedCreature"); 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; inited = true;
} }
@ -95,10 +106,12 @@ namespace MWClass
data->mCreatureStats.getSpells().add (*iter); data->mCreatureStats.getSpells().add (*iter);
// inventory // inventory
data->mContainerStore.fill(ref->mBase->mInventory, getId(ptr), data->mContainerStore.fill(ref->mBase->mInventory, getId(ptr), "",
MWBase::Environment::get().getWorld()->getStore()); MWBase::Environment::get().getWorld()->getStore());
data->mContainerStore.add("gold_001", ref->mBase->mData.mGold, ptr); // TODO: this is not quite correct, in vanilla the merchant's gold pool is not available in his inventory.
// (except for gold you gave him)
data->mContainerStore.add(MWWorld::ContainerStore::sGoldId, ref->mBase->mData.mGold, ptr);
// store // store
ptr.getRefData().setCustomData (data.release()); ptr.getRefData().setCustomData (data.release());
@ -163,6 +176,62 @@ namespace MWClass
void Creature::hit(const MWWorld::Ptr& ptr, int type) const 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 void Creature::onHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, bool successful) const
@ -189,6 +258,19 @@ namespace MWClass
ptr.getRefData().getLocals().setVarByInt(script, "onpchitme", 1); 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(ishealth)
{ {
if(damage > 0.0f) if(damage > 0.0f)
@ -284,10 +366,51 @@ namespace MWClass
float Creature::getSpeed(const MWWorld::Ptr &ptr) const float Creature::getSpeed(const MWWorld::Ptr &ptr) const
{ {
MWMechanics::CreatureStats& stats = getCreatureStats(ptr); MWMechanics::CreatureStats& stats = getCreatureStats(ptr);
float walkSpeed = fMinWalkSpeedCreature->getFloat() + 0.01 * stats.getAttribute(ESM::Attribute::Speed).getModified() float walkSpeed = fMinWalkSpeedCreature->getFloat() + 0.01 * stats.getAttribute(ESM::Attribute::Speed).getModified()
* (fMaxWalkSpeedCreature->getFloat() - fMinWalkSpeedCreature->getFloat()); * (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 MWMechanics::Movement& Creature::getMovementSettings (const MWWorld::Ptr& ptr) const
@ -459,6 +582,49 @@ namespace MWClass
throw std::runtime_error(std::string("Unexpected soundgen type: ")+name); 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::fMinWalkSpeedCreature;
const ESM::GameSetting* Creature::fMaxWalkSpeedCreature; 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 *fMinWalkSpeedCreature;
static const ESM::GameSetting *fMaxWalkSpeedCreature; 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: public:
@ -101,6 +113,11 @@ namespace MWClass
} }
virtual bool isFlying (const MWWorld::Ptr &ptr) const; 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;
}; };
} }

@ -8,7 +8,6 @@
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwbase/soundmanager.hpp" #include "../mwbase/soundmanager.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/ptr.hpp" #include "../mwworld/ptr.hpp"
#include "../mwworld/nullaction.hpp" #include "../mwworld/nullaction.hpp"
#include "../mwworld/failedaction.hpp" #include "../mwworld/failedaction.hpp"
@ -97,7 +96,7 @@ namespace MWClass
if (needKey && hasKey) if (needKey && hasKey)
{ {
if(actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer()) if(actor == MWBase::Environment::get().getWorld()->getPlayerPtr())
MWBase::Environment::get().getWindowManager()->messageBox(keyName + " #{sKeyUsed}"); MWBase::Environment::get().getWindowManager()->messageBox(keyName + " #{sKeyUsed}");
ptr.getCellRef().mLockLevel = 0; ptr.getCellRef().mLockLevel = 0;
// using a key disarms the trap // using a key disarms the trap
@ -118,7 +117,7 @@ namespace MWClass
{ {
// teleport door // teleport door
/// \todo remove this if clause once ActionTeleport can also support other actors /// \todo remove this if clause once ActionTeleport can also support other actors
if (MWBase::Environment::get().getWorld()->getPlayer().getPlayer()==actor) if (MWBase::Environment::get().getWorld()->getPlayerPtr()==actor)
{ {
boost::shared_ptr<MWWorld::Action> action(new MWWorld::ActionTeleport (ref->mRef.mDestCell, ref->mRef.mDoorDest)); boost::shared_ptr<MWWorld::Action> action(new MWWorld::ActionTeleport (ref->mRef.mDestCell, ref->mRef.mDoorDest));

@ -12,7 +12,6 @@
#include "../mwworld/cellstore.hpp" #include "../mwworld/cellstore.hpp"
#include "../mwworld/physicssystem.hpp" #include "../mwworld/physicssystem.hpp"
#include "../mwworld/actioneat.hpp" #include "../mwworld/actioneat.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/nullaction.hpp" #include "../mwworld/nullaction.hpp"
#include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/npcstats.hpp"
@ -149,10 +148,11 @@ namespace MWClass
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner");
text += MWGui::ToolTips::getMiscString(ref->mRef.mFaction, "Faction");
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
} }
MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr();
MWMechanics::NpcStats& npcStats = MWWorld::Class::get(player).getNpcStats (player); MWMechanics::NpcStats& npcStats = MWWorld::Class::get(player).getNpcStats (player);
int alchemySkill = npcStats.getSkill (ESM::Skill::Alchemy).getBase(); int alchemySkill = npcStats.getSkill (ESM::Skill::Alchemy).getBase();

@ -187,6 +187,7 @@ namespace MWClass
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner");
text += MWGui::ToolTips::getMiscString(ref->mRef.mFaction, "Faction");
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
} }

@ -145,6 +145,7 @@ namespace MWClass
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner");
text += MWGui::ToolTips::getMiscString(ref->mRef.mFaction, "Faction");
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
} }

@ -93,7 +93,9 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Miscellaneous> *ref = MWWorld::LiveCellRef<ESM::Miscellaneous> *ref =
ptr.get<ESM::Miscellaneous>(); ptr.get<ESM::Miscellaneous>();
int value = (ptr.getCellRef().mGoldValue == 1) ? ref->mBase->mData.mValue : ptr.getCellRef().mGoldValue; int value = ref->mBase->mData.mValue;
if (ptr.getCellRef().mGoldValue > 1 && ptr.getRefData().getCount() == 1)
value = ptr.getCellRef().mGoldValue;
if (ptr.getCellRef().mSoul != "") if (ptr.getCellRef().mSoul != "")
{ {
@ -184,6 +186,7 @@ namespace MWClass
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner");
text += MWGui::ToolTips::getMiscString(ref->mRef.mFaction, "Faction");
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
} }

@ -3,8 +3,6 @@
#include <memory> #include <memory>
#include <boost/algorithm/string.hpp>
#include <OgreSceneNode.h> #include <OgreSceneNode.h>
#include <components/esm/loadmgef.hpp> #include <components/esm/loadmgef.hpp>
@ -242,6 +240,9 @@ namespace MWClass
fJumpAcroMultiplier = gmst.find("fJumpAcroMultiplier"); fJumpAcroMultiplier = gmst.find("fJumpAcroMultiplier");
fJumpRunMultiplier = gmst.find("fJumpRunMultiplier"); fJumpRunMultiplier = gmst.find("fJumpRunMultiplier");
fWereWolfRunMult = gmst.find("fWereWolfRunMult"); fWereWolfRunMult = gmst.find("fWereWolfRunMult");
fKnockDownMult = gmst.find("fKnockDownMult");
iKnockDownOddsMult = gmst.find("iKnockDownOddsMult");
iKnockDownOddsBase = gmst.find("iKnockDownOddsBase");
inited = true; inited = true;
} }
@ -307,6 +308,17 @@ namespace MWClass
autoCalculateSkills(ref->mBase, data->mNpcStats); 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.getAiSequence().fill(ref->mBase->mAiPackage);
data->mNpcStats.setAiSetting (MWMechanics::CreatureStats::AI_Hello, ref->mBase->mAiData.mHello); data->mNpcStats.setAiSetting (MWMechanics::CreatureStats::AI_Hello, ref->mBase->mAiData.mHello);
@ -320,13 +332,15 @@ namespace MWClass
data->mNpcStats.getSpells().add (*iter); data->mNpcStats.getSpells().add (*iter);
// inventory // inventory
data->mInventoryStore.fill(ref->mBase->mInventory, getId(ptr), data->mInventoryStore.fill(ref->mBase->mInventory, getId(ptr), "",
MWBase::Environment::get().getWorld()->getStore()); MWBase::Environment::get().getWorld()->getStore());
// store // store
ptr.getRefData().setCustomData (data.release()); ptr.getRefData().setCustomData (data.release());
getContainerStore(ptr).add("gold_001", gold, ptr); // TODO: this is not quite correct, in vanilla the merchant's gold pool is not available in his inventory.
// (except for gold you gave him)
getContainerStore(ptr).add(MWWorld::ContainerStore::sGoldId, gold, ptr);
getInventoryStore(ptr).autoEquip(ptr); getInventoryStore(ptr).autoEquip(ptr);
} }
@ -423,11 +437,27 @@ namespace MWClass
if(!weapon.isEmpty() && weapon.getTypeName() != typeid(ESM::Weapon).name()) if(!weapon.isEmpty() && weapon.getTypeName() != typeid(ESM::Weapon).name())
weapon = MWWorld::Ptr(); 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() ? float dist = 100.0f * (!weapon.isEmpty() ?
weapon.get<ESM::Weapon>()->mBase->mData.mReach : weapon.get<ESM::Weapon>()->mBase->mData.mReach :
gmst.find("fHandToHandReach")->getFloat()); gmst.find("fHandToHandReach")->getFloat());
// TODO: Use second to work out the hit angle and where to spawn the blood effect // TODO: Use second to work out the hit angle
MWWorld::Ptr victim = world->getHitContact(ptr, dist).first; 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 if(victim.isEmpty()) // Didn't hit anything
return; return;
@ -484,12 +514,6 @@ namespace MWClass
weapon.getCellRef().mCharge = weapmaxhealth; weapon.getCellRef().mCharge = weapmaxhealth;
damage *= float(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()) if (!MWBase::Environment::get().getWorld()->getGodModeState())
weapon.getCellRef().mCharge -= std::min(std::max(1, weapon.getCellRef().mCharge -= std::min(std::max(1,
@ -511,12 +535,6 @@ namespace MWClass
float maxstrike = gmst.find("fMaxHandToHandMult")->getFloat(); float maxstrike = gmst.find("fMaxHandToHandMult")->getFloat();
damage = stats.getSkill(weapskill).getModified(); damage = stats.getSkill(weapskill).getModified();
damage *= minstrike + ((maxstrike-minstrike)*stats.getAttackStrength()); 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) healthdmg = (otherstats.getFatigue().getCurrent() < 1.0f)
|| (otherstats.getMagicEffects().get(ESM::MagicEffect::Paralyze).mMagnitude > 0); || (otherstats.getMagicEffects().get(ESM::MagicEffect::Paralyze).mMagnitude > 0);
@ -543,6 +561,16 @@ namespace MWClass
if(ptr.getRefData().getHandle() == "player") if(ptr.getRefData().getHandle() == "player")
skillUsageSucceeded(ptr, weapskill, 0); 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 // Apply "On hit" enchanted weapons
std::string enchantmentName = !weapon.isEmpty() ? weapon.getClass().getEnchantment(weapon) : ""; std::string enchantmentName = !weapon.isEmpty() ? weapon.getClass().getEnchantment(weapon) : "";
if (!enchantmentName.empty()) if (!enchantmentName.empty())
@ -576,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); othercls.onHit(victim, damage, healthdmg, weapon, ptr, true);
} }
@ -585,6 +617,10 @@ namespace MWClass
// NOTE: 'object' and/or 'attacker' may be empty. // 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) if(!successful)
{ {
// TODO: Handle HitAttemptOnMe script function // TODO: Handle HitAttemptOnMe script function
@ -599,7 +635,7 @@ namespace MWClass
if(!attacker.isEmpty() && attacker.getRefData().getHandle() == "player") 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. */ /* Set the OnPCHitMe script variable. The script is responsible for clearing it. */
if(!script.empty()) if(!script.empty())
ptr.getRefData().getLocals().setVarByInt(script, "onpchitme", 1); ptr.getRefData().getLocals().setVarByInt(script, "onpchitme", 1);
@ -613,7 +649,27 @@ namespace MWClass
// 'ptr' is losing health. Play a 'hit' voiced dialog entry if not already saying // 'ptr' is losing health. Play a 'hit' voiced dialog entry if not already saying
// something, alert the character controller, scripts, etc. // something, alert the character controller, scripts, etc.
MWBase::Environment::get().getDialogueManager()->say(ptr, "thief"); const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
int chance = store.get<ESM::GameSetting>().find("iVoiceHitOdds")->getInt();
int roll = std::rand()/ (static_cast<double> (RAND_MAX) + 1) * 100; // [0, 99]
if (roll < chance)
{
MWBase::Environment::get().getDialogueManager()->say(ptr, "hit");
}
getCreatureStats(ptr).setAttacked(true);
// Check for knockdown
float agilityTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * fKnockDownMult->getFloat();
float knockdownTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified()
* iKnockDownOddsMult->getInt() * 0.01 + iKnockDownOddsBase->getInt();
roll = std::rand()/ (static_cast<double> (RAND_MAX) + 1) * 100; // [0, 99]
if (ishealth && agilityTerm <= damage && knockdownTerm <= roll)
{
getCreatureStats(ptr).setKnockedDown(true);
}
else
getCreatureStats(ptr).setHitRecovery(true); // Is this supposed to always occur?
if(object.isEmpty()) if(object.isEmpty())
{ {
@ -725,10 +781,10 @@ namespace MWClass
} }
if(getCreatureStats(ptr).isDead()) if(getCreatureStats(ptr).isDead())
return boost::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr, true)); 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()) if(get(ptr).getCreatureStats(ptr).isHostile())
return boost::shared_ptr<MWWorld::Action>(new MWWorld::FailedAction("#{sActorInCombat}")); 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)); return boost::shared_ptr<MWWorld::Action>(new MWWorld::ActionTalk(ptr));
} }
@ -756,80 +812,6 @@ namespace MWClass
return ref->mBase->mScript; 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 float Npc::getSpeed(const MWWorld::Ptr& ptr) const
{ {
const MWBase::World *world = MWBase::Environment::get().getWorld(); const MWBase::World *world = MWBase::Environment::get().getWorld();
@ -838,11 +820,14 @@ namespace MWClass
const float normalizedEncumbrance = Npc::getEncumbrance(ptr) / Npc::getCapacity(ptr); 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()* float walkSpeed = fMinWalkSpeed->getFloat() + 0.01f*npcdata->mNpcStats.getAttribute(ESM::Attribute::Speed).getModified()*
(fMaxWalkSpeed->getFloat() - fMinWalkSpeed->getFloat()); (fMaxWalkSpeed->getFloat() - fMinWalkSpeed->getFloat());
walkSpeed *= 1.0f - fEncumberedMoveEffect->getFloat()*normalizedEncumbrance; walkSpeed *= 1.0f - fEncumberedMoveEffect->getFloat()*normalizedEncumbrance;
walkSpeed = std::max(0.0f, walkSpeed); walkSpeed = std::max(0.0f, walkSpeed);
if(Npc::getStance(ptr, Sneak, false)) if(sneaking)
walkSpeed *= fSneakSpeedMultiplier->getFloat(); walkSpeed *= fSneakSpeedMultiplier->getFloat();
float runSpeed = walkSpeed*(0.01f * npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified() * float runSpeed = walkSpeed*(0.01f * npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified() *
@ -866,14 +851,14 @@ namespace MWClass
else if(world->isSwimming(ptr)) else if(world->isSwimming(ptr))
{ {
float swimSpeed = walkSpeed; float swimSpeed = walkSpeed;
if(Npc::getStance(ptr, Run, false)) if(running)
swimSpeed = runSpeed; swimSpeed = runSpeed;
swimSpeed *= 1.0f + 0.01f * mageffects.get(ESM::MagicEffect::SwiftSwim).mMagnitude; swimSpeed *= 1.0f + 0.01f * mageffects.get(ESM::MagicEffect::SwiftSwim).mMagnitude;
swimSpeed *= fSwimRunBase->getFloat() + 0.01f*npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified()* swimSpeed *= fSwimRunBase->getFloat() + 0.01f*npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified()*
fSwimRunAthleticsMult->getFloat(); fSwimRunAthleticsMult->getFloat();
moveSpeed = swimSpeed; moveSpeed = swimSpeed;
} }
else if(Npc::getStance(ptr, Run, false) && !Npc::getStance(ptr, Sneak, false)) else if(running && !sneaking)
moveSpeed = runSpeed; moveSpeed = runSpeed;
else else
moveSpeed = walkSpeed; moveSpeed = walkSpeed;
@ -905,7 +890,7 @@ namespace MWClass
x += mageffects.get(ESM::MagicEffect::Jump).mMagnitude * 64; x += mageffects.get(ESM::MagicEffect::Jump).mMagnitude * 64;
x *= encumbranceTerm; x *= encumbranceTerm;
if(Npc::getStance(ptr, Run, false)) if(ptr.getClass().getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Run))
x *= fJumpRunMultiplier->getFloat(); x *= fJumpRunMultiplier->getFloat();
x *= npcdata->mNpcStats.getFatigueTerm(); x *= npcdata->mNpcStats.getFatigueTerm();
x -= -627.2f;/*gravity constant*/ x -= -627.2f;/*gravity constant*/
@ -1017,7 +1002,8 @@ namespace MWClass
float Npc::getCapacity (const MWWorld::Ptr& ptr) const float Npc::getCapacity (const MWWorld::Ptr& ptr) const
{ {
const MWMechanics::CreatureStats& stats = getCreatureStats (ptr); 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 float Npc::getEncumbrance (const MWWorld::Ptr& ptr) const
@ -1231,6 +1217,22 @@ namespace MWClass
return MWWorld::Ptr(&cell.mNpcs.insert(*ref), &cell); 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::fMinWalkSpeed;
const ESM::GameSetting *Npc::fMaxWalkSpeed; const ESM::GameSetting *Npc::fMaxWalkSpeed;
const ESM::GameSetting *Npc::fEncumberedMoveEffect; const ESM::GameSetting *Npc::fEncumberedMoveEffect;
@ -1247,4 +1249,7 @@ namespace MWClass
const ESM::GameSetting *Npc::fJumpAcroMultiplier; const ESM::GameSetting *Npc::fJumpAcroMultiplier;
const ESM::GameSetting *Npc::fJumpRunMultiplier; const ESM::GameSetting *Npc::fJumpRunMultiplier;
const ESM::GameSetting *Npc::fWereWolfRunMult; 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 *fJumpAcroMultiplier;
static const ESM::GameSetting *fJumpRunMultiplier; static const ESM::GameSetting *fJumpRunMultiplier;
static const ESM::GameSetting *fWereWolfRunMult; static const ESM::GameSetting *fWereWolfRunMult;
static const ESM::GameSetting *fKnockDownMult;
static const ESM::GameSetting *iKnockDownOddsMult;
static const ESM::GameSetting *iKnockDownOddsBase;
public: public:
@ -81,16 +84,6 @@ namespace MWClass
virtual std::string getScript (const MWWorld::Ptr& ptr) const; virtual std::string getScript (const MWWorld::Ptr& ptr) const;
///< Return name of the script attached to ptr ///< 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; virtual float getSpeed (const MWWorld::Ptr& ptr) const;
///< Return movement speed. ///< Return movement speed.
@ -147,6 +140,11 @@ namespace MWClass
virtual std::string getModel(const MWWorld::Ptr &ptr) const; 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 { virtual bool isActor() const {
return true; return true;
} }

@ -13,7 +13,6 @@
#include "../mwworld/cellstore.hpp" #include "../mwworld/cellstore.hpp"
#include "../mwworld/containerstore.hpp" #include "../mwworld/containerstore.hpp"
#include "../mwworld/physicssystem.hpp" #include "../mwworld/physicssystem.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/nullaction.hpp" #include "../mwworld/nullaction.hpp"
#include "../mwgui/tooltips.hpp" #include "../mwgui/tooltips.hpp"
@ -133,7 +132,7 @@ namespace MWClass
info.effects = MWGui::Widgets::MWEffectList::effectListFromESM(&ref->mBase->mEffects); info.effects = MWGui::Widgets::MWEffectList::effectListFromESM(&ref->mBase->mEffects);
// hide effects the player doesnt know about // hide effects the player doesnt know about
MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr();
MWMechanics::NpcStats& npcStats = MWWorld::Class::get(player).getNpcStats (player); MWMechanics::NpcStats& npcStats = MWWorld::Class::get(player).getNpcStats (player);
int alchemySkill = npcStats.getSkill (ESM::Skill::Alchemy).getBase(); int alchemySkill = npcStats.getSkill (ESM::Skill::Alchemy).getBase();
int i=0; int i=0;
@ -153,6 +152,7 @@ namespace MWClass
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner");
text += MWGui::ToolTips::getMiscString(ref->mRef.mFaction, "Faction");
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
} }
@ -166,7 +166,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Potion> *ref = MWWorld::LiveCellRef<ESM::Potion> *ref =
ptr.get<ESM::Potion>(); ptr.get<ESM::Potion>();
MWWorld::Ptr actor = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Ptr actor = MWBase::Environment::get().getWorld()->getPlayerPtr();
// remove used potion (assume it is present in inventory) // remove used potion (assume it is present in inventory)
ptr.getContainerStore()->remove(ptr, 1, actor); ptr.getContainerStore()->remove(ptr, 1, actor);

@ -144,6 +144,7 @@ namespace MWClass
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner");
text += MWGui::ToolTips::getMiscString(ref->mRef.mFaction, "Faction");
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
} }

@ -148,6 +148,7 @@ namespace MWClass
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner");
text += MWGui::ToolTips::getMiscString(ref->mRef.mFaction, "Faction");
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
} }

@ -355,6 +355,7 @@ namespace MWClass
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner");
text += MWGui::ToolTips::getMiscString(ref->mRef.mFaction, "Faction");
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
} }

@ -30,7 +30,6 @@
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/containerstore.hpp" #include "../mwworld/containerstore.hpp"
#include "../mwworld/esmstore.hpp" #include "../mwworld/esmstore.hpp"
#include "../mwworld/player.hpp"
#include "../mwgui/dialogue.hpp" #include "../mwgui/dialogue.hpp"
@ -126,6 +125,8 @@ namespace MWDialogue
void DialogueManager::startDialogue (const MWWorld::Ptr& actor) void DialogueManager::startDialogue (const MWWorld::Ptr& actor)
{ {
mLastTopic = ""; mLastTopic = "";
mPermanentDispositionChange = 0;
mTemporaryDispositionChange = 0;
mChoice = -1; mChoice = -1;
mIsInChoice = false; mIsInChoice = false;
@ -142,6 +143,7 @@ namespace MWDialogue
//setup the list of topics known by the actor. Topics who are also on the knownTopics list will be added to the GUI //setup the list of topics known by the actor. Topics who are also on the knownTopics list will be added to the GUI
updateTopics(); updateTopics();
updateGlobals();
//greeting //greeting
const MWWorld::Store<ESM::Dialogue> &dialogs = const MWWorld::Store<ESM::Dialogue> &dialogs =
@ -297,6 +299,11 @@ namespace MWDialogue
} }
} }
void DialogueManager::updateGlobals()
{
MWBase::Environment::get().getWorld()->updateDialogueGlobals();
}
void DialogueManager::updateTopics() void DialogueManager::updateTopics()
{ {
std::list<std::string> keywordList; std::list<std::string> keywordList;
@ -491,7 +498,7 @@ namespace MWDialogue
else if (curDisp + mTemporaryDispositionChange > 100) else if (curDisp + mTemporaryDispositionChange > 100)
mTemporaryDispositionChange = 100 - curDisp; mTemporaryDispositionChange = 100 - curDisp;
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
MWWorld::Class::get(player).skillUsageSucceeded(player, ESM::Skill::Speechcraft, success ? 0 : 1); MWWorld::Class::get(player).skillUsageSucceeded(player, ESM::Skill::Speechcraft, success ? 0 : 1);
std::string text; std::string text;
@ -514,9 +521,19 @@ namespace MWDialogue
return mTemporaryDispositionChange; return mTemporaryDispositionChange;
} }
void DialogueManager::applyTemporaryDispositionChange(int delta) void DialogueManager::applyDispositionChange(int delta)
{ {
int oldTemp = mTemporaryDispositionChange;
mTemporaryDispositionChange += delta; mTemporaryDispositionChange += delta;
// don't allow increasing beyond 100 or decreasing below 0
int curDisp = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mActor);
if (curDisp + mTemporaryDispositionChange < 0)
mTemporaryDispositionChange = -curDisp;
else if (curDisp + mTemporaryDispositionChange > 100)
mTemporaryDispositionChange = 100 - curDisp;
int diff = mTemporaryDispositionChange - oldTemp;
mPermanentDispositionChange += diff;
} }
bool DialogueManager::checkServiceRefused() bool DialogueManager::checkServiceRefused()

@ -40,6 +40,7 @@ namespace MWDialogue
void parseText (const std::string& text); void parseText (const std::string& text);
void updateTopics(); void updateTopics();
void updateGlobals();
bool compile (const std::string& cmd,std::vector<Interpreter::Type_Code>& code); bool compile (const std::string& cmd,std::vector<Interpreter::Type_Code>& code);
void executeScript (const std::string& script); void executeScript (const std::string& script);
@ -76,7 +77,7 @@ namespace MWDialogue
virtual void persuade (int type); virtual void persuade (int type);
virtual int getTemporaryDispositionChange () const; virtual int getTemporaryDispositionChange () const;
virtual void applyTemporaryDispositionChange (int delta); virtual void applyDispositionChange (int delta);
}; };

@ -8,7 +8,6 @@
#include "../mwbase/dialoguemanager.hpp" #include "../mwbase/dialoguemanager.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/containerstore.hpp" #include "../mwworld/containerstore.hpp"
#include "../mwworld/inventorystore.hpp" #include "../mwworld/inventorystore.hpp"
@ -25,7 +24,7 @@ bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const
// actor id // actor id
if (!info.mActor.empty()) 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; return false;
} }
else if (isCreature) else if (isCreature)
@ -42,7 +41,7 @@ bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const
MWWorld::LiveCellRef<ESM::NPC> *cellRef = mActor.get<ESM::NPC>(); 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; return false;
} }
@ -54,7 +53,7 @@ bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const
MWWorld::LiveCellRef<ESM::NPC> *cellRef = mActor.get<ESM::NPC>(); 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; return false;
} }
@ -93,7 +92,7 @@ bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const
bool MWDialogue::Filter::testPlayer (const ESM::DialInfo& info) const bool MWDialogue::Filter::testPlayer (const ESM::DialInfo& info) const
{ {
const MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); const MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
// check player faction // check player faction
if (!info.mPcFaction.empty()) if (!info.mPcFaction.empty())
@ -111,7 +110,7 @@ bool MWDialogue::Filter::testPlayer (const ESM::DialInfo& info) const
// check cell // check cell
if (!info.mCell.empty()) 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 false;
return true; return true;
@ -189,7 +188,7 @@ bool MWDialogue::Filter::testSelectStructNumeric (const SelectWrapper& select) c
int i = 0; int i = 0;
for (; i<static_cast<int> (script->mVarNames.size()); ++i) 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; break;
if (i>=static_cast<int> (script->mVarNames.size())) if (i>=static_cast<int> (script->mVarNames.size()))
@ -212,7 +211,7 @@ bool MWDialogue::Filter::testSelectStructNumeric (const SelectWrapper& select) c
case SelectWrapper::Function_PcHealthPercent: case SelectWrapper::Function_PcHealthPercent:
{ {
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
float ratio = MWWorld::Class::get (player).getCreatureStats (player).getHealth().getCurrent() / float ratio = MWWorld::Class::get (player).getCreatureStats (player).getHealth().getCurrent() /
MWWorld::Class::get (player).getCreatureStats (player).getHealth().getModified(); MWWorld::Class::get (player).getCreatureStats (player).getHealth().getModified();
@ -222,7 +221,7 @@ bool MWDialogue::Filter::testSelectStructNumeric (const SelectWrapper& select) c
case SelectWrapper::Function_PcDynamicStat: case SelectWrapper::Function_PcDynamicStat:
{ {
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
float value = MWWorld::Class::get (player).getCreatureStats (player). float value = MWWorld::Class::get (player).getCreatureStats (player).
getDynamic (select.getArgument()).getCurrent(); getDynamic (select.getArgument()).getCurrent();
@ -246,7 +245,7 @@ bool MWDialogue::Filter::testSelectStructNumeric (const SelectWrapper& select) c
int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) const int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) const
{ {
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
switch (select.getFunction()) switch (select.getFunction())
{ {
@ -263,7 +262,7 @@ int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) con
std::string name = select.getName(); std::string name = select.getName();
for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter) 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(); sum += iter->getRefData().getCount();
return sum; return sum;
@ -420,7 +419,7 @@ int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) con
bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) const bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) const
{ {
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
switch (select.getFunction()) switch (select.getFunction())
{ {
@ -430,23 +429,23 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co
case SelectWrapper::Function_NotId: 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: 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: 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: 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: 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: case SelectWrapper::Function_NotLocal:
{ {
@ -463,7 +462,7 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co
int i = 0; int i = 0;
for (; i < static_cast<int> (script->mVarNames.size()); ++i) 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; break;
if (i >= static_cast<int> (script->mVarNames.size())) if (i >= static_cast<int> (script->mVarNames.size()))
@ -479,8 +478,7 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co
case SelectWrapper::Function_SameRace: case SelectWrapper::Function_SameRace:
return Misc::StringUtils::lowerCase (mActor.get<ESM::NPC>()->mBase->mRace)!= return !Misc::StringUtils::ciEqual(mActor.get<ESM::NPC>()->mBase->mRace, player.get<ESM::NPC>()->mBase->mRace);
Misc::StringUtils::lowerCase (player.get<ESM::NPC>()->mBase->mRace);
case SelectWrapper::Function_SameFaction: case SelectWrapper::Function_SameFaction:
@ -508,9 +506,7 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co
std::string faction = std::string faction =
MWWorld::Class::get (mActor).getNpcStats (mActor).getFactionRanks().begin()->first; MWWorld::Class::get (mActor).getNpcStats (mActor).getFactionRanks().begin()->first;
std::set<std::string>& expelled = MWWorld::Class::get (player).getNpcStats (player).getExpelled(); return player.getClass().getNpcStats(player).getExpelled(faction);
return expelled.find (faction)!=expelled.end();
} }
case SelectWrapper::Function_PcVampire: case SelectWrapper::Function_PcVampire:
@ -528,7 +524,7 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co
case SelectWrapper::Function_Detected: case SelectWrapper::Function_Detected:
return MWWorld::Class::get (mActor).hasDetected (mActor, player); return MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, mActor);
case SelectWrapper::Function_Attacked: case SelectWrapper::Function_Attacked:

@ -8,7 +8,6 @@
#include "../mwbase/soundmanager.hpp" #include "../mwbase/soundmanager.hpp"
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "inventoryitemmodel.hpp" #include "inventoryitemmodel.hpp"
@ -143,9 +142,9 @@ namespace MWGui
void AlchemyWindow::open() void AlchemyWindow::open()
{ {
mAlchemy.setAlchemist (MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); mAlchemy.setAlchemist (MWBase::Environment::get().getWorld()->getPlayerPtr());
InventoryItemModel* model = new InventoryItemModel(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); InventoryItemModel* model = new InventoryItemModel(MWBase::Environment::get().getWorld()->getPlayerPtr());
mSortModel = new SortFilterItemModel(model); mSortModel = new SortFilterItemModel(model);
mSortModel->setFilter(SortFilterItemModel::Filter_OnlyIngredients); mSortModel->setFilter(SortFilterItemModel::Filter_OnlyIngredients);
mItemView->setModel (mSortModel); mItemView->setModel (mSortModel);
@ -154,7 +153,7 @@ namespace MWGui
int index = 0; int index = 0;
mAlchemy.setAlchemist (MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); mAlchemy.setAlchemist (MWBase::Environment::get().getWorld()->getPlayerPtr());
for (MWMechanics::Alchemy::TToolsIterator iter (mAlchemy.beginTools()); for (MWMechanics::Alchemy::TToolsIterator iter (mAlchemy.beginTools());
iter!=mAlchemy.endTools() && index<static_cast<int> (mApparatus.size()); ++iter, ++index) iter!=mAlchemy.endTools() && index<static_cast<int> (mApparatus.size()); ++iter, ++index)

@ -1,6 +1,5 @@
#include "birth.hpp" #include "birth.hpp"
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
@ -77,7 +76,7 @@ namespace MWGui
size_t count = mBirthList->getItemCount(); size_t count = mBirthList->getItemCount();
for (size_t i = 0; i < count; ++i) 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); mBirthList->setIndexSelected(i);
MyGUI::Button* okButton; MyGUI::Button* okButton;
@ -112,7 +111,7 @@ namespace MWGui
getWidget(okButton, "OKButton"); getWidget(okButton, "OKButton");
const std::string *birthId = mBirthList->getItemDataAt<std::string>(_index); const std::string *birthId = mBirthList->getItemDataAt<std::string>(_index);
if (boost::iequals(mCurrentBirthId, *birthId)) if (Misc::StringUtils::ciEqual(mCurrentBirthId, *birthId))
return; return;
mCurrentBirthId = *birthId; mCurrentBirthId = *birthId;
@ -148,7 +147,7 @@ namespace MWGui
mBirthList->setIndexSelected(index); mBirthList->setIndexSelected(index);
mCurrentBirthId = it2->first; mCurrentBirthId = it2->first;
} }
else if (boost::iequals(it2->first, mCurrentBirthId)) else if (Misc::StringUtils::ciEqual(it2->first, mCurrentBirthId))
{ {
mBirthList->setIndexSelected(index); mBirthList->setIndexSelected(index);
} }

@ -8,7 +8,6 @@
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwworld/actiontake.hpp" #include "../mwworld/actiontake.hpp"
#include "../mwworld/player.hpp"
#include "formatting.hpp" #include "formatting.hpp"
@ -138,7 +137,7 @@ namespace MWGui
MWBase::Environment::get().getSoundManager()->playSound("Item Book Up", 1.0, 1.0); MWBase::Environment::get().getSoundManager()->playSound("Item Book Up", 1.0, 1.0);
MWWorld::ActionTake take(mBook); MWWorld::ActionTake take(mBook);
take.execute (MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); take.execute (MWBase::Environment::get().getWorld()->getPlayerPtr());
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Book); MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Book);
} }

@ -13,7 +13,6 @@
#include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/creaturestats.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/fallback.hpp" #include "../mwworld/fallback.hpp"
#include "../mwworld/player.hpp"
namespace namespace
{ {
@ -47,7 +46,7 @@ namespace
void updatePlayerHealth() void updatePlayerHealth()
{ {
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
MWMechanics::CreatureStats& creatureStats = MWWorld::Class::get(player).getCreatureStats(player); MWMechanics::CreatureStats& creatureStats = MWWorld::Class::get(player).getCreatureStats(player);
creatureStats.updateHealth(); creatureStats.updateHealth();
@ -220,8 +219,8 @@ namespace MWGui
mReviewDialog->setBirthSign(mPlayerBirthSignId); mReviewDialog->setBirthSign(mPlayerBirthSignId);
{ {
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
MWMechanics::CreatureStats stats = MWWorld::Class::get(player).getCreatureStats(player); const MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player);
mReviewDialog->setHealth ( stats.getHealth() ); mReviewDialog->setHealth ( stats.getHealth() );
mReviewDialog->setMagicka( stats.getMagicka() ); mReviewDialog->setMagicka( stats.getMagicka() );

@ -1,7 +1,5 @@
#include "class.hpp" #include "class.hpp"
#include <boost/algorithm/string.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
@ -29,11 +27,12 @@ namespace MWGui
MyGUI::Button* backButton; MyGUI::Button* backButton;
getWidget(backButton, "BackButton"); getWidget(backButton, "BackButton");
backButton->setCaptionWithReplacing("#{sMessageQuestionAnswer3}");
backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onBackClicked); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onBackClicked);
MyGUI::Button* okButton; MyGUI::Button* okButton;
getWidget(okButton, "OKButton"); getWidget(okButton, "OKButton");
okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); okButton->setCaptionWithReplacing("#{sMessageQuestionAnswer2}");
okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onOkClicked); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onOkClicked);
} }
@ -127,7 +126,7 @@ namespace MWGui
size_t count = mClassList->getItemCount(); size_t count = mClassList->getItemCount();
for (size_t i = 0; i < count; ++i) 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); mClassList->setIndexSelected(i);
MyGUI::Button* okButton; MyGUI::Button* okButton;
@ -162,7 +161,7 @@ namespace MWGui
getWidget(okButton, "OKButton"); getWidget(okButton, "OKButton");
const std::string *classId = mClassList->getItemDataAt<std::string>(_index); const std::string *classId = mClassList->getItemDataAt<std::string>(_index);
if (boost::iequals(mCurrentClassId, *classId)) if (Misc::StringUtils::ciEqual(mCurrentClassId, *classId))
return; return;
mCurrentClassId = *classId; mCurrentClassId = *classId;
@ -192,7 +191,7 @@ namespace MWGui
mCurrentClassId = id; mCurrentClassId = id;
mClassList->setIndexSelected(index); mClassList->setIndexSelected(index);
} }
else if (boost::iequals(id, mCurrentClassId)) else if (Misc::StringUtils::ciEqual(id, mCurrentClassId))
{ {
mClassList->setIndexSelected(index); mClassList->setIndexSelected(index);
} }

@ -6,9 +6,13 @@
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwbase/soundmanager.hpp" #include "../mwbase/soundmanager.hpp"
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwbase/dialoguemanager.hpp"
#include "../mwbase/mechanicsmanager.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/player.hpp" #include "../mwworld/containerstore.hpp"
#include "../mwmechanics/pickpocket.hpp"
#include "countdialog.hpp" #include "countdialog.hpp"
#include "tradewindow.hpp" #include "tradewindow.hpp"
@ -123,6 +127,7 @@ namespace MWGui
, mSelectedItem(-1) , mSelectedItem(-1)
, mModel(NULL) , mModel(NULL)
, mSortModel(NULL) , mSortModel(NULL)
, mPickpocketDetected(false)
{ {
getWidget(mDisposeCorpseButton, "DisposeCorpseButton"); getWidget(mDisposeCorpseButton, "DisposeCorpseButton");
getWidget(mTakeButton, "TakeButton"); getWidget(mTakeButton, "TakeButton");
@ -134,6 +139,7 @@ namespace MWGui
mDisposeCorpseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onDisposeCorpseButtonClicked); mDisposeCorpseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onDisposeCorpseButtonClicked);
mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onCloseButtonClicked); mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onCloseButtonClicked);
mCloseButton->eventKeyButtonPressed += MyGUI::newDelegate(this, &ContainerWindow::onKeyPressed);
mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onTakeAllButtonClicked); mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onTakeAllButtonClicked);
setCoord(200,0,600,300); setCoord(200,0,600,300);
@ -171,6 +177,9 @@ namespace MWGui
void ContainerWindow::dragItem(MyGUI::Widget* sender, int count) void ContainerWindow::dragItem(MyGUI::Widget* sender, int count)
{ {
if (!onTakeItem(mModel->getItem(mSelectedItem), count))
return;
mDragAndDrop->startDrag(mSelectedItem, mSortModel, mModel, mItemView, count); mDragAndDrop->startDrag(mSelectedItem, mSortModel, mModel, mItemView, count);
} }
@ -208,12 +217,13 @@ namespace MWGui
void ContainerWindow::open(const MWWorld::Ptr& container, bool loot) void ContainerWindow::open(const MWWorld::Ptr& container, bool loot)
{ {
mPickpocketDetected = false;
mPtr = container; mPtr = container;
if (mPtr.getTypeName() == typeid(ESM::NPC).name() && !loot) if (mPtr.getTypeName() == typeid(ESM::NPC).name() && !loot)
{ {
// we are stealing stuff // we are stealing stuff
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
mModel = new PickpocketItemModel(player, new InventoryItemModel(container)); mModel = new PickpocketItemModel(player, new InventoryItemModel(container));
} }
else else
@ -225,11 +235,46 @@ namespace MWGui
mItemView->setModel (mSortModel); 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 // 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. // or we end up using a possibly invalid model.
setTitle(MWWorld::Class::get(container).getName(container)); 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();
if (dynamic_cast<PickpocketItemModel*>(mModel)
// Make sure we were actually closed, rather than just temporarily hidden (e.g. console or main menu opened)
&& !MWBase::Environment::get().getWindowManager()->containsMode(GM_Container)
// If it was already detected while taking an item, no need to check now
&& !mPickpocketDetected
)
{
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
MWMechanics::Pickpocket pickpocket(player, mPtr);
if (pickpocket.finish())
{
MWBase::Environment::get().getMechanicsManager()->reportCrime(
player, mPtr, MWBase::MechanicsManager::OT_Pickpocket);
MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container);
MWBase::Environment::get().getDialogueManager()->say(mPtr, "Thief");
mPickpocketDetected = true;
return;
}
}
}
void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender) void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender)
{ {
if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop) if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop)
@ -255,8 +300,13 @@ namespace MWGui
MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0);
} }
playerModel->copyItem(mModel->getItem(i), mModel->getItem(i).mCount); const ItemStack& item = mModel->getItem(i);
mModel->removeItem(mModel->getItem(i), mModel->getItem(i).mCount);
if (!onTakeItem(item, item.mCount))
break;
playerModel->copyItem(item, item.mCount);
mModel->removeItem(item, item.mCount);
} }
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container);
@ -283,4 +333,30 @@ namespace MWGui
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container);
} }
bool ContainerWindow::onTakeItem(const ItemStack &item, int count)
{
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
if (dynamic_cast<PickpocketItemModel*>(mModel))
{
MWMechanics::Pickpocket pickpocket(player, mPtr);
if (pickpocket.pick(item.mBase, count))
{
int value = item.mBase.getClass().getValue(item.mBase) * count;
MWBase::Environment::get().getMechanicsManager()->reportCrime(
player, MWWorld::Ptr(), MWBase::MechanicsManager::OT_Theft, value);
MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container);
MWBase::Environment::get().getDialogueManager()->say(mPtr, "Thief");
mPickpocketDetected = true;
return false;
}
else
player.getClass().skillUsageSucceeded(player, ESM::Skill::Sneak, 1);
}
else
{
MWBase::Environment::get().getMechanicsManager()->itemTaken(player, item.mBase, count);
}
return true;
}
} }

@ -52,10 +52,13 @@ namespace MWGui
ContainerWindow(DragAndDrop* dragAndDrop); ContainerWindow(DragAndDrop* dragAndDrop);
void open(const MWWorld::Ptr& container, bool loot=false); void open(const MWWorld::Ptr& container, bool loot=false);
virtual void close();
private: private:
DragAndDrop* mDragAndDrop; DragAndDrop* mDragAndDrop;
bool mPickpocketDetected;
MWGui::ItemView* mItemView; MWGui::ItemView* mItemView;
SortFilterItemModel* mSortModel; SortFilterItemModel* mSortModel;
ItemModel* mModel; ItemModel* mModel;
@ -72,6 +75,10 @@ namespace MWGui
void onCloseButtonClicked(MyGUI::Widget* _sender); void onCloseButtonClicked(MyGUI::Widget* _sender);
void onTakeAllButtonClicked(MyGUI::Widget* _sender); void onTakeAllButtonClicked(MyGUI::Widget* _sender);
void onDisposeCorpseButtonClicked(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);
virtual void onReferenceUnavailable(); virtual void onReferenceUnavailable();
}; };

@ -12,7 +12,6 @@
#include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/npcstats.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/containerstore.hpp" #include "../mwworld/containerstore.hpp"
#include "../mwdialogue/dialoguemanagerimp.hpp" #include "../mwdialogue/dialoguemanagerimp.hpp"
@ -21,7 +20,6 @@
#include "list.hpp" #include "list.hpp"
#include "tradewindow.hpp" #include "tradewindow.hpp"
#include "spellbuyingwindow.hpp" #include "spellbuyingwindow.hpp"
#include "inventorywindow.hpp"
#include "travelwindow.hpp" #include "travelwindow.hpp"
#include "bookpage.hpp" #include "bookpage.hpp"
@ -69,24 +67,24 @@ namespace MWGui
void PersuasionDialog::onPersuade(MyGUI::Widget *sender) void PersuasionDialog::onPersuade(MyGUI::Widget *sender)
{ {
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
MWBase::MechanicsManager::PersuasionType type; MWBase::MechanicsManager::PersuasionType type;
if (sender == mAdmireButton) type = MWBase::MechanicsManager::PT_Admire; if (sender == mAdmireButton) type = MWBase::MechanicsManager::PT_Admire;
else if (sender == mIntimidateButton) type = MWBase::MechanicsManager::PT_Intimidate; else if (sender == mIntimidateButton) type = MWBase::MechanicsManager::PT_Intimidate;
else if (sender == mTauntButton) type = MWBase::MechanicsManager::PT_Taunt; else if (sender == mTauntButton) type = MWBase::MechanicsManager::PT_Taunt;
else if (sender == mBribe10Button) else if (sender == mBribe10Button)
{ {
player.getClass().getContainerStore(player).remove("gold_001", 10, player); player.getClass().getContainerStore(player).remove(MWWorld::ContainerStore::sGoldId, 10, player);
type = MWBase::MechanicsManager::PT_Bribe10; type = MWBase::MechanicsManager::PT_Bribe10;
} }
else if (sender == mBribe100Button) else if (sender == mBribe100Button)
{ {
player.getClass().getContainerStore(player).remove("gold_001", 100, player); player.getClass().getContainerStore(player).remove(MWWorld::ContainerStore::sGoldId, 100, player);
type = MWBase::MechanicsManager::PT_Bribe100; type = MWBase::MechanicsManager::PT_Bribe100;
} }
else /*if (sender == mBribe1000Button)*/ else /*if (sender == mBribe1000Button)*/
{ {
player.getClass().getContainerStore(player).remove("gold_001", 1000, player); player.getClass().getContainerStore(player).remove(MWWorld::ContainerStore::sGoldId, 1000, player);
type = MWBase::MechanicsManager::PT_Bribe1000; type = MWBase::MechanicsManager::PT_Bribe1000;
} }
@ -100,7 +98,8 @@ namespace MWGui
WindowModal::open(); WindowModal::open();
center(); center();
int playerGold = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId);
mBribe10Button->setEnabled (playerGold >= 10); mBribe10Button->setEnabled (playerGold >= 10);
mBribe100Button->setEnabled (playerGold >= 100); mBribe100Button->setEnabled (playerGold >= 100);
@ -546,7 +545,7 @@ namespace MWGui
for (size_t i=0; i<mTopicsList->getItemCount(); ++i) for (size_t i=0; i<mTopicsList->getItemCount(); ++i)
{ {
std::string item = mTopicsList->getItemNameAt(i); std::string item = mTopicsList->getItemNameAt(i);
if (Misc::StringUtils::lowerCase(item) == title) if (Misc::StringUtils::ciEqual(item, title))
{ {
realTitle = item; realTitle = item;
break; break;

@ -5,13 +5,11 @@
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwbase/soundmanager.hpp" #include "../mwbase/soundmanager.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/manualref.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/containerstore.hpp"
#include "itemselection.hpp" #include "itemselection.hpp"
#include "container.hpp" #include "container.hpp"
#include "inventorywindow.hpp"
#include "sortfilteritemmodel.hpp" #include "sortfilteritemmodel.hpp"
@ -106,7 +104,7 @@ namespace MWGui
void EnchantingDialog::startSelfEnchanting(MWWorld::Ptr soulgem) void EnchantingDialog::startSelfEnchanting(MWWorld::Ptr soulgem)
{ {
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
mEnchanting.setSelfEnchanting(true); mEnchanting.setSelfEnchanting(true);
mEnchanting.setEnchanter(player); mEnchanting.setEnchanter(player);
@ -149,7 +147,7 @@ namespace MWGui
mItemSelectionDialog->eventItemSelected += MyGUI::newDelegate(this, &EnchantingDialog::onItemSelected); mItemSelectionDialog->eventItemSelected += MyGUI::newDelegate(this, &EnchantingDialog::onItemSelected);
mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &EnchantingDialog::onItemCancel); mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &EnchantingDialog::onItemCancel);
mItemSelectionDialog->setVisible(true); mItemSelectionDialog->setVisible(true);
mItemSelectionDialog->openContainer(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); mItemSelectionDialog->openContainer(MWBase::Environment::get().getWorld()->getPlayerPtr());
mItemSelectionDialog->setFilter(SortFilterItemModel::Filter_OnlyEnchantable); mItemSelectionDialog->setFilter(SortFilterItemModel::Filter_OnlyEnchantable);
} }
@ -236,7 +234,7 @@ namespace MWGui
mItemSelectionDialog->eventItemSelected += MyGUI::newDelegate(this, &EnchantingDialog::onSoulSelected); mItemSelectionDialog->eventItemSelected += MyGUI::newDelegate(this, &EnchantingDialog::onSoulSelected);
mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &EnchantingDialog::onSoulCancel); mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &EnchantingDialog::onSoulCancel);
mItemSelectionDialog->setVisible(true); mItemSelectionDialog->setVisible(true);
mItemSelectionDialog->openContainer(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); mItemSelectionDialog->openContainer(MWBase::Environment::get().getWorld()->getPlayerPtr());
mItemSelectionDialog->setFilter(SortFilterItemModel::Filter_OnlyChargedSoulstones); mItemSelectionDialog->setFilter(SortFilterItemModel::Filter_OnlyChargedSoulstones);
//MWBase::Environment::get().getWindowManager()->messageBox("#{sInventorySelectNoSoul}"); //MWBase::Environment::get().getWindowManager()->messageBox("#{sInventorySelectNoSoul}");
@ -259,7 +257,7 @@ namespace MWGui
{ {
if (mEffects.size() <= 0) if (mEffects.size() <= 0)
{ {
MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage30}"); MWBase::Environment::get().getWindowManager()->messageBox ("#{sEnchantmentMenu11}");
return; return;
} }
@ -290,7 +288,9 @@ namespace MWGui
mEnchanting.setNewItemName(mName->getCaption()); mEnchanting.setNewItemName(mName->getCaption());
mEnchanting.setEffect(mEffectList); mEnchanting.setEffect(mEffectList);
if (mEnchanting.getEnchantPrice() > MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold()) MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId);
if (mEnchanting.getEnchantPrice() > playerGold)
{ {
MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage18}"); MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage18}");
return; return;

@ -6,7 +6,6 @@
#include "../mwbase/soundmanager.hpp" #include "../mwbase/soundmanager.hpp"
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/creaturestats.hpp"
@ -242,7 +241,7 @@ namespace MWGui
if (world->canPlaceObject(mouseX, mouseY)) if (world->canPlaceObject(mouseX, mouseY))
world->placeObject(object, mouseX, mouseY, mDragAndDrop->mDraggedCount); world->placeObject(object, mouseX, mouseY, mDragAndDrop->mDraggedCount);
else else
world->dropObjectOnGround(world->getPlayer().getPlayer(), object, mDragAndDrop->mDraggedCount); world->dropObjectOnGround(world->getPlayerPtr(), object, mDragAndDrop->mDraggedCount);
MWBase::Environment::get().getWindowManager()->changePointer("arrow"); MWBase::Environment::get().getWindowManager()->changePointer("arrow");
@ -268,7 +267,8 @@ namespace MWGui
else if ((mode == GM_Container) || (mode == GM_Inventory)) else if ((mode == GM_Container) || (mode == GM_Inventory))
{ {
// pick up object // pick up object
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->pickUpObject(object); if (!object.isEmpty())
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->pickUpObject(object);
} }
} }
} }
@ -320,7 +320,7 @@ namespace MWGui
void HUD::onWeaponClicked(MyGUI::Widget* _sender) void HUD::onWeaponClicked(MyGUI::Widget* _sender)
{ {
const MWWorld::Ptr& player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); const MWWorld::Ptr& player = MWBase::Environment::get().getWorld()->getPlayerPtr();
if (MWWorld::Class::get(player).getNpcStats(player).isWerewolf()) if (MWWorld::Class::get(player).getNpcStats(player).isWerewolf())
{ {
MWBase::Environment::get().getWindowManager()->messageBox("#{sWerewolfRefusal}"); MWBase::Environment::get().getWindowManager()->messageBox("#{sWerewolfRefusal}");
@ -332,7 +332,7 @@ namespace MWGui
void HUD::onMagicClicked(MyGUI::Widget* _sender) void HUD::onMagicClicked(MyGUI::Widget* _sender)
{ {
const MWWorld::Ptr& player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); const MWWorld::Ptr& player = MWBase::Environment::get().getWorld()->getPlayerPtr();
if (MWWorld::Class::get(player).getNpcStats(player).isWerewolf()) if (MWWorld::Class::get(player).getNpcStats(player).isWerewolf())
{ {
MWBase::Environment::get().getWindowManager()->messageBox("#{sWerewolfRefusal}"); MWBase::Environment::get().getWindowManager()->messageBox("#{sWerewolfRefusal}");
@ -517,7 +517,7 @@ namespace MWGui
mWeapStatus->setProgressPosition(0); mWeapStatus->setProgressPosition(0);
MWBase::World *world = MWBase::Environment::get().getWorld(); MWBase::World *world = MWBase::Environment::get().getWorld();
MWWorld::Ptr player = world->getPlayer().getPlayer(); MWWorld::Ptr player = world->getPlayerPtr();
if (MWWorld::Class::get(player).getNpcStats(player).isWerewolf()) if (MWWorld::Class::get(player).getNpcStats(player).isWerewolf())
mWeapImage->setImageTexture("icons\\k\\tx_werewolf_hand.dds"); mWeapImage->setImageTexture("icons\\k\\tx_werewolf_hand.dds");
else else

@ -8,11 +8,13 @@
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/soundmanager.hpp" #include "../mwbase/soundmanager.hpp"
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwbase/mechanicsmanager.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/inventorystore.hpp" #include "../mwworld/inventorystore.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/action.hpp" #include "../mwworld/action.hpp"
#include "../mwscript/interpretercontext.hpp"
#include "../mwbase/scriptmanager.hpp"
#include "bookwindow.hpp" #include "bookwindow.hpp"
#include "scrollwindow.hpp" #include "scrollwindow.hpp"
@ -33,7 +35,7 @@ namespace MWGui
, mTrading(false) , mTrading(false)
, mLastXSize(0) , mLastXSize(0)
, mLastYSize(0) , mLastYSize(0)
, mPreview(MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer ()) , mPreview(MWBase::Environment::get().getWorld ()->getPlayerPtr())
, mPreviewDirty(true) , mPreviewDirty(true)
, mDragAndDrop(dragAndDrop) , mDragAndDrop(dragAndDrop)
, mSelectedItem(-1) , mSelectedItem(-1)
@ -84,7 +86,7 @@ namespace MWGui
void InventoryWindow::updatePlayer() void InventoryWindow::updatePlayer()
{ {
mPtr = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer (); mPtr = MWBase::Environment::get().getWorld ()->getPlayerPtr();
mTradeModel = new TradeItemModel(new InventoryItemModel(mPtr), MWWorld::Ptr()); mTradeModel = new TradeItemModel(new InventoryItemModel(mPtr), MWWorld::Ptr());
mSortModel = new SortFilterItemModel(mTradeModel); mSortModel = new SortFilterItemModel(mTradeModel);
mItemView->setModel(mSortModel); mItemView->setModel(mSortModel);
@ -276,7 +278,7 @@ namespace MWGui
void InventoryWindow::open() void InventoryWindow::open()
{ {
mPtr = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); mPtr = MWBase::Environment::get().getWorld()->getPlayerPtr();
updateEncumbranceBar(); updateEncumbranceBar();
@ -351,6 +353,48 @@ namespace MWGui
MWBase::Environment::get().getWindowManager()->setWeaponVisibility(!mPinned); 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) void InventoryWindow::onAvatarClicked(MyGUI::Widget* _sender)
{ {
if (mDragAndDrop->mIsOnDragAndDrop) if (mDragAndDrop->mIsOnDragAndDrop)
@ -369,21 +413,7 @@ namespace MWGui
mDragAndDrop->mSourceModel->removeItem(mDragAndDrop->mItem, mDragAndDrop->mDraggedCount); mDragAndDrop->mSourceModel->removeItem(mDragAndDrop->mItem, mDragAndDrop->mDraggedCount);
ptr = *it; ptr = *it;
} }
useItem(ptr);
boost::shared_ptr<MWWorld::Action> action = MWWorld::Class::get(ptr).use(ptr);
action->execute (MWBase::Environment::get().getWorld()->getPlayer().getPlayer());
// 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();
} }
else else
{ {
@ -432,7 +462,7 @@ namespace MWGui
void InventoryWindow::updateEncumbranceBar() void InventoryWindow::updateEncumbranceBar()
{ {
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
float capacity = MWWorld::Class::get(player).getCapacity(player); float capacity = MWWorld::Class::get(player).getCapacity(player);
float encumbrance = MWWorld::Class::get(player).getEncumbrance(player); float encumbrance = MWWorld::Class::get(player).getEncumbrance(player);
@ -447,19 +477,6 @@ namespace MWGui
updateEncumbranceBar(); updateEncumbranceBar();
} }
int InventoryWindow::getPlayerGold()
{
MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr);
for (MWWorld::ContainerStoreIterator it = invStore.begin();
it != invStore.end(); ++it)
{
if (Misc::StringUtils::ciEqual(it->getCellRef().mRefID, "gold_001"))
return it->getRefData().getCount();
}
return 0;
}
void InventoryWindow::setTrading(bool trading) void InventoryWindow::setTrading(bool trading)
{ {
mTrading = trading; mTrading = trading;
@ -512,12 +529,10 @@ namespace MWGui
return; return;
int count = object.getRefData().getCount(); int count = object.getRefData().getCount();
if (object.getCellRef().mGoldValue > 1)
count = object.getCellRef().mGoldValue;
// add to player inventory // add to player inventory
// can't use ActionTake here because we need an MWWorld::Ptr to the newly inserted object // can't use ActionTake here because we need an MWWorld::Ptr to the newly inserted object
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
MWWorld::Ptr newObject = *player.getClass().getContainerStore (player).add (object, object.getRefData().getCount(), player); MWWorld::Ptr newObject = *player.getClass().getContainerStore (player).add (object, object.getRefData().getCount(), player);
// remove from world // remove from world
MWBase::Environment::get().getWorld()->deleteObject (object); MWBase::Environment::get().getWorld()->deleteObject (object);
@ -533,6 +548,8 @@ namespace MWGui
if (i == mTradeModel->getItemCount()) if (i == mTradeModel->getItemCount())
throw std::runtime_error("Added item not found"); throw std::runtime_error("Added item not found");
mDragAndDrop->startDrag(i, mSortModel, mTradeModel, mItemView, count); mDragAndDrop->startDrag(i, mSortModel, mTradeModel, mItemView, count);
MWBase::Environment::get().getMechanicsManager()->itemTaken(player, newObject, count);
} }
MyGUI::IntCoord InventoryWindow::getAvatarScreenCoord () MyGUI::IntCoord InventoryWindow::getAvatarScreenCoord ()

@ -31,8 +31,6 @@ namespace MWGui
void pickUpObject (MWWorld::Ptr object); void pickUpObject (MWWorld::Ptr object);
int getPlayerGold();
MyGUI::IntCoord getAvatarScreenCoord(); MyGUI::IntCoord getAvatarScreenCoord();
MWWorld::Ptr getAvatarSelectedItem(int x, int y); MWWorld::Ptr getAvatarSelectedItem(int x, int y);
@ -48,6 +46,8 @@ namespace MWGui
void updatePlayer(); void updatePlayer();
void useItem(const MWWorld::Ptr& ptr);
void setGuiMode(GuiMode mode); void setGuiMode(GuiMode mode);
private: private:
@ -76,6 +76,8 @@ namespace MWGui
MyGUI::Button* mFilterMagic; MyGUI::Button* mFilterMagic;
MyGUI::Button* mFilterMisc; MyGUI::Button* mFilterMisc;
MWWorld::Ptr mSkippedToEquip;
GuiMode mGuiMode; GuiMode mGuiMode;
int mLastXSize; int mLastXSize;

@ -6,7 +6,6 @@
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/fallback.hpp" #include "../mwworld/fallback.hpp"
@ -59,7 +58,7 @@ namespace MWGui
void LevelupDialog::setAttributeValues() void LevelupDialog::setAttributeValues()
{ {
MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayer().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr();
MWMechanics::CreatureStats& creatureStats = MWWorld::Class::get(player).getCreatureStats (player); MWMechanics::CreatureStats& creatureStats = MWWorld::Class::get(player).getCreatureStats (player);
MWMechanics::NpcStats& pcStats = MWWorld::Class::get(player).getNpcStats (player); MWMechanics::NpcStats& pcStats = MWWorld::Class::get(player).getNpcStats (player);
@ -115,7 +114,7 @@ namespace MWGui
void LevelupDialog::open() void LevelupDialog::open()
{ {
MWBase::World *world = MWBase::Environment::get().getWorld(); MWBase::World *world = MWBase::Environment::get().getWorld();
MWWorld::Ptr player = world->getPlayer().getPlayer(); MWWorld::Ptr player = world->getPlayerPtr();
MWMechanics::CreatureStats& creatureStats = MWWorld::Class::get(player).getCreatureStats (player); MWMechanics::CreatureStats& creatureStats = MWWorld::Class::get(player).getCreatureStats (player);
MWMechanics::NpcStats& pcStats = MWWorld::Class::get(player).getNpcStats (player); MWMechanics::NpcStats& pcStats = MWWorld::Class::get(player).getNpcStats (player);
@ -155,7 +154,7 @@ namespace MWGui
void LevelupDialog::onOkButtonClicked (MyGUI::Widget* sender) void LevelupDialog::onOkButtonClicked (MyGUI::Widget* sender)
{ {
MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayer().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr();
MWMechanics::CreatureStats& creatureStats = MWWorld::Class::get(player).getCreatureStats (player); MWMechanics::CreatureStats& creatureStats = MWWorld::Class::get(player).getCreatureStats (player);
MWMechanics::NpcStats& pcStats = MWWorld::Class::get(player).getNpcStats (player); MWMechanics::NpcStats& pcStats = MWWorld::Class::get(player).getNpcStats (player);

@ -294,7 +294,7 @@ namespace MWGui
std::vector<MWWorld::Ptr> markers; std::vector<MWWorld::Ptr> markers;
MWBase::World* world = MWBase::Environment::get().getWorld(); MWBase::World* world = MWBase::Environment::get().getWorld();
world->listDetectedReferences( world->listDetectedReferences(
world->getPlayer().getPlayer(), world->getPlayerPtr(),
markers, MWBase::World::DetectionType(type)); markers, MWBase::World::DetectionType(type));
if (markers.empty()) if (markers.empty())
return; return;
@ -515,8 +515,8 @@ namespace MWGui
// For interiors, position is set by WindowManager via setGlobalMapPlayerPosition // For interiors, position is set by WindowManager via setGlobalMapPlayerPosition
if (MWBase::Environment::get().getWorld ()->isCellExterior ()) if (MWBase::Environment::get().getWorld ()->isCellExterior ())
{ {
Ogre::Vector3 pos = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedPosition (); Ogre::Vector3 pos = MWBase::Environment::get().getWorld ()->getPlayerPtr().getRefData ().getBaseNode ()->_getDerivedPosition ();
Ogre::Quaternion orient = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedOrientation (); Ogre::Quaternion orient = MWBase::Environment::get().getWorld ()->getPlayerPtr().getRefData ().getBaseNode ()->_getDerivedOrientation ();
Ogre::Vector2 dir (orient.yAxis ().x, orient.yAxis().y); Ogre::Vector2 dir (orient.yAxis ().x, orient.yAxis().y);
float worldX, worldY; float worldX, worldY;

@ -8,12 +8,9 @@
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwbase/soundmanager.hpp" #include "../mwbase/soundmanager.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/containerstore.hpp" #include "../mwworld/containerstore.hpp"
#include "inventorywindow.hpp"
namespace MWGui namespace MWGui
{ {
@ -36,7 +33,9 @@ void MerchantRepair::startRepair(const MWWorld::Ptr &actor)
int currentY = 0; int currentY = 0;
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId);
MWWorld::ContainerStore& store = MWWorld::Class::get(player).getContainerStore(player); MWWorld::ContainerStore& store = MWWorld::Class::get(player).getContainerStore(player);
int categories = MWWorld::ContainerStore::Type_Weapon | MWWorld::ContainerStore::Type_Armor; int categories = MWWorld::ContainerStore::Type_Weapon | MWWorld::ContainerStore::Type_Armor;
for (MWWorld::ContainerStoreIterator iter (store.begin(categories)); for (MWWorld::ContainerStoreIterator iter (store.begin(categories));
@ -69,8 +68,7 @@ void MerchantRepair::startRepair(const MWWorld::Ptr &actor)
MyGUI::Button* button = MyGUI::Button* button =
mList->createWidget<MyGUI::Button>( mList->createWidget<MyGUI::Button>("SandTextButton",
(price>MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold()) ? "SandTextGreyedOut" : "SandTextButton",
0, 0,
currentY, currentY,
0, 0,
@ -80,7 +78,7 @@ void MerchantRepair::startRepair(const MWWorld::Ptr &actor)
currentY += 18; currentY += 18;
button->setEnabled(price<=MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold()); button->setEnabled(price<=playerGold);
button->setUserString("Price", boost::lexical_cast<std::string>(price)); button->setUserString("Price", boost::lexical_cast<std::string>(price));
button->setUserData(*iter); button->setUserData(*iter);
button->setCaptionWithReplacing(name); button->setCaptionWithReplacing(name);
@ -93,7 +91,7 @@ void MerchantRepair::startRepair(const MWWorld::Ptr &actor)
mList->setCanvasSize (MyGUI::IntSize(mList->getWidth(), std::max(mList->getHeight(), currentY))); mList->setCanvasSize (MyGUI::IntSize(mList->getWidth(), std::max(mList->getHeight(), currentY)));
mGoldLabel->setCaptionWithReplacing("#{sGold}: " mGoldLabel->setCaptionWithReplacing("#{sGold}: "
+ boost::lexical_cast<std::string>(MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold())); + boost::lexical_cast<std::string>(playerGold));
} }
void MerchantRepair::onMouseWheel(MyGUI::Widget* _sender, int _rel) void MerchantRepair::onMouseWheel(MyGUI::Widget* _sender, int _rel)
@ -119,8 +117,8 @@ void MerchantRepair::onRepairButtonClick(MyGUI::Widget *sender)
int price = boost::lexical_cast<int>(sender->getUserString("Price")); int price = boost::lexical_cast<int>(sender->getUserString("Price"));
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
player.getClass().getContainerStore(player).remove("gold_001", price, player); player.getClass().getContainerStore(player).remove(MWWorld::ContainerStore::sGoldId, price, player);
startRepair(mActor); startRepair(mActor);
} }

@ -8,12 +8,12 @@
namespace MWGui namespace MWGui
{ {
MessageBoxManager::MessageBoxManager () MessageBoxManager::MessageBoxManager (float timePerChar)
{ {
mMessageBoxSpeed = 0.1;
mInterMessageBoxe = NULL; mInterMessageBoxe = NULL;
mStaticMessageBox = NULL; mStaticMessageBox = NULL;
mLastButtonPressed = -1; mLastButtonPressed = -1;
mMessageBoxSpeed = timePerChar;
} }
MessageBoxManager::~MessageBoxManager () MessageBoxManager::~MessageBoxManager ()
@ -62,7 +62,8 @@ namespace MWGui
{ {
MessageBox *box = new MessageBox(*this, message); MessageBox *box = new MessageBox(*this, message);
box->mCurrentTime = 0; box->mCurrentTime = 0;
box->mMaxTime = message.length()*mMessageBoxSpeed; std::string realMessage = MyGUI::LanguageManager::getInstance().replaceTags(message);
box->mMaxTime = realMessage.length()*mMessageBoxSpeed;
if(stat) if(stat)
mStaticMessageBox = box; mStaticMessageBox = box;
@ -126,12 +127,6 @@ namespace MWGui
mMessageBoxSpeed = speed; mMessageBoxSpeed = speed;
} }
void MessageBoxManager::okayPressed ()
{
if(mInterMessageBoxe != NULL)
mInterMessageBoxe->okayPressed();
}
int MessageBoxManager::readPressedButton () int MessageBoxManager::readPressedButton ()
{ {
int pressed = mLastButtonPressed; int pressed = mLastButtonPressed;
@ -332,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::string ok = Misc::StringUtils::lowerCase(MyGUI::LanguageManager::getInstance().replaceTags("#{sOK}"));
std::vector<MyGUI::Button*>::const_iterator button; std::vector<MyGUI::Button*>::const_iterator button;
for(button = mButtons.begin(); button != mButtons.end(); ++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); MyGUI::InputManager::getInstance().setKeyFocusWidget(*button);
MWBase::Environment::get().getSoundManager()->playSound("Menu Click", 1.f, 1.f); (*button)->eventKeyButtonPressed += MyGUI::newDelegate(this, &InteractiveMessageBox::onKeyPressed);
break; 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) void InteractiveMessageBox::mousePressed (MyGUI::Widget* pressed)

@ -22,7 +22,7 @@ namespace MWGui
class MessageBoxManager class MessageBoxManager
{ {
public: public:
MessageBoxManager (); MessageBoxManager (float timePerChar);
~MessageBoxManager (); ~MessageBoxManager ();
void onFrame (float frameDuration); void onFrame (float frameDuration);
void createMessageBox (const std::string& message, bool stat = false); void createMessageBox (const std::string& message, bool stat = false);
@ -33,7 +33,6 @@ namespace MWGui
bool removeMessageBox (MessageBox *msgbox); bool removeMessageBox (MessageBox *msgbox);
void setMessageBoxSpeed (int speed); void setMessageBoxSpeed (int speed);
void okayPressed();
int readPressedButton (); int readPressedButton ();
typedef MyGUI::delegates::CMultiDelegate1<int> EventHandle_Int; typedef MyGUI::delegates::CMultiDelegate1<int> EventHandle_Int;
@ -74,7 +73,6 @@ namespace MWGui
{ {
public: public:
InteractiveMessageBox (MessageBoxManager& parMessageBoxManager, const std::string& message, const std::vector<std::string>& buttons); InteractiveMessageBox (MessageBoxManager& parMessageBoxManager, const std::string& message, const std::vector<std::string>& buttons);
void okayPressed ();
void mousePressed (MyGUI::Widget* _widget); void mousePressed (MyGUI::Widget* _widget);
int readPressedButton (); int readPressedButton ();
@ -82,6 +80,7 @@ namespace MWGui
private: private:
void buttonActivated (MyGUI::Widget* _widget); void buttonActivated (MyGUI::Widget* _widget);
void onKeyPressed(MyGUI::Widget* _sender, MyGUI::KeyCode _key, MyGUI::Char _char);
MessageBoxManager& mMessageBoxManager; MessageBoxManager& mMessageBoxManager;
MyGUI::EditBox* mMessageWidget; MyGUI::EditBox* mMessageWidget;

@ -9,7 +9,7 @@ namespace MWGui
PickpocketItemModel::PickpocketItemModel(const MWWorld::Ptr& thief, ItemModel *sourceModel) PickpocketItemModel::PickpocketItemModel(const MWWorld::Ptr& thief, ItemModel *sourceModel)
{ {
mSourceModel = 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(); mSourceModel->update();
for (size_t i = 0; i<mSourceModel->getItemCount(); ++i) for (size_t i = 0; i<mSourceModel->getItemCount(); ++i)

@ -2,7 +2,6 @@
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include "../mwworld/player.hpp"
#include "../mwworld/inventorystore.hpp" #include "../mwworld/inventorystore.hpp"
#include "../mwworld/actionequip.hpp" #include "../mwworld/actionequip.hpp"
#include "../mwmechanics/spellcasting.hpp" #include "../mwmechanics/spellcasting.hpp"
@ -126,7 +125,7 @@ namespace MWGui
mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &QuickKeysMenu::onAssignItemCancel); mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &QuickKeysMenu::onAssignItemCancel);
} }
mItemSelectionDialog->setVisible(true); mItemSelectionDialog->setVisible(true);
mItemSelectionDialog->openContainer(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); mItemSelectionDialog->openContainer(MWBase::Environment::get().getWorld()->getPlayerPtr());
mAssignDialog->setVisible (false); mAssignDialog->setVisible (false);
} }
@ -267,7 +266,7 @@ namespace MWGui
QuickKeyType type = *button->getUserData<QuickKeyType>(); QuickKeyType type = *button->getUserData<QuickKeyType>();
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
MWWorld::InventoryStore& store = MWWorld::Class::get(player).getInventoryStore(player); MWWorld::InventoryStore& store = MWWorld::Class::get(player).getInventoryStore(player);
if (type == Type_Item || type == Type_MagicItem) if (type == Type_Item || type == Type_MagicItem)
@ -302,6 +301,12 @@ namespace MWGui
if (type == Type_Magic) if (type == Type_Magic)
{ {
std::string spellId = button->getChildAt(0)->getUserString("Spell"); 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()); store.setSelectedEnchantItem(store.end());
MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player))); MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player)));
} }
@ -309,19 +314,7 @@ namespace MWGui
{ {
MWWorld::Ptr item = *button->getChildAt (0)->getUserData<MWWorld::Ptr>(); MWWorld::Ptr item = *button->getChildAt (0)->getUserData<MWWorld::Ptr>();
boost::shared_ptr<MWWorld::Action> action = MWWorld::Class::get(item).use(item); MWBase::Environment::get().getWindowManager()->getInventoryWindow()->useItem(item);
action->execute (MWBase::Environment::get().getWorld()->getPlayer().getPlayer());
// 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();
} }
else if (type == Type_MagicItem) else if (type == Type_MagicItem)
{ {
@ -344,7 +337,7 @@ namespace MWGui
// Note: can't use Class::use here because enchanted scrolls for example would then open the scroll window instead of equipping // Note: can't use Class::use here because enchanted scrolls for example would then open the scroll window instead of equipping
MWWorld::ActionEquip action(item); MWWorld::ActionEquip action(item);
action.execute (MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer ()); action.execute (MWBase::Environment::get().getWorld ()->getPlayerPtr());
} }
store.setSelectedEnchantItem(it); store.setSelectedEnchantItem(it);
@ -430,7 +423,7 @@ namespace MWGui
const int spellHeight = 18; const int spellHeight = 18;
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
MWWorld::InventoryStore& store = MWWorld::Class::get(player).getInventoryStore(player); MWWorld::InventoryStore& store = MWWorld::Class::get(player).getInventoryStore(player);
MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player); MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player);
MWMechanics::Spells& spells = stats.getSpells(); MWMechanics::Spells& spells = stats.getSpells();

@ -1,6 +1,5 @@
#include "race.hpp" #include "race.hpp"
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <boost/format.hpp> #include <boost/format.hpp>
@ -140,7 +139,7 @@ namespace MWGui
size_t count = mRaceList->getItemCount(); size_t count = mRaceList->getItemCount();
for (size_t i = 0; i < count; ++i) 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); mRaceList->setIndexSelected(i);
MyGUI::Button* okButton; MyGUI::Button* okButton;
@ -230,7 +229,7 @@ namespace MWGui
MyGUI::Button* okButton; MyGUI::Button* okButton;
getWidget(okButton, "OKButton"); getWidget(okButton, "OKButton");
const std::string *raceId = mRaceList->getItemDataAt<std::string>(_index); const std::string *raceId = mRaceList->getItemDataAt<std::string>(_index);
if (boost::iequals(mCurrentRaceId, *raceId)) if (Misc::StringUtils::ciEqual(mCurrentRaceId, *raceId))
return; return;
mCurrentRaceId = *raceId; mCurrentRaceId = *raceId;
@ -320,7 +319,7 @@ namespace MWGui
continue; continue;
mRaceList->addItem(it->mName, it->mId); mRaceList->addItem(it->mName, it->mId);
if (boost::iequals(it->mId, mCurrentRaceId)) if (Misc::StringUtils::ciEqual(it->mId, mCurrentRaceId))
mRaceList->setIndexSelected(index); mRaceList->setIndexSelected(index);
++index; ++index;
} }

@ -7,7 +7,6 @@
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/containerstore.hpp" #include "../mwworld/containerstore.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
@ -85,7 +84,7 @@ void Recharge::updateView()
int currentY = 0; int currentY = 0;
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
MWWorld::ContainerStore& store = MWWorld::Class::get(player).getContainerStore(player); MWWorld::ContainerStore& store = MWWorld::Class::get(player).getContainerStore(player);
for (MWWorld::ContainerStoreIterator iter (store.begin()); for (MWWorld::ContainerStoreIterator iter (store.begin());
iter!=store.end(); ++iter) iter!=store.end(); ++iter)
@ -141,7 +140,7 @@ void Recharge::onItemClicked(MyGUI::Widget *sender)
MWWorld::Ptr item = *sender->getUserData<MWWorld::Ptr>(); MWWorld::Ptr item = *sender->getUserData<MWWorld::Ptr>();
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player);
MWMechanics::NpcStats& npcStats = player.getClass().getNpcStats(player); MWMechanics::NpcStats& npcStats = player.getClass().getNpcStats(player);

@ -3,8 +3,6 @@
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwworld/player.hpp"
namespace MWGui namespace MWGui
{ {
ReferenceInterface::ReferenceInterface() ReferenceInterface::ReferenceInterface()
@ -18,7 +16,7 @@ namespace MWGui
void ReferenceInterface::checkReferenceAvailable() void ReferenceInterface::checkReferenceAvailable()
{ {
MWWorld::CellStore* playerCell = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell(); MWWorld::CellStore* playerCell = MWBase::Environment::get().getWorld()->getPlayerPtr().getCell();
// check if player has changed cell, or count of the reference has become 0 // check if player has changed cell, or count of the reference has become 0
if ((playerCell != mCurrentPlayerCell && mCurrentPlayerCell != NULL) if ((playerCell != mCurrentPlayerCell && mCurrentPlayerCell != NULL)

@ -6,7 +6,6 @@
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/containerstore.hpp" #include "../mwworld/containerstore.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
@ -88,7 +87,7 @@ void Repair::updateRepairView()
int currentY = 0; int currentY = 0;
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
MWWorld::ContainerStore& store = MWWorld::Class::get(player).getContainerStore(player); MWWorld::ContainerStore& store = MWWorld::Class::get(player).getContainerStore(player);
int categories = MWWorld::ContainerStore::Type_Weapon | MWWorld::ContainerStore::Type_Armor; int categories = MWWorld::ContainerStore::Type_Weapon | MWWorld::ContainerStore::Type_Armor;
for (MWWorld::ContainerStoreIterator iter (store.begin(categories)); for (MWWorld::ContainerStoreIterator iter (store.begin(categories));

@ -6,7 +6,6 @@
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwworld/actiontake.hpp" #include "../mwworld/actiontake.hpp"
#include "../mwworld/player.hpp"
#include "formatting.hpp" #include "formatting.hpp"
@ -90,7 +89,7 @@ namespace MWGui
MWBase::Environment::get().getSoundManager()->playSound("Item Book Up", 1.0, 1.0); MWBase::Environment::get().getSoundManager()->playSound("Item Book Up", 1.0, 1.0);
MWWorld::ActionTake take(mScroll); MWWorld::ActionTake take(mScroll);
take.execute (MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); take.execute (MWBase::Environment::get().getWorld()->getPlayerPtr());
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Scroll); MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Scroll);
} }

@ -8,14 +8,11 @@
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/mechanicsmanager.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/containerstore.hpp" #include "../mwworld/containerstore.hpp"
#include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/creaturestats.hpp"
#include "inventorywindow.hpp"
namespace MWGui namespace MWGui
{ {
const int SpellBuyingWindow::sLineHeight = 18; const int SpellBuyingWindow::sLineHeight = 18;
@ -43,15 +40,19 @@ namespace MWGui
int price = spell->mData.mCost*store.get<ESM::GameSetting>().find("fSpellValueMult")->getFloat(); int price = spell->mData.mCost*store.get<ESM::GameSetting>().find("fSpellValueMult")->getFloat();
price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr,price,true); price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr,price,true);
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId);
MyGUI::Button* toAdd = MyGUI::Button* toAdd =
mSpellsView->createWidget<MyGUI::Button>( mSpellsView->createWidget<MyGUI::Button>(
(price>MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold()) ? "SandTextGreyedOut" : "SandTextButton", "SandTextButton",
0, 0,
mCurrentY, mCurrentY,
200, 200,
sLineHeight, sLineHeight,
MyGUI::Align::Default MyGUI::Align::Default
); );
toAdd->setEnabled(price<=playerGold);
mCurrentY += sLineHeight; mCurrentY += sLineHeight;
@ -103,7 +104,7 @@ namespace MWGui
bool SpellBuyingWindow::playerHasSpell(const std::string &id) bool SpellBuyingWindow::playerHasSpell(const std::string &id)
{ {
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
MWMechanics::Spells& playerSpells = MWWorld::Class::get (player).getCreatureStats (player).getSpells(); MWMechanics::Spells& playerSpells = MWWorld::Class::get (player).getCreatureStats (player).getSpells();
for (MWMechanics::Spells::TIterator it = playerSpells.begin(); it != playerSpells.end(); ++it) for (MWMechanics::Spells::TIterator it = playerSpells.begin(); it != playerSpells.end(); ++it)
{ {
@ -117,17 +118,14 @@ namespace MWGui
{ {
int price = *_sender->getUserData<int>(); int price = *_sender->getUserData<int>();
if (MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold()>=price) MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
{ MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player);
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWMechanics::Spells& spells = stats.getSpells();
MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player); spells.add (mSpellsWidgetMap.find(_sender)->second);
MWMechanics::Spells& spells = stats.getSpells(); player.getClass().getContainerStore(player).remove(MWWorld::ContainerStore::sGoldId, price, player);
spells.add (mSpellsWidgetMap.find(_sender)->second); startSpellBuying(mPtr);
player.getClass().getContainerStore(player).remove("gold_001", price, player);
startSpellBuying(mPtr); MWBase::Environment::get().getSoundManager()->playSound ("Item Gold Up", 1.0, 1.0);
MWBase::Environment::get().getSoundManager()->playSound ("Item Gold Up", 1.0, 1.0);
}
} }
void SpellBuyingWindow::onCancelButtonClicked(MyGUI::Widget* _sender) void SpellBuyingWindow::onCancelButtonClicked(MyGUI::Widget* _sender)
@ -137,7 +135,10 @@ namespace MWGui
void SpellBuyingWindow::updateLabels() void SpellBuyingWindow::updateLabels()
{ {
mPlayerGold->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast<std::string>(MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold())); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId);
mPlayerGold->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast<std::string>(playerGold));
mPlayerGold->setCoord(8, mPlayerGold->setCoord(8,
mPlayerGold->getTop(), mPlayerGold->getTop(),
mPlayerGold->getTextSize().width, mPlayerGold->getTextSize().width,

@ -7,14 +7,12 @@
#include "../mwbase/soundmanager.hpp" #include "../mwbase/soundmanager.hpp"
#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/mechanicsmanager.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/containerstore.hpp" #include "../mwworld/containerstore.hpp"
#include "../mwmechanics/spellcasting.hpp" #include "../mwmechanics/spellcasting.hpp"
#include "tooltips.hpp" #include "tooltips.hpp"
#include "class.hpp" #include "class.hpp"
#include "inventorywindow.hpp"
namespace namespace
{ {
@ -334,7 +332,10 @@ namespace MWGui
return; return;
} }
if (boost::lexical_cast<int>(mPriceLabel->getCaption()) > MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold()) MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId);
if (boost::lexical_cast<int>(mPriceLabel->getCaption()) > playerGold)
{ {
MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage18}"); MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage18}");
return; return;
@ -342,9 +343,7 @@ namespace MWGui
mSpell.mName = mNameEdit->getCaption(); mSpell.mName = mNameEdit->getCaption();
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); player.getClass().getContainerStore(player).remove(MWWorld::ContainerStore::sGoldId, boost::lexical_cast<int>(mPriceLabel->getCaption()), player);
player.getClass().getContainerStore(player).remove("gold_001", boost::lexical_cast<int>(mPriceLabel->getCaption()), player);
MWBase::Environment::get().getSoundManager()->playSound ("Item Gold Up", 1.0, 1.0); MWBase::Environment::get().getSoundManager()->playSound ("Item Gold Up", 1.0, 1.0);
@ -414,7 +413,7 @@ namespace MWGui
mPriceLabel->setCaption(boost::lexical_cast<std::string>(int(price))); mPriceLabel->setCaption(boost::lexical_cast<std::string>(int(price)));
float chance = MWMechanics::getSpellSuccessChance(&mSpell, MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); float chance = MWMechanics::getSpellSuccessChance(&mSpell, MWBase::Environment::get().getWorld()->getPlayerPtr());
mSuccessChance->setCaption(boost::lexical_cast<std::string>(int(chance))); mSuccessChance->setCaption(boost::lexical_cast<std::string>(int(chance)));
} }
@ -441,7 +440,7 @@ namespace MWGui
{ {
// get the list of magic effects that are known to the player // get the list of magic effects that are known to the player
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player); MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player);
MWMechanics::Spells& spells = stats.getSpells(); MWMechanics::Spells& spells = stats.getSpells();

@ -9,7 +9,6 @@
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/inventorystore.hpp" #include "../mwworld/inventorystore.hpp"
@ -40,7 +39,7 @@ namespace MWGui
{ {
// TODO: Tracking add/remove/expire would be better than force updating every frame // TODO: Tracking add/remove/expire would be better than force updating every frame
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
const MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player); const MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player);

@ -5,7 +5,6 @@
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/inventorystore.hpp" #include "../mwworld/inventorystore.hpp"
#include "../mwworld/actionequip.hpp" #include "../mwworld/actionequip.hpp"
@ -81,7 +80,7 @@ namespace MWGui
// retrieve all player spells, divide them into Powers and Spells and sort them // retrieve all player spells, divide them into Powers and Spells and sort them
std::vector<std::string> spellList; std::vector<std::string> spellList;
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
MWWorld::InventoryStore& store = MWWorld::Class::get(player).getInventoryStore(player); MWWorld::InventoryStore& store = MWWorld::Class::get(player).getInventoryStore(player);
MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player); MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player);
MWMechanics::Spells& spells = stats.getSpells(); MWMechanics::Spells& spells = stats.getSpells();
@ -298,7 +297,7 @@ namespace MWGui
void SpellWindow::onEnchantedItemSelected(MyGUI::Widget* _sender) void SpellWindow::onEnchantedItemSelected(MyGUI::Widget* _sender)
{ {
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
MWWorld::InventoryStore& store = MWWorld::Class::get(player).getInventoryStore(player); MWWorld::InventoryStore& store = MWWorld::Class::get(player).getInventoryStore(player);
MWWorld::Ptr item = *_sender->getUserData<MWWorld::Ptr>(); MWWorld::Ptr item = *_sender->getUserData<MWWorld::Ptr>();
@ -320,7 +319,7 @@ namespace MWGui
// Note: can't use Class::use here because enchanted scrolls for example would then open the scroll window instead of equipping // Note: can't use Class::use here because enchanted scrolls for example would then open the scroll window instead of equipping
MWWorld::ActionEquip action(item); MWWorld::ActionEquip action(item);
action.execute (MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer ()); action.execute (MWBase::Environment::get().getWorld ()->getPlayerPtr());
// since we changed equipping status, update the inventory window // since we changed equipping status, update the inventory window
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->updateItemView(); MWBase::Environment::get().getWindowManager()->getInventoryWindow()->updateItemView();
@ -335,7 +334,7 @@ namespace MWGui
void SpellWindow::onSpellSelected(MyGUI::Widget* _sender) void SpellWindow::onSpellSelected(MyGUI::Widget* _sender)
{ {
std::string spellId = _sender->getUserString("Spell"); std::string spellId = _sender->getUserString("Spell");
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
MWWorld::InventoryStore& store = MWWorld::Class::get(player).getInventoryStore(player); MWWorld::InventoryStore& store = MWWorld::Class::get(player).getInventoryStore(player);
if (MyGUI::InputManager::getInstance().isShiftPressed()) if (MyGUI::InputManager::getInstance().isShiftPressed())
@ -389,7 +388,7 @@ namespace MWGui
void SpellWindow::onDeleteSpellAccept() void SpellWindow::onDeleteSpellAccept()
{ {
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player); MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player);
MWMechanics::Spells& spells = stats.getSpells(); MWMechanics::Spells& spells = stats.getSpells();

@ -6,8 +6,8 @@
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/player.hpp"
#include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/npcstats.hpp"
@ -185,8 +185,8 @@ namespace MWGui
MyGUI::TextBox* widget = mSkillWidgetMap[(int)parSkill]; MyGUI::TextBox* widget = mSkillWidgetMap[(int)parSkill];
if (widget) if (widget)
{ {
float modified = value.getModified(), base = value.getBase(); int modified = value.getModified(), base = value.getBase();
std::string text = boost::lexical_cast<std::string>(std::floor(modified)); std::string text = boost::lexical_cast<std::string>(modified);
std::string state = "normal"; std::string state = "normal";
if (modified > base) if (modified > base)
state = "increased"; state = "increased";
@ -224,7 +224,7 @@ namespace MWGui
if (!mMainWidget->getVisible()) if (!mMainWidget->getVisible())
return; return;
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
const MWMechanics::NpcStats &PCstats = MWWorld::Class::get(player).getNpcStats(player); const MWMechanics::NpcStats &PCstats = MWWorld::Class::get(player).getNpcStats(player);
// level progress // level progress
@ -424,7 +424,7 @@ namespace MWGui
MWBase::World *world = MWBase::Environment::get().getWorld(); MWBase::World *world = MWBase::Environment::get().getWorld();
const MWWorld::ESMStore &store = world->getStore(); const MWWorld::ESMStore &store = world->getStore();
const ESM::NPC *player = const ESM::NPC *player =
world->getPlayer().getPlayer().get<ESM::NPC>()->mBase; world->getPlayerPtr().get<ESM::NPC>()->mBase;
// race tooltip // race tooltip
const ESM::Race* playerRace = store.get<ESM::Race>().find(player->mRace); const ESM::Race* playerRace = store.get<ESM::Race>().find(player->mRace);
@ -452,7 +452,7 @@ namespace MWGui
if (!mSkillWidgets.empty()) if (!mSkillWidgets.empty())
addSeparator(coord1, coord2); addSeparator(coord1, coord2);
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
const MWMechanics::NpcStats &PCstats = MWWorld::Class::get(player).getNpcStats(player); const MWMechanics::NpcStats &PCstats = MWWorld::Class::get(player).getNpcStats(player);
const std::set<std::string> &expelled = PCstats.getExpelled(); const std::set<std::string> &expelled = PCstats.getExpelled();

@ -149,7 +149,7 @@ namespace MWGui
if(!mMerchant.isEmpty()) if(!mMerchant.isEmpty())
{ {
MWWorld::Ptr base = item.mBase; MWWorld::Ptr base = item.mBase;
if(Misc::StringUtils::ciEqual(base.getCellRef().mRefID, "gold_001")) if(Misc::StringUtils::ciEqual(base.getCellRef().mRefID, MWWorld::ContainerStore::sGoldId))
continue; continue;
if(!MWWorld::Class::get(base).canSell(base, services)) if(!MWWorld::Class::get(base).canSell(base, services))
continue; continue;

@ -16,8 +16,6 @@
#include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/creaturestats.hpp"
#include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/npcstats.hpp"
#include "../mwworld/player.hpp"
#include "inventorywindow.hpp" #include "inventorywindow.hpp"
#include "itemview.hpp" #include "itemview.hpp"
#include "sortfilteritemmodel.hpp" #include "sortfilteritemmodel.hpp"
@ -212,11 +210,11 @@ namespace MWGui
if (amount > 0) if (amount > 0)
{ {
store.add("gold_001", amount, actor); store.add(MWWorld::ContainerStore::sGoldId, amount, actor);
} }
else else
{ {
store.remove("gold_001", - amount, actor); store.remove(MWWorld::ContainerStore::sGoldId, - amount, actor);
} }
} }
@ -253,8 +251,11 @@ namespace MWGui
return; return;
} }
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId);
// check if the player can afford this // check if the player can afford this
if (mCurrentBalance < 0 && MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold() < std::abs(mCurrentBalance)) if (mCurrentBalance < 0 && playerGold < std::abs(mCurrentBalance))
{ {
// user notification // user notification
MWBase::Environment::get().getWindowManager()-> MWBase::Environment::get().getWindowManager()->
@ -271,8 +272,6 @@ namespace MWGui
return; return;
} }
MWWorld::Ptr playerPtr = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
if(mCurrentBalance > mCurrentMerchantOffer) if(mCurrentBalance > mCurrentMerchantOffer)
{ {
//if npc is a creature: reject (no haggle) //if npc is a creature: reject (no haggle)
@ -294,13 +293,13 @@ namespace MWGui
float clampedDisposition = std::max<int>(0,std::min<int>(int(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr) float clampedDisposition = std::max<int>(0,std::min<int>(int(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr)
+ MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange()),100)); + MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange()),100));
const MWMechanics::NpcStats &sellerStats = MWWorld::Class::get(mPtr).getNpcStats(mPtr); const MWMechanics::NpcStats &sellerStats = mPtr.getClass().getNpcStats(mPtr);
const MWMechanics::NpcStats &playerStats = MWWorld::Class::get(playerPtr).getNpcStats(playerPtr); 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 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 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 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); float f1 = std::min(0.2f * sellerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f);
@ -319,16 +318,18 @@ namespace MWGui
messageBox("#{sNotifyMessage9}"); messageBox("#{sNotifyMessage9}");
int iBarterFailDisposition = gmst.find("iBarterFailDisposition")->getInt(); int iBarterFailDisposition = gmst.find("iBarterFailDisposition")->getInt();
MWBase::Environment::get().getDialogueManager()->applyTemporaryDispositionChange(iBarterFailDisposition); if (mPtr.getClass().isNpc())
MWBase::Environment::get().getDialogueManager()->applyDispositionChange(iBarterFailDisposition);
return; return;
} }
//skill use! //skill use!
MWWorld::Class::get(playerPtr).skillUsageSucceeded(playerPtr, ESM::Skill::Mercantile, 0); player.getClass().skillUsageSucceeded(player, ESM::Skill::Mercantile, 0);
} }
int iBarterSuccessDisposition = gmst.find("iBarterSuccessDisposition")->getInt(); int iBarterSuccessDisposition = gmst.find("iBarterSuccessDisposition")->getInt();
MWBase::Environment::get().getDialogueManager()->applyTemporaryDispositionChange(iBarterSuccessDisposition); if (mPtr.getClass().isNpc())
MWBase::Environment::get().getDialogueManager()->applyDispositionChange(iBarterSuccessDisposition);
// make the item transfer // make the item transfer
mTradeModel->transferItems(); mTradeModel->transferItems();
@ -337,7 +338,7 @@ namespace MWGui
// transfer the gold // transfer the gold
if (mCurrentBalance != 0) if (mCurrentBalance != 0)
{ {
addOrRemoveGold(mCurrentBalance, playerPtr); addOrRemoveGold(mCurrentBalance, player);
addOrRemoveGold(-mCurrentBalance, mPtr); addOrRemoveGold(-mCurrentBalance, mPtr);
} }
@ -398,7 +399,10 @@ namespace MWGui
void TradeWindow::updateLabels() void TradeWindow::updateLabels()
{ {
mPlayerGold->setCaptionWithReplacing("#{sYourGold} " + boost::lexical_cast<std::string>(MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold())); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId);
mPlayerGold->setCaptionWithReplacing("#{sYourGold} " + boost::lexical_cast<std::string>(playerGold));
if (mCurrentBalance > 0) if (mCurrentBalance > 0)
{ {
@ -447,7 +451,7 @@ namespace MWGui
MWWorld::ContainerStore store = mPtr.getClass().getContainerStore(mPtr); MWWorld::ContainerStore store = mPtr.getClass().getContainerStore(mPtr);
for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it)
{ {
if (Misc::StringUtils::ciEqual(it->getCellRef().mRefID, "gold_001")) if (Misc::StringUtils::ciEqual(it->getCellRef().mRefID, MWWorld::ContainerStore::sGoldId))
merchantGold += it->getRefData().getCount(); merchantGold += it->getRefData().getCount();
} }
return merchantGold; return merchantGold;

@ -28,8 +28,6 @@ namespace MWGui
void startTrade(const MWWorld::Ptr& actor); void startTrade(const MWWorld::Ptr& actor);
void addOrRemoveGold(int gold, const MWWorld::Ptr& actor);
void onFrame(float frameDuration); void onFrame(float frameDuration);
void borrowItem (int index, size_t count); void borrowItem (int index, size_t count);
@ -95,6 +93,8 @@ namespace MWGui
void onIncreaseButtonTriggered(); void onIncreaseButtonTriggered();
void onDecreaseButtonTriggered(); void onDecreaseButtonTriggered();
void addOrRemoveGold(int gold, const MWWorld::Ptr& actor);
void updateLabels(); void updateLabels();
virtual void onReferenceUnavailable(); virtual void onReferenceUnavailable();

@ -9,13 +9,11 @@
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/mechanicsmanager.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/containerstore.hpp" #include "../mwworld/containerstore.hpp"
#include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/npcstats.hpp"
#include "inventorywindow.hpp"
#include "tooltips.hpp" #include "tooltips.hpp"
namespace MWGui namespace MWGui
@ -41,7 +39,10 @@ namespace MWGui
{ {
mPtr = actor; mPtr = actor;
mPlayerGold->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast<std::string>(MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold())); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId);
mPlayerGold->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast<std::string>(playerGold));
MWMechanics::NpcStats& npcStats = MWWorld::Class::get(actor).getNpcStats (actor); MWMechanics::NpcStats& npcStats = MWWorld::Class::get(actor).getNpcStats (actor);
@ -72,7 +73,6 @@ namespace MWGui
MyGUI::EnumeratorWidgetPtr widgets = mTrainingOptions->getEnumerator (); MyGUI::EnumeratorWidgetPtr widgets = mTrainingOptions->getEnumerator ();
MyGUI::Gui::getInstance ().destroyWidgets (widgets); MyGUI::Gui::getInstance ().destroyWidgets (widgets);
MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer ();
MWMechanics::NpcStats& pcStats = MWWorld::Class::get(player).getNpcStats (player); MWMechanics::NpcStats& pcStats = MWWorld::Class::get(player).getNpcStats (player);
const MWWorld::Store<ESM::GameSetting> &gmst = const MWWorld::Store<ESM::GameSetting> &gmst =
@ -83,11 +83,10 @@ namespace MWGui
int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer
(mPtr,pcStats.getSkill (bestSkills[i].first).getBase() * gmst.find("iTrainingMod")->getInt (),true); (mPtr,pcStats.getSkill (bestSkills[i].first).getBase() * gmst.find("iTrainingMod")->getInt (),true);
std::string skin = (price > MWBase::Environment::get().getWindowManager()->getInventoryWindow ()->getPlayerGold ()) ? "SandTextGreyedOut" : "SandTextButton"; MyGUI::Button* button = mTrainingOptions->createWidget<MyGUI::Button>("SandTextButton",
MyGUI::Button* button = mTrainingOptions->createWidget<MyGUI::Button>(skin,
MyGUI::IntCoord(5, 5+i*18, mTrainingOptions->getWidth()-10, 18), MyGUI::Align::Default); MyGUI::IntCoord(5, 5+i*18, mTrainingOptions->getWidth()-10, 18), MyGUI::Align::Default);
button->setEnabled(price <= playerGold);
button->setUserData(bestSkills[i].first); button->setUserData(bestSkills[i].first);
button->eventMouseButtonClick += MyGUI::newDelegate(this, &TrainingWindow::onTrainingSelected); button->eventMouseButtonClick += MyGUI::newDelegate(this, &TrainingWindow::onTrainingSelected);
@ -115,7 +114,7 @@ namespace MWGui
{ {
int skillId = *sender->getUserData<int>(); int skillId = *sender->getUserData<int>();
MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer (); MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr();
MWMechanics::NpcStats& pcStats = MWWorld::Class::get(player).getNpcStats (player); MWMechanics::NpcStats& pcStats = MWWorld::Class::get(player).getNpcStats (player);
const MWWorld::ESMStore &store = const MWWorld::ESMStore &store =
@ -124,9 +123,6 @@ namespace MWGui
int price = pcStats.getSkill (skillId).getBase() * store.get<ESM::GameSetting>().find("iTrainingMod")->getInt (); int price = pcStats.getSkill (skillId).getBase() * store.get<ESM::GameSetting>().find("iTrainingMod")->getInt ();
price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr,price,true); price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr,price,true);
if (MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold()<price)
return;
MWMechanics::NpcStats& npcStats = MWWorld::Class::get(mPtr).getNpcStats (mPtr); MWMechanics::NpcStats& npcStats = MWWorld::Class::get(mPtr).getNpcStats (mPtr);
if (npcStats.getSkill (skillId).getBase () <= pcStats.getSkill (skillId).getBase ()) if (npcStats.getSkill (skillId).getBase () <= pcStats.getSkill (skillId).getBase ())
{ {
@ -134,6 +130,14 @@ namespace MWGui
return; 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 // increase skill
MWWorld::LiveCellRef<ESM::NPC> *playerRef = player.get<ESM::NPC>(); MWWorld::LiveCellRef<ESM::NPC> *playerRef = player.get<ESM::NPC>();
@ -142,7 +146,7 @@ namespace MWGui
pcStats.increaseSkill (skillId, *class_, true); pcStats.increaseSkill (skillId, *class_, true);
// remove gold // remove gold
player.getClass().getContainerStore(player).remove("gold_001", price, player); player.getClass().getContainerStore(player).remove(MWWorld::ContainerStore::sGoldId, price, player);
// go back to game mode // go back to game mode
MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Training); MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Training);
@ -150,6 +154,8 @@ namespace MWGui
// advance time // advance time
MWBase::Environment::get().getWorld ()->advanceTime (2); 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); MWBase::Environment::get().getWorld ()->getFader()->fadeOut(0.25);
mFadeTimeRemaining = 0.5; mFadeTimeRemaining = 0.5;

@ -2,6 +2,8 @@
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <OgreVector3.h>
#include <libs/openengine/ogre/fader.hpp> #include <libs/openengine/ogre/fader.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
@ -9,12 +11,9 @@
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/mechanicsmanager.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/containerstore.hpp" #include "../mwworld/containerstore.hpp"
#include "inventorywindow.hpp"
namespace MWGui namespace MWGui
{ {
const int TravelWindow::sLineHeight = 18; const int TravelWindow::sLineHeight = 18;
@ -51,13 +50,15 @@ namespace MWGui
const MWWorld::Store<ESM::GameSetting> &gmst = const MWWorld::Store<ESM::GameSetting> &gmst =
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>(); MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr();
int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId);
if(interior) if(interior)
{ {
price = gmst.find("fMagesGuildTravel")->getFloat(); price = gmst.find("fMagesGuildTravel")->getFloat();
} }
else else
{ {
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
ESM::Position PlayerPos = player.getRefData().getPosition(); ESM::Position PlayerPos = player.getRefData().getPosition();
float d = sqrt( pow(pos.pos[0] - PlayerPos.pos[0],2) + pow(pos.pos[1] - PlayerPos.pos[1],2) + pow(pos.pos[2] - PlayerPos.pos[2],2) ); float d = sqrt( pow(pos.pos[0] - PlayerPos.pos[0],2) + pow(pos.pos[1] - PlayerPos.pos[1],2) + pow(pos.pos[2] - PlayerPos.pos[2],2) );
price = d/gmst.find("fTravelMult")->getFloat(); price = d/gmst.find("fTravelMult")->getFloat();
@ -65,7 +66,8 @@ namespace MWGui
price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr,price,true); price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr,price,true);
MyGUI::Button* toAdd = mDestinationsView->createWidget<MyGUI::Button>((price>MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold()) ? "SandTextGreyedOut" : "SandTextButton", 0, mCurrentY, 200, sLineHeight, MyGUI::Align::Default); MyGUI::Button* toAdd = mDestinationsView->createWidget<MyGUI::Button>("SandTextButton", 0, mCurrentY, 200, sLineHeight, MyGUI::Align::Default);
toAdd->setEnabled(price<=playerGold);
mCurrentY += sLineHeight; mCurrentY += sLineHeight;
if(interior) if(interior)
toAdd->setUserString("interior","y"); toAdd->setUserString("interior","y");
@ -121,13 +123,14 @@ namespace MWGui
int price; int price;
iss >> price; iss >> price;
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId);
if (MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold()<price) if (playerGold<price)
return; return;
player.getClass().getContainerStore(player).remove("gold_001", price, player); player.getClass().getContainerStore(player).remove(MWWorld::ContainerStore::sGoldId, price, player);
MWBase::Environment::get().getWorld ()->getFader ()->fadeOut(1); MWBase::Environment::get().getWorld ()->getFader ()->fadeOut(1);
ESM::Position pos = *_sender->getUserData<ESM::Position>(); ESM::Position pos = *_sender->getUserData<ESM::Position>();
@ -145,7 +148,7 @@ namespace MWGui
int hours = static_cast<int>(d /MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fTravelTimeMult")->getFloat()); int hours = static_cast<int>(d /MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fTravelTimeMult")->getFloat());
for(int i = 0;i < hours;i++) for(int i = 0;i < hours;i++)
{ {
MWBase::Environment::get().getMechanicsManager ()->restoreDynamicStats (); MWBase::Environment::get().getMechanicsManager ()->rest (true);
} }
MWBase::Environment::get().getWorld()->advanceTime(hours); MWBase::Environment::get().getWorld()->advanceTime(hours);
@ -166,7 +169,10 @@ namespace MWGui
void TravelWindow::updateLabels() void TravelWindow::updateLabels()
{ {
mPlayerGold->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast<std::string>(MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold())); MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr();
int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId);
mPlayerGold->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast<std::string>(playerGold));
mPlayerGold->setCoord(8, mPlayerGold->setCoord(8,
mPlayerGold->getTop(), mPlayerGold->getTop(),
mPlayerGold->getTextSize().width, mPlayerGold->getTextSize().width,

@ -9,7 +9,6 @@
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/mechanicsmanager.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/creaturestats.hpp"
@ -49,6 +48,7 @@ namespace MWGui
, mRemainingTime(0.05) , mRemainingTime(0.05)
, mCurHour(0) , mCurHour(0)
, mManualHours(1) , mManualHours(1)
, mInterruptAt(-1)
{ {
getWidget(mDateTimeText, "DateTimeText"); getWidget(mDateTimeText, "DateTimeText");
getWidget(mRestText, "RestText"); getWidget(mRestText, "RestText");
@ -103,43 +103,7 @@ namespace MWGui
void WaitDialog::onUntilHealedButtonClicked(MyGUI::Widget* sender) 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 int autoHours = MWBase::Environment::get().getMechanicsManager()->getHoursToRest();
// 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()->getPlayer().getPlayer();
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
startWaiting(autoHours); startWaiting(autoHours);
} }
@ -151,7 +115,8 @@ namespace MWGui
void WaitDialog::startWaiting(int hoursToWait) 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); setVisible(false);
mProgressBar.setVisible (true); mProgressBar.setVisible (true);
@ -159,6 +124,30 @@ namespace MWGui
mCurHour = 0; mCurHour = 0;
mHours = hoursToWait; 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; mRemainingTime = 0.05;
mProgressBar.setProgress (0, mHours); mProgressBar.setProgress (0, mHours);
} }
@ -176,7 +165,7 @@ namespace MWGui
void WaitDialog::setCanRest (bool canRest) void WaitDialog::setCanRest (bool canRest)
{ {
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player); MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player);
bool full = (stats.getFatigue().getCurrent() >= stats.getFatigue().getModified()) bool full = (stats.getFatigue().getCurrent() >= stats.getFatigue().getModified())
&& (stats.getHealth().getCurrent() >= stats.getHealth().getModified()) && (stats.getHealth().getCurrent() >= stats.getHealth().getModified())
@ -201,6 +190,13 @@ namespace MWGui
if (!mWaiting) if (!mWaiting)
return; return;
if (mCurHour == mInterruptAt)
{
MWBase::Environment::get().getWindowManager()->messageBox("#{sSleepInterrupt}");
MWBase::Environment::get().getWorld()->spawnRandomCreature(mInterruptCreatureList);
stopWaiting();
}
mRemainingTime -= dt; mRemainingTime -= dt;
while (mRemainingTime < 0) while (mRemainingTime < 0)
@ -212,8 +208,7 @@ namespace MWGui
if (mCurHour <= mHours) if (mCurHour <= mHours)
{ {
MWBase::Environment::get().getWorld ()->advanceTime (1); MWBase::Environment::get().getWorld ()->advanceTime (1);
if (mSleeping) MWBase::Environment::get().getMechanicsManager ()->rest (mSleeping);
MWBase::Environment::get().getMechanicsManager ()->restoreDynamicStats ();
} }
} }
@ -230,7 +225,7 @@ namespace MWGui
MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_RestBed); MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_RestBed);
mWaiting = false; mWaiting = false;
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
const MWMechanics::NpcStats &pcstats = MWWorld::Class::get(player).getNpcStats(player); const MWMechanics::NpcStats &pcstats = MWWorld::Class::get(player).getNpcStats(player);
// trigger levelup if possible // trigger levelup if possible

@ -51,6 +51,9 @@ namespace MWGui
int mManualHours; // stores the hours to rest selected via slider int mManualHours; // stores the hours to rest selected via slider
float mRemainingTime; float mRemainingTime;
int mInterruptAt;
std::string mInterruptCreatureList;
WaitDialogProgressBar mProgressBar; WaitDialogProgressBar mProgressBar;
void onUntilHealedButtonClicked(MyGUI::Widget* sender); void onUntilHealedButtonClicked(MyGUI::Widget* sender);

@ -208,7 +208,8 @@ namespace MWGui
mConsole = new Console(w,h, mConsoleOnlyScripts); mConsole = new Console(w,h, mConsoleOnlyScripts);
trackWindow(mConsole, "console"); trackWindow(mConsole, "console");
mJournal = JournalWindow::create(JournalViewModel::create ()); 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); mInventoryWindow = new InventoryWindow(mDragAndDrop);
mTradeWindow = new TradeWindow(); mTradeWindow = new TradeWindow();
trackWindow(mTradeWindow, "barter"); trackWindow(mTradeWindow, "barter");
@ -677,17 +678,6 @@ namespace MWGui
mMessageBoxManager->removeStaticMessageBox(); mMessageBoxManager->removeStaticMessageBox();
} }
void WindowManager::enterPressed ()
{
mMessageBoxManager->okayPressed();
}
void WindowManager::activateKeyPressed ()
{
mMessageBoxManager->okayPressed();
mCountDialog->cancel();
}
int WindowManager::readPressedButton () int WindowManager::readPressedButton ()
{ {
return mMessageBoxManager->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 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 staticMessageBox(const std::string& message);
virtual void removeStaticMessageBox(); 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 int readPressedButton (); ///< returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox)
virtual void onFrame (float frameDuration); virtual void onFrame (float frameDuration);

@ -198,14 +198,7 @@ namespace MWInput
case A_Activate: case A_Activate:
resetIdleTime(); resetIdleTime();
if (MWBase::Environment::get().getWindowManager()->isGuiMode()) if (!MWBase::Environment::get().getWindowManager()->isGuiMode())
{
if (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Container)
toggleContainer ();
else
MWBase::Environment::get().getWindowManager()->activateKeyPressed();
}
else
activate(); activate();
break; break;
case A_Journal: case A_Journal:
@ -360,7 +353,7 @@ namespace MWInput
// if player tried to start moving, but can't (due to being overencumbered), display a notification. // if player tried to start moving, but can't (due to being overencumbered), display a notification.
if (triedToMove) if (triedToMove)
{ {
MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer (); MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr();
mOverencumberedMessageDelay -= dt; mOverencumberedMessageDelay -= dt;
if (MWWorld::Class::get(player).getEncumbrance(player) >= MWWorld::Class::get(player).getCapacity(player)) if (MWWorld::Class::get(player).getEncumbrance(player) >= MWWorld::Class::get(player).getCapacity(player))
{ {
@ -516,13 +509,6 @@ namespace MWInput
mInputBinder->keyPressed (arg); 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); OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym);
if (kc != OIS::KC_UNASSIGNED) if (kc != OIS::KC_UNASSIGNED)
@ -560,7 +546,7 @@ namespace MWInput
if (MyGUI::InputManager::getInstance ().getMouseFocusWidget () != 0) if (MyGUI::InputManager::getInstance ().getMouseFocusWidget () != 0)
{ {
MyGUI::Button* b = MyGUI::InputManager::getInstance ().getMouseFocusWidget ()->castType<MyGUI::Button>(false); MyGUI::Button* b = MyGUI::InputManager::getInstance ().getMouseFocusWidget ()->castType<MyGUI::Button>(false);
if (b) if (b && b->getEnabled())
{ {
MWBase::Environment::get().getSoundManager ()->playSound ("Menu Click", 1.f, 1.f); MWBase::Environment::get().getSoundManager ()->playSound ("Menu Click", 1.f, 1.f);
} }
@ -735,21 +721,6 @@ namespace MWInput
// .. but don't touch any other mode, except container. // .. 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() void InputManager::toggleConsole()
{ {
if (MyGUI::InputManager::getInstance ().isModalAny()) if (MyGUI::InputManager::getInstance ().isModalAny())

@ -173,7 +173,6 @@ namespace MWInput
void toggleSpell(); void toggleSpell();
void toggleWeapon(); void toggleWeapon();
void toggleInventory(); void toggleInventory();
void toggleContainer();
void toggleConsole(); void toggleConsole();
void screenshot(); void screenshot();
void toggleJournal(); void toggleJournal();

@ -205,4 +205,22 @@ namespace MWMechanics
} }
mSpellsChanged = true; 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) /// Remove all active effects, if roll succeeds (for each effect)
void purgeAll (float chance); 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; bool isSpellActive (std::string id) const;
///< case insensitive ///< case insensitive

@ -11,7 +11,6 @@
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/inventorystore.hpp" #include "../mwworld/inventorystore.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/manualref.hpp" #include "../mwworld/manualref.hpp"
#include "../mwworld/actionequip.hpp" #include "../mwworld/actionequip.hpp"
@ -80,9 +79,26 @@ bool disintegrateSlot (MWWorld::Ptr ptr, int slot, float disintegrate)
return true; return true;
} }
} }
return true; 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();
}
}
} }
@ -158,50 +174,49 @@ namespace MWMechanics
calculateDynamicStats (ptr); calculateDynamicStats (ptr);
calculateCreatureStatModifiers (ptr, duration); calculateCreatureStatModifiers (ptr, duration);
if(!MWBase::Environment::get().getWindowManager()->isGuiMode()) // AI
if(MWBase::Environment::get().getMechanicsManager()->isAIActive())
{ {
// AI CreatureStats& creatureStats = MWWorld::Class::get (ptr).getCreatureStats (ptr);
if(MWBase::Environment::get().getMechanicsManager()->isAIActive()) //engage combat or not?
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
if(ptr != player && !creatureStats.isHostile())
{ {
CreatureStats& creatureStats = MWWorld::Class::get (ptr).getCreatureStats (ptr); ESM::Position playerpos = player.getRefData().getPosition();
//engage combat or not? ESM::Position actorpos = ptr.getRefData().getPosition();
if(ptr != MWBase::Environment::get().getWorld()->getPlayer().getPlayer() && !creatureStats.isHostile()) float d = sqrt((actorpos.pos[0] - playerpos.pos[0])*(actorpos.pos[0] - playerpos.pos[0])
+(actorpos.pos[1] - playerpos.pos[1])*(actorpos.pos[1] - playerpos.pos[1])
+(actorpos.pos[2] - playerpos.pos[2])*(actorpos.pos[2] - playerpos.pos[2]));
float fight = ptr.getClass().getCreatureStats(ptr).getAiSetting(CreatureStats::AI_Fight).getModified();
float disp = 100; //creatures don't have disposition, so set it to 100 by default
if(ptr.getTypeName() == typeid(ESM::NPC).name())
{ {
ESM::Position playerpos = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getRefData().getPosition(); disp = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(ptr);
ESM::Position actorpos = ptr.getRefData().getPosition(); }
float d = sqrt((actorpos.pos[0] - playerpos.pos[0])*(actorpos.pos[0] - playerpos.pos[0]) bool LOS = MWBase::Environment::get().getWorld()->getLOS(ptr,player)
+(actorpos.pos[1] - playerpos.pos[1])*(actorpos.pos[1] - playerpos.pos[1]) && MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, ptr);
+(actorpos.pos[2] - playerpos.pos[2])*(actorpos.pos[2] - playerpos.pos[2])); if( ( (fight == 100 )
float fight = ptr.getClass().getCreatureStats(ptr).getAiSetting(CreatureStats::AI_Fight).getModified(); || (fight >= 95 && d <= 3000)
float disp = 100; //creatures don't have disposition, so set it to 100 by default || (fight >= 90 && d <= 2000)
if(ptr.getTypeName() == typeid(ESM::NPC).name()) || (fight >= 80 && d <= 1000)
{ || (fight >= 80 && disp <= 40)
disp = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(ptr); || (fight >= 70 && disp <= 35 && d <= 1000)
} || (fight >= 60 && disp <= 30 && d <= 1000)
bool LOS = MWBase::Environment::get().getWorld()->getLOS(ptr,MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); || (fight >= 50 && disp == 0)
if( ( (fight == 100 ) || (fight >= 40 && disp <= 10 && d <= 500) )
|| (fight >= 95 && d <= 3000) && LOS
|| (fight >= 90 && d <= 2000) )
|| (fight >= 80 && d <= 1000) {
|| (fight >= 80 && disp <= 40) creatureStats.getAiSequence().stack(AiCombat("player"));
|| (fight >= 70 && disp <= 35 && d <= 1000) creatureStats.setHostile(true);
|| (fight >= 60 && disp <= 30 && d <= 1000)
|| (fight >= 50 && disp == 0)
|| (fight >= 40 && disp <= 10 && d <= 500) )
&& LOS
)
{
creatureStats.getAiSequence().stack(AiCombat("player"));
creatureStats.setHostile(true);
}
} }
creatureStats.getAiSequence().execute (ptr,duration);
} }
// fatigue restoration creatureStats.getAiSequence().execute (ptr,duration);
calculateRestoration(ptr, duration);
} }
// fatigue restoration
calculateRestoration(ptr, duration, false);
} }
void Actors::updateNpc (const MWWorld::Ptr& ptr, float duration, bool paused) void Actors::updateNpc (const MWWorld::Ptr& ptr, float duration, bool paused)
@ -259,44 +274,37 @@ namespace MWMechanics
creatureStats.setFatigue(fatigue); 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()) if (ptr.getClass().getCreatureStats(ptr).isDead())
return; return;
CreatureStats& stats = MWWorld::Class::get (ptr).getCreatureStats (ptr);
const MWWorld::Store<ESM::GameSetting>& settings = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
int endurance = stats.getAttribute (ESM::Attribute::Endurance).getModified (); MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats (ptr);
const MWWorld::Store<ESM::GameSetting>& settings = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
float capacity = MWWorld::Class::get(ptr).getCapacity(ptr);
float encumbrance = MWWorld::Class::get(ptr).getEncumbrance(ptr);
float normalizedEncumbrance = (capacity == 0 ? 1 : encumbrance/capacity);
if (normalizedEncumbrance > 1)
normalizedEncumbrance = 1;
if (duration == 3600) if (sleep)
{ {
// the actor is sleeping, restore health and magicka float health, magicka;
getRestorationPerHourOfSleep(ptr, health, magicka);
bool stunted = stats.getMagicEffects ().get(ESM::MagicEffect::StuntedMagicka).mMagnitude > 0; DynamicStat<float> stat = stats.getHealth();
stat.setCurrent(stat.getCurrent() + health);
stats.setHealth(stat);
DynamicStat<float> health = stats.getHealth(); stat = stats.getMagicka();
health.setCurrent (health.getCurrent() + 0.1 * endurance); stat.setCurrent(stat.getCurrent() + magicka);
stats.setHealth (health); stats.setMagicka(stat);
}
if (!stunted) int endurance = stats.getAttribute (ESM::Attribute::Endurance).getModified ();
{
float fRestMagicMult = settings.find("fRestMagicMult")->getFloat ();
DynamicStat<float> magicka = stats.getMagicka(); float capacity = ptr.getClass().getCapacity(ptr);
magicka.setCurrent (magicka.getCurrent() float encumbrance = ptr.getClass().getEncumbrance(ptr);
+ fRestMagicMult * stats.getAttribute(ESM::Attribute::Intelligence).getModified()); float normalizedEncumbrance = (capacity == 0 ? 1 : encumbrance/capacity);
stats.setMagicka (magicka); if (normalizedEncumbrance > 1)
} normalizedEncumbrance = 1;
}
// restore fatigue // restore fatigue
float fFatigueReturnBase = settings.find("fFatigueReturnBase")->getFloat (); float fFatigueReturnBase = settings.find("fFatigueReturnBase")->getFloat ();
float fFatigueReturnMult = settings.find("fFatigueReturnMult")->getFloat (); float fFatigueReturnMult = settings.find("fFatigueReturnMult")->getFloat ();
float fEndFatigueMult = settings.find("fEndFatigueMult")->getFloat (); float fEndFatigueMult = settings.find("fEndFatigueMult")->getFloat ();
@ -307,6 +315,7 @@ namespace MWMechanics
DynamicStat<float> fatigue = stats.getFatigue(); DynamicStat<float> fatigue = stats.getFatigue();
fatigue.setCurrent (fatigue.getCurrent() + duration * x); fatigue.setCurrent (fatigue.getCurrent() + duration * x);
stats.setFatigue (fatigue); stats.setFatigue (fatigue);
} }
void Actors::calculateCreatureStatModifiers (const MWWorld::Ptr& ptr, float duration) void Actors::calculateCreatureStatModifiers (const MWWorld::Ptr& ptr, float duration)
@ -336,7 +345,7 @@ namespace MWMechanics
float currentDiff = creatureStats.getMagicEffects().get(ESM::MagicEffect::RestoreHealth+i).mMagnitude float currentDiff = creatureStats.getMagicEffects().get(ESM::MagicEffect::RestoreHealth+i).mMagnitude
- creatureStats.getMagicEffects().get(ESM::MagicEffect::DamageHealth+i).mMagnitude - creatureStats.getMagicEffects().get(ESM::MagicEffect::DamageHealth+i).mMagnitude
- creatureStats.getMagicEffects().get(ESM::MagicEffect::AbsorbHealth+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); creatureStats.setDynamic(i, stat);
} }
@ -506,7 +515,7 @@ namespace MWMechanics
if (magnitude > 0) if (magnitude > 0)
{ {
ESM::Position ipos = ptr.getRefData().getPosition(); 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); Ogre::Quaternion rot(Ogre::Radian(-ipos.rot[2]), Ogre::Vector3::UNIT_Z);
const float distance = 50; const float distance = 50;
pos = pos + distance*rot.yAxis(); pos = pos + distance*rot.yAxis();
@ -527,7 +536,7 @@ namespace MWMechanics
ref.getPtr().getCellRef().mPos = ipos; ref.getPtr().getCellRef().mPos = ipos;
// TODO: Add AI to follow player and fight for him // TODO: Add AI to follow player and fight for him
// TODO: VFX_SummonStart, VFX_SummonEnd
creatureStats.mSummonedCreatures.insert(std::make_pair(it->first, creatureStats.mSummonedCreatures.insert(std::make_pair(it->first,
MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),*store,ipos).getRefData().getHandle())); MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),*store,ipos).getRefData().getHandle()));
} }
@ -583,10 +592,11 @@ namespace MWMechanics
if(timeLeft == 0.0f) if(timeLeft == 0.0f)
{ {
// If drowning, apply 3 points of damage per second // 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 // Play a drowning sound as necessary for the player
if(ptr == world->getPlayer().getPlayer()) if(ptr == world->getPlayerPtr())
{ {
MWBase::SoundManager *sndmgr = MWBase::Environment::get().getSoundManager(); MWBase::SoundManager *sndmgr = MWBase::Environment::get().getSoundManager();
if(!sndmgr->getSoundPlaying(MWWorld::Ptr(), "drown")) if(!sndmgr->getSoundPlaying(MWWorld::Ptr(), "drown"))
@ -595,7 +605,10 @@ namespace MWMechanics
} }
} }
else 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) void Actors::updateEquippedLight (const MWWorld::Ptr& ptr, float duration)
@ -797,6 +810,14 @@ namespace MWMechanics
} }
} }
// Make sure spell effects with CasterLinked flag are removed
// TODO: would be nice not to do this all the time...
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());
}
if (iter->second->kill()) if (iter->second->kill())
{ {
++mDeathCount[cls.getId(iter->first)]; ++mDeathCount[cls.getId(iter->first)];
@ -837,10 +858,28 @@ namespace MWMechanics
} }
} }
} }
void Actors::restoreDynamicStats() void Actors::restoreDynamicStats(bool sleep)
{ {
for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) 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 int Actors::countDeaths (const std::string& id) const

@ -25,9 +25,6 @@ namespace MWMechanics
{ {
class Actors class Actors
{ {
typedef std::map<MWWorld::Ptr,CharacterController*> PtrControllerMap;
PtrControllerMap mActors;
std::map<std::string, int> mDeathCount; std::map<std::string, int> mDeathCount;
void updateNpc(const MWWorld::Ptr &ptr, float duration, bool paused); void updateNpc(const MWWorld::Ptr &ptr, float duration, bool paused);
@ -39,7 +36,7 @@ namespace MWMechanics
void calculateCreatureStatModifiers (const MWWorld::Ptr& ptr, float duration); void calculateCreatureStatModifiers (const MWWorld::Ptr& ptr, float duration);
void calculateNpcStatModifiers (const MWWorld::Ptr& ptr); 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); void updateDrowning (const MWWorld::Ptr& ptr, float duration);
@ -50,6 +47,11 @@ namespace MWMechanics
Actors(); Actors();
~Actors(); ~Actors();
typedef std::map<MWWorld::Ptr,CharacterController*> PtrControllerMap;
PtrControllerMap::const_iterator begin() { return mActors.begin(); }
PtrControllerMap::const_iterator end() { return mActors.end(); }
/// Update magic effects for an actor. Usually done automatically once per frame, but if we're currently /// Update magic effects for an actor. Usually done automatically once per frame, but if we're currently
/// paused we may want to do it manually (after equipping permanent enchantment) /// paused we may want to do it manually (after equipping permanent enchantment)
void updateMagicEffects (const MWWorld::Ptr& ptr) { adjustMagicEffects(ptr); } void updateMagicEffects (const MWWorld::Ptr& ptr) { adjustMagicEffects(ptr); }
@ -77,8 +79,11 @@ namespace MWMechanics
///< This function is normally called automatically during the update process, but it can ///< This function is normally called automatically during the update process, but it can
/// also be called explicitly at any time to force an update. /// 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. ///< 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; int countDeaths (const std::string& id) const;
///< Return the number of deaths for actors with the given ID. ///< Return the number of deaths for actors with the given ID.
@ -88,6 +93,10 @@ namespace MWMechanics
void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number);
void skipAnimation(const MWWorld::Ptr& ptr); void skipAnimation(const MWWorld::Ptr& ptr);
bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName); bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName);
private:
PtrControllerMap mActors;
}; };
} }

@ -1,21 +1,21 @@
#include "aiactivate.hpp" #include "aiactivate.hpp"
#include <iostream> #include <iostream>
MWMechanics::AiActivate::AiActivate(const std::string &objectId) MWMechanics::AiActivate::AiActivate(const std::string &objectId)
: mObjectId(objectId) : mObjectId(objectId)
{ {
} }
MWMechanics::AiActivate *MWMechanics::AiActivate::clone() const MWMechanics::AiActivate *MWMechanics::AiActivate::clone() const
{ {
return new AiActivate(*this); return new AiActivate(*this);
} }
bool MWMechanics::AiActivate::execute (const MWWorld::Ptr& actor,float duration) bool MWMechanics::AiActivate::execute (const MWWorld::Ptr& actor,float duration)
{ {
std::cout << "AiActivate completed.\n"; std::cout << "AiActivate completed.\n";
return true; return true;
} }
int MWMechanics::AiActivate::getTypeId() const int MWMechanics::AiActivate::getTypeId() const
{ {
return 4; return TypeIdActivate;
} }

@ -3,22 +3,22 @@
#include "movement.hpp" #include "movement.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/timestamp.hpp" #include "../mwworld/timestamp.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/mechanicsmanager.hpp"
#include "../mwbase/dialoguemanager.hpp"
#include "creaturestats.hpp" #include "creaturestats.hpp"
#include "npcstats.hpp" #include "npcstats.hpp"
#include "OgreMath.h" #include <OgreMath.h>
namespace namespace
{ {
static float sgn(float a) static float sgn(Ogre::Radian a)
{ {
if(a > 0) if(a.valueDegrees() > 0)
return 1.0; return 1.0;
return -1.0; return -1.0;
} }
@ -40,13 +40,13 @@ namespace MWMechanics
if(MWWorld::Class::get(actor).getCreatureStats(actor).getHealth().getCurrent() <= 0) return true; 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()) if(actor.getTypeName() == typeid(ESM::NPC).name())
{ {
MWWorld::Class::get(actor). MWMechanics::DrawState_ state = actor.getClass().getNpcStats(actor).getDrawState();
MWWorld::Class::get(actor).setStance(actor, MWWorld::Class::Run,true);
MWMechanics::DrawState_ state = MWWorld::Class::get(actor).getNpcStats(actor).getDrawState();
if (state == MWMechanics::DrawState_Spell || state == MWMechanics::DrawState_Nothing) 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); //MWWorld::Class::get(actor).getCreatureStats(actor).setAttackingOrSpell(true);
} }
ESM::Position pos = actor.getRefData().getPosition(); ESM::Position pos = actor.getRefData().getPosition();
@ -106,7 +106,7 @@ namespace MWMechanics
float directionY = dest.mY - start.mY; float directionY = dest.mY - start.mY;
float directionResult = sqrt(directionX * directionX + directionY * directionY); float directionResult = sqrt(directionX * directionX + directionY * directionY);
zAngle = Ogre::Radian( acos(directionY / directionResult) * sgn(asin(directionX / directionResult)) ).valueDegrees(); zAngle = Ogre::Radian( Ogre::Math::ACos(directionY / directionResult) * sgn(Ogre::Math::ASin(directionX / directionResult)) ).valueDegrees();
// TODO: use movement settings instead of rotating directly // TODO: use movement settings instead of rotating directly
MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false); MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false);
@ -119,6 +119,17 @@ namespace MWMechanics
} }
if( mTimer > 1) 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); MWWorld::Class::get(actor).getCreatureStats(actor).setAttackingOrSpell(true);
mTimer = 0; mTimer = 0;
} }
@ -135,7 +146,7 @@ namespace MWMechanics
int AiCombat::getTypeId() const int AiCombat::getTypeId() const
{ {
return 5; return TypeIdCombat;
} }
unsigned int AiCombat::getPriority() const unsigned int AiCombat::getPriority() const
@ -143,6 +154,11 @@ namespace MWMechanics
return 1; return 1;
} }
const std::string &AiCombat::getTargetId() const
{
return mTargetId;
}
AiCombat *MWMechanics::AiCombat::clone() const AiCombat *MWMechanics::AiCombat::clone() const
{ {
return new AiCombat(*this); return new AiCombat(*this);

@ -23,6 +23,8 @@ namespace MWMechanics
virtual unsigned int getPriority() const; virtual unsigned int getPriority() const;
const std::string &getTargetId() const;
private: private:
std::string mTargetId; std::string mTargetId;
@ -33,4 +35,4 @@ namespace MWMechanics
}; };
} }
#endif #endif

@ -3,7 +3,6 @@
#include "movement.hpp" #include "movement.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/timestamp.hpp" #include "../mwworld/timestamp.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
@ -83,7 +82,7 @@ namespace MWMechanics
return true; return true;
} }
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
ESM::Position pos = actor.getRefData().getPosition(); ESM::Position pos = actor.getRefData().getPosition();
bool cellChange = actor.getCell()->mCell->mData.mX != cellX || actor.getCell()->mCell->mData.mY != cellY; bool cellChange = actor.getCell()->mCell->mData.mX != cellX || actor.getCell()->mCell->mData.mY != cellY;
const ESM::Pathgrid *pathgrid = const ESM::Pathgrid *pathgrid =
@ -179,7 +178,7 @@ namespace MWMechanics
int AiEscort::getTypeId() const int AiEscort::getTypeId() const
{ {
return 2; return TypeIdEscort;
} }
} }

@ -1,7 +1,7 @@
#include "aifollow.hpp" #include "aifollow.hpp"
#include <iostream> #include <iostream>
MWMechanics::AiFollow::AiFollow(const std::string &actorId,float duration, float x, float y, float z) MWMechanics::AiFollow::AiFollow(const std::string &actorId,float duration, float x, float y, float z)
: mDuration(duration), mX(x), mY(y), mZ(z), mActorId(actorId) : mDuration(duration), mX(x), mY(y), mZ(z), mActorId(actorId)
{ {
} }
@ -10,18 +10,18 @@ MWMechanics::AiFollow::AiFollow(const std::string &actorId,const std::string &ce
{ {
} }
MWMechanics::AiFollow *MWMechanics::AiFollow::clone() const MWMechanics::AiFollow *MWMechanics::AiFollow::clone() const
{ {
return new AiFollow(*this); return new AiFollow(*this);
} }
bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor,float duration) bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor,float duration)
{ {
std::cout << "AiFollow completed.\n"; std::cout << "AiFollow completed.\n";
return true; return true;
} }
int MWMechanics::AiFollow::getTypeId() const int MWMechanics::AiFollow::getTypeId() const
{ {
return 3; return TypeIdFollow;
} }

@ -12,7 +12,16 @@ namespace MWMechanics
class AiPackage class AiPackage
{ {
public: public:
enum TypeId {
TypeIdNone = -1,
TypeIdWander = 0,
TypeIdTravel = 1,
TypeIdEscort = 2,
TypeIdFollow = 3,
TypeIdActivate = 4,
TypeIdCombat = 5
};
virtual ~AiPackage(); virtual ~AiPackage();
virtual AiPackage *clone() const = 0; virtual AiPackage *clone() const = 0;
@ -21,7 +30,7 @@ namespace MWMechanics
///< \return Package completed? ///< \return Package completed?
virtual int getTypeId() const = 0; 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;} virtual unsigned int getPriority() const {return 0;}
///< higher number is higher priority (0 beeing the lowest) ///< higher number is higher priority (0 beeing the lowest)

@ -15,7 +15,6 @@
#include "npcstats.hpp" #include "npcstats.hpp"
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwworld/player.hpp"
void MWMechanics::AiSequence::copy (const AiSequence& sequence) void MWMechanics::AiSequence::copy (const AiSequence& sequence)
{ {
@ -56,6 +55,24 @@ int MWMechanics::AiSequence::getTypeId() const
return mPackages.front()->getTypeId(); 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 bool MWMechanics::AiSequence::isPackageDone() const
{ {
return mDone; return mDone;
@ -63,12 +80,13 @@ bool MWMechanics::AiSequence::isPackageDone() const
void MWMechanics::AiSequence::execute (const MWWorld::Ptr& actor,float duration) void MWMechanics::AiSequence::execute (const MWWorld::Ptr& actor,float duration)
{ {
if(actor != MWBase::Environment::get().getWorld()->getPlayer().getPlayer()) if(actor != MWBase::Environment::get().getWorld()->getPlayerPtr())
{ {
if (!mPackages.empty()) if (!mPackages.empty())
{ {
if (mPackages.front()->execute (actor,duration)) if (mPackages.front()->execute (actor,duration))
{ {
delete *mPackages.begin();
mPackages.erase (mPackages.begin()); mPackages.erase (mPackages.begin());
mDone = true; mDone = true;
} }
@ -91,7 +109,10 @@ void MWMechanics::AiSequence::stack (const AiPackage& package)
for(std::list<AiPackage *>::iterator it = mPackages.begin(); it != mPackages.end(); it++) for(std::list<AiPackage *>::iterator it = mPackages.begin(); it != mPackages.end(); it++)
{ {
if(mPackages.front()->getPriority() <= package.getPriority()) if(mPackages.front()->getPriority() <= package.getPriority())
{
mPackages.insert(it,package.clone()); mPackages.insert(it,package.clone());
return;
}
} }
if(mPackages.empty()) if(mPackages.empty())
@ -114,7 +135,7 @@ void MWMechanics::AiSequence::fill(const ESM::AIPackageList &list)
std::vector<int> idles; std::vector<int> idles;
for (int i=0; i<8; ++i) for (int i=0; i<8; ++i)
idles.push_back(data.mIdle[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) else if (it->mType == ESM::AI_Escort)
{ {

@ -34,7 +34,14 @@ namespace MWMechanics
virtual ~AiSequence(); virtual ~AiSequence();
int getTypeId() const; 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; bool isPackageDone() const;
///< Has a package been completed during the last update? ///< Has a package been completed during the last update?

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save