diff --git a/.gitignore b/.gitignore index 26ba80e1a..9734ac35c 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ Makefile makefile data *.kdev4 +CMakeLists.txt.user diff --git a/.gitmodules b/.gitmodules index d2a4cf0d3..8b1378917 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1 @@ -[submodule "extern/shiny"] - path = extern/shiny - url = git://github.com/scrawl/shiny.git + diff --git a/CMakeLists.txt b/CMakeLists.txt index 78388e20f..d7115583f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ include (OpenMWMacros) # Version set (OPENMW_VERSION_MAJOR 0) -set (OPENMW_VERSION_MINOR 19) +set (OPENMW_VERSION_MINOR 20) set (OPENMW_VERSION_RELEASE 0) set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}") @@ -25,12 +25,14 @@ set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VE configure_file ("${OpenMW_SOURCE_DIR}/Docs/mainpage.hpp.cmake" "${OpenMW_SOURCE_DIR}/Docs/mainpage.hpp") option(MYGUI_STATIC "Link static build of Mygui into the binaries" FALSE) -option(OGRE_STATIC "Link static build of Ogre and Ogre Plugins into the binaries" FALSE) +option(OGRE_STATIC "Link static build of Ogre and Ogre Plugins into the binaries" FALSE) +option(BOOST_STATIC "Link static build of Boost into the binaries" FALSE) # Apps and tools option(BUILD_ESMTOOL "build ESM inspector" ON) option(BUILD_LAUNCHER "build Launcher" ON) option(BUILD_MWINIIMPORTER "build MWiniImporter" ON) +option(BUILD_OPENCS "build OpenMW Construction Set" ON) option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF) option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest ang GMock frameworks" OFF) @@ -167,9 +169,9 @@ if (WIN32) set(PLATFORM_INCLUDE_DIR "platform") add_definitions(-DBOOST_ALL_NO_LIB) else (WIN32) -set(PLATFORM_INCLUDE_DIR "") -find_path (UUID_INCLUDE_DIR uuid/uuid.h) -include_directories(${UUID_INCLUDE_DIR}) + set(PLATFORM_INCLUDE_DIR "") + find_path (UUID_INCLUDE_DIR uuid/uuid.h) + include_directories(${UUID_INCLUDE_DIR}) endif (WIN32) if (MSVC10) set(PLATFORM_INCLUDE_DIR "") @@ -183,7 +185,7 @@ endif (APPLE) # Fix for not visible pthreads functions for linker with glibc 2.15 if (UNIX AND NOT APPLE) -find_package (Threads) + find_package (Threads) endif() # find boost without components so we can use Boost_VERSION @@ -196,6 +198,10 @@ if (Boost_VERSION LESS 104900) set(BOOST_COMPONENTS ${BOOST_COMPONENTS} wave) endif() +IF(BOOST_STATIC) + set(Boost_USE_STATIC_LIBS ON) +endif() + find_package(OGRE REQUIRED) find_package(MyGUI REQUIRED) find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) @@ -244,7 +250,7 @@ if (APPLE) else () set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_DBG}) endif () - + #set(OGRE_PLUGIN_DIR "${OGRE_PLUGIN_DIR}/") configure_file(${OpenMW_SOURCE_DIR}/files/mac/Info.plist @@ -356,7 +362,7 @@ if(DPKG_PROGRAM) SET(CPACK_DEBIAN_PACKAGE_NAME "openmw") SET(CPACK_DEBIAN_PACKAGE_VERSION "${VERSION_STRING}") SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW esmtool;Esmtool omwlauncher;OMWLauncher mwiniimporter;MWiniImporter") - SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libboost-filesystem1.46.1 (>= 1.46.1), libboost-program-options1.46.1 (>= 1.46.1), libboost-system1.46.1 (>= 1.46.1), libboost-thread1.46.1 (>= 1.46.1), libc6 (>= 2.11.2), libfreetype6 (>= 2.2.1), libgcc1 (>= 1:4.1.1), libmpg123-0 (>= 1.12.1), libois-1.3.0 (>= 1.3.0), 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_DEPENDS "libc6 (>= 2.11.2), libfreetype6 (>= 2.2.1), libgcc1 (>= 1:4.1.1), libmpg123-0 (>= 1.12.1), libois-1.3.0 (>= 1.3.0), 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") @@ -462,6 +468,10 @@ if (BUILD_MWINIIMPORTER) add_subdirectory( apps/mwiniimporter ) endif() +if (BUILD_OPENCS) + add_subdirectory (apps/opencs) +endif() + # UnitTests if (BUILD_UNITTESTS) add_subdirectory( apps/openmw_test_suite ) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index 4f6d9dbfc..0cd6e3905 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -59,7 +59,7 @@ struct Arguments std::string outname; std::vector types; - + ESMData data; ESM::ESMReader reader; ESM::ESMWriter writer; @@ -74,7 +74,7 @@ bool parseOptions (int argc, char** argv, Arguments &info) ("version,v", "print version information and quit.") ("raw,r", "Show an unformatted list of all records and subrecords.") // The intention is that this option would interact better - // with other modes including clone, dump, and raw. + // with other modes including clone, dump, and raw. ("type,t", bpo::value< std::vector >(), "Show only records of this type (four character record code). May " "be specified multiple times. Only affects dump mode.") @@ -262,7 +262,7 @@ void printRaw(ESM::ESMReader &esm) int load(Arguments& info) { ESM::ESMReader& esm = info.reader; - esm.setEncoding(info.encoding); + esm.setEncoding(ToUTF8::calculateEncoding(info.encoding)); std::string filename = info.filename; std::cout << "Loading file: " << filename << std::endl; @@ -321,7 +321,7 @@ int load(Arguments& info) if (info.types.size() > 0) { std::vector::iterator match; - match = std::find(info.types.begin(), info.types.end(), + match = std::find(info.types.begin(), info.types.end(), n.toString()); if (match == info.types.end()) interested = false; } @@ -425,7 +425,7 @@ int clone(Arguments& info) if (++i % 3 == 0) std::cout << std::endl; } - + if (i % 3 != 0) std::cout << std::endl; @@ -450,7 +450,7 @@ int clone(Arguments& info) for (Records::iterator it = records.begin(); it != records.end() && i > 0; ++it) { EsmTool::RecordBase *record = *it; - + name.val = record->getType().val; esm.startRecord(name.toString(), record->getFlags()); @@ -485,7 +485,7 @@ int clone(Arguments& info) std::cerr << "\r" << perc << "%"; } } - + std::cout << "\rDone!" << std::endl; esm.close(); @@ -513,7 +513,7 @@ int comp(Arguments& info) fileOne.encoding = info.encoding; fileTwo.encoding = info.encoding; - + fileOne.filename = info.filename; fileTwo.filename = info.outname; @@ -534,9 +534,9 @@ int comp(Arguments& info) std::cout << "Not equal, different amount of records." << std::endl; return 1; } - - - + + + return 0; } diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 856700f5e..a732f1938 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -15,7 +15,7 @@ void printAIPackage(ESM::AIPackage p) std::cout << " Time of Day: " << (int)p.mWander.mTimeOfDay << std::endl; if (p.mWander.mUnk != 1) std::cout << " Unknown: " << (int)p.mWander.mUnk << std::endl; - + std::cout << " Idle: "; for (int i = 0; i != 8; i++) std::cout << (int)p.mWander.mIdle[i] << " "; @@ -28,7 +28,7 @@ void printAIPackage(ESM::AIPackage p) std::cout << " Travel Unknown: " << (int)p.mTravel.mUnk << std::endl; } else if (p.mType == ESM::AI_Follow || p.mType == ESM::AI_Escort) - { + { std::cout << " Follow Coordinates: (" << p.mTarget.mX << "," << p.mTarget.mY << "," << p.mTarget.mZ << ")" << std::endl; std::cout << " Duration: " << p.mTarget.mDuration << std::endl; @@ -43,7 +43,7 @@ void printAIPackage(ESM::AIPackage p) else { std::cout << " BadPackage: " << boost::format("0x%08x") % p.mType << std::endl; } - + if (p.mCellName != "") std::cout << " Cell Name: " << p.mCellName << std::endl; } @@ -51,13 +51,13 @@ void printAIPackage(ESM::AIPackage p) std::string ruleString(ESM::DialInfo::SelectStruct ss) { std::string rule = ss.mSelectRule; - + if (rule.length() < 5) return "INVALID"; - + char type = rule[1]; char indicator = rule[2]; - + std::string type_str = "INVALID"; std::string func_str = str(boost::format("INVALID=%s") % rule.substr(1,3)); int func; @@ -71,14 +71,14 @@ std::string ruleString(ESM::DialInfo::SelectStruct ss) func_str = ruleFunction(func); break; case '2': - if (indicator == 's') type_str = "Global short"; - else if (indicator == 'l') type_str = "Global long"; - else if (indicator == 'f') type_str = "Global float"; + if (indicator == 's') type_str = "Global short"; + else if (indicator == 'l') type_str = "Global long"; + else if (indicator == 'f') type_str = "Global float"; break; case '3': - if (indicator == 's') type_str = "Local short"; - else if (indicator == 'l') type_str = "Local long"; - else if (indicator == 'f') type_str = "Local float"; + if (indicator == 's') type_str = "Local short"; + else if (indicator == 'l') type_str = "Local long"; + else if (indicator == 'f') type_str = "Local float"; break; case '4': if (indicator == 'J') type_str = "Journal"; break; case '5': if (indicator == 'I') type_str = "Item type"; break; @@ -90,15 +90,15 @@ std::string ruleString(ESM::DialInfo::SelectStruct ss) case 'B': if (indicator == 'L') type_str = "Not Cell"; break; case 'C': if (indicator == 's') type_str = "Not Local"; break; } - + // Append the variable name to the function string if any. if (type != '1') func_str = rule.substr(5); - + // In the previous switch, we assumed that the second char was X // for all types not qual to one. If this wasn't true, go back to // the error message. if (type != '1' && rule[3] != 'X') - func_str = str(boost::format("INVALID=%s") % rule.substr(1,3)); + func_str = str(boost::format("INVALID=%s") % rule.substr(1,3)); char oper = rule[4]; std::string oper_str = "??"; @@ -117,8 +117,8 @@ std::string ruleString(ESM::DialInfo::SelectStruct ss) value_str = str(boost::format("%d") % ss.mI); else if (ss.mType == ESM::VT_Float) value_str = str(boost::format("%f") % ss.mF); - - std::string result = str(boost::format("%-12s %-32s %2s %s") + + std::string result = str(boost::format("%-12s %-32s %2s %s") % type_str % func_str % oper_str % value_str); return result; } @@ -136,7 +136,7 @@ void printEffectList(ESM::EffectList effects) << " (" << (int)eit->mSkill << ")" << std::endl; if (eit->mAttribute != -1) std::cout << " Attribute: " << attributeLabel(eit->mAttribute) - << " (" << (int)eit->mAttribute << ")" << std::endl; + << " (" << (int)eit->mAttribute << ")" << std::endl; std::cout << " Range: " << rangeTypeLabel(eit->mRange) << " (" << eit->mRange << ")" << std::endl; // Area is always zero if range type is "Self" @@ -412,7 +412,7 @@ void Record::print() std::cout << " Weight: " << mData.mData.mWeight << std::endl; std::cout << " Value: " << mData.mData.mValue << std::endl; std::cout << " Health: " << mData.mData.mHealth << std::endl; - std::cout << " Armor: " << mData.mData.mArmor << std::endl; + std::cout << " Armor: " << mData.mData.mArmor << std::endl; std::cout << " Enchantment Points: " << mData.mData.mEnchant << std::endl; std::vector::iterator pit; for (pit = mData.mParts.mParts.begin(); pit != mData.mParts.mParts.end(); pit++) @@ -483,7 +483,7 @@ void Record::print() std::cout << " Description: " << mData.mDescription << std::endl; std::vector::iterator pit; for (pit = mData.mPowers.mList.begin(); pit != mData.mPowers.mList.end(); pit++) - std::cout << " Power: " << *pit << std::endl; + std::cout << " Power: " << *pit << std::endl; } template<> @@ -495,12 +495,12 @@ void Record::print() if (mData.mRegion != "") std::cout << " Region: " << mData.mRegion << std::endl; std::cout << " Flags: " << cellFlags(mData.mData.mFlags) << std::endl; - + std::cout << " Coordinates: " << " (" << mData.getGridX() << "," << mData.getGridY() << ")" << std::endl; - - if (mData.mData.mFlags & ESM::Cell::Interior && - !(mData.mData.mFlags & ESM::Cell::QuasiEx)) + + if (mData.mData.mFlags & ESM::Cell::Interior && + !(mData.mData.mFlags & ESM::Cell::QuasiEx)) { std::cout << " Ambient Light Color: " << mData.mAmbi.mAmbient << std::endl; std::cout << " Sunlight Color: " << mData.mAmbi.mSunlight << std::endl; @@ -508,7 +508,7 @@ void Record::print() std::cout << " Fog Density: " << mData.mAmbi.mFogDensity << std::endl; std::cout << " Water Level: " << mData.mWater << std::endl; } - else + else std::cout << " Map Color: " << boost::format("0x%08X") % mData.mMapColor << std::endl; std::cout << " Water Level Int: " << mData.mWaterInt << std::endl; std::cout << " NAM0: " << mData.mNAM0 << std::endl; @@ -530,7 +530,7 @@ void Record::print() << " (" << mData.mData.mSpecialization << ")" << std::endl; for (int i = 0; i != 5; i++) std::cout << " Major Skill: " << skillLabel(mData.mData.mSkills[i][0]) - << " (" << mData.mData.mSkills[i][0] << ")" << std::endl; + << " (" << mData.mData.mSkills[i][0] << ")" << std::endl; for (int i = 0; i != 5; i++) std::cout << " Minor Skill: " << skillLabel(mData.mData.mSkills[i][1]) << " (" << mData.mData.mSkills[i][1] << ")" << std::endl; @@ -573,7 +573,7 @@ void Record::print() std::cout << " Weight: " << mData.mWeight << std::endl; std::vector::iterator cit; for (cit = mData.mInventory.mList.begin(); cit != mData.mInventory.mList.end(); cit++) - std::cout << " Inventory: Count: " << boost::format("%4d") % cit->mCount + std::cout << " Inventory: Count: " << boost::format("%4d") % cit->mCount << " Item: " << cit->mItem.toString() << std::endl; } @@ -608,17 +608,17 @@ void Record::print() std::cout << " Combat: " << mData.mData.mCombat << std::endl; std::cout << " Magic: " << mData.mData.mMagic << std::endl; std::cout << " Stealth: " << mData.mData.mStealth << std::endl; - std::cout << " Attack1: " << mData.mData.mAttack[0] + std::cout << " Attack1: " << mData.mData.mAttack[0] << "-" << mData.mData.mAttack[1] << std::endl; - std::cout << " Attack2: " << mData.mData.mAttack[2] + std::cout << " Attack2: " << mData.mData.mAttack[2] << "-" << mData.mData.mAttack[3] << std::endl; - std::cout << " Attack3: " << mData.mData.mAttack[4] + std::cout << " Attack3: " << mData.mData.mAttack[4] << "-" << mData.mData.mAttack[5] << std::endl; std::cout << " Gold: " << mData.mData.mGold << std::endl; std::vector::iterator cit; for (cit = mData.mInventory.mList.begin(); cit != mData.mInventory.mList.end(); cit++) - std::cout << " Inventory: Count: " << boost::format("%4d") % cit->mCount + std::cout << " Inventory: Count: " << boost::format("%4d") % cit->mCount << " Item: " << cit->mItem.toString() << std::endl; std::vector::iterator sit; @@ -694,15 +694,15 @@ void Record::print() if (mData.mRanks[i] != "") { std::cout << " Rank: " << mData.mRanks[i] << std::endl; - std::cout << " Attribute1 Requirement: " + std::cout << " Attribute1 Requirement: " << mData.mData.mRankData[i].mAttribute1 << std::endl; - std::cout << " Attribute2 Requirement: " + std::cout << " Attribute2 Requirement: " << mData.mData.mRankData[i].mAttribute2 << std::endl; std::cout << " One Skill at Level: " << mData.mData.mRankData[i].mSkill1 << std::endl; - std::cout << " Two Skills at Level: " + std::cout << " Two Skills at Level: " << mData.mData.mRankData[i].mSkill2 << std::endl; - std::cout << " Faction Reaction: " + std::cout << " Faction Reaction: " << mData.mData.mRankData[i].mFactReaction << std::endl; } std::vector::iterator rit; @@ -738,7 +738,6 @@ void Record::print() default: std::cout << "unknown type"; } - std::cout << "\n Dirty: " << mData.mDirty << std::endl; } template<> @@ -849,7 +848,7 @@ void Record::print() std::cout << " Number of items: " << mData.mList.size() << std::endl; std::vector::iterator iit; for (iit = mData.mList.begin(); iit != mData.mList.end(); iit++) - std::cout << " Creature: Level: " << iit->mLevel + std::cout << " Creature: Level: " << iit->mLevel << " Creature: " << iit->mId << std::endl; } @@ -1012,11 +1011,11 @@ void Record::print() std::cout << " Disposition: " << (int)mData.mNpdt12.mDisposition << std::endl; std::cout << " Faction: " << (int)mData.mNpdt52.mFactionID << std::endl; std::cout << " Rank: " << (int)mData.mNpdt12.mRank << std::endl; - std::cout << " Unknown1: " + std::cout << " Unknown1: " << (unsigned int)((unsigned char)mData.mNpdt12.mUnknown1) << std::endl; - std::cout << " Unknown2: " + std::cout << " Unknown2: " << (unsigned int)((unsigned char)mData.mNpdt12.mUnknown2) << std::endl; - std::cout << " Unknown3: " + std::cout << " Unknown3: " << (unsigned int)((unsigned char)mData.mNpdt12.mUnknown3) << std::endl; std::cout << " Gold: " << (int)mData.mNpdt12.mGold << std::endl; } @@ -1038,9 +1037,9 @@ void Record::print() std::cout << " Skills:" << std::endl; for (int i = 0; i != 27; i++) - std::cout << " " << skillLabel(i) << ": " - << (int)((unsigned char)mData.mNpdt52.mSkills[i]) << std::endl; - + std::cout << " " << skillLabel(i) << ": " + << (int)((unsigned char)mData.mNpdt52.mSkills[i]) << std::endl; + std::cout << " Health: " << mData.mNpdt52.mHealth << std::endl; std::cout << " Magicka: " << mData.mNpdt52.mMana << std::endl; std::cout << " Fatigue: " << mData.mNpdt52.mFatigue << std::endl; @@ -1050,9 +1049,9 @@ void Record::print() std::vector::iterator cit; for (cit = mData.mInventory.mList.begin(); cit != mData.mInventory.mList.end(); cit++) - std::cout << " Inventory: Count: " << boost::format("%4d") % cit->mCount + std::cout << " Inventory: Count: " << boost::format("%4d") % cit->mCount << " Item: " << cit->mItem.toString() << std::endl; - + std::vector::iterator sit; for (sit = mData.mSpells.mList.begin(); sit != mData.mSpells.mList.end(); sit++) std::cout << " Spell: " << *sit << std::endl; @@ -1060,18 +1059,18 @@ void Record::print() std::vector::iterator dit; for (dit = mData.mTransport.begin(); dit != mData.mTransport.end(); dit++) { - std::cout << " Destination Position: " + std::cout << " Destination Position: " << boost::format("%12.3f") % dit->mPos.pos[0] << "," << boost::format("%12.3f") % dit->mPos.pos[1] << "," << boost::format("%12.3f") % dit->mPos.pos[2] << ")" << std::endl; - std::cout << " Destination Rotation: " + std::cout << " Destination Rotation: " << boost::format("%9.6f") % dit->mPos.rot[0] << "," << boost::format("%9.6f") % dit->mPos.rot[1] << "," - << boost::format("%9.6f") % dit->mPos.rot[2] << ")" << std::endl; + << boost::format("%9.6f") % dit->mPos.rot[2] << ")" << std::endl; if (dit->mCellName != "") std::cout << " Destination Cell: " << dit->mCellName << std::endl; } - + std::cout << " Artifical Intelligence: " << mData.mHasAI << std::endl; std::cout << " AI Hello:" << (int)mData.mAiData.mHello << std::endl; std::cout << " AI Fight:" << (int)mData.mAiData.mFight << std::endl; @@ -1104,7 +1103,7 @@ void Record::print() for (pit = mData.mPoints.begin(); pit != mData.mPoints.end(); pit++) { std::cout << " Point[" << i << "]:" << std::endl; - std::cout << " Coordinates: (" << pit->mX << "," + std::cout << " Coordinates: (" << pit->mX << "," << pit->mY << "," << pit->mZ << ")" << std::endl; std::cout << " Auto-Generated: " << (int)pit->mAutogenerated << std::endl; std::cout << " Connections: " << (int)pit->mConnectionNum << std::endl; @@ -1213,7 +1212,7 @@ void Record::print() template<> void Record::print() { - std::cout << " Name: " << mData.mData.mName.toString() << std::endl; + std::cout << " Name: " << mData.mId << std::endl; std::cout << " Num Shorts: " << mData.mData.mNumShorts << std::endl; std::cout << " Num Longs: " << mData.mData.mNumLongs << std::endl; @@ -1267,7 +1266,7 @@ void Record::print() std::cout << " Sound: " << mData.mSound << std::endl; std::cout << " Volume: " << (int)mData.mData.mVolume << std::endl; if (mData.mData.mMinRange != 0 && mData.mData.mMaxRange != 0) - std::cout << " Range: " << (int)mData.mData.mMinRange << " - " + std::cout << " Range: " << (int)mData.mData.mMinRange << " - " << (int)mData.mData.mMaxRange << std::endl; } @@ -1308,7 +1307,7 @@ void Record::print() if (mData.mScript != "") std::cout << " Script: " << mData.mScript << std::endl; if (mData.mEnchant != "") - std::cout << " Enchantment: " << mData.mEnchant << std::endl; + std::cout << " Enchantment: " << mData.mEnchant << std::endl; std::cout << " Type: " << weaponTypeLabel(mData.mData.mType) << " (" << mData.mData.mType << ")" << std::endl; std::cout << " Flags: " << weaponFlags(mData.mData.mFlags) << std::endl; @@ -1319,23 +1318,14 @@ void Record::print() std::cout << " Reach: " << mData.mData.mReach << std::endl; std::cout << " Enchantment Points: " << mData.mData.mEnchant << std::endl; if (mData.mData.mChop[0] != 0 && mData.mData.mChop[1] != 0) - std::cout << " Chop: " << (int)mData.mData.mChop[0] << "-" + std::cout << " Chop: " << (int)mData.mData.mChop[0] << "-" << (int)mData.mData.mChop[1] << std::endl; if (mData.mData.mSlash[0] != 0 && mData.mData.mSlash[1] != 0) std::cout << " Slash: " << (int)mData.mData.mSlash[0] << "-" << (int)mData.mData.mSlash[1] << std::endl; if (mData.mData.mThrust[0] != 0 && mData.mData.mThrust[1] != 0) - std::cout << " Thrust: " << (int)mData.mData.mThrust[0] << "-" + std::cout << " Thrust: " << (int)mData.mData.mThrust[0] << "-" << (int)mData.mData.mThrust[1] << std::endl; } -template<> -void Record::print() -{ - std::cout << " Refnum: " << mData.mRefnum << std::endl; - std::cout << " ID: '" << mData.mRefID << "'\n"; - std::cout << " Owner: '" << mData.mOwner << "'\n"; - std::cout << " INTV: " << mData.mIntv << " NAM9: " << mData.mIntv << std::endl; -} - } // end namespace diff --git a/apps/launcher/model/datafilesmodel.cpp b/apps/launcher/model/datafilesmodel.cpp index 47811dcaf..716c9e902 100644 --- a/apps/launcher/model/datafilesmodel.cpp +++ b/apps/launcher/model/datafilesmodel.cpp @@ -2,6 +2,8 @@ #include #include +#include + #include #include "esm/esmfile.hpp" @@ -270,7 +272,7 @@ void DataFilesModel::addMasters(const QString &path) foreach (const QString &path, dir.entryList()) { try { ESM::ESMReader fileReader; - fileReader.setEncoding(mEncoding.toStdString()); + fileReader.setEncoding(ToUTF8::calculateEncoding(mEncoding.toStdString())); fileReader.open(dir.absoluteFilePath(path).toStdString()); ESM::ESMReader::MasterList mlist = fileReader.getMasters(); @@ -333,7 +335,7 @@ void DataFilesModel::addPlugins(const QString &path) try { ESM::ESMReader fileReader; - fileReader.setEncoding(mEncoding.toStdString()); + fileReader.setEncoding(ToUTF8::calculateEncoding(mEncoding.toStdString())); fileReader.open(dir.absoluteFilePath(path).toStdString()); ESM::ESMReader::MasterList mlist = fileReader.getMasters(); diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt new file mode 100644 index 000000000..abbc953ca --- /dev/null +++ b/apps/opencs/CMakeLists.txt @@ -0,0 +1,76 @@ + +set (OPENCS_SRC + main.cpp editor.cpp + + model/doc/documentmanager.cpp model/doc/document.cpp + + model/world/universalid.cpp model/world/idcollection.cpp model/world/data.cpp model/world/idtable.cpp + model/world/commands.cpp model/world/idtableproxymodel.cpp model/world/record.cpp + model/world/columnbase.cpp + + model/tools/tools.cpp model/tools/operation.cpp model/tools/stage.cpp model/tools/verifier.cpp + model/tools/mandatoryid.cpp model/tools/reportmodel.cpp + + view/doc/viewmanager.cpp view/doc/view.cpp view/doc/operations.cpp view/doc/operation.cpp view/doc/subviewfactory.cpp + view/doc/subview.cpp + + view/world/table.cpp view/world/tablesubview.cpp view/world/subviews.cpp view/world/util.cpp + view/world/dialoguesubview.cpp + + view/tools/reportsubview.cpp view/tools/subviews.cpp + ) + +set (OPENCS_HDR + editor.hpp + + model/doc/documentmanager.hpp model/doc/document.hpp model/doc/state.hpp + + model/world/universalid.hpp model/world/record.hpp model/world/idcollection.hpp model/world/data.hpp + model/world/idtable.hpp model/world/columns.hpp model/world/idtableproxymodel.hpp + model/world/commands.hpp model/world/columnbase.hpp + + model/tools/tools.hpp model/tools/operation.hpp model/tools/stage.hpp model/tools/verifier.hpp + model/tools/mandatoryid.hpp model/tools/reportmodel.hpp + + view/doc/viewmanager.hpp view/doc/view.hpp view/doc/operations.hpp view/doc/operation.hpp view/doc/subviewfactory.hpp + view/doc/subview.hpp view/doc/subviewfactoryimp.hpp + + view/world/table.hpp view/world/tablesubview.hpp view/world/subviews.hpp view/world/util.hpp + view/world/dialoguesubview.hpp + + view/tools/reportsubview.hpp view/tools/subviews.hpp + ) + +set (OPENCS_US + ) + +set (OPENCS_RES + ) + +source_group (opencs FILES ${OPENCS_SRC} ${OPENCS_HDR}) + +if(WIN32) + set(QT_USE_QTMAIN TRUE) +endif(WIN32) + +find_package(Qt4 COMPONENTS QtCore QtGui QtXml QtXmlPatterns REQUIRED) +include(${QT_USE_FILE}) + +qt4_wrap_ui(OPENCS_UI_HDR ${OPENCS_UI}) +qt4_wrap_cpp(OPENCS_MOC_SRC ${OPENCS_HDR}) +qt4_add_resources(OPENCS_RES_SRC ${OPENCS_RES}) + +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +add_executable(opencs + ${OPENCS_SRC} + ${OPENCS_UI_HDR} + ${OPENCS_MOC_SRC} + ${OPENCS_RES_SRC} +) + +target_link_libraries(opencs + ${Boost_LIBRARIES} + ${QT_LIBRARIES} + components +) \ No newline at end of file diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp new file mode 100644 index 000000000..1632ed220 --- /dev/null +++ b/apps/opencs/editor.cpp @@ -0,0 +1,49 @@ + +#include "editor.hpp" + +#include + +#include + +#include "model/doc/document.hpp" +#include "model/world/data.hpp" + +CS::Editor::Editor() : mViewManager (mDocumentManager), mNewDocumentIndex (0) +{ + connect (&mViewManager, SIGNAL (newDocumentRequest ()), this, SLOT (createDocument ())); +} + +void CS::Editor::createDocument() +{ + std::ostringstream stream; + + stream << "NewDocument" << (++mNewDocumentIndex); + + CSMDoc::Document *document = mDocumentManager.addDocument (stream.str()); + + static const char *sGlobals[] = + { + "Day", "DaysPassed", "GameHour", "Month", "PCRace", "PCVampire", "PCWerewolf", "PCYear", 0 + }; + + for (int i=0; sGlobals[i]; ++i) + { + ESM::Global record; + record.mId = sGlobals[i]; + record.mValue = i==0 ? 1 : 0; + record.mType = ESM::VT_Float; + document->getData().getGlobals().add (record); + } + + document->getData().merge(); /// \todo remove once proper ESX loading is implemented + + mViewManager.addView (document); +} + +int CS::Editor::run() +{ + /// \todo Instead of creating an empty document, open a small welcome dialogue window with buttons for new/load/recent projects + createDocument(); + + return QApplication::exec(); +} \ No newline at end of file diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp new file mode 100644 index 000000000..60f7beaf1 --- /dev/null +++ b/apps/opencs/editor.hpp @@ -0,0 +1,37 @@ +#ifndef CS_EDITOR_H +#define CS_EDITOR_H + +#include + +#include "model/doc/documentmanager.hpp" +#include "view/doc/viewmanager.hpp" + +namespace CS +{ + class Editor : public QObject + { + Q_OBJECT + + int mNewDocumentIndex; ///< \todo remove when the proper new document dialogue is implemented. + + CSMDoc::DocumentManager mDocumentManager; + CSVDoc::ViewManager mViewManager; + + // not implemented + Editor (const Editor&); + Editor& operator= (const Editor&); + + public: + + Editor(); + + int run(); + ///< \return error status + + public slots: + + void createDocument(); + }; +} + +#endif \ No newline at end of file diff --git a/apps/opencs/main.cpp b/apps/opencs/main.cpp new file mode 100644 index 000000000..4b1a688c2 --- /dev/null +++ b/apps/opencs/main.cpp @@ -0,0 +1,39 @@ + +#include "editor.hpp" + +#include +#include + +#include + +class Application : public QApplication +{ + private: + + bool notify (QObject *receiver, QEvent *event) + { + try + { + return QApplication::notify (receiver, event); + } + catch (const std::exception& exception) + { + std::cerr << "An exception has been caught: " << exception.what() << std::endl; + } + + return false; + } + + public: + + Application (int& argc, char *argv[]) : QApplication (argc, argv) {} +}; + +int main(int argc, char *argv[]) +{ + Application mApplication (argc, argv); + + CS::Editor editor; + + return editor.run(); +} \ No newline at end of file diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp new file mode 100644 index 000000000..9d2694483 --- /dev/null +++ b/apps/opencs/model/doc/document.cpp @@ -0,0 +1,114 @@ + +#include "document.hpp" + +CSMDoc::Document::Document (const std::string& name) +: mTools (mData) +{ + mName = name; ///< \todo replace with ESX list + + connect (&mUndoStack, SIGNAL (cleanChanged (bool)), this, SLOT (modificationStateChanged (bool))); + + connect (&mTools, SIGNAL (progress (int, int, int)), this, SLOT (progress (int, int, int))); + connect (&mTools, SIGNAL (done (int)), this, SLOT (operationDone (int))); + + // dummy implementation -> remove when proper save is implemented. + mSaveCount = 0; + connect (&mSaveTimer, SIGNAL(timeout()), this, SLOT (saving())); +} + +QUndoStack& CSMDoc::Document::getUndoStack() +{ + return mUndoStack; +} + +int CSMDoc::Document::getState() const +{ + int state = 0; + + if (!mUndoStack.isClean()) + state |= State_Modified; + + if (mSaveCount) + state |= State_Locked | State_Saving | State_Operation; + + if (int operations = mTools.getRunningOperations()) + state |= State_Locked | State_Operation | operations; + + return state; +} + +const std::string& CSMDoc::Document::getName() const +{ + return mName; +} + +void CSMDoc::Document::save() +{ + mSaveCount = 1; + mSaveTimer.start (500); + emit stateChanged (getState(), this); + emit progress (1, 16, State_Saving, 1, this); +} + +CSMWorld::UniversalId CSMDoc::Document::verify() +{ + CSMWorld::UniversalId id = mTools.runVerifier(); + emit stateChanged (getState(), this); + return id; +} + +void CSMDoc::Document::abortOperation (int type) +{ + mTools.abortOperation (type); + + if (type==State_Saving) + { + mSaveTimer.stop(); + emit stateChanged (getState(), this); + } +} + +void CSMDoc::Document::modificationStateChanged (bool clean) +{ + emit stateChanged (getState(), this); +} + +void CSMDoc::Document::operationDone (int type) +{ + emit stateChanged (getState(), this); +} + +void CSMDoc::Document::saving() +{ + ++mSaveCount; + + emit progress (mSaveCount, 16, State_Saving, 1, this); + + if (mSaveCount>15) + { + mSaveCount = 0; + mSaveTimer.stop(); + mUndoStack.setClean(); + emit stateChanged (getState(), this); + } +} + +const CSMWorld::Data& CSMDoc::Document::getData() const +{ + return mData; +} + +CSMWorld::Data& CSMDoc::Document::getData() +{ + return mData; +} + +CSMTools::ReportModel *CSMDoc::Document::getReport (const CSMWorld::UniversalId& id) +{ + return mTools.getReport (id); +} + +void CSMDoc::Document::progress (int current, int max, int type) +{ + emit progress (current, max, type, 1, this); +} \ No newline at end of file diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp new file mode 100644 index 000000000..43e8bba37 --- /dev/null +++ b/apps/opencs/model/doc/document.hpp @@ -0,0 +1,87 @@ +#ifndef CSM_DOC_DOCUMENT_H +#define CSM_DOC_DOCUMENT_H + +#include + +#include +#include +#include + +#include "../world/data.hpp" + +#include "../tools/tools.hpp" + +#include "state.hpp" + +class QAbstractItemModel; + +namespace CSMDoc +{ + class Document : public QObject + { + Q_OBJECT + + private: + + std::string mName; ///< \todo replace name with ESX list + CSMWorld::Data mData; + CSMTools::Tools mTools; + + // It is important that the undo stack is declared last, because on desctruction it fires a signal, that is connected to a slot, that is + // using other member variables. Unfortunately this connection is cut only in the QObject destructor, which is way too late. + QUndoStack mUndoStack; + + int mSaveCount; ///< dummy implementation -> remove when proper save is implemented. + QTimer mSaveTimer; ///< dummy implementation -> remove when proper save is implemented. + + // not implemented + Document (const Document&); + Document& operator= (const Document&); + + public: + + Document (const std::string& name); + ///< \todo replace name with ESX list + + QUndoStack& getUndoStack(); + + int getState() const; + + const std::string& getName() const; + ///< \todo replace with ESX list + + void save(); + + CSMWorld::UniversalId verify(); + + void abortOperation (int type); + + const CSMWorld::Data& getData() const; + + CSMWorld::Data& getData(); + + CSMTools::ReportModel *getReport (const CSMWorld::UniversalId& id); + ///< The ownership of the returned report is not transferred. + + signals: + + void stateChanged (int state, CSMDoc::Document *document); + + void progress (int current, int max, int type, int threads, CSMDoc::Document *document); + + private slots: + + void modificationStateChanged (bool clean); + + void operationDone (int type); + + void saving(); + ///< dummy implementation -> remove when proper save is implemented. + + public slots: + + void progress (int current, int max, int type); + }; +} + +#endif \ No newline at end of file diff --git a/apps/opencs/model/doc/documentmanager.cpp b/apps/opencs/model/doc/documentmanager.cpp new file mode 100644 index 000000000..8ae2764f2 --- /dev/null +++ b/apps/opencs/model/doc/documentmanager.cpp @@ -0,0 +1,37 @@ + +#include "documentmanager.hpp" + +#include +#include + +#include "document.hpp" + +CSMDoc::DocumentManager::DocumentManager() {} + +CSMDoc::DocumentManager::~DocumentManager() +{ + for (std::vector::iterator iter (mDocuments.begin()); iter!=mDocuments.end(); ++iter) + delete *iter; +} + +CSMDoc::Document *CSMDoc::DocumentManager::addDocument (const std::string& name) +{ + Document *document = new Document (name); + + mDocuments.push_back (document); + + return document; +} + +bool CSMDoc::DocumentManager::removeDocument (Document *document) +{ + std::vector::iterator iter = std::find (mDocuments.begin(), mDocuments.end(), document); + + if (iter==mDocuments.end()) + throw std::runtime_error ("removing invalid document"); + + mDocuments.erase (iter); + delete document; + + return mDocuments.empty(); +} \ No newline at end of file diff --git a/apps/opencs/model/doc/documentmanager.hpp b/apps/opencs/model/doc/documentmanager.hpp new file mode 100644 index 000000000..730c7fae1 --- /dev/null +++ b/apps/opencs/model/doc/documentmanager.hpp @@ -0,0 +1,32 @@ +#ifndef CSM_DOC_DOCUMENTMGR_H +#define CSM_DOC_DOCUMENTMGR_H + +#include +#include + +namespace CSMDoc +{ + class Document; + + class DocumentManager + { + std::vector mDocuments; + + DocumentManager (const DocumentManager&); + DocumentManager& operator= (const DocumentManager&); + + public: + + DocumentManager(); + + ~DocumentManager(); + + Document *addDocument (const std::string& name); + ///< The ownership of the returned document is not transferred to the caller. + + bool removeDocument (Document *document); + ///< \return last document removed? + }; +} + +#endif \ No newline at end of file diff --git a/apps/opencs/model/doc/state.hpp b/apps/opencs/model/doc/state.hpp new file mode 100644 index 000000000..04e6fae89 --- /dev/null +++ b/apps/opencs/model/doc/state.hpp @@ -0,0 +1,19 @@ +#ifndef CSM_DOC_STATE_H +#define CSM_DOC_STATE_H + +namespace CSMDoc +{ + enum State + { + State_Modified = 1, + State_Locked = 2, + State_Operation = 4, + + State_Saving = 8, + State_Verifying = 16, + State_Compiling = 32, // not implemented yet + State_Searching = 64 // not implemented yet + }; +} + +#endif diff --git a/apps/opencs/model/tools/mandatoryid.cpp b/apps/opencs/model/tools/mandatoryid.cpp new file mode 100644 index 000000000..f9f2ca378 --- /dev/null +++ b/apps/opencs/model/tools/mandatoryid.cpp @@ -0,0 +1,21 @@ + +#include "mandatoryid.hpp" + +#include "../world/idcollection.hpp" + +CSMTools::MandatoryIdStage::MandatoryIdStage (const CSMWorld::IdCollectionBase& idCollection, + const CSMWorld::UniversalId& collectionId, const std::vector& ids) +: mIdCollection (idCollection), mCollectionId (collectionId), mIds (ids) +{} + +int CSMTools::MandatoryIdStage::setup() +{ + return mIds.size(); +} + +void CSMTools::MandatoryIdStage::perform (int stage, std::vector& messages) +{ + if (mIdCollection.searchId (mIds.at (stage))==-1 || + mIdCollection.getRecord (mIds.at (stage)).isDeleted()) + messages.push_back (mCollectionId.toString() + "|Missing mandatory record: " + mIds.at (stage)); +} \ No newline at end of file diff --git a/apps/opencs/model/tools/mandatoryid.hpp b/apps/opencs/model/tools/mandatoryid.hpp new file mode 100644 index 000000000..14fcec204 --- /dev/null +++ b/apps/opencs/model/tools/mandatoryid.hpp @@ -0,0 +1,38 @@ +#ifndef CSM_TOOLS_MANDATORYID_H +#define CSM_TOOLS_MANDATORYID_H + +#include +#include + +#include "../world/universalid.hpp" + +#include "stage.hpp" + +namespace CSMWorld +{ + class IdCollectionBase; +} + +namespace CSMTools +{ + /// \brief Verify stage: make sure that records with specific IDs exist. + class MandatoryIdStage : public Stage + { + const CSMWorld::IdCollectionBase& mIdCollection; + CSMWorld::UniversalId mCollectionId; + std::vector mIds; + + public: + + MandatoryIdStage (const CSMWorld::IdCollectionBase& idCollection, const CSMWorld::UniversalId& collectionId, + const std::vector& ids); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, std::vector& messages); + ///< Messages resulting from this tage will be appended to \a messages. + }; +} + +#endif diff --git a/apps/opencs/model/tools/operation.cpp b/apps/opencs/model/tools/operation.cpp new file mode 100644 index 000000000..71761cdae --- /dev/null +++ b/apps/opencs/model/tools/operation.cpp @@ -0,0 +1,84 @@ + +#include "operation.hpp" + +#include +#include + +#include + +#include "../doc/state.hpp" + +#include "stage.hpp" + +void CSMTools::Operation::prepareStages() +{ + mCurrentStage = mStages.begin(); + mCurrentStep = 0; + mCurrentStepTotal = 0; + mTotalSteps = 0; + + for (std::vector >::iterator iter (mStages.begin()); iter!=mStages.end(); ++iter) + { + iter->second = iter->first->setup(); + mTotalSteps += iter->second; + } +} + +CSMTools::Operation::Operation (int type) : mType (type) {} + +CSMTools::Operation::~Operation() +{ + for (std::vector >::iterator iter (mStages.begin()); iter!=mStages.end(); ++iter) + delete iter->first; +} + +void CSMTools::Operation::run() +{ + prepareStages(); + + QTimer timer; + + timer.connect (&timer, SIGNAL (timeout()), this, SLOT (verify())); + + timer.start (0); + + exec(); +} + +void CSMTools::Operation::appendStage (Stage *stage) +{ + mStages.push_back (std::make_pair (stage, 0)); +} + +void CSMTools::Operation::abort() +{ + exit(); +} + +void CSMTools::Operation::verify() +{ + std::vector messages; + + while (mCurrentStage!=mStages.end()) + { + if (mCurrentStep>=mCurrentStage->second) + { + mCurrentStep = 0; + ++mCurrentStage; + } + else + { + mCurrentStage->first->perform (mCurrentStep++, messages); + ++mCurrentStepTotal; + break; + } + } + + emit progress (mCurrentStepTotal, mTotalSteps ? mTotalSteps : 1, mType); + + for (std::vector::const_iterator iter (messages.begin()); iter!=messages.end(); ++iter) + emit reportMessage (iter->c_str(), mType); + + if (mCurrentStage==mStages.end()) + exit(); +} \ No newline at end of file diff --git a/apps/opencs/model/tools/operation.hpp b/apps/opencs/model/tools/operation.hpp new file mode 100644 index 000000000..4731c58fa --- /dev/null +++ b/apps/opencs/model/tools/operation.hpp @@ -0,0 +1,54 @@ +#ifndef CSM_TOOLS_OPERATION_H +#define CSM_TOOLS_OPERATION_H + +#include + +#include + +namespace CSMTools +{ + class Stage; + + class Operation : public QThread + { + Q_OBJECT + + int mType; + std::vector > mStages; // stage, number of steps + std::vector >::iterator mCurrentStage; + int mCurrentStep; + int mCurrentStepTotal; + int mTotalSteps; + + void prepareStages(); + + public: + + Operation (int type); + + virtual ~Operation(); + + virtual void run(); + + void appendStage (Stage *stage); + ///< The ownership of \a stage is transferred to *this. + /// + /// \attention Do no call this function while this Operation is running. + + signals: + + void progress (int current, int max, int type); + + void reportMessage (const QString& message, int type); + + public slots: + + void abort(); + + private slots: + + void verify(); + }; +} + +#endif \ No newline at end of file diff --git a/apps/opencs/model/tools/reportmodel.cpp b/apps/opencs/model/tools/reportmodel.cpp new file mode 100644 index 000000000..b12531875 --- /dev/null +++ b/apps/opencs/model/tools/reportmodel.cpp @@ -0,0 +1,71 @@ + +#include "reportmodel.hpp" + +#include + +int CSMTools::ReportModel::rowCount (const QModelIndex & parent) const +{ + if (parent.isValid()) + return 0; + + return mRows.size(); +} + +int CSMTools::ReportModel::columnCount (const QModelIndex & parent) const +{ + if (parent.isValid()) + return 0; + + return 2; +} + +QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const +{ + if (role!=Qt::DisplayRole) + return QVariant(); + + if (index.column()==0) + return static_cast (mRows.at (index.row()).first.getType()); + else + return mRows.at (index.row()).second.c_str(); +} + +QVariant CSMTools::ReportModel::headerData (int section, Qt::Orientation orientation, int role) const +{ + if (role!=Qt::DisplayRole) + return QVariant(); + + if (orientation==Qt::Vertical) + return QVariant(); + + return tr (section==0 ? "Type" : "Description"); +} + +bool CSMTools::ReportModel::removeRows (int row, int count, const QModelIndex& parent) +{ + if (parent.isValid()) + return false; + + mRows.erase (mRows.begin()+row, mRows.begin()+row+count); + + return true; +} + +void CSMTools::ReportModel::add (const std::string& row) +{ + std::string::size_type index = row.find ('|'); + + if (index==std::string::npos) + throw std::logic_error ("invalid report message"); + + beginInsertRows (QModelIndex(), mRows.size(), mRows.size()); + + mRows.push_back (std::make_pair (row.substr (0, index), row.substr (index+1))); + + endInsertRows(); +} + +const CSMWorld::UniversalId& CSMTools::ReportModel::getUniversalId (int row) const +{ + return mRows.at (row).first; +} \ No newline at end of file diff --git a/apps/opencs/model/tools/reportmodel.hpp b/apps/opencs/model/tools/reportmodel.hpp new file mode 100644 index 000000000..55c25d907 --- /dev/null +++ b/apps/opencs/model/tools/reportmodel.hpp @@ -0,0 +1,37 @@ +#ifndef CSM_TOOLS_REPORTMODEL_H +#define CSM_TOOLS_REPORTMODEL_H + +#include +#include + +#include + +#include "../world/universalid.hpp" + +namespace CSMTools +{ + class ReportModel : public QAbstractTableModel + { + Q_OBJECT + + std::vector > mRows; + + public: + + virtual int rowCount (const QModelIndex & parent = QModelIndex()) const; + + virtual int columnCount (const QModelIndex & parent = QModelIndex()) const; + + virtual QVariant data (const QModelIndex & index, int role = Qt::DisplayRole) const; + + virtual QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + + virtual bool removeRows (int row, int count, const QModelIndex& parent = QModelIndex()); + + void add (const std::string& row); + + const CSMWorld::UniversalId& getUniversalId (int row) const; + }; +} + +#endif diff --git a/apps/opencs/model/tools/stage.cpp b/apps/opencs/model/tools/stage.cpp new file mode 100644 index 000000000..6f4567e57 --- /dev/null +++ b/apps/opencs/model/tools/stage.cpp @@ -0,0 +1,4 @@ + +#include "stage.hpp" + +CSMTools::Stage::~Stage() {} \ No newline at end of file diff --git a/apps/opencs/model/tools/stage.hpp b/apps/opencs/model/tools/stage.hpp new file mode 100644 index 000000000..3020936f3 --- /dev/null +++ b/apps/opencs/model/tools/stage.hpp @@ -0,0 +1,24 @@ +#ifndef CSM_TOOLS_STAGE_H +#define CSM_TOOLS_STAGE_H + +#include +#include + +namespace CSMTools +{ + class Stage + { + public: + + virtual ~Stage(); + + virtual int setup() = 0; + ///< \return number of steps + + virtual void perform (int stage, std::vector& messages) = 0; + ///< Messages resulting from this tage will be appended to \a messages. + }; +} + +#endif + diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp new file mode 100644 index 000000000..8dd1c0fe6 --- /dev/null +++ b/apps/opencs/model/tools/tools.cpp @@ -0,0 +1,123 @@ + +#include "tools.hpp" + +#include + +#include "verifier.hpp" + +#include "../doc/state.hpp" + +#include "../world/data.hpp" +#include "../world/universalid.hpp" + +#include "reportmodel.hpp" +#include "mandatoryid.hpp" + +CSMTools::Operation *CSMTools::Tools::get (int type) +{ + switch (type) + { + case CSMDoc::State_Verifying: return mVerifier; + } + + return 0; +} + +const CSMTools::Operation *CSMTools::Tools::get (int type) const +{ + return const_cast (this)->get (type); +} + +CSMTools::Verifier *CSMTools::Tools::getVerifier() +{ + if (!mVerifier) + { + mVerifier = new Verifier; + + connect (mVerifier, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int))); + connect (mVerifier, SIGNAL (finished()), this, SLOT (verifierDone())); + connect (mVerifier, SIGNAL (reportMessage (const QString&, int)), + this, SLOT (verifierMessage (const QString&, int))); + + std::vector mandatoryIds; // I want C++11, damn it! + mandatoryIds.push_back ("Day"); + mandatoryIds.push_back ("DaysPassed"); + mandatoryIds.push_back ("GameHour"); + mandatoryIds.push_back ("Month"); + mandatoryIds.push_back ("PCRace"); + mandatoryIds.push_back ("PCVampire"); + mandatoryIds.push_back ("PCWerewolf"); + mandatoryIds.push_back ("PCYear"); + + mVerifier->appendStage (new MandatoryIdStage (mData.getGlobals(), + CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Globals), mandatoryIds)); + } + + return mVerifier; +} + +CSMTools::Tools::Tools (CSMWorld::Data& data) : mData (data), mVerifier (0), mNextReportNumber (0) +{ + for (std::map::iterator iter (mReports.begin()); iter!=mReports.end(); ++iter) + delete iter->second; +} + +CSMTools::Tools::~Tools() +{ + delete mVerifier; +} + +CSMWorld::UniversalId CSMTools::Tools::runVerifier() +{ + mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel)); + mActiveReports[CSMDoc::State_Verifying] = mNextReportNumber-1; + + getVerifier()->start(); + + return CSMWorld::UniversalId (CSMWorld::UniversalId::Type_VerificationResults, mNextReportNumber-1); +} + +void CSMTools::Tools::abortOperation (int type) +{ + if (Operation *operation = get (type)) + operation->abort(); +} + +int CSMTools::Tools::getRunningOperations() const +{ + static const int sOperations[] = + { + CSMDoc::State_Verifying, + -1 + }; + + int result = 0; + + for (int i=0; sOperations[i]!=-1; ++i) + if (const Operation *operation = get (sOperations[i])) + if (operation->isRunning()) + result |= sOperations[i]; + + return result; +} + +CSMTools::ReportModel *CSMTools::Tools::getReport (const CSMWorld::UniversalId& id) +{ + if (id.getType()!=CSMWorld::UniversalId::Type_VerificationResults) + throw std::logic_error ("invalid request for report model: " + id.toString()); + + return mReports.at (id.getIndex()); +} + +void CSMTools::Tools::verifierDone() +{ + emit done (CSMDoc::State_Verifying); +} + +void CSMTools::Tools::verifierMessage (const QString& message, int type) +{ + std::map::iterator iter = mActiveReports.find (type); + + if (iter!=mActiveReports.end()) + mReports[iter->second]->add (message.toStdString()); +} \ No newline at end of file diff --git a/apps/opencs/model/tools/tools.hpp b/apps/opencs/model/tools/tools.hpp new file mode 100644 index 000000000..652345c6d --- /dev/null +++ b/apps/opencs/model/tools/tools.hpp @@ -0,0 +1,73 @@ +#ifndef CSM_TOOLS_TOOLS_H +#define CSM_TOOLS_TOOLS_H + +#include + +#include + +namespace CSMWorld +{ + class Data; + class UniversalId; +} + +namespace CSMTools +{ + class Verifier; + class Operation; + class ReportModel; + + class Tools : public QObject + { + Q_OBJECT + + CSMWorld::Data& mData; + Verifier *mVerifier; + std::map mReports; + int mNextReportNumber; + std::map mActiveReports; // type, report number + + // not implemented + Tools (const Tools&); + Tools& operator= (const Tools&); + + Verifier *getVerifier(); + + Operation *get (int type); + ///< Returns a 0-pointer, if operation hasn't been used yet. + + const Operation *get (int type) const; + ///< Returns a 0-pointer, if operation hasn't been used yet. + + public: + + Tools (CSMWorld::Data& data); + + virtual ~Tools(); + + CSMWorld::UniversalId runVerifier(); + ///< \return ID of the report for this verification run + + void abortOperation (int type); + ///< \attention The operation is not aborted immediately. + + int getRunningOperations() const; + + ReportModel *getReport (const CSMWorld::UniversalId& id); + ///< The ownership of the returned report is not transferred. + + private slots: + + void verifierDone(); + + void verifierMessage (const QString& message, int type); + + signals: + + void progress (int current, int max, int type); + + void done (int type); + }; +} + +#endif diff --git a/apps/opencs/model/tools/verifier.cpp b/apps/opencs/model/tools/verifier.cpp new file mode 100644 index 000000000..9c00d4ea7 --- /dev/null +++ b/apps/opencs/model/tools/verifier.cpp @@ -0,0 +1,7 @@ + +#include "verifier.hpp" + +#include "../doc/state.hpp" + +CSMTools::Verifier::Verifier() : Operation (CSMDoc::State_Verifying) +{} diff --git a/apps/opencs/model/tools/verifier.hpp b/apps/opencs/model/tools/verifier.hpp new file mode 100644 index 000000000..054f87169 --- /dev/null +++ b/apps/opencs/model/tools/verifier.hpp @@ -0,0 +1,17 @@ +#ifndef CSM_TOOLS_VERIFIER_H +#define CSM_TOOLS_VERIFIER_H + +#include "operation.hpp" + +namespace CSMTools +{ + class Verifier : public Operation + { + public: + + Verifier(); + + }; +} + +#endif diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp new file mode 100644 index 000000000..7adc7e6c3 --- /dev/null +++ b/apps/opencs/model/world/columnbase.cpp @@ -0,0 +1,13 @@ + +#include "columnbase.hpp" + +CSMWorld::ColumnBase::ColumnBase (const std::string& title, int flags) +: mTitle (title), mFlags (flags) +{} + +CSMWorld::ColumnBase::~ColumnBase() {} + +bool CSMWorld::ColumnBase::isUserEditable() const +{ + return isEditable(); +} \ No newline at end of file diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp new file mode 100644 index 000000000..dc077eff6 --- /dev/null +++ b/apps/opencs/model/world/columnbase.hpp @@ -0,0 +1,57 @@ +#ifndef CSM_WOLRD_COLUMNBASE_H +#define CSM_WOLRD_COLUMNBASE_H + +#include + +#include +#include + +#include "record.hpp" + +namespace CSMWorld +{ + struct ColumnBase + { + enum Roles + { + Role_Flags = Qt::UserRole + }; + + enum Flags + { + Flag_Table = 1, // column should be displayed in table view + Flag_Dialogue = 2 // column should be displayed in dialogue view + }; + + std::string mTitle; + int mFlags; + + ColumnBase (const std::string& title, int flag); + + virtual ~ColumnBase(); + + virtual bool isEditable() const = 0; + + virtual bool isUserEditable() const; + ///< Can this column be edited directly by the user? + }; + + template + struct Column : public ColumnBase + { + std::string mTitle; + int mFlags; + + Column (const std::string& title, int flags = Flag_Table | Flag_Dialogue) + : ColumnBase (title, flags) {} + + virtual QVariant get (const Record& record) const = 0; + + virtual void set (Record& record, const QVariant& data) + { + throw std::logic_error ("Column " + mTitle + " is not editable"); + } + }; +} + +#endif diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp new file mode 100644 index 000000000..f58d77c90 --- /dev/null +++ b/apps/opencs/model/world/columns.hpp @@ -0,0 +1,95 @@ +#ifndef CSM_WOLRD_COLUMNS_H +#define CSM_WOLRD_COLUMNS_H + +#include "idcollection.hpp" + +namespace CSMWorld +{ + template + struct FloatValueColumn : public Column + { + FloatValueColumn() : Column ("Value") {} + + virtual QVariant get (const Record& record) const + { + return record.get().mValue; + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT base = record.getBase(); + base.mValue = data.toFloat(); + record.setModified (base); + } + + virtual bool isEditable() const + { + return true; + } + }; + + template + struct StringIdColumn : public Column + { + StringIdColumn() : Column ("ID") {} + + virtual QVariant get (const Record& record) const + { + return record.get().mId.c_str(); + } + + virtual bool isEditable() const + { + return false; + } + }; + + template + struct RecordStateColumn : public Column + { + RecordStateColumn() : Column ("*") {} + + virtual QVariant get (const Record& record) const + { + if (record.mState==Record::State_Erased) + return static_cast (Record::State_Deleted); + + return static_cast (record.mState); + } + + virtual void set (Record& record, const QVariant& data) + { + record.mState = static_cast (data.toInt()); + } + + virtual bool isEditable() const + { + return true; + } + + virtual bool isUserEditable() const + { + return false; + } + }; + + template + struct FixedRecordTypeColumn : public Column + { + int mType; + + FixedRecordTypeColumn (int type) : Column ("Type", 0), mType (type) {} + + virtual QVariant get (const Record& record) const + { + return mType; + } + + virtual bool isEditable() const + { + return false; + } + }; +} + +#endif \ No newline at end of file diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp new file mode 100644 index 000000000..e22ecf992 --- /dev/null +++ b/apps/opencs/model/world/commands.cpp @@ -0,0 +1,108 @@ + +#include "commands.hpp" + +#include + +#include "idtableproxymodel.hpp" +#include "idtable.hpp" + +CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelIndex& index, + const QVariant& new_, QUndoCommand *parent) +: QUndoCommand (parent), mModel (model), mIndex (index), mNew (new_) +{ + mOld = mModel.data (mIndex, Qt::EditRole); + + setText ("Modify " + mModel.headerData (mIndex.column(), Qt::Horizontal, Qt::DisplayRole).toString()); +} + +void CSMWorld::ModifyCommand::redo() +{ + mModel.setData (mIndex, mNew); +} + +void CSMWorld::ModifyCommand::undo() +{ + mModel.setData (mIndex, mOld); +} + +CSMWorld::CreateCommand::CreateCommand (IdTableProxyModel& model, const std::string& id, QUndoCommand *parent) +: QUndoCommand (parent), mModel (model), mId (id) +{ + setText (("Create record " + id).c_str()); +} + +void CSMWorld::CreateCommand::redo() +{ + mModel.addRecord (mId); +} + +void CSMWorld::CreateCommand::undo() +{ + mModel.removeRow (mModel.getModelIndex (mId, 0).row()); +} + +CSMWorld::RevertCommand::RevertCommand (IdTable& model, const std::string& id, QUndoCommand *parent) +: QUndoCommand (parent), mModel (model), mId (id), mOld (0) +{ + setText (("Revert record " + id).c_str()); + + mOld = model.getRecord (id).clone(); +} + +CSMWorld::RevertCommand::~RevertCommand() +{ + delete mOld; +} + +void CSMWorld::RevertCommand::redo() +{ + QModelIndex index = mModel.getModelIndex (mId, 1); + RecordBase::State state = static_cast (mModel.data (index).toInt()); + + if (state==RecordBase::State_ModifiedOnly) + { + mModel.removeRows (index.row(), 1); + } + else + { + mModel.setData (index, static_cast (RecordBase::State_BaseOnly)); + } +} + +void CSMWorld::RevertCommand::undo() +{ + mModel.setRecord (*mOld); +} + +CSMWorld::DeleteCommand::DeleteCommand (IdTable& model, const std::string& id, QUndoCommand *parent) +: QUndoCommand (parent), mModel (model), mId (id), mOld (0) +{ + setText (("Delete record " + id).c_str()); + + mOld = model.getRecord (id).clone(); +} + +CSMWorld::DeleteCommand::~DeleteCommand() +{ + delete mOld; +} + +void CSMWorld::DeleteCommand::redo() +{ + QModelIndex index = mModel.getModelIndex (mId, 1); + RecordBase::State state = static_cast (mModel.data (index).toInt()); + + if (state==RecordBase::State_ModifiedOnly) + { + mModel.removeRows (index.row(), 1); + } + else + { + mModel.setData (index, static_cast (RecordBase::State_Deleted)); + } +} + +void CSMWorld::DeleteCommand::undo() +{ + mModel.setRecord (*mOld); +} \ No newline at end of file diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp new file mode 100644 index 000000000..af419215d --- /dev/null +++ b/apps/opencs/model/world/commands.hpp @@ -0,0 +1,95 @@ +#ifndef CSM_WOLRD_COMMANDS_H +#define CSM_WOLRD_COMMANDS_H + +#include "record.hpp" + +#include + +#include +#include +#include + +class QModelIndex; +class QAbstractItemModel; + +namespace CSMWorld +{ + class IdTableProxyModel; + class IdTable; + class RecordBase; + + class ModifyCommand : public QUndoCommand + { + QAbstractItemModel& mModel; + QModelIndex mIndex; + QVariant mNew; + QVariant mOld; + + public: + + ModifyCommand (QAbstractItemModel& model, const QModelIndex& index, const QVariant& new_, + QUndoCommand *parent = 0); + + virtual void redo(); + + virtual void undo(); + }; + + class CreateCommand : public QUndoCommand + { + IdTableProxyModel& mModel; + std::string mId; + + public: + + CreateCommand (IdTableProxyModel& model, const std::string& id, QUndoCommand *parent = 0); + + virtual void redo(); + + virtual void undo(); + }; + + class RevertCommand : public QUndoCommand + { + IdTable& mModel; + std::string mId; + RecordBase *mOld; + + // not implemented + RevertCommand (const RevertCommand&); + RevertCommand& operator= (const RevertCommand&); + + public: + + RevertCommand (IdTable& model, const std::string& id, QUndoCommand *parent = 0); + + virtual ~RevertCommand(); + + virtual void redo(); + + virtual void undo(); + }; + + class DeleteCommand : public QUndoCommand + { + IdTable& mModel; + std::string mId; + RecordBase *mOld; + + // not implemented + DeleteCommand (const DeleteCommand&); + DeleteCommand& operator= (const DeleteCommand&); + + public: + + DeleteCommand (IdTable& model, const std::string& id, QUndoCommand *parent = 0); + + virtual ~DeleteCommand(); + + virtual void redo(); + + virtual void undo(); + }; +} + +#endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp new file mode 100644 index 000000000..0da0cba83 --- /dev/null +++ b/apps/opencs/model/world/data.cpp @@ -0,0 +1,55 @@ + +#include "data.hpp" + +#include + +#include + +#include + +#include "idtable.hpp" +#include "columns.hpp" + +CSMWorld::Data::Data() +{ + mGlobals.addColumn (new StringIdColumn); + mGlobals.addColumn (new RecordStateColumn); + mGlobals.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Global)); + mGlobals.addColumn (new FloatValueColumn); + + mModels.insert (std::make_pair ( + UniversalId (UniversalId::Type_Globals), + new IdTable (&mGlobals) + )); +} + +CSMWorld::Data::~Data() +{ + for (std::map::iterator iter (mModels.begin()); iter!=mModels.end(); ++iter) + delete iter->second; +} + +const CSMWorld::IdCollection& CSMWorld::Data::getGlobals() const +{ + return mGlobals; +} + +CSMWorld::IdCollection& CSMWorld::Data::getGlobals() +{ + return mGlobals; +} + +QAbstractTableModel *CSMWorld::Data::getTableModel (const UniversalId& id) +{ + std::map::iterator iter = mModels.find (id); + + if (iter==mModels.end()) + throw std::logic_error ("No table model available for " + id.toString()); + + return iter->second; +} + +void CSMWorld::Data::merge() +{ + mGlobals.merge(); +} \ No newline at end of file diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp new file mode 100644 index 000000000..a8a21e205 --- /dev/null +++ b/apps/opencs/model/world/data.hpp @@ -0,0 +1,42 @@ +#ifndef CSM_WOLRD_IDLIST_H +#define CSM_WOLRD_IDLIST_H + +#include + +#include + +#include "idcollection.hpp" +#include "universalid.hpp" + +class QAbstractTableModel; + +namespace CSMWorld +{ + class Data + { + IdCollection mGlobals; + std::map mModels; + + // not implemented + Data (const Data&); + Data& operator= (const Data&); + + public: + + Data(); + + ~Data(); + + const IdCollection& getGlobals() const; + + IdCollection& getGlobals(); + + QAbstractTableModel *getTableModel (const UniversalId& id); + ///< If no table model is available for \æ id, an exception is thrown. + + void merge(); + ///< Merge modified into base. + }; +} + +#endif \ No newline at end of file diff --git a/apps/opencs/model/world/idcollection.cpp b/apps/opencs/model/world/idcollection.cpp new file mode 100644 index 000000000..fc4bb1ef6 --- /dev/null +++ b/apps/opencs/model/world/idcollection.cpp @@ -0,0 +1,6 @@ + +#include "idcollection.hpp" + +CSMWorld::IdCollectionBase::IdCollectionBase() {} + +CSMWorld::IdCollectionBase::~IdCollectionBase() {} \ No newline at end of file diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp new file mode 100644 index 000000000..1b2d1e349 --- /dev/null +++ b/apps/opencs/model/world/idcollection.hpp @@ -0,0 +1,325 @@ +#ifndef CSM_WOLRD_IDCOLLECTION_H +#define CSM_WOLRD_IDCOLLECTION_H + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "columnbase.hpp" + +namespace CSMWorld +{ + class IdCollectionBase + { + // not implemented + IdCollectionBase (const IdCollectionBase&); + IdCollectionBase& operator= (const IdCollectionBase&); + + public: + + IdCollectionBase(); + + virtual ~IdCollectionBase(); + + virtual int getSize() const = 0; + + virtual std::string getId (int index) const = 0; + + virtual int getIndex (const std::string& id) const = 0; + + virtual int getColumns() const = 0; + + virtual const ColumnBase& getColumn (int column) const = 0; + + virtual QVariant getData (int index, int column) const = 0; + + virtual void setData (int index, int column, const QVariant& data) = 0; + + virtual void merge() = 0; + ///< Merge modified into base. + + virtual void purge() = 0; + ///< Remove records that are flagged as erased. + + virtual void removeRows (int index, int count) = 0; + + virtual void appendBlankRecord (const std::string& id) = 0; + + virtual int searchId (const std::string& id) const = 0; + ////< Search record with \a id. + /// \return index of record (if found) or -1 (not found) + + virtual void replace (int index, const RecordBase& record) = 0; + ///< If the record type does not match, an exception is thrown. + /// + /// \attention \a record must not change the ID. + + virtual void appendRecord (const RecordBase& record) = 0; + ///< If the record type does not match, an exception is thrown. + + virtual std::string getId (const RecordBase& record) const = 0; + ///< Return ID for \a record. + /// + /// \attention Throw san exception, if the type of \a record does not match. + + virtual const RecordBase& getRecord (const std::string& id) const = 0; + }; + + ///< \brief Collection of ID-based records + template + class IdCollection : public IdCollectionBase + { + std::vector > mRecords; + std::map mIndex; + std::vector *> mColumns; + + // not implemented + IdCollection (const IdCollection&); + IdCollection& operator= (const IdCollection&); + + public: + + IdCollection(); + + virtual ~IdCollection(); + + void add (const ESXRecordT& record); + ///< Add a new record (modified) + + virtual int getSize() const; + + virtual std::string getId (int index) const; + + virtual int getIndex (const std::string& id) const; + + virtual int getColumns() const; + + virtual QVariant getData (int index, int column) const; + + virtual void setData (int index, int column, const QVariant& data); + + virtual const ColumnBase& getColumn (int column) const; + + virtual void merge(); + ///< Merge modified into base. + + virtual void purge(); + ///< Remove records that are flagged as erased. + + virtual void removeRows (int index, int count) ; + + virtual void appendBlankRecord (const std::string& id); + + virtual int searchId (const std::string& id) const; + ////< Search record with \a id. + /// \return index of record (if found) or -1 (not found) + + virtual void replace (int index, const RecordBase& record); + ///< If the record type does not match, an exception is thrown. + /// + /// \attention \a record must not change the ID. + + virtual void appendRecord (const RecordBase& record); + ///< If the record type does not match, an exception is thrown. + + virtual std::string getId (const RecordBase& record) const; + ///< Return ID for \a record. + /// + /// \attention Throw san exception, if the type of \a record does not match. + + virtual const RecordBase& getRecord (const std::string& id) const; + + void addColumn (Column *column); + }; + + template + IdCollection::IdCollection() + {} + + template + IdCollection::~IdCollection() + { + for (typename std::vector *>::iterator iter (mColumns.begin()); iter!=mColumns.end(); ++iter) + delete *iter; + } + + template + void IdCollection::add (const ESXRecordT& record) + { + std::string id; + + std::transform (record.mId.begin(), record.mId.end(), std::back_inserter (id), + (int(*)(int)) std::tolower); + + std::map::iterator iter = mIndex.find (id); + + if (iter==mIndex.end()) + { + Record record2; + record2.mState = Record::State_ModifiedOnly; + record2.mModified = record; + + mRecords.push_back (record2); + mIndex.insert (std::make_pair (id, mRecords.size()-1)); + } + else + { + mRecords[iter->second].setModified (record); + } + } + + template + int IdCollection::getSize() const + { + return mRecords.size(); + } + + template + std::string IdCollection::getId (int index) const + { + return mRecords.at (index).get().mId; + } + + template + int IdCollection::getIndex (const std::string& id) const + { + int index = searchId (id); + + if (index==-1) + throw std::runtime_error ("invalid ID: " + id); + + return index; + } + + template + int IdCollection::getColumns() const + { + return mColumns.size(); + } + + template + QVariant IdCollection::getData (int index, int column) const + { + return mColumns.at (column)->get (mRecords.at (index)); + } + + template + void IdCollection::setData (int index, int column, const QVariant& data) + { + return mColumns.at (column)->set (mRecords.at (index), data); + } + + template + const ColumnBase& IdCollection::getColumn (int column) const + { + return *mColumns.at (column); + } + + template + void IdCollection::addColumn (Column *column) + { + mColumns.push_back (column); + } + + template + void IdCollection::merge() + { + for (typename std::vector >::iterator iter (mRecords.begin()); iter!=mRecords.end(); ++iter) + iter->merge(); + + purge(); + } + + template + void IdCollection::purge() + { + mRecords.erase (std::remove_if (mRecords.begin(), mRecords.end(), + std::mem_fun_ref (&Record::isErased) // I want lambda :( + ), mRecords.end()); + } + + template + void IdCollection::removeRows (int index, int count) + { + mRecords.erase (mRecords.begin()+index, mRecords.begin()+index+count); + + typename std::map::iterator iter = mIndex.begin(); + + while (iter!=mIndex.end()) + { + if (iter->second>=index) + { + if (iter->second>=index+count) + { + iter->second -= count; + } + else + { + mIndex.erase (iter++); + } + } + + ++iter; + } + } + + template + void IdCollection::appendBlankRecord (const std::string& id) + { + ESXRecordT record; + record.mId = id; + record.blank(); + add (record); + } + + template + int IdCollection::searchId (const std::string& id) const + { + std::string id2; + + std::transform (id.begin(), id.end(), std::back_inserter (id2), + (int(*)(int)) std::tolower); + + std::map::const_iterator iter = mIndex.find (id2); + + if (iter==mIndex.end()) + return -1; + + return iter->second; + } + + template + void IdCollection::replace (int index, const RecordBase& record) + { + mRecords.at (index) = dynamic_cast&> (record); + } + + template + void IdCollection::appendRecord (const RecordBase& record) + { + mRecords.push_back (dynamic_cast&> (record)); + mIndex.insert (std::make_pair (getId (record), mRecords.size()-1)); + } + + template + std::string IdCollection::getId (const RecordBase& record) const + { + const Record& record2 = dynamic_cast&> (record); + return (record2.isModified() ? record2.mModified : record2.mBase).mId; + } + + template + const RecordBase& IdCollection::getRecord (const std::string& id) const + { + int index = getIndex (id); + return mRecords.at (index); + } +} + +#endif diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp new file mode 100644 index 000000000..2815e318c --- /dev/null +++ b/apps/opencs/model/world/idtable.cpp @@ -0,0 +1,137 @@ + +#include "idtable.hpp" + +#include "idcollection.hpp" + +CSMWorld::IdTable::IdTable (IdCollectionBase *idCollection) : mIdCollection (idCollection) +{ + +} + +CSMWorld::IdTable::~IdTable() +{ + +} + +int CSMWorld::IdTable::rowCount (const QModelIndex & parent) const +{ + if (parent.isValid()) + return 0; + + return mIdCollection->getSize(); +} + +int CSMWorld::IdTable::columnCount (const QModelIndex & parent) const +{ + if (parent.isValid()) + return 0; + + return mIdCollection->getColumns(); +} + +QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const +{ + if (role!=Qt::DisplayRole && role!=Qt::EditRole) + return QVariant(); + + if (role==Qt::EditRole && !mIdCollection->getColumn (index.column()).isEditable()) + return QVariant(); + + return mIdCollection->getData (index.row(), index.column()); +} + +QVariant CSMWorld::IdTable::headerData (int section, Qt::Orientation orientation, int role) const +{ + if (orientation==Qt::Vertical) + return QVariant(); + + if (role==Qt::DisplayRole) + return tr (mIdCollection->getColumn (section).mTitle.c_str()); + + if (role==ColumnBase::Role_Flags) + return mIdCollection->getColumn (section).mFlags; + + return QVariant(); +} + +bool CSMWorld::IdTable::setData ( const QModelIndex &index, const QVariant &value, int role) +{ + if (mIdCollection->getColumn (index.column()).isEditable() && role==Qt::EditRole) + { + mIdCollection->setData (index.row(), index.column(), value); + + emit dataChanged (CSMWorld::IdTable::index (index.row(), 0), + CSMWorld::IdTable::index (index.row(), mIdCollection->getColumns()-1)); + + return true; + } + + return false; +} + +Qt::ItemFlags CSMWorld::IdTable::flags (const QModelIndex & index) const +{ + Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled; + + if (mIdCollection->getColumn (index.column()).isUserEditable()) + flags |= Qt::ItemIsEditable; + + return flags; +} + +bool CSMWorld::IdTable::removeRows (int row, int count, const QModelIndex& parent) +{ + if (parent.isValid()) + return false; + + beginRemoveRows (parent, row, row+count-1); + + mIdCollection->removeRows (row, count); + + endRemoveRows(); + + return true; +} + +void CSMWorld::IdTable::addRecord (const std::string& id) +{ + int index = mIdCollection->getSize(); + + beginInsertRows (QModelIndex(), index, index); + + mIdCollection->appendBlankRecord (id); + + endInsertRows(); +} + +QModelIndex CSMWorld::IdTable::getModelIndex (const std::string& id, int column) const +{ + return index (mIdCollection->getIndex (id), column); +} + +void CSMWorld::IdTable::setRecord (const RecordBase& record) +{ + int index = mIdCollection->searchId (mIdCollection->getId (record)); + + if (index==-1) + { + int index = mIdCollection->getSize(); + + beginInsertRows (QModelIndex(), index, index); + + mIdCollection->appendRecord (record); + + endInsertRows(); + } + else + { + mIdCollection->replace (index, record); + emit dataChanged (CSMWorld::IdTable::index (index, 0), + CSMWorld::IdTable::index (index, mIdCollection->getColumns()-1)); + } +} + +const CSMWorld::RecordBase& CSMWorld::IdTable::getRecord (const std::string& id) const +{ + return mIdCollection->getRecord (id); +} \ No newline at end of file diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp new file mode 100644 index 000000000..deaebaa38 --- /dev/null +++ b/apps/opencs/model/world/idtable.hpp @@ -0,0 +1,53 @@ +#ifndef CSM_WOLRD_IDTABLE_H +#define CSM_WOLRD_IDTABLE_H + +#include + +namespace CSMWorld +{ + class IdCollectionBase; + class RecordBase; + + class IdTable : public QAbstractTableModel + { + Q_OBJECT + + IdCollectionBase *mIdCollection; + + // not implemented + IdTable (const IdTable&); + IdTable& operator= (const IdTable&); + + public: + + IdTable (IdCollectionBase *idCollection); + ///< The ownership of \a idCollection is not transferred. + + virtual ~IdTable(); + + virtual int rowCount (const QModelIndex & parent = QModelIndex()) const; + + virtual int columnCount (const QModelIndex & parent = QModelIndex()) const; + + virtual QVariant data (const QModelIndex & index, int role = Qt::DisplayRole) const; + + virtual QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + + virtual bool setData ( const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); + + virtual Qt::ItemFlags flags (const QModelIndex & index) const; + + virtual bool removeRows (int row, int count, const QModelIndex& parent = QModelIndex()); + + void addRecord (const std::string& id); + + QModelIndex getModelIndex (const std::string& id, int column) const; + + void setRecord (const RecordBase& record); + ///< Add record or overwrite existing recrod. + + const RecordBase& getRecord (const std::string& id) const; + }; +} + +#endif diff --git a/apps/opencs/model/world/idtableproxymodel.cpp b/apps/opencs/model/world/idtableproxymodel.cpp new file mode 100644 index 000000000..78995f60b --- /dev/null +++ b/apps/opencs/model/world/idtableproxymodel.cpp @@ -0,0 +1,18 @@ + +#include "idtableproxymodel.hpp" + +#include "idtable.hpp" + +CSMWorld::IdTableProxyModel::IdTableProxyModel (QObject *parent) +: QSortFilterProxyModel (parent) +{} + +void CSMWorld::IdTableProxyModel::addRecord (const std::string& id) +{ + dynamic_cast (*sourceModel()).addRecord (id); +} + +QModelIndex CSMWorld::IdTableProxyModel::getModelIndex (const std::string& id, int column) const +{ + return mapFromSource (dynamic_cast (*sourceModel()).getModelIndex (id, column)); +} \ No newline at end of file diff --git a/apps/opencs/model/world/idtableproxymodel.hpp b/apps/opencs/model/world/idtableproxymodel.hpp new file mode 100644 index 000000000..3f1537cce --- /dev/null +++ b/apps/opencs/model/world/idtableproxymodel.hpp @@ -0,0 +1,24 @@ +#ifndef CSM_WOLRD_IDTABLEPROXYMODEL_H +#define CSM_WOLRD_IDTABLEPROXYMODEL_H + +#include + +#include + +namespace CSMWorld +{ + class IdTableProxyModel : public QSortFilterProxyModel + { + Q_OBJECT + + public: + + IdTableProxyModel (QObject *parent = 0); + + virtual void addRecord (const std::string& id); + + virtual QModelIndex getModelIndex (const std::string& id, int column) const; + }; +} + +#endif \ No newline at end of file diff --git a/apps/opencs/model/world/record.cpp b/apps/opencs/model/world/record.cpp new file mode 100644 index 000000000..229985a8a --- /dev/null +++ b/apps/opencs/model/world/record.cpp @@ -0,0 +1,21 @@ + +#include "record.hpp" + +CSMWorld::RecordBase::~RecordBase() {} + +bool CSMWorld::RecordBase::RecordBase::isDeleted() const +{ + return mState==State_Deleted || mState==State_Erased; +} + + +bool CSMWorld::RecordBase::RecordBase::isErased() const +{ + return mState==State_Erased; +} + + +bool CSMWorld::RecordBase::RecordBase::isModified() const +{ + return mState==State_Modified || mState==State_ModifiedOnly; +} \ No newline at end of file diff --git a/apps/opencs/model/world/record.hpp b/apps/opencs/model/world/record.hpp new file mode 100644 index 000000000..53bb7ea2c --- /dev/null +++ b/apps/opencs/model/world/record.hpp @@ -0,0 +1,104 @@ +#ifndef CSM_WOLRD_RECORD_H +#define CSM_WOLRD_RECORD_H + +#include + +namespace CSMWorld +{ + struct RecordBase + { + enum State + { + State_BaseOnly = 0, // defined in base only + State_Modified = 1, // exists in base, but has been modified + State_ModifiedOnly = 2, // newly created in modified + State_Deleted = 3, // exists in base, but has been deleted + State_Erased = 4 // does not exist at all (we mostly treat that the same way as deleted) + }; + + State mState; + + virtual ~RecordBase(); + + virtual RecordBase *clone() const = 0; + + bool isDeleted() const; + + bool isErased() const; + + bool isModified() const; + }; + + template + struct Record : public RecordBase + { + ESXRecordT mBase; + ESXRecordT mModified; + + virtual RecordBase *clone() const; + + const ESXRecordT& get() const; + ///< Throws an exception, if the record is deleted. + + const ESXRecordT& getBase() const; + ///< Throws an exception, if the record is deleted. Returns modified, if there is no base. + + void setModified (const ESXRecordT& modified); + ///< Throws an exception, if the record is deleted. + + void merge(); + ///< Merge modified into base. + }; + + template + RecordBase *Record::clone() const + { + return new Record (*this); + } + + template + const ESXRecordT& Record::get() const + { + if (mState==State_Erased) + throw std::logic_error ("attempt to access a deleted record"); + + return mState==State_BaseOnly ? mBase : mModified; + } + + template + const ESXRecordT& Record::getBase() const + { + if (mState==State_Erased) + throw std::logic_error ("attempt to access a deleted record"); + + return mState==State_ModifiedOnly ? mModified : mBase; + } + + template + void Record::setModified (const ESXRecordT& modified) + { + if (mState==State_Erased) + throw std::logic_error ("attempt to modify a deleted record"); + + mModified = modified; + + if (mState!=State_ModifiedOnly) + mState = mBase==mModified ? State_BaseOnly : State_Modified; + } + + template + void Record::merge() + { + if (isModified()) + { + mBase = mModified; + mState = State_BaseOnly; + } + else if (mState==State_Deleted) + { + mState = State_Erased; + } + } +} + +#endif diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp new file mode 100644 index 000000000..d8775643a --- /dev/null +++ b/apps/opencs/model/world/universalid.cpp @@ -0,0 +1,237 @@ + +#include "universalid.hpp" + +#include +#include +#include + +namespace +{ + struct TypeData + { + CSMWorld::UniversalId::Class mClass; + CSMWorld::UniversalId::Type mType; + const char *mName; + }; + + static const TypeData sNoArg[] = + { + { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, "empty" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Globals, "Global Variables" }, + + { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker + }; + + static const TypeData sIdArg[] = + { + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Global, "Global Variable" }, + + { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker + }; + + static const TypeData sIndexArg[] = + { + { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_VerificationResults, "Verification Results" }, + + { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker + }; +} + +CSMWorld::UniversalId::UniversalId (const std::string& universalId) +{ + std::string::size_type index = universalId.find (':'); + + if (index==std::string::npos) + { + std::string type = universalId.substr (0, index); + + if (index==std::string::npos) + { + for (int i=0; sNoArg[i].mName; ++i) + if (type==sNoArg[i].mName) + { + mArgumentType = ArgumentType_None; + mType = sNoArg[i].mType; + mClass = sNoArg[i].mClass; + return; + } + } + else + { + for (int i=0; sIdArg[i].mName; ++i) + if (type==sIdArg[i].mName) + { + mArgumentType = ArgumentType_Id; + mType = sIdArg[i].mType; + mClass = sIdArg[i].mClass; + mId = universalId.substr (0, index); + return; + } + + for (int i=0; sIndexArg[i].mName; ++i) + if (type==sIndexArg[i].mName) + { + mArgumentType = ArgumentType_Index; + mType = sIndexArg[i].mType; + mClass = sIndexArg[i].mClass; + + std::istringstream stream (universalId.substr (0, index)); + + if (stream >> mIndex) + return; + + break; + } + } + } + + throw std::runtime_error ("invalid UniversalId: " + universalId); +} + +CSMWorld::UniversalId::UniversalId (Type type) : mArgumentType (ArgumentType_None), mType (type), mIndex (0) +{ + for (int i=0; sNoArg[i].mName; ++i) + if (type==sNoArg[i].mType) + { + mClass = sNoArg[i].mClass; + return; + } + + throw std::logic_error ("invalid argument-less UniversalId type"); +} + +CSMWorld::UniversalId::UniversalId (Type type, const std::string& id) +: mArgumentType (ArgumentType_Id), mType (type), mId (id), mIndex (0) +{ + for (int i=0; sIdArg[i].mName; ++i) + if (type==sIdArg[i].mType) + { + mClass = sIdArg[i].mClass; + return; + } + + throw std::logic_error ("invalid ID argument UniversalId type"); +} + +CSMWorld::UniversalId::UniversalId (Type type, int index) +: mArgumentType (ArgumentType_Index), mType (type), mIndex (index) +{ + for (int i=0; sIndexArg[i].mName; ++i) + if (type==sIndexArg[i].mType) + { + mClass = sIndexArg[i].mClass; + return; + } + + throw std::logic_error ("invalid index argument UniversalId type"); +} + +CSMWorld::UniversalId::Class CSMWorld::UniversalId::getClass() const +{ + return mClass; +} + +CSMWorld::UniversalId::ArgumentType CSMWorld::UniversalId::getArgumentType() const +{ + return mArgumentType; +} + +CSMWorld::UniversalId::Type CSMWorld::UniversalId::getType() const +{ + return mType; +} + +const std::string& CSMWorld::UniversalId::getId() const +{ + if (mArgumentType!=ArgumentType_Id) + throw std::logic_error ("invalid access to ID of non-ID UniversalId"); + + return mId; +} + +int CSMWorld::UniversalId::getIndex() const +{ + if (mArgumentType!=ArgumentType_Index) + throw std::logic_error ("invalid access to index of non-index UniversalId"); + + return mIndex; +} + +bool CSMWorld::UniversalId::isEqual (const UniversalId& universalId) const +{ + if (mClass!=universalId.mClass || mArgumentType!=universalId.mArgumentType || mType!=universalId.mType) + return false; + + switch (mArgumentType) + { + case ArgumentType_Id: return mId==universalId.mId; + case ArgumentType_Index: return mIndex==universalId.mIndex; + + default: return true; + } +} + +bool CSMWorld::UniversalId::isLess (const UniversalId& universalId) const +{ + if (mTypeuniversalId.mType) + return false; + + switch (mArgumentType) + { + case ArgumentType_Id: return mId +#include + +#include + +namespace CSMWorld +{ + class UniversalId + { + public: + + enum Class + { + Class_None = 0, + Class_Record, + Class_SubRecord, + Class_RecordList, + Class_Collection, // multiple types of records combined + Class_Transient, // not part of the world data or the project data + Class_NonRecord // record like data that is not part of the world + }; + + enum ArgumentType + { + ArgumentType_None, + ArgumentType_Id, + ArgumentType_Index + }; + + enum Type + { + Type_None, + + Type_Globals, + + Type_Global, + + Type_VerificationResults + }; + + private: + + Class mClass; + ArgumentType mArgumentType; + Type mType; + std::string mId; + int mIndex; + + public: + + UniversalId (const std::string& universalId); + + UniversalId (Type type = Type_None); + ///< Using a type for a non-argument-less UniversalId will throw an exception. + + UniversalId (Type type, const std::string& id); + ///< Using a type for a non-ID-argument UniversalId will throw an exception. + + UniversalId (Type type, int index); + ///< Using a type for a non-index-argument UniversalId will throw an exception. + + Class getClass() const; + + ArgumentType getArgumentType() const; + + Type getType() const; + + const std::string& getId() const; + ///< Calling this function for a non-ID type will throw an exception. + + int getIndex() const; + ///< Calling this function for a non-index type will throw an exception. + + bool isEqual (const UniversalId& universalId) const; + + bool isLess (const UniversalId& universalId) const; + + std::string getTypeName() const; + + std::string toString() const; + }; + + bool operator== (const UniversalId& left, const UniversalId& right); + bool operator!= (const UniversalId& left, const UniversalId& right); + + bool operator< (const UniversalId& left, const UniversalId& right); + + std::ostream& operator< (std::ostream& stream, const UniversalId& universalId); +} + +Q_DECLARE_METATYPE (CSMWorld::UniversalId) + +#endif diff --git a/apps/opencs/view/doc/operation.cpp b/apps/opencs/view/doc/operation.cpp new file mode 100644 index 000000000..3f415da03 --- /dev/null +++ b/apps/opencs/view/doc/operation.cpp @@ -0,0 +1,54 @@ + +#include "operation.hpp" + +#include + +#include "../../model/doc/document.hpp" + +void CSVDoc::Operation::updateLabel (int threads) +{ + if (threads==-1 || ((threads==0)!=mStalling)) + { + std::string name ("unknown operation"); + + switch (mType) + { + case CSMDoc::State_Saving: name = "saving"; break; + case CSMDoc::State_Verifying: name = "verifying"; break; + } + + std::ostringstream stream; + + if ((mStalling = (threads<=0))) + { + stream << name << " (waiting for a free worker thread)"; + } + else + { + stream << name << " (%p%)"; + } + + setFormat (stream.str().c_str()); + } +} + +CSVDoc::Operation::Operation (int type) : mType (type), mStalling (false) +{ + /// \todo Add a cancel button or a pop up menu with a cancel item + + updateLabel(); + + /// \todo assign different progress bar colours to allow the user to distinguish easily between operation types +} + +void CSVDoc::Operation::setProgress (int current, int max, int threads) +{ + updateLabel (threads); + setRange (0, max); + setValue (current); +} + +int CSVDoc::Operation::getType() const +{ + return mType; +} \ No newline at end of file diff --git a/apps/opencs/view/doc/operation.hpp b/apps/opencs/view/doc/operation.hpp new file mode 100644 index 000000000..362725b6f --- /dev/null +++ b/apps/opencs/view/doc/operation.hpp @@ -0,0 +1,31 @@ +#ifndef CSV_DOC_OPERATION_H +#define CSV_DOC_OPERATION_H + +#include + +namespace CSVDoc +{ + class Operation : public QProgressBar + { + Q_OBJECT + + int mType; + bool mStalling; + + // not implemented + Operation (const Operation&); + Operation& operator= (const Operation&); + + void updateLabel (int threads = -1); + + public: + + Operation (int type); + + void setProgress (int current, int max, int threads); + + int getType() const; + }; +} + +#endif \ No newline at end of file diff --git a/apps/opencs/view/doc/operations.cpp b/apps/opencs/view/doc/operations.cpp new file mode 100644 index 000000000..ba444a119 --- /dev/null +++ b/apps/opencs/view/doc/operations.cpp @@ -0,0 +1,47 @@ + +#include "operations.hpp" + +#include + +#include "operation.hpp" + +CSVDoc::Operations::Operations() +{ + /// \todo make widget height fixed (exactly the height required to display all operations) + + setFeatures (QDockWidget::NoDockWidgetFeatures); + + QWidget *widget = new QWidget; + setWidget (widget); + + mLayout = new QVBoxLayout; + + widget->setLayout (mLayout); +} + +void CSVDoc::Operations::setProgress (int current, int max, int type, int threads) +{ + for (std::vector::iterator iter (mOperations.begin()); iter!=mOperations.end(); ++iter) + if ((*iter)->getType()==type) + { + (*iter)->setProgress (current, max, threads); + return; + } + + Operation *operation = new Operation (type); + + mLayout->addWidget (operation); + mOperations.push_back (operation); + operation->setProgress (current, max, threads); +} + +void CSVDoc::Operations::quitOperation (int type) +{ + for (std::vector::iterator iter (mOperations.begin()); iter!=mOperations.end(); ++iter) + if ((*iter)->getType()==type) + { + delete *iter; + mOperations.erase (iter); + break; + } +} \ No newline at end of file diff --git a/apps/opencs/view/doc/operations.hpp b/apps/opencs/view/doc/operations.hpp new file mode 100644 index 000000000..b96677450 --- /dev/null +++ b/apps/opencs/view/doc/operations.hpp @@ -0,0 +1,37 @@ +#ifndef CSV_DOC_OPERATIONS_H +#define CSV_DOC_OPERATIONS_H + +#include + +#include + +class QVBoxLayout; + +namespace CSVDoc +{ + class Operation; + + class Operations : public QDockWidget + { + Q_OBJECT + + QVBoxLayout *mLayout; + std::vector mOperations; + + // not implemented + Operations (const Operations&); + Operations& operator= (const Operations&); + + public: + + Operations(); + + void setProgress (int current, int max, int type, int threads); + ///< Implicitly starts the operation, if it is not running already. + + void quitOperation (int type); + ///< Calling this function for an operation that is not running is a no-op. + }; +} + +#endif \ No newline at end of file diff --git a/apps/opencs/view/doc/subview.cpp b/apps/opencs/view/doc/subview.cpp new file mode 100644 index 000000000..1c356fa73 --- /dev/null +++ b/apps/opencs/view/doc/subview.cpp @@ -0,0 +1,18 @@ + +#include "subview.hpp" + +CSVDoc::SubView::SubView (const CSMWorld::UniversalId& id) : mUniversalId (id) +{ + /// \todo add a button to the title bar that clones this sub view + + setWindowTitle (mUniversalId.toString().c_str()); + + /// \todo remove (for testing only) + setMinimumWidth (100); + setMinimumHeight (60); +} + +CSMWorld::UniversalId CSVDoc::SubView::getUniversalId() const +{ + return mUniversalId; +} diff --git a/apps/opencs/view/doc/subview.hpp b/apps/opencs/view/doc/subview.hpp new file mode 100644 index 000000000..985c5eb3c --- /dev/null +++ b/apps/opencs/view/doc/subview.hpp @@ -0,0 +1,45 @@ +#ifndef CSV_DOC_SUBVIEW_H +#define CSV_DOC_SUBVIEW_H + +#include "../../model/doc/document.hpp" + +#include "../../model/world/universalid.hpp" + +#include "subviewfactory.hpp" + +#include + +class QUndoStack; + +namespace CSMWorld +{ + class Data; +} + +namespace CSVDoc +{ + class SubView : public QDockWidget + { + Q_OBJECT + + CSMWorld::UniversalId mUniversalId; + + // not implemented + SubView (const SubView&); + SubView& operator= (SubView&); + + public: + + SubView (const CSMWorld::UniversalId& id); + + CSMWorld::UniversalId getUniversalId() const; + + virtual void setEditLock (bool locked) = 0; + + signals: + + void focusId (const CSMWorld::UniversalId& universalId); + }; +} + +#endif \ No newline at end of file diff --git a/apps/opencs/view/doc/subviewfactory.cpp b/apps/opencs/view/doc/subviewfactory.cpp new file mode 100644 index 000000000..8576f6b1d --- /dev/null +++ b/apps/opencs/view/doc/subviewfactory.cpp @@ -0,0 +1,38 @@ + +#include "subviewfactory.hpp" + +#include + +#include + +CSVDoc::SubViewFactoryBase::SubViewFactoryBase() {} + +CSVDoc::SubViewFactoryBase::~SubViewFactoryBase() {} + + +CSVDoc::SubViewFactoryManager::SubViewFactoryManager() {} + +CSVDoc::SubViewFactoryManager::~SubViewFactoryManager() +{ + for (std::map::iterator iter (mSubViewFactories.begin()); + iter!=mSubViewFactories.end(); ++iter) + delete iter->second; +} + +void CSVDoc::SubViewFactoryManager::add (const CSMWorld::UniversalId::Type& id, SubViewFactoryBase *factory) +{ + assert (mSubViewFactories.find (id)==mSubViewFactories.end()); + + mSubViewFactories.insert (std::make_pair (id, factory)); +} + +CSVDoc::SubView *CSVDoc::SubViewFactoryManager::makeSubView (const CSMWorld::UniversalId& id, + CSMDoc::Document& document) +{ + std::map::iterator iter = mSubViewFactories.find (id.getType()); + + if (iter==mSubViewFactories.end()) + throw std::runtime_error ("Failed to create a sub view for: " + id.toString()); + + return iter->second->makeSubView (id, document); +} \ No newline at end of file diff --git a/apps/opencs/view/doc/subviewfactory.hpp b/apps/opencs/view/doc/subviewfactory.hpp new file mode 100644 index 000000000..1f7c15480 --- /dev/null +++ b/apps/opencs/view/doc/subviewfactory.hpp @@ -0,0 +1,55 @@ +#ifndef CSV_DOC_SUBVIEWFACTORY_H +#define CSV_DOC_SUBVIEWFACTORY_H + +#include + +#include "../../model/world/universalid.hpp" + +namespace CSMDoc +{ + class Document; +} + +namespace CSVDoc +{ + class SubView; + + class SubViewFactoryBase + { + // not implemented + SubViewFactoryBase (const SubViewFactoryBase&); + SubViewFactoryBase& operator= (const SubViewFactoryBase&); + + public: + + SubViewFactoryBase(); + + virtual ~SubViewFactoryBase(); + + virtual SubView *makeSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) = 0; + ///< The ownership of the returned sub view is not transferred. + }; + + class SubViewFactoryManager + { + std::map mSubViewFactories; + + // not implemented + SubViewFactoryManager (const SubViewFactoryManager&); + SubViewFactoryManager& operator= (const SubViewFactoryManager&); + + public: + + SubViewFactoryManager(); + + ~SubViewFactoryManager(); + + void add (const CSMWorld::UniversalId::Type& id, SubViewFactoryBase *factory); + ///< The ownership of \a factory is transferred to this. + + SubView *makeSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document); + ///< The ownership of the returned sub view is not transferred. + }; +} + +#endif diff --git a/apps/opencs/view/doc/subviewfactoryimp.hpp b/apps/opencs/view/doc/subviewfactoryimp.hpp new file mode 100644 index 000000000..d16e0b2b7 --- /dev/null +++ b/apps/opencs/view/doc/subviewfactoryimp.hpp @@ -0,0 +1,50 @@ +#ifndef CSV_DOC_SUBVIEWFACTORYIMP_H +#define CSV_DOC_SUBVIEWFACTORYIMP_H + +#include "../../model/doc/document.hpp" + +#include "subviewfactory.hpp" + +namespace CSVDoc +{ + template + class SubViewFactory : public SubViewFactoryBase + { + public: + + virtual CSVDoc::SubView *makeSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document); + }; + + template + CSVDoc::SubView *SubViewFactory::makeSubView (const CSMWorld::UniversalId& id, + CSMDoc::Document& document) + { + return new SubViewT (id, document); + } + + template + class SubViewFactoryWithCreateFlag : public SubViewFactoryBase + { + bool mCreateAndDelete; + + public: + + SubViewFactoryWithCreateFlag (bool createAndDelete); + + virtual CSVDoc::SubView *makeSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document); + }; + + template + SubViewFactoryWithCreateFlag::SubViewFactoryWithCreateFlag (bool createAndDelete) + : mCreateAndDelete (createAndDelete) + {} + + template + CSVDoc::SubView *SubViewFactoryWithCreateFlag::makeSubView (const CSMWorld::UniversalId& id, + CSMDoc::Document& document) + { + return new SubViewT (id, document, mCreateAndDelete); + } +} + +#endif \ No newline at end of file diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp new file mode 100644 index 000000000..13edb6e74 --- /dev/null +++ b/apps/opencs/view/doc/view.cpp @@ -0,0 +1,216 @@ + +#include "view.hpp" + +#include +#include + +#include +#include +#include + +#include "../../model/doc/document.hpp" + +#include "../world/subviews.hpp" + +#include "../tools/subviews.hpp" + +#include "viewmanager.hpp" +#include "operations.hpp" +#include "subview.hpp" + +void CSVDoc::View::closeEvent (QCloseEvent *event) +{ + if (!mViewManager.closeRequest (this)) + event->ignore(); +} + +void CSVDoc::View::setupFileMenu() +{ + QMenu *file = menuBar()->addMenu (tr ("&File")); + + QAction *new_ = new QAction (tr ("New"), this); + connect (new_, SIGNAL (triggered()), this, SIGNAL (newDocumentRequest())); + file->addAction (new_); + + mSave = new QAction (tr ("&Save"), this); + connect (mSave, SIGNAL (triggered()), this, SLOT (save())); + file->addAction (mSave); +} + +void CSVDoc::View::setupEditMenu() +{ + QMenu *edit = menuBar()->addMenu (tr ("&Edit")); + + mUndo = mDocument->getUndoStack().createUndoAction (this, tr("&Undo")); + mUndo->setShortcuts (QKeySequence::Undo); + edit->addAction (mUndo); + + mRedo= mDocument->getUndoStack().createRedoAction (this, tr("&Redo")); + mRedo->setShortcuts (QKeySequence::Redo); + edit->addAction (mRedo); +} + +void CSVDoc::View::setupViewMenu() +{ + QMenu *view = menuBar()->addMenu (tr ("&View")); + + QAction *newWindow = new QAction (tr ("&New View"), this); + connect (newWindow, SIGNAL (triggered()), this, SLOT (newView())); + view->addAction (newWindow); +} + +void CSVDoc::View::setupWorldMenu() +{ + QMenu *world = menuBar()->addMenu (tr ("&World")); + + QAction *globals = new QAction (tr ("Globals"), this); + connect (globals, SIGNAL (triggered()), this, SLOT (addGlobalsSubView())); + world->addAction (globals); + + mVerify = new QAction (tr ("&Verify"), this); + connect (mVerify, SIGNAL (triggered()), this, SLOT (verify())); + world->addAction (mVerify); +} + +void CSVDoc::View::setupUi() +{ + setupFileMenu(); + setupEditMenu(); + setupViewMenu(); + setupWorldMenu(); +} + +void CSVDoc::View::updateTitle() +{ + std::ostringstream stream; + + stream << mDocument->getName(); + + if (mDocument->getState() & CSMDoc::State_Modified) + stream << " *"; + + if (mViewTotal>1) + stream << " [" << (mViewIndex+1) << "/" << mViewTotal << "]"; + + setWindowTitle (stream.str().c_str()); +} + +void CSVDoc::View::updateActions() +{ + bool editing = !(mDocument->getState() & CSMDoc::State_Locked); + + for (std::vector::iterator iter (mEditingActions.begin()); iter!=mEditingActions.end(); ++iter) + (*iter)->setEnabled (editing); + + mUndo->setEnabled (editing & mDocument->getUndoStack().canUndo()); + mRedo->setEnabled (editing & mDocument->getUndoStack().canRedo()); + + mSave->setEnabled (!(mDocument->getState() & CSMDoc::State_Saving)); + mVerify->setEnabled (!(mDocument->getState() & CSMDoc::State_Verifying)); +} + +CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews) +: mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), mViewTotal (totalViews) +{ + setDockOptions (QMainWindow::AllowNestedDocks); + + resize (300, 300); /// \todo get default size from settings and set reasonable minimal size + + mOperations = new Operations; + addDockWidget (Qt::BottomDockWidgetArea, mOperations); + + updateTitle(); + + setupUi(); + + CSVWorld::addSubViewFactories (mSubViewFactory); + CSVTools::addSubViewFactories (mSubViewFactory); +} + +CSVDoc::View::~View() +{ +} + +const CSMDoc::Document *CSVDoc::View::getDocument() const +{ + return mDocument; +} + +CSMDoc::Document *CSVDoc::View::getDocument() +{ + return mDocument; +} + +void CSVDoc::View::setIndex (int viewIndex, int totalViews) +{ + mViewIndex = viewIndex; + mViewTotal = totalViews; + updateTitle(); +} + +void CSVDoc::View::updateDocumentState() +{ + updateTitle(); + updateActions(); + + static const int operations[] = + { + CSMDoc::State_Saving, CSMDoc::State_Verifying, + -1 // end marker + }; + + int state = mDocument->getState() ; + + for (int i=0; operations[i]!=-1; ++i) + if (!(state & operations[i])) + mOperations->quitOperation (operations[i]); + + QList subViews = findChildren(); + + for (QList::iterator iter (subViews.begin()); iter!=subViews.end(); ++iter) + (*iter)->setEditLock (state & CSMDoc::State_Locked); +} + +void CSVDoc::View::updateProgress (int current, int max, int type, int threads) +{ + mOperations->setProgress (current, max, type, threads); +} + +void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id) +{ + /// \todo add an user setting for limiting the number of sub views per top level view. Automatically open a new top level view if this + /// number is exceeded + + /// \todo if the sub view limit setting is one, the sub view title bar should be hidden and the text in the main title bar adjusted + /// accordingly + + /// \todo add an user setting to reuse sub views (on a per document basis or on a per top level view basis) + + SubView *view = mSubViewFactory.makeSubView (id, *mDocument); + addDockWidget (Qt::TopDockWidgetArea, view); + + connect (view, SIGNAL (focusId (const CSMWorld::UniversalId&)), this, + SLOT (addSubView (const CSMWorld::UniversalId&))); + + view->show(); +} + +void CSVDoc::View::newView() +{ + mViewManager.addView (mDocument); +} + +void CSVDoc::View::save() +{ + mDocument->save(); +} + +void CSVDoc::View::verify() +{ + addSubView (mDocument->verify()); +} + +void CSVDoc::View::addGlobalsSubView() +{ + addSubView (CSMWorld::UniversalId::Type_Globals); +} \ No newline at end of file diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp new file mode 100644 index 000000000..b1dedafe9 --- /dev/null +++ b/apps/opencs/view/doc/view.hpp @@ -0,0 +1,103 @@ +#ifndef CSV_DOC_VIEW_H +#define CSV_DOC_VIEW_H + +#include +#include + +#include + +#include "subviewfactory.hpp" + +class QAction; + +namespace CSMDoc +{ + class Document; +} + +namespace CSMWorld +{ + class UniversalId; +} + +namespace CSVDoc +{ + class ViewManager; + class Operations; + + class View : public QMainWindow + { + Q_OBJECT + + ViewManager& mViewManager; + CSMDoc::Document *mDocument; + int mViewIndex; + int mViewTotal; + QAction *mUndo; + QAction *mRedo; + QAction *mSave; + QAction *mVerify; + std::vector mEditingActions; + Operations *mOperations; + SubViewFactoryManager mSubViewFactory; + + // not implemented + View (const View&); + View& operator= (const View&); + + private: + + void closeEvent (QCloseEvent *event); + + void setupFileMenu(); + + void setupEditMenu(); + + void setupViewMenu(); + + void setupWorldMenu(); + + void setupUi(); + + void updateTitle(); + + void updateActions(); + + public: + + View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews); + ///< The ownership of \a document is not transferred to *this. + + virtual ~View(); + + const CSMDoc::Document *getDocument() const; + + CSMDoc::Document *getDocument(); + + void setIndex (int viewIndex, int totalViews); + + void updateDocumentState(); + + void updateProgress (int current, int max, int type, int threads); + + signals: + + void newDocumentRequest(); + + public slots: + + void addSubView (const CSMWorld::UniversalId& id); + + private slots: + + void newView(); + + void save(); + + void verify(); + + void addGlobalsSubView(); + }; +} + +#endif \ No newline at end of file diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp new file mode 100644 index 000000000..22847c78b --- /dev/null +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -0,0 +1,112 @@ + +#include "viewmanager.hpp" + +#include + +#include "../../model/doc/documentmanager.hpp" +#include "../../model/doc/document.hpp" + +#include "view.hpp" + +void CSVDoc::ViewManager::updateIndices() +{ + std::map > documents; + + for (std::vector::const_iterator iter (mViews.begin()); iter!=mViews.end(); ++iter) + { + std::map >::iterator document = documents.find ((*iter)->getDocument()); + + if (document==documents.end()) + document = + documents.insert ( + std::make_pair ((*iter)->getDocument(), std::make_pair (0, countViews ((*iter)->getDocument())))). + first; + + (*iter)->setIndex (document->second.first++, document->second.second); + } +} + +CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) +: mDocumentManager (documentManager) +{ + +} + +CSVDoc::ViewManager::~ViewManager() +{ + for (std::vector::iterator iter (mViews.begin()); iter!=mViews.end(); ++iter) + delete *iter; +} + +CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document) +{ + if (countViews (document)==0) + { + // new document + connect (document, SIGNAL (stateChanged (int, CSMDoc::Document *)), + this, SLOT (documentStateChanged (int, CSMDoc::Document *))); + + connect (document, SIGNAL (progress (int, int, int, int, CSMDoc::Document *)), + this, SLOT (progress (int, int, int, int, CSMDoc::Document *))); + } + + View *view = new View (*this, document, countViews (document)+1); + + mViews.push_back (view); + + view->show(); + + connect (view, SIGNAL (newDocumentRequest ()), this, SIGNAL (newDocumentRequest())); + + updateIndices(); + + return view; +} + +int CSVDoc::ViewManager::countViews (const CSMDoc::Document *document) const +{ + int count = 0; + + for (std::vector::const_iterator iter (mViews.begin()); iter!=mViews.end(); ++iter) + if ((*iter)->getDocument()==document) + ++count; + + return count; +} + +bool CSVDoc::ViewManager::closeRequest (View *view) +{ + std::vector::iterator iter = std::find (mViews.begin(), mViews.end(), view); + + if (iter!=mViews.end()) + { + bool last = countViews (view->getDocument())<=1; + + /// \todo check if save is in progress -> warn user about possible data loss + /// \todo check if document has not been saved -> return false and start close dialogue + + mViews.erase (iter); + view->deleteLater(); + + if (last) + mDocumentManager.removeDocument (view->getDocument()); + else + updateIndices(); + } + + return true; +} + +void CSVDoc::ViewManager::documentStateChanged (int state, CSMDoc::Document *document) +{ + for (std::vector::const_iterator iter (mViews.begin()); iter!=mViews.end(); ++iter) + if ((*iter)->getDocument()==document) + (*iter)->updateDocumentState(); +} + +void CSVDoc::ViewManager::progress (int current, int max, int type, int threads, CSMDoc::Document *document) +{ + for (std::vector::const_iterator iter (mViews.begin()); iter!=mViews.end(); ++iter) + if ((*iter)->getDocument()==document) + (*iter)->updateProgress (current, max, type, threads); +} \ No newline at end of file diff --git a/apps/opencs/view/doc/viewmanager.hpp b/apps/opencs/view/doc/viewmanager.hpp new file mode 100644 index 000000000..5e4b1be07 --- /dev/null +++ b/apps/opencs/view/doc/viewmanager.hpp @@ -0,0 +1,58 @@ +#ifndef CSV_DOC_VIEWMANAGER_H +#define CSV_DOC_VIEWMANAGER_H + +#include + +#include + +namespace CSMDoc +{ + class Document; + class DocumentManager; +} + +namespace CSVDoc +{ + class View; + + class ViewManager : public QObject + { + Q_OBJECT + + CSMDoc::DocumentManager& mDocumentManager; + std::vector mViews; + + // not implemented + ViewManager (const ViewManager&); + ViewManager& operator= (const ViewManager&); + + void updateIndices(); + + public: + + ViewManager (CSMDoc::DocumentManager& documentManager); + + virtual ~ViewManager(); + + View *addView (CSMDoc::Document *document); + ///< The ownership of the returned view is not transferred. + + int countViews (const CSMDoc::Document *document) const; + ///< Return number of views for \a document. + + bool closeRequest (View *view); + + signals: + + void newDocumentRequest(); + + private slots: + + void documentStateChanged (int state, CSMDoc::Document *document); + + void progress (int current, int max, int type, int threads, CSMDoc::Document *document); + }; + +} + +#endif \ No newline at end of file diff --git a/apps/opencs/view/tools/reportsubview.cpp b/apps/opencs/view/tools/reportsubview.cpp new file mode 100644 index 000000000..fe1be85d7 --- /dev/null +++ b/apps/opencs/view/tools/reportsubview.cpp @@ -0,0 +1,32 @@ + +#include "reportsubview.hpp" + +#include +#include + +#include "../../model/tools/reportmodel.hpp" + +CSVTools::ReportSubView::ReportSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) +: CSVDoc::SubView (id), mModel (document.getReport (id)) +{ + setWidget (mTable = new QTableView (this)); + mTable->setModel (mModel); + + mTable->horizontalHeader()->setResizeMode (QHeaderView::Interactive); + mTable->verticalHeader()->hide(); + mTable->setSortingEnabled (true); + mTable->setSelectionBehavior (QAbstractItemView::SelectRows); + mTable->setSelectionMode (QAbstractItemView::ExtendedSelection); + + connect (mTable, SIGNAL (doubleClicked (const QModelIndex&)), this, SLOT (show (const QModelIndex&))); +} + +void CSVTools::ReportSubView::setEditLock (bool locked) +{ + // ignored. We don't change document state anyway. +} + +void CSVTools::ReportSubView::show (const QModelIndex& index) +{ + focusId (mModel->getUniversalId (index.row())); +} \ No newline at end of file diff --git a/apps/opencs/view/tools/reportsubview.hpp b/apps/opencs/view/tools/reportsubview.hpp new file mode 100644 index 000000000..626ceb663 --- /dev/null +++ b/apps/opencs/view/tools/reportsubview.hpp @@ -0,0 +1,42 @@ +#ifndef CSV_TOOLS_REPORTSUBVIEW_H +#define CSV_TOOLS_REPORTSUBVIEW_H + +#include "../doc/subview.hpp" + +class QTableView; +class QModelIndex; + +namespace CSMDoc +{ + class Document; +} + +namespace CSMTools +{ + class ReportModel; +} + +namespace CSVTools +{ + class Table; + + class ReportSubView : public CSVDoc::SubView + { + Q_OBJECT + + CSMTools::ReportModel *mModel; + QTableView *mTable; + + public: + + ReportSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document); + + virtual void setEditLock (bool locked); + + private slots: + + void show (const QModelIndex& index); + }; +} + +#endif \ No newline at end of file diff --git a/apps/opencs/view/tools/subviews.cpp b/apps/opencs/view/tools/subviews.cpp new file mode 100644 index 000000000..781cf602e --- /dev/null +++ b/apps/opencs/view/tools/subviews.cpp @@ -0,0 +1,12 @@ + +#include "subviews.hpp" + +#include "../doc/subviewfactoryimp.hpp" + +#include "reportsubview.hpp" + +void CSVTools::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) +{ + manager.add (CSMWorld::UniversalId::Type_VerificationResults, + new CSVDoc::SubViewFactory); +} \ No newline at end of file diff --git a/apps/opencs/view/tools/subviews.hpp b/apps/opencs/view/tools/subviews.hpp new file mode 100644 index 000000000..1bac32228 --- /dev/null +++ b/apps/opencs/view/tools/subviews.hpp @@ -0,0 +1,14 @@ +#ifndef CSV_TOOLS_SUBVIEWS_H +#define CSV_TOOLS_SUBVIEWS_H + +namespace CSVDoc +{ + class SubViewFactoryManager; +} + +namespace CSVTools +{ + void addSubViewFactories (CSVDoc::SubViewFactoryManager& manager); +} + +#endif diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp new file mode 100644 index 000000000..e2d16f1e3 --- /dev/null +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -0,0 +1,14 @@ + +#include "dialoguesubview.hpp" + +CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, + bool createAndDelete) +: SubView (id) +{ + +} + +void CSVWorld::DialogueSubView::setEditLock (bool locked) +{ + +} \ No newline at end of file diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp new file mode 100644 index 000000000..c57dab108 --- /dev/null +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -0,0 +1,24 @@ +#ifndef CSV_WORLD_DIALOGUESUBVIEW_H +#define CSV_WORLD_DIALOGUESUBVIEW_H + +#include "../doc/subview.hpp" + +namespace CSMDoc +{ + class Document; +} + +namespace CSVWorld +{ + class DialogueSubView : public CSVDoc::SubView + { + + public: + + DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, bool createAndDelete); + + virtual void setEditLock (bool locked); + }; +} + +#endif \ No newline at end of file diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp new file mode 100644 index 000000000..080a175ea --- /dev/null +++ b/apps/opencs/view/world/subviews.cpp @@ -0,0 +1,16 @@ + +#include "subviews.hpp" + +#include "../doc/subviewfactoryimp.hpp" + +#include "tablesubview.hpp" +#include "dialoguesubview.hpp" + +void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) +{ + manager.add (CSMWorld::UniversalId::Type_Globals, + new CSVDoc::SubViewFactoryWithCreateFlag (true)); + + manager.add (CSMWorld::UniversalId::Type_Global, + new CSVDoc::SubViewFactoryWithCreateFlag (true)); +} \ No newline at end of file diff --git a/apps/opencs/view/world/subviews.hpp b/apps/opencs/view/world/subviews.hpp new file mode 100644 index 000000000..51e4cb083 --- /dev/null +++ b/apps/opencs/view/world/subviews.hpp @@ -0,0 +1,14 @@ +#ifndef CSV_WORLD_SUBVIEWS_H +#define CSV_WORLD_SUBVIEWS_H + +namespace CSVDoc +{ + class SubViewFactoryManager; +} + +namespace CSVWorld +{ + void addSubViewFactories (CSVDoc::SubViewFactoryManager& manager); +} + +#endif diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp new file mode 100644 index 000000000..0721ead2c --- /dev/null +++ b/apps/opencs/view/world/table.cpp @@ -0,0 +1,199 @@ + +#include "table.hpp" + +#include + +#include +#include +#include + +#include "../../model/world/data.hpp" +#include "../../model/world/commands.hpp" +#include "../../model/world/idtableproxymodel.hpp" +#include "../../model/world/idtable.hpp" +#include "../../model/world/record.hpp" + +#include "util.hpp" + +void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event) +{ + QModelIndexList selectedRows = selectionModel()->selectedRows(); + + QMenu menu (this); + + /// \todo add menu items for select all and clear selection + + if (!mEditLock) + { + if (mCreateAction) + menu.addAction (mCreateAction); + + if (listRevertableSelectedIds().size()>0) + menu.addAction (mRevertAction); + + if (listDeletableSelectedIds().size()>0) + menu.addAction (mDeleteAction); + } + + menu.exec (event->globalPos()); +} + +std::vector CSVWorld::Table::listRevertableSelectedIds() const +{ + QModelIndexList selectedRows = selectionModel()->selectedRows(); + + std::vector revertableIds; + + for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end(); ++iter) + { + std::string id = mProxyModel->data (*iter).toString().toStdString(); + + CSMWorld::RecordBase::State state = + static_cast (mModel->data (mModel->getModelIndex (id, 1)).toInt()); + + if (state!=CSMWorld::RecordBase::State_BaseOnly) + revertableIds.push_back (id); + } + + return revertableIds; +} + +std::vector CSVWorld::Table::listDeletableSelectedIds() const +{ + QModelIndexList selectedRows = selectionModel()->selectedRows(); + + std::vector deletableIds; + + for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end(); ++iter) + { + std::string id = mProxyModel->data (*iter).toString().toStdString(); + + CSMWorld::RecordBase::State state = + static_cast (mModel->data (mModel->getModelIndex (id, 1)).toInt()); + + if (state!=CSMWorld::RecordBase::State_Deleted) + deletableIds.push_back (id); + } + + return deletableIds; +} + +CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack, + bool createAndDelete) +: mUndoStack (undoStack), mCreateAction (0), mEditLock (false) +{ + mModel = &dynamic_cast (*data.getTableModel (id)); + + mProxyModel = new CSMWorld::IdTableProxyModel (this); + mProxyModel->setSourceModel (mModel); + + setModel (mProxyModel); + horizontalHeader()->setResizeMode (QHeaderView::Interactive); + verticalHeader()->hide(); + setSortingEnabled (true); + setSelectionBehavior (QAbstractItemView::SelectRows); + setSelectionMode (QAbstractItemView::ExtendedSelection); + + int columns = mModel->columnCount(); + + for (int i=0; iheaderData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags).toInt(); + + if (flags & CSMWorld::ColumnBase::Flag_Table) + { + CommandDelegate *delegate = new CommandDelegate (undoStack, this); + mDelegates.push_back (delegate); + setItemDelegateForColumn (i, delegate); + } + else + hideColumn (i); + } + + /// \todo make initial layout fill the whole width of the table + + if (createAndDelete) + { + mCreateAction = new QAction (tr ("Add Record"), this); + connect (mCreateAction, SIGNAL (triggered()), this, SLOT (createRecord())); + addAction (mCreateAction); + } + + mRevertAction = new QAction (tr ("Revert Record"), this); + connect (mRevertAction, SIGNAL (triggered()), this, SLOT (revertRecord())); + addAction (mRevertAction); + + mDeleteAction = new QAction (tr ("Delete Record"), this); + connect (mDeleteAction, SIGNAL (triggered()), this, SLOT (deleteRecord())); + addAction (mDeleteAction); +} + +void CSVWorld::Table::setEditLock (bool locked) +{ + for (std::vector::iterator iter (mDelegates.begin()); iter!=mDelegates.end(); ++iter) + (*iter)->setEditLock (locked); + + mEditLock = locked; +} + +CSMWorld::UniversalId CSVWorld::Table::getUniversalId (int row) const +{ + return CSMWorld::UniversalId ( + static_cast (mProxyModel->data (mProxyModel->index (row, 2)).toInt()), + mProxyModel->data (mProxyModel->index (row, 0)).toString().toStdString()); +} + +#include /// \todo remove +void CSVWorld::Table::createRecord() +{ + if (!mEditLock) + { + /// \todo ask the user for an ID instead. + static int index = 0; + + std::ostringstream stream; + stream << "id" << index++; + + mUndoStack.push (new CSMWorld::CreateCommand (*mProxyModel, stream.str())); + } +} + +void CSVWorld::Table::revertRecord() +{ + if (!mEditLock) + { + std::vector revertableIds = listRevertableSelectedIds(); + + if (revertableIds.size()>0) + { + if (revertableIds.size()>1) + mUndoStack.beginMacro (tr ("Revert multiple records")); + + for (std::vector::const_iterator iter (revertableIds.begin()); iter!=revertableIds.end(); ++iter) + mUndoStack.push (new CSMWorld::RevertCommand (*mModel, *iter)); + + if (revertableIds.size()>1) + mUndoStack.endMacro(); + } + } +} + +void CSVWorld::Table::deleteRecord() +{ + if (!mEditLock) + { + std::vector deletableIds = listDeletableSelectedIds(); + + if (deletableIds.size()>0) + { + if (deletableIds.size()>1) + mUndoStack.beginMacro (tr ("Delete multiple records")); + + for (std::vector::const_iterator iter (deletableIds.begin()); iter!=deletableIds.end(); ++iter) + mUndoStack.push (new CSMWorld::DeleteCommand (*mModel, *iter)); + + if (deletableIds.size()>1) + mUndoStack.endMacro(); + } + } +} \ No newline at end of file diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp new file mode 100644 index 000000000..df0224583 --- /dev/null +++ b/apps/opencs/view/world/table.hpp @@ -0,0 +1,65 @@ +#ifndef CSV_WORLD_TABLE_H +#define CSV_WORLD_TABLE_H + +#include +#include + +#include + +class QUndoStack; +class QAction; + +namespace CSMWorld +{ + class Data; + class UniversalId; + class IdTableProxyModel; + class IdTable; +} + +namespace CSVWorld +{ + class CommandDelegate; + + ///< Table widget + class Table : public QTableView + { + Q_OBJECT + + std::vector mDelegates; + QUndoStack& mUndoStack; + QAction *mCreateAction; + QAction *mRevertAction; + QAction *mDeleteAction; + CSMWorld::IdTableProxyModel *mProxyModel; + CSMWorld::IdTable *mModel; + bool mEditLock; + + private: + + void contextMenuEvent (QContextMenuEvent *event); + + std::vector listRevertableSelectedIds() const; + + std::vector listDeletableSelectedIds() const; + + public: + + Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack, bool createAndDelete); + ///< \param createAndDelete Allow creation and deletion of records. + + void setEditLock (bool locked); + + CSMWorld::UniversalId getUniversalId (int row) const; + + private slots: + + void createRecord(); + + void revertRecord(); + + void deleteRecord(); + }; +} + +#endif diff --git a/apps/opencs/view/world/tablesubview.cpp b/apps/opencs/view/world/tablesubview.cpp new file mode 100644 index 000000000..bb4bb76c6 --- /dev/null +++ b/apps/opencs/view/world/tablesubview.cpp @@ -0,0 +1,25 @@ + +#include "tablesubview.hpp" + +#include "../../model/doc/document.hpp" + +#include "table.hpp" + +CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, + bool createAndDelete) +: SubView (id) +{ + setWidget (mTable = new Table (id, document.getData(), document.getUndoStack(), createAndDelete)); + + connect (mTable, SIGNAL (doubleClicked (const QModelIndex&)), this, SLOT (rowActivated (const QModelIndex&))); +} + +void CSVWorld::TableSubView::setEditLock (bool locked) +{ + mTable->setEditLock (locked); +} + +void CSVWorld::TableSubView::rowActivated (const QModelIndex& index) +{ + focusId (mTable->getUniversalId (index.row())); +} \ No newline at end of file diff --git a/apps/opencs/view/world/tablesubview.hpp b/apps/opencs/view/world/tablesubview.hpp new file mode 100644 index 000000000..0e7b8aa30 --- /dev/null +++ b/apps/opencs/view/world/tablesubview.hpp @@ -0,0 +1,35 @@ +#ifndef CSV_WORLD_TABLESUBVIEW_H +#define CSV_WORLD_TABLESUBVIEW_H + +#include "../doc/subview.hpp" + +class QModelIndex; + +namespace CSMDoc +{ + class Document; +} + +namespace CSVWorld +{ + class Table; + + class TableSubView : public CSVDoc::SubView + { + Q_OBJECT + + Table *mTable; + + public: + + TableSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, bool createAndDelete); + + virtual void setEditLock (bool locked); + + private slots: + + void rowActivated (const QModelIndex& index); + }; +} + +#endif \ No newline at end of file diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp new file mode 100644 index 000000000..7181dd4d1 --- /dev/null +++ b/apps/opencs/view/world/util.cpp @@ -0,0 +1,57 @@ + +#include "util.hpp" + +#include + +#include "../../model/world/commands.hpp" + +CSVWorld::NastyTableModelHack::NastyTableModelHack (QAbstractItemModel& model) +: mModel (model) +{} + +int CSVWorld::NastyTableModelHack::rowCount (const QModelIndex & parent) const +{ + return mModel.rowCount (parent); +} + +int CSVWorld::NastyTableModelHack::columnCount (const QModelIndex & parent) const +{ + return mModel.columnCount (parent); +} + +QVariant CSVWorld::NastyTableModelHack::data (const QModelIndex & index, int role) const +{ + return mModel.data (index, role); +} + +bool CSVWorld::NastyTableModelHack::setData ( const QModelIndex &index, const QVariant &value, int role) +{ + mData = value; + return true; +} + +QVariant CSVWorld::NastyTableModelHack::getData() const +{ + return mData; +} + +CSVWorld::CommandDelegate::CommandDelegate (QUndoStack& undoStack, QObject *parent) +: QStyledItemDelegate (parent), mUndoStack (undoStack), mEditLock (false) +{} + +void CSVWorld::CommandDelegate::setModelData (QWidget *editor, QAbstractItemModel *model, + const QModelIndex& index) const +{ + if (!mEditLock) + { + NastyTableModelHack hack (*model); + QStyledItemDelegate::setModelData (editor, &hack, index); + mUndoStack.push (new CSMWorld::ModifyCommand (*model, index, hack.getData())); + } + ///< \todo provide some kind of feedback to the user, indicating that editing is currently not possible. +} + +void CSVWorld::CommandDelegate::setEditLock (bool locked) +{ + mEditLock = locked; +} \ No newline at end of file diff --git a/apps/opencs/view/world/util.hpp b/apps/opencs/view/world/util.hpp new file mode 100644 index 000000000..136583118 --- /dev/null +++ b/apps/opencs/view/world/util.hpp @@ -0,0 +1,50 @@ +#ifndef CSV_WORLD_UTIL_H +#define CSV_WORLD_UTIL_H + +#include +#include + +class QUndoStack; + +namespace CSVWorld +{ + ///< \brief Getting the data out of an editor widget + /// + /// Really, Qt? Really? + class NastyTableModelHack : public QAbstractTableModel + { + QAbstractItemModel& mModel; + QVariant mData; + + public: + + NastyTableModelHack (QAbstractItemModel& model); + + int rowCount (const QModelIndex & parent = QModelIndex()) const; + + int columnCount (const QModelIndex & parent = QModelIndex()) const; + + QVariant data (const QModelIndex & index, int role = Qt::DisplayRole) const; + + bool setData (const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); + + QVariant getData() const; + }; + + ///< \brief Use commands instead of manipulating the model directly + class CommandDelegate : public QStyledItemDelegate + { + QUndoStack& mUndoStack; + bool mEditLock; + + public: + + CommandDelegate (QUndoStack& undoStack, QObject *parent); + + void setModelData (QWidget *editor, QAbstractItemModel *model, const QModelIndex& index) const; + + void setEditLock (bool locked); + }; +} + +#endif diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 67533cf4b..e2a2e7f14 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -34,7 +34,7 @@ add_openmw_dir (mwgui ) add_openmw_dir (mwdialogue - dialoguemanagerimp journalimp journalentry quest topic + dialoguemanagerimp journalimp journalentry quest topic filter selectwrapper ) add_openmw_dir (mwscript @@ -53,6 +53,7 @@ add_openmw_dir (mwworld containerstore actiontalk actiontake manualref player cellfunctors failedaction cells localscripts customdata weather inventorystore ptr actionopen actionread actionequip timestamp actionalchemy cellstore actionapply actioneat + esmstore store recordcmp ) add_openmw_dir (mwclass @@ -62,7 +63,7 @@ add_openmw_dir (mwclass add_openmw_dir (mwmechanics mechanicsmanagerimp stat creaturestats magiceffects movement actors drawstate spells - activespells npcstats aipackage aisequence alchemy + activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow aiescort aiactivate ) add_openmw_dir (mwbase diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 617689bc6..b995300d5 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -20,6 +21,7 @@ #include "mwscript/scriptmanagerimp.hpp" #include "mwscript/extensions.hpp" +#include "mwscript/interpretercontext.hpp" #include "mwsound/soundmanagerimp.hpp" @@ -101,7 +103,7 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) MWBase::Environment::get().getWorld()->doPhysics (movement, mEnvironment.getFrameDuration()); // update world - MWBase::Environment::get().getWorld()->update (evt.timeSinceLastFrame); + MWBase::Environment::get().getWorld()->update (evt.timeSinceLastFrame, MWBase::Environment::get().getWindowManager()->isGuiMode()); // update GUI Ogre::RenderWindow* window = mOgre->getWindow(); @@ -333,12 +335,15 @@ void OMW::Engine::go() mEnvironment.setWorld (new MWWorld::World (*mOgre, mFileCollections, mMaster, mResDir, mCfgMgr.getCachePath(), mNewGame, mEncoding, mFallbackMap)); + //Load translation data + mTranslationDataStorage.loadTranslationData(mFileCollections, mMaster); + // Create window manager - this manages all the MW-specific GUI windows MWScript::registerExtensions (mExtensions); mEnvironment.setWindowManager (new MWGui::WindowManager( mExtensions, mFpsLevel, mNewGame, mOgre, mCfgMgr.getLogPath().string() + std::string("/"), - mCfgMgr.getCachePath ().string(), mScriptConsoleMode)); + mCfgMgr.getCachePath ().string(), mScriptConsoleMode, mTranslationDataStorage)); // Create sound system mEnvironment.setSoundManager (new MWSound::SoundManager(mUseSound)); @@ -355,7 +360,7 @@ void OMW::Engine::go() // Create dialog system mEnvironment.setJournal (new MWDialogue::Journal); - mEnvironment.setDialogueManager (new MWDialogue::DialogueManager (mExtensions)); + mEnvironment.setDialogueManager (new MWDialogue::DialogueManager (mExtensions, mVerboseScripts)); // Sets up the input system mEnvironment.setInputManager (new MWInput::InputManager (*mOgre, @@ -486,9 +491,10 @@ void OMW::Engine::showFPS(int level) mFpsLevel = level; } -void OMW::Engine::setEncoding(const std::string& encoding) +void OMW::Engine::setEncoding(const ToUTF8::FromType& encoding) { mEncoding = encoding; + mTranslationDataStorage.setEncoding (encoding); } void OMW::Engine::setFallbackValues(std::map fallbackMap) diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 57402c91e..00889197e 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -5,6 +5,7 @@ #include #include +#include #include "mwbase/environment.hpp" @@ -59,7 +60,7 @@ namespace OMW class Engine : private Ogre::FrameListener { MWBase::Environment mEnvironment; - std::string mEncoding; + ToUTF8::FromType mEncoding; Files::PathContainer mDataDirs; boost::filesystem::path mResDir; OEngine::Render::OgreRenderer *mOgre; @@ -79,9 +80,9 @@ namespace OMW Compiler::Extensions mExtensions; Compiler::Context *mScriptContext; - Files::Collections mFileCollections; bool mFSStrict; + Translation::Storage mTranslationDataStorage; // not implemented Engine (const Engine&); @@ -154,7 +155,7 @@ namespace OMW void setCompileAll (bool all); /// Font encoding - void setEncoding(const std::string& encoding); + void setEncoding(const ToUTF8::FromType& encoding); void setAnimationVerbose(bool animverbose); diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 2da52311f..96dbf8987 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -131,9 +131,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ->default_value(false), "enable console-only script functionality") ("script-run", bpo::value()->default_value(""), - "select a file that is executed in the console on startup\n\n" - "Note: The file contains a list of script lines, but not a complete scripts. " - "That means no begin/end and no variable declarations.") + "select a file containing a list of console commands that is executed on startup") ("new-game", bpo::value()->implicit_value(true) ->default_value(false), "activate char gen/new game mechanics") @@ -183,21 +181,8 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat // Font encoding settings std::string encoding(variables["encoding"].as()); - if (encoding == "win1250") - { - std::cout << "Using Central and Eastern European font encoding." << std::endl; - engine.setEncoding(encoding); - } - else if (encoding == "win1251") - { - std::cout << "Using Cyrillic font encoding." << std::endl; - engine.setEncoding(encoding); - } - else - { - std::cout << "Using default (English) font encoding." << std::endl; - engine.setEncoding("win1252"); - } + std::cout << ToUTF8::encodingUsingMessage(encoding) << std::endl; + engine.setEncoding(ToUTF8::calculateEncoding(encoding)); // directory settings engine.enableFSStrict(variables["fs-strict"].as()); diff --git a/apps/openmw/mwbase/dialoguemanager.hpp b/apps/openmw/mwbase/dialoguemanager.hpp index ccffc6b21..a205e78db 100644 --- a/apps/openmw/mwbase/dialoguemanager.hpp +++ b/apps/openmw/mwbase/dialoguemanager.hpp @@ -33,13 +33,17 @@ namespace MWBase virtual void goodbye() = 0; - ///get the faction of the actor you are talking with - virtual std::string getFaction() const = 0; + virtual MWWorld::Ptr getActor() const = 0; + ///< Return the actor the player is currently talking to. //calbacks for the GUI virtual void keywordSelected (const std::string& keyword) = 0; virtual void goodbyeSelected() = 0; virtual void questionAnswered (const std::string& answer) = 0; + + virtual void persuade (int type) = 0; + virtual int getTemporaryDispositionChange () const = 0; + virtual void applyTemporaryDispositionChange (int delta) = 0; }; } diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 750fc2fff..a1023c986 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -62,7 +62,7 @@ namespace MWBase virtual void setPlayerName (const std::string& name) = 0; ///< Set player name. - virtual void setPlayerRace (const std::string& id, bool male) = 0; + virtual void setPlayerRace (const std::string& id, bool male, const std::string &head, const std::string &hair) = 0; ///< Set player race. virtual void setPlayerBirthsign (const std::string& id) = 0; @@ -76,9 +76,28 @@ namespace MWBase virtual void restoreDynamicStats() = 0; ///< If the player is sleeping, this should be called every hour. + + 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. + + virtual int getDerivedDisposition(const MWWorld::Ptr& ptr) = 0; + ///< Calculate the diposition of an NPC toward the player. virtual int countDeaths (const std::string& id) const = 0; ///< Return the number of deaths for actors with the given ID. + + enum PersuasionType + { + PT_Admire, + PT_Intimidate, + PT_Taunt, + PT_Bribe10, + PT_Bribe100, + PT_Bribe1000 + }; + virtual void getPersuasionDispositionChange (const MWWorld::Ptr& npc, PersuasionType type, + float currentTemporaryDispositionDelta, bool& success, float& tempChange, float& permChange) = 0; + ///< Perform a persuasion action on NPC }; } diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index d29e23c18..cc625b306 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -29,11 +29,7 @@ namespace ESM struct Class; struct Potion; struct Spell; -} - -namespace ESMS -{ - struct ESMStore; + struct NPC; } namespace MWRender @@ -48,6 +44,7 @@ namespace MWWorld class LocalScripts; class Ptr; class TimeStamp; + class ESMStore; } namespace MWBase @@ -68,7 +65,8 @@ namespace MWBase Render_CollisionDebug, Render_Wireframe, Render_Pathgrid, - Render_Compositors + Render_Compositors, + Render_BoundingBoxes }; struct DoorMarker @@ -104,7 +102,7 @@ namespace MWBase virtual MWWorld::Player& getPlayer() = 0; - virtual const ESMS::ESMStore& getStore() const = 0; + virtual const MWWorld::ESMStore& getStore() const = 0; virtual ESM::ESMReader& getEsmReader() = 0; @@ -135,6 +133,10 @@ namespace MWBase virtual char getGlobalVariableType (const std::string& name) const = 0; ///< Return ' ', if there is no global variable with this name. + + virtual std::vector getGlobals () const = 0; + + virtual std::string getCurrentCellName() const = 0; virtual MWWorld::Ptr getPtr (const std::string& name, bool activeOnly) = 0; ///< Return a pointer to a liveCellRef with the given name. @@ -234,24 +236,28 @@ namespace MWBase ///< Toggle a render mode. ///< \return Resulting mode - virtual std::pair createRecord (const ESM::Potion& record) + virtual const ESM::Potion *createRecord (const ESM::Potion& record) = 0; ///< Create a new recrod (of type potion) in the ESM store. - /// \return ID, pointer to created record + /// \return pointer to created record - virtual std::pair createRecord (const ESM::Spell& record) + virtual const ESM::Spell *createRecord (const ESM::Spell& record) = 0; ///< Create a new recrod (of type spell) in the ESM store. - /// \return ID, pointer to created record + /// \return pointer to created record - virtual std::pair createRecord (const ESM::Class& record) + virtual const ESM::Class *createRecord (const ESM::Class& record) = 0; ///< Create a new recrod (of type class) in the ESM store. - /// \return ID, pointer to created record + /// \return pointer to created record virtual const ESM::Cell *createRecord (const ESM::Cell& record) = 0; ///< Create a new recrod (of type cell) in the ESM store. - /// \return ID, pointer to created record + /// \return pointer to created record + + virtual const ESM::NPC *createRecord(const ESM::NPC &record) = 0; + ///< Create a new recrod (of type npc) in the ESM store. + /// \return pointer to created record virtual void playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number = 1) = 0; @@ -265,7 +271,7 @@ namespace MWBase ///< Skip the animation for the given MW-reference for one frame. Calls to this function for /// references that are currently not in the rendered scene should be ignored. - virtual void update (float duration) = 0; + virtual void update (float duration, bool paused) = 0; virtual bool placeObject(const MWWorld::Ptr& object, float cursorX, float cursorY) = 0; ///< place an object into the gameworld at the specified cursor position diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index e815549d8..26d286aa1 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -30,18 +30,17 @@ namespace MWClass void Activator::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { const std::string model = getModel(ptr); - if(!model.empty()) { - physics.insertObjectPhysics(ptr, model); - } + if(!model.empty()) + physics.addObject(ptr); } std::string Activator::getModel(const MWWorld::Ptr &ptr) const { MWWorld::LiveCellRef *ref = ptr.get(); - assert(ref->base != NULL); + assert(ref->mBase != NULL); - const std::string &model = ref->base->mModel; + const std::string &model = ref->mBase->mModel; if (!model.empty()) { return "meshes\\" + model; } @@ -53,7 +52,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mName; + return ref->mBase->mName; } std::string Activator::getScript (const MWWorld::Ptr& ptr) const @@ -61,7 +60,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mScript; + return ref->mBase->mScript; } void Activator::registerSelf() @@ -76,7 +75,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return (ref->base->mName != ""); + return (ref->mBase->mName != ""); } MWGui::ToolTipInfo Activator::getToolTipInfo (const MWWorld::Ptr& ptr) const @@ -85,22 +84,22 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); + info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); std::string text; if (MWBase::Environment::get().getWindowManager()->getFullHelp()) - text += MWGui::ToolTips::getMiscString(ref->base->mScript, "Script"); + text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); info.text = text; return info; } - + MWWorld::Ptr Activator::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const { MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(&cell.activators.insert(*ref), &cell); + return MWWorld::Ptr(&cell.mActivators.insert(*ref), &cell); } } diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index a05c24e86..06467bb21 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -33,18 +33,17 @@ namespace MWClass void Apparatus::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { const std::string model = getModel(ptr); - if(!model.empty()) { - physics.insertObjectPhysics(ptr, model); - } + if(!model.empty()) + physics.addObject(ptr); } std::string Apparatus::getModel(const MWWorld::Ptr &ptr) const { MWWorld::LiveCellRef *ref = ptr.get(); - assert(ref->base != NULL); + assert(ref->mBase != NULL); - const std::string &model = ref->base->mModel; + const std::string &model = ref->mBase->mModel; if (!model.empty()) { return "meshes\\" + model; } @@ -56,7 +55,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mName; + return ref->mBase->mName; } boost::shared_ptr Apparatus::activate (const MWWorld::Ptr& ptr, @@ -75,7 +74,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mScript; + return ref->mBase->mScript; } int Apparatus::getValue (const MWWorld::Ptr& ptr) const @@ -83,7 +82,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mData.mValue; + return ref->mBase->mData.mValue; } void Apparatus::registerSelf() @@ -108,7 +107,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mIcon; + return ref->mBase->mIcon; } bool Apparatus::hasToolTip (const MWWorld::Ptr& ptr) const @@ -116,7 +115,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return (ref->base->mName != ""); + return (ref->mBase->mName != ""); } MWGui::ToolTipInfo Apparatus::getToolTipInfo (const MWWorld::Ptr& ptr) const @@ -125,17 +124,17 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); - info.icon = ref->base->mIcon; + info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); + info.icon = ref->mBase->mIcon; std::string text; - text += "\n#{sQuality}: " + MWGui::ToolTips::toString(ref->base->mData.mQuality); - text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->base->mData.mWeight); - text += MWGui::ToolTips::getValueString(ref->base->mData.mValue, "#{sValue}"); + text += "\n#{sQuality}: " + MWGui::ToolTips::toString(ref->mBase->mData.mQuality); + text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); + text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { - text += MWGui::ToolTips::getMiscString(ref->ref.mOwner, "Owner"); - text += MWGui::ToolTips::getMiscString(ref->base->mScript, "Script"); + text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); + text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); } info.text = text; @@ -154,6 +153,6 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(&cell.appas.insert(*ref), &cell); + return MWWorld::Ptr(&cell.mAppas.insert(*ref), &cell); } } diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 7254c37f8..704173b1c 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -36,18 +36,17 @@ namespace MWClass void Armor::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { const std::string model = getModel(ptr); - if(!model.empty()) { - physics.insertObjectPhysics(ptr, model); - } + if(!model.empty()) + physics.addObject(ptr); } std::string Armor::getModel(const MWWorld::Ptr &ptr) const { MWWorld::LiveCellRef *ref = ptr.get(); - assert(ref->base != NULL); + assert(ref->mBase != NULL); - const std::string &model = ref->base->mModel; + const std::string &model = ref->mBase->mModel; if (!model.empty()) { return "meshes\\" + model; } @@ -59,7 +58,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mName; + return ref->mBase->mName; } boost::shared_ptr Armor::activate (const MWWorld::Ptr& ptr, @@ -82,7 +81,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mData.mHealth; + return ref->mBase->mData.mHealth; } std::string Armor::getScript (const MWWorld::Ptr& ptr) const @@ -90,7 +89,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mScript; + return ref->mBase->mScript; } std::pair, bool> Armor::getEquipmentSlots (const MWWorld::Ptr& ptr) const @@ -118,7 +117,7 @@ namespace MWClass }; for (int i=0; ibase->mData.mType) + if (sMapping[i][0]==ref->mBase->mData.mType) { slots.push_back (int (sMapping[i][1])); break; @@ -134,7 +133,7 @@ namespace MWClass std::string typeGmst; - switch (ref->base->mData.mType) + switch (ref->mBase->mData.mType) { case ESM::Armor::Helmet: typeGmst = "iHelmWeight"; break; case ESM::Armor::Cuirass: typeGmst = "iCuirassWeight"; break; @@ -152,14 +151,17 @@ namespace MWClass if (typeGmst.empty()) return -1; - float iWeight = MWBase::Environment::get().getWorld()->getStore().gameSettings.find (typeGmst)->getInt(); + const MWWorld::Store &gmst = + MWBase::Environment::get().getWorld()->getStore().get(); - if (iWeight * MWBase::Environment::get().getWorld()->getStore().gameSettings.find ("fLightMaxMod")->getFloat()>= - ref->base->mData.mWeight) + float iWeight = gmst.find (typeGmst)->getInt(); + + if (iWeight * gmst.find ("fLightMaxMod")->getFloat()>= + ref->mBase->mData.mWeight) return ESM::Skill::LightArmor; - if (iWeight * MWBase::Environment::get().getWorld()->getStore().gameSettings.find ("fMedMaxMod")->getFloat()>= - ref->base->mData.mWeight) + if (iWeight * gmst.find ("fMedMaxMod")->getFloat()>= + ref->mBase->mData.mWeight) return ESM::Skill::MediumArmor; return ESM::Skill::HeavyArmor; @@ -170,7 +172,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mData.mValue; + return ref->mBase->mData.mValue; } void Armor::registerSelf() @@ -207,7 +209,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mIcon; + return ref->mBase->mIcon; } bool Armor::hasToolTip (const MWWorld::Ptr& ptr) const @@ -215,7 +217,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return (ref->base->mName != ""); + return (ref->mBase->mName != ""); } MWGui::ToolTipInfo Armor::getToolTipInfo (const MWWorld::Ptr& ptr) const @@ -224,8 +226,8 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); - info.icon = ref->base->mIcon; + info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); + info.icon = ref->mBase->mIcon; std::string text; @@ -239,20 +241,20 @@ namespace MWClass else typeText = "#{sHeavy}"; - text += "\n#{sArmorRating}: " + MWGui::ToolTips::toString(ref->base->mData.mArmor); + text += "\n#{sArmorRating}: " + MWGui::ToolTips::toString(ref->mBase->mData.mArmor); /// \todo store the current armor health somewhere - text += "\n#{sCondition}: " + MWGui::ToolTips::toString(ref->base->mData.mHealth); + text += "\n#{sCondition}: " + MWGui::ToolTips::toString(ref->mBase->mData.mHealth); - text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->base->mData.mWeight) + " (" + typeText + ")"; - text += MWGui::ToolTips::getValueString(ref->base->mData.mValue, "#{sValue}"); + text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight) + " (" + typeText + ")"; + text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { - text += MWGui::ToolTips::getMiscString(ref->ref.mOwner, "Owner"); - text += MWGui::ToolTips::getMiscString(ref->base->mScript, "Script"); + text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); + text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); } - info.enchant = ref->base->mEnchant; + info.enchant = ref->mBase->mEnchant; info.text = text; @@ -264,7 +266,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mEnchant; + return ref->mBase->mEnchant; } boost::shared_ptr Armor::use (const MWWorld::Ptr& ptr) const @@ -282,6 +284,6 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(&cell.armors.insert(*ref), &cell); + return MWWorld::Ptr(&cell.mArmors.insert(*ref), &cell); } } diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 4a2ad1dcb..6c3b7b86c 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -32,18 +32,17 @@ namespace MWClass void Book::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { const std::string model = getModel(ptr); - if(!model.empty()) { - physics.insertObjectPhysics(ptr, model); - } + if(!model.empty()) + physics.addObject(ptr); } std::string Book::getModel(const MWWorld::Ptr &ptr) const { MWWorld::LiveCellRef *ref = ptr.get(); - assert(ref->base != NULL); + assert(ref->mBase != NULL); - const std::string &model = ref->base->mModel; + const std::string &model = ref->mBase->mModel; if (!model.empty()) { return "meshes\\" + model; } @@ -55,7 +54,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mName; + return ref->mBase->mName; } boost::shared_ptr Book::activate (const MWWorld::Ptr& ptr, @@ -70,7 +69,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mScript; + return ref->mBase->mScript; } int Book::getValue (const MWWorld::Ptr& ptr) const @@ -78,7 +77,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mData.mValue; + return ref->mBase->mData.mValue; } void Book::registerSelf() @@ -103,7 +102,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mIcon; + return ref->mBase->mIcon; } bool Book::hasToolTip (const MWWorld::Ptr& ptr) const @@ -111,7 +110,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return (ref->base->mName != ""); + return (ref->mBase->mName != ""); } MWGui::ToolTipInfo Book::getToolTipInfo (const MWWorld::Ptr& ptr) const @@ -120,20 +119,20 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); - info.icon = ref->base->mIcon; + info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); + info.icon = ref->mBase->mIcon; std::string text; - text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->base->mData.mWeight); - text += MWGui::ToolTips::getValueString(ref->base->mData.mValue, "#{sValue}"); + text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); + text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { - text += MWGui::ToolTips::getMiscString(ref->ref.mOwner, "Owner"); - text += MWGui::ToolTips::getMiscString(ref->base->mScript, "Script"); + text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); + text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); } - info.enchant = ref->base->mEnchant; + info.enchant = ref->mBase->mEnchant; info.text = text; @@ -145,7 +144,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mEnchant; + return ref->mBase->mEnchant; } boost::shared_ptr Book::use (const MWWorld::Ptr& ptr) const @@ -159,6 +158,6 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(&cell.books.insert(*ref), &cell); + return MWWorld::Ptr(&cell.mBooks.insert(*ref), &cell); } } diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index d746350df..c411bb193 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -34,18 +34,17 @@ namespace MWClass void Clothing::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { const std::string model = getModel(ptr); - if(!model.empty()) { - physics.insertObjectPhysics(ptr, model); - } + if(!model.empty()) + physics.addObject(ptr); } std::string Clothing::getModel(const MWWorld::Ptr &ptr) const { MWWorld::LiveCellRef *ref = ptr.get(); - assert(ref->base != NULL); + assert(ref->mBase != NULL); - const std::string &model = ref->base->mModel; + const std::string &model = ref->mBase->mModel; if (!model.empty()) { return "meshes\\" + model; } @@ -57,7 +56,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mName; + return ref->mBase->mName; } boost::shared_ptr Clothing::activate (const MWWorld::Ptr& ptr, @@ -75,7 +74,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mScript; + return ref->mBase->mScript; } std::pair, bool> Clothing::getEquipmentSlots (const MWWorld::Ptr& ptr) const @@ -85,7 +84,7 @@ namespace MWClass std::vector slots; - if (ref->base->mData.mType==ESM::Clothing::Ring) + if (ref->mBase->mData.mType==ESM::Clothing::Ring) { slots.push_back (int (MWWorld::InventoryStore::Slot_LeftRing)); slots.push_back (int (MWWorld::InventoryStore::Slot_RightRing)); @@ -108,7 +107,7 @@ namespace MWClass }; for (int i=0; ibase->mData.mType) + if (sMapping[i][0]==ref->mBase->mData.mType) { slots.push_back (int (sMapping[i][1])); break; @@ -123,7 +122,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - if (ref->base->mData.mType==ESM::Clothing::Shoes) + if (ref->mBase->mData.mType==ESM::Clothing::Shoes) return ESM::Skill::Unarmored; return -1; @@ -134,7 +133,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mData.mValue; + return ref->mBase->mData.mValue; } void Clothing::registerSelf() @@ -149,7 +148,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - if (ref->base->mData.mType == 8) + if (ref->mBase->mData.mType == 8) { return std::string("Item Ring Up"); } @@ -161,7 +160,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - if (ref->base->mData.mType == 8) + if (ref->mBase->mData.mType == 8) { return std::string("Item Ring Down"); } @@ -173,7 +172,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mIcon; + return ref->mBase->mIcon; } bool Clothing::hasToolTip (const MWWorld::Ptr& ptr) const @@ -181,7 +180,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return (ref->base->mName != ""); + return (ref->mBase->mName != ""); } MWGui::ToolTipInfo Clothing::getToolTipInfo (const MWWorld::Ptr& ptr) const @@ -190,20 +189,20 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); - info.icon = ref->base->mIcon; + info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); + info.icon = ref->mBase->mIcon; std::string text; - text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->base->mData.mWeight); - text += MWGui::ToolTips::getValueString(ref->base->mData.mValue, "#{sValue}"); + text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); + text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { - text += MWGui::ToolTips::getMiscString(ref->ref.mOwner, "Owner"); - text += MWGui::ToolTips::getMiscString(ref->base->mScript, "Script"); + text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); + text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); } - info.enchant = ref->base->mEnchant; + info.enchant = ref->mBase->mEnchant; info.text = text; @@ -215,7 +214,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mEnchant; + return ref->mBase->mEnchant; } boost::shared_ptr Clothing::use (const MWWorld::Ptr& ptr) const @@ -233,6 +232,6 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(&cell.clothes.insert(*ref), &cell); + return MWWorld::Ptr(&cell.mClothes.insert(*ref), &cell); } } diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 28c292dfe..76c1c40f1 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -65,18 +65,17 @@ namespace MWClass void Container::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { const std::string model = getModel(ptr); - if(!model.empty()) { - physics.insertObjectPhysics(ptr, model); - } + if(!model.empty()) + physics.addObject(ptr); } std::string Container::getModel(const MWWorld::Ptr &ptr) const { MWWorld::LiveCellRef *ref = ptr.get(); - assert(ref->base != NULL); + assert(ref->mBase != NULL); - const std::string &model = ref->base->mModel; + const std::string &model = ref->mBase->mModel; if (!model.empty()) { return "meshes\\" + model; } @@ -149,7 +148,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mName; + return ref->mBase->mName; } MWWorld::ContainerStore& Container::getContainerStore (const MWWorld::Ptr& ptr) @@ -165,7 +164,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mScript; + return ref->mBase->mScript; } void Container::registerSelf() @@ -180,7 +179,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return (ref->base->mName != ""); + return (ref->mBase->mName != ""); } MWGui::ToolTipInfo Container::getToolTipInfo (const MWWorld::Ptr& ptr) const @@ -189,17 +188,17 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->mName; + info.caption = ref->mBase->mName; std::string text; - if (ref->ref.mLockLevel > 0) - text += "\n#{sLockLevel}: " + MWGui::ToolTips::toString(ref->ref.mLockLevel); - if (ref->ref.mTrap != "") + if (ref->mRef.mLockLevel > 0) + text += "\n#{sLockLevel}: " + MWGui::ToolTips::toString(ref->mRef.mLockLevel); + if (ref->mRef.mTrap != "") text += "\n#{sTrapped}"; if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { - text += MWGui::ToolTips::getMiscString(ref->ref.mOwner, "Owner"); - text += MWGui::ToolTips::getMiscString(ref->base->mScript, "Script"); + text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); + text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); } info.text = text; @@ -212,7 +211,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mWeight; + return ref->mBase->mWeight; } float Container::getEncumbrance (const MWWorld::Ptr& ptr) const @@ -239,6 +238,6 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(&cell.containers.insert(*ref), &cell); + return MWWorld::Ptr(&cell.mContainers.insert(*ref), &cell); } } diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index e4ff3c95b..edf5dd25d 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -48,28 +48,28 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); // creature stats - data->mCreatureStats.getAttribute(0).set (ref->base->mData.mStrength); - data->mCreatureStats.getAttribute(1).set (ref->base->mData.mIntelligence); - data->mCreatureStats.getAttribute(2).set (ref->base->mData.mWillpower); - data->mCreatureStats.getAttribute(3).set (ref->base->mData.mAgility); - data->mCreatureStats.getAttribute(4).set (ref->base->mData.mSpeed); - data->mCreatureStats.getAttribute(5).set (ref->base->mData.mEndurance); - data->mCreatureStats.getAttribute(6).set (ref->base->mData.mPersonality); - data->mCreatureStats.getAttribute(7).set (ref->base->mData.mLuck); - data->mCreatureStats.setHealth (ref->base->mData.mHealth); - data->mCreatureStats.setMagicka (ref->base->mData.mMana); - data->mCreatureStats.setFatigue (ref->base->mData.mFatigue); + data->mCreatureStats.getAttribute(0).set (ref->mBase->mData.mStrength); + data->mCreatureStats.getAttribute(1).set (ref->mBase->mData.mIntelligence); + data->mCreatureStats.getAttribute(2).set (ref->mBase->mData.mWillpower); + data->mCreatureStats.getAttribute(3).set (ref->mBase->mData.mAgility); + data->mCreatureStats.getAttribute(4).set (ref->mBase->mData.mSpeed); + data->mCreatureStats.getAttribute(5).set (ref->mBase->mData.mEndurance); + data->mCreatureStats.getAttribute(6).set (ref->mBase->mData.mPersonality); + data->mCreatureStats.getAttribute(7).set (ref->mBase->mData.mLuck); + data->mCreatureStats.setHealth (ref->mBase->mData.mHealth); + data->mCreatureStats.setMagicka (ref->mBase->mData.mMana); + data->mCreatureStats.setFatigue (ref->mBase->mData.mFatigue); - data->mCreatureStats.setLevel(ref->base->mData.mLevel); + data->mCreatureStats.setLevel(ref->mBase->mData.mLevel); - data->mCreatureStats.setHello(ref->base->mAiData.mHello); - data->mCreatureStats.setFight(ref->base->mAiData.mFight); - data->mCreatureStats.setFlee(ref->base->mAiData.mFlee); - data->mCreatureStats.setAlarm(ref->base->mAiData.mAlarm); + data->mCreatureStats.setAiSetting (0, ref->mBase->mAiData.mHello); + data->mCreatureStats.setAiSetting (1, ref->mBase->mAiData.mFight); + data->mCreatureStats.setAiSetting (2, ref->mBase->mAiData.mFlee); + data->mCreatureStats.setAiSetting (3, ref->mBase->mAiData.mAlarm); // spells - for (std::vector::const_iterator iter (ref->base->mSpells.mList.begin()); - iter!=ref->base->mSpells.mList.end(); ++iter) + for (std::vector::const_iterator iter (ref->mBase->mSpells.mList.begin()); + iter!=ref->mBase->mSpells.mList.end(); ++iter) data->mCreatureStats.getSpells().add (*iter); // store @@ -82,7 +82,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mId; + return ref->mBase->mId; } void Creature::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const @@ -94,9 +94,8 @@ namespace MWClass void Creature::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { const std::string model = getModel(ptr); - if(!model.empty()){ - physics.insertActorPhysics(ptr, model); - } + if(!model.empty()) + physics.addActor(ptr); MWBase::Environment::get().getMechanicsManager()->addActor (ptr); } @@ -104,9 +103,9 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); - assert (ref->base != NULL); + assert (ref->mBase != NULL); - const std::string &model = ref->base->mModel; + const std::string &model = ref->mBase->mModel; if (!model.empty()) { return "meshes\\" + model; } @@ -118,7 +117,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mName; + return ref->mBase->mName; } MWMechanics::CreatureStats& Creature::getCreatureStats (const MWWorld::Ptr& ptr) const @@ -150,7 +149,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mScript; + return ref->mBase->mScript; } bool Creature::isEssential (const MWWorld::Ptr& ptr) const @@ -158,7 +157,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mFlags & ESM::Creature::Essential; + return ref->mBase->mFlags & ESM::Creature::Essential; } void Creature::registerSelf() @@ -181,11 +180,11 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->mName; + info.caption = ref->mBase->mName; std::string text; if (MWBase::Environment::get().getWindowManager()->getFullHelp()) - text += MWGui::ToolTips::getMiscString(ref->base->mScript, "Script"); + text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); info.text = text; return info; @@ -219,6 +218,6 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(&cell.creatures.insert(*ref), &cell); + return MWWorld::Ptr(&cell.mCreatures.insert(*ref), &cell); } } diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index f9a135f37..09a15a2cb 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -36,18 +36,17 @@ namespace MWClass void Door::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { const std::string model = getModel(ptr); - if(!model.empty()) { - physics.insertObjectPhysics(ptr, model); - } + if(!model.empty()) + physics.addObject(ptr); } std::string Door::getModel(const MWWorld::Ptr &ptr) const { MWWorld::LiveCellRef *ref = ptr.get(); - assert(ref->base != NULL); + assert(ref->mBase != NULL); - const std::string &model = ref->base->mModel; + const std::string &model = ref->mBase->mModel; if (!model.empty()) { return "meshes\\" + model; } @@ -59,10 +58,10 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - if (ref->ref.mTeleport && !ref->ref.mDestCell.empty()) // TODO doors that lead to exteriors - return ref->ref.mDestCell; + if (ref->mRef.mTeleport && !ref->mRef.mDestCell.empty()) // TODO doors that lead to exteriors + return ref->mRef.mDestCell; - return ref->base->mName; + return ref->mBase->mName; } boost::shared_ptr Door::activate (const MWWorld::Ptr& ptr, @@ -71,8 +70,8 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - const std::string &openSound = ref->base->mOpenSound; - //const std::string &closeSound = ref->base->closeSound; + const std::string &openSound = ref->mBase->mOpenSound; + //const std::string &closeSound = ref->mBase->closeSound; const std::string lockedSound = "LockedDoor"; const std::string trapActivationSound = "Disarm Trap Fail"; @@ -119,13 +118,13 @@ namespace MWClass return action; } - if (ref->ref.mTeleport) + if (ref->mRef.mTeleport) { // teleport door /// \todo remove this if clause once ActionTeleport can also support other actors if (MWBase::Environment::get().getWorld()->getPlayer().getPlayer()==actor) { - boost::shared_ptr action(new MWWorld::ActionTeleport (ref->ref.mDestCell, ref->ref.mDoorDest)); + boost::shared_ptr action(new MWWorld::ActionTeleport (ref->mRef.mDestCell, ref->mRef.mDoorDest)); action->setSound(openSound); @@ -177,7 +176,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mScript; + return ref->mBase->mScript; } void Door::registerSelf() @@ -192,7 +191,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return (ref->base->mName != ""); + return (ref->mBase->mName != ""); } MWGui::ToolTipInfo Door::getToolTipInfo (const MWWorld::Ptr& ptr) const @@ -201,57 +200,66 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->mName; + info.caption = ref->mBase->mName; std::string text; - const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); - - if (ref->ref.mTeleport) + if (ref->mRef.mTeleport) { - std::string dest; - if (ref->ref.mDestCell != "") - { - // door leads to an interior, use interior name as tooltip - dest = ref->ref.mDestCell; - } - else - { - // door leads to exterior, use cell name (if any), otherwise translated region name - int x,y; - MWBase::Environment::get().getWorld()->positionToIndex (ref->ref.mDoorDest.pos[0], ref->ref.mDoorDest.pos[1], x, y); - const ESM::Cell* cell = store.cells.findExt(x,y); - if (cell->mName != "") - dest = cell->mName; - else - { - const ESM::Region* region = store.regions.search(cell->mRegion); - dest = region->mName; - } - } text += "\n#{sTo}"; - text += "\n"+dest; + text += "\n" + getDestination(*ref); } - if (ref->ref.mLockLevel > 0) - text += "\n#{sLockLevel}: " + MWGui::ToolTips::toString(ref->ref.mLockLevel); - if (ref->ref.mTrap != "") + if (ref->mRef.mLockLevel > 0) + text += "\n#{sLockLevel}: " + MWGui::ToolTips::toString(ref->mRef.mLockLevel); + if (ref->mRef.mTrap != "") text += "\n#{sTrapped}"; if (MWBase::Environment::get().getWindowManager()->getFullHelp()) - text += MWGui::ToolTips::getMiscString(ref->base->mScript, "Script"); + text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); info.text = text; return info; } + std::string Door::getDestination (const MWWorld::LiveCellRef& door) + { + const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + + std::string dest; + if (door.mRef.mDestCell != "") + { + // door leads to an interior, use interior name as tooltip + dest = door.mRef.mDestCell; + } + else + { + // door leads to exterior, use cell name (if any), otherwise translated region name + int x,y; + MWBase::Environment::get().getWorld()->positionToIndex (door.mRef.mDoorDest.pos[0], door.mRef.mDoorDest.pos[1], x, y); + const ESM::Cell* cell = store.get().find(x,y); + if (cell->mName != "") + dest = cell->mName; + else + { + const ESM::Region* region = + store.get().find(cell->mRegion); + + //name as is, not a token + return region->mName; + } + } + + return "#{sCell=" + dest + "}"; + } + MWWorld::Ptr Door::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const { MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(&cell.doors.insert(*ref), &cell); + return MWWorld::Ptr(&cell.mDoors.insert(*ref), &cell); } } diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index b0f86f12d..05ba0248b 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -31,6 +31,9 @@ namespace MWClass virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. + static std::string getDestination (const MWWorld::LiveCellRef& door); + ///< @return destination cell name or token + virtual void lock (const MWWorld::Ptr& ptr, int lockLevel) const; ///< Lock object diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 45779287f..1be8d66b3 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -25,7 +25,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mId; + return ref->mBase->mId; } void Ingredient::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const @@ -41,18 +41,17 @@ namespace MWClass void Ingredient::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { const std::string model = getModel(ptr); - if(!model.empty()) { - physics.insertObjectPhysics(ptr, model); - } + if(!model.empty()) + physics.addObject(ptr); } std::string Ingredient::getModel(const MWWorld::Ptr &ptr) const { MWWorld::LiveCellRef *ref = ptr.get(); - assert(ref->base != NULL); + assert(ref->mBase != NULL); - const std::string &model = ref->base->mModel; + const std::string &model = ref->mBase->mModel; if (!model.empty()) { return "meshes\\" + model; } @@ -64,7 +63,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mName; + return ref->mBase->mName; } boost::shared_ptr Ingredient::activate (const MWWorld::Ptr& ptr, @@ -82,7 +81,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mScript; + return ref->mBase->mScript; } int Ingredient::getValue (const MWWorld::Ptr& ptr) const @@ -90,7 +89,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mData.mValue; + return ref->mBase->mData.mValue; } @@ -125,7 +124,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mIcon; + return ref->mBase->mIcon; } bool Ingredient::hasToolTip (const MWWorld::Ptr& ptr) const @@ -133,7 +132,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return (ref->base->mName != ""); + return (ref->mBase->mName != ""); } MWGui::ToolTipInfo Ingredient::getToolTipInfo (const MWWorld::Ptr& ptr) const @@ -142,28 +141,28 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); - info.icon = ref->base->mIcon; + info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); + info.icon = ref->mBase->mIcon; std::string text; - text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->base->mData.mWeight); - text += MWGui::ToolTips::getValueString(ref->base->mData.mValue, "#{sValue}"); + text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); + text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { - text += MWGui::ToolTips::getMiscString(ref->ref.mOwner, "Owner"); - text += MWGui::ToolTips::getMiscString(ref->base->mScript, "Script"); + text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); + text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); } MWGui::Widgets::SpellEffectList list; for (int i=0; i<4; ++i) { - if (ref->base->mData.mEffectID[i] < 0) + if (ref->mBase->mData.mEffectID[i] < 0) continue; MWGui::Widgets::SpellEffectParams params; - params.mEffectID = ref->base->mData.mEffectID[i]; - params.mAttribute = ref->base->mData.mAttributes[i]; - params.mSkill = ref->base->mData.mSkills[i]; + params.mEffectID = ref->mBase->mData.mEffectID[i]; + params.mAttribute = ref->mBase->mData.mAttributes[i]; + params.mSkill = ref->mBase->mData.mSkills[i]; list.push_back(params); } info.effects = list; @@ -179,6 +178,6 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(&cell.ingreds.insert(*ref), &cell); + return MWWorld::Ptr(&cell.mIngreds.insert(*ref), &cell); } } diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 71dfe683e..b94b0d395 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -28,9 +28,9 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); - assert (ref->base != NULL); + assert (ref->mBase != NULL); - const std::string &model = ref->base->mModel; + const std::string &model = ref->mBase->mModel; MWRender::Objects& objects = renderingInterface.getObjects(); objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false); @@ -38,11 +38,11 @@ namespace MWClass if (!model.empty()) objects.insertMesh(ptr, "meshes\\" + model); - const int color = ref->base->mData.mColor; + const int color = ref->mBase->mData.mColor; const float r = ((color >> 0) & 0xFF) / 255.0f; const float g = ((color >> 8) & 0xFF) / 255.0f; const float b = ((color >> 16) & 0xFF) / 255.0f; - const float radius = float (ref->base->mData.mRadius); + const float radius = float (ref->mBase->mData.mRadius); objects.insertLight (ptr, r, g, b, radius); } @@ -50,25 +50,24 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); - assert (ref->base != NULL); + assert (ref->mBase != NULL); - const std::string &model = ref->base->mModel; + const std::string &model = ref->mBase->mModel; - if(!model.empty()) { - physics.insertObjectPhysics(ptr, "meshes\\" + model); - } - if (!ref->base->mSound.empty()) { - MWBase::Environment::get().getSoundManager()->playSound3D(ptr, ref->base->mSound, 1.0, 1.0, MWBase::SoundManager::Play_Loop); - } + if(!model.empty()) + physics.addObject(ptr); + + if (!ref->mBase->mSound.empty()) + MWBase::Environment::get().getSoundManager()->playSound3D(ptr, ref->mBase->mSound, 1.0, 1.0, MWBase::SoundManager::Play_Loop); } std::string Light::getModel(const MWWorld::Ptr &ptr) const { MWWorld::LiveCellRef *ref = ptr.get(); - assert (ref->base != NULL); + assert (ref->mBase != NULL); - const std::string &model = ref->base->mModel; + const std::string &model = ref->mBase->mModel; if (!model.empty()) { return "meshes\\" + model; } @@ -80,10 +79,10 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - if (ref->base->mModel.empty()) + if (ref->mBase->mModel.empty()) return ""; - return ref->base->mName; + return ref->mBase->mName; } boost::shared_ptr Light::activate (const MWWorld::Ptr& ptr, @@ -92,7 +91,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - if (!(ref->base->mData.mFlags & ESM::Light::Carry)) + if (!(ref->mBase->mData.mFlags & ESM::Light::Carry)) return boost::shared_ptr (new MWWorld::FailedAction); boost::shared_ptr action(new MWWorld::ActionTake (ptr)); @@ -107,7 +106,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mScript; + return ref->mBase->mScript; } std::pair, bool> Light::getEquipmentSlots (const MWWorld::Ptr& ptr) const @@ -117,7 +116,7 @@ namespace MWClass std::vector slots; - if (ref->base->mData.mFlags & ESM::Light::Carry) + if (ref->mBase->mData.mFlags & ESM::Light::Carry) slots.push_back (int (MWWorld::InventoryStore::Slot_CarriedLeft)); return std::make_pair (slots, false); @@ -128,7 +127,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mData.mValue; + return ref->mBase->mData.mValue; } void Light::registerSelf() @@ -154,7 +153,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mIcon; + return ref->mBase->mIcon; } bool Light::hasToolTip (const MWWorld::Ptr& ptr) const @@ -162,7 +161,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return (ref->base->mName != ""); + return (ref->mBase->mName != ""); } MWGui::ToolTipInfo Light::getToolTipInfo (const MWWorld::Ptr& ptr) const @@ -171,17 +170,17 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); - info.icon = ref->base->mIcon; + info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); + info.icon = ref->mBase->mIcon; std::string text; - text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->base->mData.mWeight); - text += MWGui::ToolTips::getValueString(ref->base->mData.mValue, "#{sValue}"); + text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); + text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { - text += MWGui::ToolTips::getMiscString(ref->ref.mOwner, "Owner"); - text += MWGui::ToolTips::getMiscString(ref->base->mScript, "Script"); + text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); + text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); } info.text = text; @@ -204,6 +203,6 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(&cell.lights.insert(*ref), &cell); + return MWWorld::Ptr(&cell.mLights.insert(*ref), &cell); } } diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index a0ec65c98..a667fefb2 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -34,18 +34,17 @@ namespace MWClass void Lockpick::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { const std::string model = getModel(ptr); - if(!model.empty()) { - physics.insertObjectPhysics(ptr, model); - } + if(!model.empty()) + physics.addObject(ptr); } std::string Lockpick::getModel(const MWWorld::Ptr &ptr) const { MWWorld::LiveCellRef *ref = ptr.get(); - assert(ref->base != NULL); + assert(ref->mBase != NULL); - const std::string &model = ref->base->mModel; + const std::string &model = ref->mBase->mModel; if (!model.empty()) { return "meshes\\" + model; } @@ -57,7 +56,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mName; + return ref->mBase->mName; } boost::shared_ptr Lockpick::activate (const MWWorld::Ptr& ptr, @@ -75,7 +74,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mScript; + return ref->mBase->mScript; } std::pair, bool> Lockpick::getEquipmentSlots (const MWWorld::Ptr& ptr) const @@ -92,7 +91,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mData.mValue; + return ref->mBase->mData.mValue; } void Lockpick::registerSelf() @@ -117,7 +116,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mIcon; + return ref->mBase->mIcon; } bool Lockpick::hasToolTip (const MWWorld::Ptr& ptr) const @@ -125,7 +124,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return (ref->base->mName != ""); + return (ref->mBase->mName != ""); } MWGui::ToolTipInfo Lockpick::getToolTipInfo (const MWWorld::Ptr& ptr) const @@ -134,21 +133,21 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); - info.icon = ref->base->mIcon; + info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); + info.icon = ref->mBase->mIcon; std::string text; /// \todo store remaining uses somewhere - text += "\n#{sUses}: " + MWGui::ToolTips::toString(ref->base->mData.mUses); - text += "\n#{sQuality}: " + MWGui::ToolTips::toString(ref->base->mData.mQuality); - text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->base->mData.mWeight); - text += MWGui::ToolTips::getValueString(ref->base->mData.mValue, "#{sValue}"); + text += "\n#{sUses}: " + MWGui::ToolTips::toString(ref->mBase->mData.mUses); + text += "\n#{sQuality}: " + MWGui::ToolTips::toString(ref->mBase->mData.mQuality); + text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); + text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { - text += MWGui::ToolTips::getMiscString(ref->ref.mOwner, "Owner"); - text += MWGui::ToolTips::getMiscString(ref->base->mScript, "Script"); + text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); + text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); } info.text = text; @@ -171,6 +170,6 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(&cell.lockpicks.insert(*ref), &cell); + return MWWorld::Ptr(&cell.mLockpicks.insert(*ref), &cell); } } diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index edcfc7daa..94d40bcb7 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -37,18 +37,17 @@ namespace MWClass void Miscellaneous::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { const std::string model = getModel(ptr); - if(!model.empty()) { - physics.insertObjectPhysics(ptr, model); - } + if(!model.empty()) + physics.addObject(ptr); } std::string Miscellaneous::getModel(const MWWorld::Ptr &ptr) const { MWWorld::LiveCellRef *ref = ptr.get(); - assert(ref->base != NULL); + assert(ref->mBase != NULL); - const std::string &model = ref->base->mModel; + const std::string &model = ref->mBase->mModel; if (!model.empty()) { return "meshes\\" + model; } @@ -60,7 +59,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mName; + return ref->mBase->mName; } boost::shared_ptr Miscellaneous::activate (const MWWorld::Ptr& ptr, @@ -78,7 +77,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mScript; + return ref->mBase->mScript; } int Miscellaneous::getValue (const MWWorld::Ptr& ptr) const @@ -86,7 +85,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mData.mValue; + return ref->mBase->mData.mValue; } void Miscellaneous::registerSelf() @@ -101,7 +100,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - if (ref->base->mName == MWBase::Environment::get().getWorld()->getStore().gameSettings.find("sGold")->getString()) + if (ref->mBase->mName == MWBase::Environment::get().getWorld()->getStore().get().find("sGold")->getString()) { return std::string("Item Gold Up"); } @@ -113,7 +112,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - if (ref->base->mName == MWBase::Environment::get().getWorld()->getStore().gameSettings.find("sGold")->getString()) + if (ref->mBase->mName == MWBase::Environment::get().getWorld()->getStore().get().find("sGold")->getString()) { return std::string("Item Gold Down"); } @@ -125,7 +124,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mIcon; + return ref->mBase->mIcon; } bool Miscellaneous::hasToolTip (const MWWorld::Ptr& ptr) const @@ -133,7 +132,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return (ref->base->mName != ""); + return (ref->mBase->mName != ""); } MWGui::ToolTipInfo Miscellaneous::getToolTipInfo (const MWWorld::Ptr& ptr) const @@ -143,13 +142,13 @@ namespace MWClass MWGui::ToolTipInfo info; - const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); int count = ptr.getRefData().getCount(); - bool isGold = (ref->base->mName == store.gameSettings.find("sGold")->getString()); + bool isGold = (ref->mBase->mName == store.get().find("sGold")->getString()); if (isGold && count == 1) - count = ref->base->mData.mValue; + count = ref->mBase->mData.mValue; std::string countString; if (!isGold) @@ -157,12 +156,12 @@ namespace MWClass else // gold displays its count also if it's 1. countString = " (" + boost::lexical_cast(count) + ")"; - info.caption = ref->base->mName + countString; - info.icon = ref->base->mIcon; + info.caption = ref->mBase->mName + countString; + info.icon = ref->mBase->mIcon; - if (ref->ref.mSoul != "") + if (ref->mRef.mSoul != "") { - const ESM::Creature *creature = store.creatures.search(ref->ref.mSoul); + const ESM::Creature *creature = store.get().find(ref->mRef.mSoul); info.caption += " (" + creature->mName + ")"; } @@ -170,13 +169,13 @@ namespace MWClass if (!isGold) { - text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->base->mData.mWeight); - text += MWGui::ToolTips::getValueString(ref->base->mData.mValue, "#{sValue}"); + text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); + text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); } if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { - text += MWGui::ToolTips::getMiscString(ref->ref.mOwner, "Owner"); - text += MWGui::ToolTips::getMiscString(ref->base->mScript, "Script"); + text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); + text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); } info.text = text; @@ -189,10 +188,10 @@ namespace MWClass { MWWorld::Ptr newPtr; - const ESMS::ESMStore &store = + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - if (MWWorld::Class::get(ptr).getName(ptr) == store.gameSettings.find("sGold")->getString()) { + if (MWWorld::Class::get(ptr).getName(ptr) == store.get().find("sGold")->getString()) { int goldAmount = ptr.getRefData().getCount(); std::string base = "Gold_001"; @@ -210,11 +209,11 @@ namespace MWClass MWWorld::ManualRef newRef(store, base); MWWorld::LiveCellRef *ref = newRef.getPtr().get(); - newPtr = MWWorld::Ptr(&cell.miscItems.insert(*ref), &cell); + newPtr = MWWorld::Ptr(&cell.mMiscItems.insert(*ref), &cell); } else { MWWorld::LiveCellRef *ref = ptr.get(); - newPtr = MWWorld::Ptr(&cell.miscItems.insert(*ref), &cell); + newPtr = MWWorld::Ptr(&cell.mMiscItems.insert(*ref), &cell); } return newPtr; } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 2e21f8f63..83a002447 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -62,39 +62,41 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); // NPC stats - if (!ref->base->mFaction.empty()) + if (!ref->mBase->mFaction.empty()) { - std::string faction = ref->base->mFaction; + std::string faction = ref->mBase->mFaction; boost::algorithm::to_lower(faction); - if(ref->base->mNpdt52.mGold != -10) + if(ref->mBase->mNpdt52.mGold != -10) { - data->mNpcStats.getFactionRanks()[faction] = (int)ref->base->mNpdt52.mRank; + data->mNpcStats.getFactionRanks()[faction] = (int)ref->mBase->mNpdt52.mRank; } else { - data->mNpcStats.getFactionRanks()[faction] = (int)ref->base->mNpdt12.mRank; + data->mNpcStats.getFactionRanks()[faction] = (int)ref->mBase->mNpdt12.mRank; } } // creature stats - if(ref->base->mNpdt52.mGold != -10) + if(ref->mBase->mNpdt52.mGold != -10) { for (int i=0; i<27; ++i) - data->mNpcStats.getSkill (i).setBase (ref->base->mNpdt52.mSkills[i]); + data->mNpcStats.getSkill (i).setBase (ref->mBase->mNpdt52.mSkills[i]); - data->mCreatureStats.getAttribute(0).set (ref->base->mNpdt52.mStrength); - data->mCreatureStats.getAttribute(1).set (ref->base->mNpdt52.mIntelligence); - data->mCreatureStats.getAttribute(2).set (ref->base->mNpdt52.mWillpower); - data->mCreatureStats.getAttribute(3).set (ref->base->mNpdt52.mAgility); - data->mCreatureStats.getAttribute(4).set (ref->base->mNpdt52.mSpeed); - data->mCreatureStats.getAttribute(5).set (ref->base->mNpdt52.mEndurance); - data->mCreatureStats.getAttribute(6).set (ref->base->mNpdt52.mPersonality); - data->mCreatureStats.getAttribute(7).set (ref->base->mNpdt52.mLuck); - data->mCreatureStats.setHealth (ref->base->mNpdt52.mHealth); - data->mCreatureStats.setMagicka (ref->base->mNpdt52.mMana); - data->mCreatureStats.setFatigue (ref->base->mNpdt52.mFatigue); + data->mCreatureStats.getAttribute(0).set (ref->mBase->mNpdt52.mStrength); + data->mCreatureStats.getAttribute(1).set (ref->mBase->mNpdt52.mIntelligence); + data->mCreatureStats.getAttribute(2).set (ref->mBase->mNpdt52.mWillpower); + data->mCreatureStats.getAttribute(3).set (ref->mBase->mNpdt52.mAgility); + data->mCreatureStats.getAttribute(4).set (ref->mBase->mNpdt52.mSpeed); + data->mCreatureStats.getAttribute(5).set (ref->mBase->mNpdt52.mEndurance); + data->mCreatureStats.getAttribute(6).set (ref->mBase->mNpdt52.mPersonality); + data->mCreatureStats.getAttribute(7).set (ref->mBase->mNpdt52.mLuck); + data->mCreatureStats.setHealth (ref->mBase->mNpdt52.mHealth); + data->mCreatureStats.setMagicka (ref->mBase->mNpdt52.mMana); + data->mCreatureStats.setFatigue (ref->mBase->mNpdt52.mFatigue); - data->mCreatureStats.setLevel(ref->base->mNpdt52.mLevel); + data->mCreatureStats.setLevel(ref->mBase->mNpdt52.mLevel); + data->mNpcStats.setBaseDisposition(ref->mBase->mNpdt52.mDisposition); + data->mNpcStats.setReputation(ref->mBase->mNpdt52.mReputation); } else { @@ -108,14 +110,14 @@ namespace MWClass data->mCreatureStats.setLevel (1); } - data->mCreatureStats.setHello(ref->base->mAiData.mHello); - data->mCreatureStats.setFight(ref->base->mAiData.mFight); - data->mCreatureStats.setFlee(ref->base->mAiData.mFlee); - data->mCreatureStats.setAlarm(ref->base->mAiData.mAlarm); + data->mCreatureStats.setAiSetting (0, ref->mBase->mAiData.mHello); + data->mCreatureStats.setAiSetting (1, ref->mBase->mAiData.mFight); + data->mCreatureStats.setAiSetting (2, ref->mBase->mAiData.mFlee); + data->mCreatureStats.setAiSetting (3, ref->mBase->mAiData.mAlarm); // spells - for (std::vector::const_iterator iter (ref->base->mSpells.mList.begin()); - iter!=ref->base->mSpells.mList.end(); ++iter) + for (std::vector::const_iterator iter (ref->mBase->mSpells.mList.begin()); + iter!=ref->mBase->mSpells.mList.end(); ++iter) data->mCreatureStats.getSpells().add (*iter); // store @@ -128,7 +130,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mId; + return ref->mBase->mId; } void Npc::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const @@ -138,7 +140,7 @@ namespace MWClass void Npc::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { - physics.insertActorPhysics(ptr, getModel(ptr)); + physics.addActor(ptr); MWBase::Environment::get().getMechanicsManager()->addActor(ptr); } @@ -146,9 +148,9 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); - assert(ref->base != NULL); + assert(ref->mBase != NULL); - std::string headID = ref->base->mHead; + std::string headID = ref->mBase->mHead; int end = headID.find_last_of("head_") - 4; std::string bodyRaceID = headID.substr(0, end); @@ -170,7 +172,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mName; + return ref->mBase->mName; } MWMechanics::CreatureStats& Npc::getCreatureStats (const MWWorld::Ptr& ptr) const @@ -217,7 +219,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mScript; + return ref->mBase->mScript; } void Npc::setForceStance (const MWWorld::Ptr& ptr, Stance stance, bool force) const @@ -325,7 +327,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mFlags & ESM::NPC::Essential; + return ref->mBase->mFlags & ESM::NPC::Essential; } void Npc::registerSelf() @@ -347,11 +349,11 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->mName; + info.caption = ref->mBase->mName; std::string text; if (MWBase::Environment::get().getWindowManager()->getFullHelp()) - text += MWGui::ToolTips::getMiscString(ref->base->mScript, "Script"); + text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); info.text = text; return info; @@ -395,8 +397,10 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - const ESM::Class *class_ = MWBase::Environment::get().getWorld()->getStore().classes.find ( - ref->base->mClass); + const ESM::Class *class_ = + MWBase::Environment::get().getWorld()->getStore().get().find ( + ref->mBase->mClass + ); stats.useSkill (skill, *class_, usageType); } @@ -413,6 +417,6 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(&cell.npcs.insert(*ref), &cell); + return MWWorld::Ptr(&cell.mNpcs.insert(*ref), &cell); } } diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index f641cc719..09d152de7 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -34,18 +34,17 @@ namespace MWClass void Potion::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { const std::string model = getModel(ptr); - if(!model.empty()) { - physics.insertObjectPhysics(ptr, model); - } + if(!model.empty()) + physics.addObject(ptr); } std::string Potion::getModel(const MWWorld::Ptr &ptr) const { MWWorld::LiveCellRef *ref = ptr.get(); - assert(ref->base != NULL); + assert(ref->mBase != NULL); - const std::string &model = ref->base->mModel; + const std::string &model = ref->mBase->mModel; if (!model.empty()) { return "meshes\\" + model; } @@ -57,7 +56,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mName; + return ref->mBase->mName; } boost::shared_ptr Potion::activate (const MWWorld::Ptr& ptr, @@ -76,7 +75,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mScript; + return ref->mBase->mScript; } int Potion::getValue (const MWWorld::Ptr& ptr) const @@ -84,7 +83,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mData.mValue; + return ref->mBase->mData.mValue; } void Potion::registerSelf() @@ -109,7 +108,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mIcon; + return ref->mBase->mIcon; } bool Potion::hasToolTip (const MWWorld::Ptr& ptr) const @@ -117,7 +116,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return (ref->base->mName != ""); + return (ref->mBase->mName != ""); } MWGui::ToolTipInfo Potion::getToolTipInfo (const MWWorld::Ptr& ptr) const @@ -126,20 +125,20 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); - info.icon = ref->base->mIcon; + info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); + info.icon = ref->mBase->mIcon; std::string text; - text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->base->mData.mWeight); - text += MWGui::ToolTips::getValueString(ref->base->mData.mValue, "#{sValue}"); + text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); + text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); - info.effects = MWGui::Widgets::MWEffectList::effectListFromESM(&ref->base->mEffects); + info.effects = MWGui::Widgets::MWEffectList::effectListFromESM(&ref->mBase->mEffects); info.isPotion = true; if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { - text += MWGui::ToolTips::getMiscString(ref->ref.mOwner, "Owner"); - text += MWGui::ToolTips::getMiscString(ref->base->mScript, "Script"); + text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); + text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); } info.text = text; @@ -157,7 +156,7 @@ namespace MWClass MWWorld::Ptr actor = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); boost::shared_ptr action ( - new MWWorld::ActionApply (actor, ref->base->mId)); + new MWWorld::ActionApply (actor, ref->mBase->mId)); action->setSound ("Drink"); @@ -170,6 +169,6 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(&cell.potions.insert(*ref), &cell); + return MWWorld::Ptr(&cell.mPotions.insert(*ref), &cell); } } diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 39472f2ec..0d8653aa8 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -34,18 +34,17 @@ namespace MWClass void Probe::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { const std::string model = getModel(ptr); - if(!model.empty()) { - physics.insertObjectPhysics(ptr, model); - } + if(!model.empty()) + physics.addObject(ptr); } std::string Probe::getModel(const MWWorld::Ptr &ptr) const { MWWorld::LiveCellRef *ref = ptr.get(); - assert(ref->base != NULL); + assert(ref->mBase != NULL); - const std::string &model = ref->base->mModel; + const std::string &model = ref->mBase->mModel; if (!model.empty()) { return "meshes\\" + model; } @@ -57,7 +56,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mName; + return ref->mBase->mName; } boost::shared_ptr Probe::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const @@ -74,7 +73,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mScript; + return ref->mBase->mScript; } std::pair, bool> Probe::getEquipmentSlots (const MWWorld::Ptr& ptr) const @@ -91,7 +90,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mData.mValue; + return ref->mBase->mData.mValue; } void Probe::registerSelf() @@ -116,7 +115,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mIcon; + return ref->mBase->mIcon; } bool Probe::hasToolTip (const MWWorld::Ptr& ptr) const @@ -124,7 +123,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return (ref->base->mName != ""); + return (ref->mBase->mName != ""); } MWGui::ToolTipInfo Probe::getToolTipInfo (const MWWorld::Ptr& ptr) const @@ -133,21 +132,21 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); - info.icon = ref->base->mIcon; + info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); + info.icon = ref->mBase->mIcon; std::string text; /// \todo store remaining uses somewhere - text += "\n#{sUses}: " + MWGui::ToolTips::toString(ref->base->mData.mUses); - text += "\n#{sQuality}: " + MWGui::ToolTips::toString(ref->base->mData.mQuality); - text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->base->mData.mWeight); - text += MWGui::ToolTips::getValueString(ref->base->mData.mValue, "#{sValue}"); + text += "\n#{sUses}: " + MWGui::ToolTips::toString(ref->mBase->mData.mUses); + text += "\n#{sQuality}: " + MWGui::ToolTips::toString(ref->mBase->mData.mQuality); + text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); + text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { - text += MWGui::ToolTips::getMiscString(ref->ref.mOwner, "Owner"); - text += MWGui::ToolTips::getMiscString(ref->base->mScript, "Script"); + text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); + text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); } info.text = text; @@ -170,6 +169,6 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(&cell.probes.insert(*ref), &cell); + return MWWorld::Ptr(&cell.mProbes.insert(*ref), &cell); } } diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 7ccb34913..edb28d16c 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -32,18 +32,17 @@ namespace MWClass void Repair::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { const std::string model = getModel(ptr); - if(!model.empty()) { - physics.insertObjectPhysics(ptr, model); - } + if(!model.empty()) + physics.addObject(ptr); } std::string Repair::getModel(const MWWorld::Ptr &ptr) const { MWWorld::LiveCellRef *ref = ptr.get(); - assert(ref->base != NULL); + assert(ref->mBase != NULL); - const std::string &model = ref->base->mModel; + const std::string &model = ref->mBase->mModel; if (!model.empty()) { return "meshes\\" + model; } @@ -55,7 +54,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mName; + return ref->mBase->mName; } boost::shared_ptr Repair::activate (const MWWorld::Ptr& ptr, @@ -73,7 +72,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mScript; + return ref->mBase->mScript; } int Repair::getValue (const MWWorld::Ptr& ptr) const @@ -81,7 +80,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mData.mValue; + return ref->mBase->mData.mValue; } void Repair::registerSelf() @@ -106,7 +105,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mIcon; + return ref->mBase->mIcon; } bool Repair::hasToolTip (const MWWorld::Ptr& ptr) const @@ -114,7 +113,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return (ref->base->mName != ""); + return (ref->mBase->mName != ""); } MWGui::ToolTipInfo Repair::getToolTipInfo (const MWWorld::Ptr& ptr) const @@ -123,21 +122,21 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); - info.icon = ref->base->mIcon; + info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); + info.icon = ref->mBase->mIcon; std::string text; /// \todo store remaining uses somewhere - text += "\n#{sUses}: " + MWGui::ToolTips::toString(ref->base->mData.mUses); - text += "\n#{sQuality}: " + MWGui::ToolTips::toString(ref->base->mData.mQuality); - text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->base->mData.mWeight); - text += MWGui::ToolTips::getValueString(ref->base->mData.mValue, "#{sValue}"); + text += "\n#{sUses}: " + MWGui::ToolTips::toString(ref->mBase->mData.mUses); + text += "\n#{sQuality}: " + MWGui::ToolTips::toString(ref->mBase->mData.mQuality); + text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); + text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { - text += MWGui::ToolTips::getMiscString(ref->ref.mOwner, "Owner"); - text += MWGui::ToolTips::getMiscString(ref->base->mScript, "Script"); + text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); + text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); } info.text = text; @@ -151,6 +150,6 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(&cell.repairs.insert(*ref), &cell); + return MWWorld::Ptr(&cell.mRepairs.insert(*ref), &cell); } } diff --git a/apps/openmw/mwclass/static.cpp b/apps/openmw/mwclass/static.cpp index 07ab54256..026eada7b 100644 --- a/apps/openmw/mwclass/static.cpp +++ b/apps/openmw/mwclass/static.cpp @@ -24,18 +24,17 @@ namespace MWClass void Static::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { const std::string model = getModel(ptr); - if(!model.empty()) { - physics.insertObjectPhysics(ptr, model); - } + if(!model.empty()) + physics.addObject(ptr); } std::string Static::getModel(const MWWorld::Ptr &ptr) const { MWWorld::LiveCellRef *ref = ptr.get(); - assert(ref->base != NULL); + assert(ref->mBase != NULL); - const std::string &model = ref->base->mModel; + const std::string &model = ref->mBase->mModel; if (!model.empty()) { return "meshes\\" + model; } @@ -60,6 +59,6 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(&cell.statics.insert(*ref), &cell); + return MWWorld::Ptr(&cell.mStatics.insert(*ref), &cell); } } diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index fee0dfdf1..c8fe0d276 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -34,18 +34,17 @@ namespace MWClass void Weapon::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { const std::string model = getModel(ptr); - if(!model.empty()) { - physics.insertObjectPhysics(ptr, model); - } + if(!model.empty()) + physics.addObject(ptr); } std::string Weapon::getModel(const MWWorld::Ptr &ptr) const { MWWorld::LiveCellRef *ref = ptr.get(); - assert(ref->base != NULL); + assert(ref->mBase != NULL); - const std::string &model = ref->base->mModel; + const std::string &model = ref->mBase->mModel; if (!model.empty()) { return "meshes\\" + model; } @@ -57,7 +56,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mName; + return ref->mBase->mName; } boost::shared_ptr Weapon::activate (const MWWorld::Ptr& ptr, @@ -80,7 +79,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mData.mHealth; + return ref->mBase->mData.mHealth; } std::string Weapon::getScript (const MWWorld::Ptr& ptr) const @@ -88,7 +87,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mScript; + return ref->mBase->mScript; } std::pair, bool> Weapon::getEquipmentSlots (const MWWorld::Ptr& ptr) const @@ -99,12 +98,12 @@ namespace MWClass std::vector slots; bool stack = false; - if (ref->base->mData.mType==ESM::Weapon::Arrow || ref->base->mData.mType==ESM::Weapon::Bolt) + if (ref->mBase->mData.mType==ESM::Weapon::Arrow || ref->mBase->mData.mType==ESM::Weapon::Bolt) { slots.push_back (int (MWWorld::InventoryStore::Slot_Ammunition)); stack = true; } - else if (ref->base->mData.mType==ESM::Weapon::MarksmanThrown) + else if (ref->mBase->mData.mType==ESM::Weapon::MarksmanThrown) { slots.push_back (int (MWWorld::InventoryStore::Slot_CarriedRight)); stack = true; @@ -139,7 +138,7 @@ namespace MWClass }; for (int i=0; ibase->mData.mType) + if (sMapping[i][0]==ref->mBase->mData.mType) return sMapping[i][1]; return -1; @@ -150,7 +149,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mData.mValue; + return ref->mBase->mData.mValue; } void Weapon::registerSelf() @@ -165,7 +164,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - int type = ref->base->mData.mType; + int type = ref->mBase->mData.mType; // Ammo if (type == 12 || type == 13) { @@ -211,7 +210,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - int type = ref->base->mData.mType; + int type = ref->mBase->mData.mType; // Ammo if (type == 12 || type == 13) { @@ -257,7 +256,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mIcon; + return ref->mBase->mIcon; } bool Weapon::hasToolTip (const MWWorld::Ptr& ptr) const @@ -265,7 +264,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return (ref->base->mName != ""); + return (ref->mBase->mName != ""); } MWGui::ToolTipInfo Weapon::getToolTipInfo (const MWWorld::Ptr& ptr) const @@ -274,15 +273,15 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); - info.icon = ref->base->mIcon; + info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); + info.icon = ref->mBase->mIcon; - const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); std::string text; // weapon type & damage. arrows / bolts don't have his info. - if (ref->base->mData.mType < 12) + if (ref->mBase->mData.mType < 12) { text += "\n#{sType} "; @@ -300,49 +299,49 @@ namespace MWClass mapping[ESM::Weapon::MarksmanCrossbow] = std::make_pair("sSkillMarksman", ""); mapping[ESM::Weapon::MarksmanThrown] = std::make_pair("sSkillMarksman", ""); - std::string type = mapping[ref->base->mData.mType].first; - std::string oneOrTwoHanded = mapping[ref->base->mData.mType].second; + std::string type = mapping[ref->mBase->mData.mType].first; + std::string oneOrTwoHanded = mapping[ref->mBase->mData.mType].second; - text += store.gameSettings.find(type)->getString() + - ((oneOrTwoHanded != "") ? ", " + store.gameSettings.find(oneOrTwoHanded)->getString() : ""); + text += store.get().find(type)->getString() + + ((oneOrTwoHanded != "") ? ", " + store.get().find(oneOrTwoHanded)->getString() : ""); // weapon damage - if (ref->base->mData.mType >= 9) + if (ref->mBase->mData.mType >= 9) { // marksman text += "\n#{sAttack}: " - + MWGui::ToolTips::toString(static_cast(ref->base->mData.mChop[0])) - + " - " + MWGui::ToolTips::toString(static_cast(ref->base->mData.mChop[1])); + + MWGui::ToolTips::toString(static_cast(ref->mBase->mData.mChop[0])) + + " - " + MWGui::ToolTips::toString(static_cast(ref->mBase->mData.mChop[1])); } else { // Chop text += "\n#{sChop}: " - + MWGui::ToolTips::toString(static_cast(ref->base->mData.mChop[0])) - + " - " + MWGui::ToolTips::toString(static_cast(ref->base->mData.mChop[1])); + + MWGui::ToolTips::toString(static_cast(ref->mBase->mData.mChop[0])) + + " - " + MWGui::ToolTips::toString(static_cast(ref->mBase->mData.mChop[1])); // Slash text += "\n#{sSlash}: " - + MWGui::ToolTips::toString(static_cast(ref->base->mData.mSlash[0])) - + " - " + MWGui::ToolTips::toString(static_cast(ref->base->mData.mSlash[1])); + + MWGui::ToolTips::toString(static_cast(ref->mBase->mData.mSlash[0])) + + " - " + MWGui::ToolTips::toString(static_cast(ref->mBase->mData.mSlash[1])); // Thrust text += "\n#{sThrust}: " - + MWGui::ToolTips::toString(static_cast(ref->base->mData.mThrust[0])) - + " - " + MWGui::ToolTips::toString(static_cast(ref->base->mData.mThrust[1])); + + MWGui::ToolTips::toString(static_cast(ref->mBase->mData.mThrust[0])) + + " - " + MWGui::ToolTips::toString(static_cast(ref->mBase->mData.mThrust[1])); } } /// \todo store the current weapon health somewhere - if (ref->base->mData.mType < 11) // thrown weapons and arrows/bolts don't have health, only quantity - text += "\n#{sCondition}: " + MWGui::ToolTips::toString(ref->base->mData.mHealth); + if (ref->mBase->mData.mType < 11) // thrown weapons and arrows/bolts don't have health, only quantity + text += "\n#{sCondition}: " + MWGui::ToolTips::toString(ref->mBase->mData.mHealth); - text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->base->mData.mWeight); - text += MWGui::ToolTips::getValueString(ref->base->mData.mValue, "#{sValue}"); + text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); + text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); - info.enchant = ref->base->mEnchant; + info.enchant = ref->mBase->mEnchant; if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { - text += MWGui::ToolTips::getMiscString(ref->ref.mOwner, "Owner"); - text += MWGui::ToolTips::getMiscString(ref->base->mScript, "Script"); + text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); + text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); } info.text = text; @@ -355,7 +354,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->base->mEnchant; + return ref->mBase->mEnchant; } boost::shared_ptr Weapon::use (const MWWorld::Ptr& ptr) const @@ -373,6 +372,6 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return MWWorld::Ptr(&cell.weapons.insert(*ref), &cell); + return MWWorld::Ptr(&cell.mWeapons.insert(*ref), &cell); } } diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 2c30ebf06..743db9a43 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -6,23 +6,7 @@ #include #include - -#include - -#include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" -#include "../mwbase/scriptmanager.hpp" -#include "../mwbase/journal.hpp" -#include "../mwbase/windowmanager.hpp" - -#include "../mwworld/class.hpp" -#include "../mwworld/refdata.hpp" -#include "../mwworld/player.hpp" -#include "../mwworld/containerstore.hpp" - -#include "../mwgui/dialogue.hpp" - -#include +#include #include #include @@ -30,18 +14,36 @@ #include #include #include + #include +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/scriptmanager.hpp" +#include "../mwbase/windowmanager.hpp" +#include "../mwbase/mechanicsmanager.hpp" + +#include "../mwworld/class.hpp" +#include "../mwworld/containerstore.hpp" +#include "../mwworld/esmstore.hpp" +#include "../mwworld/player.hpp" + +#include "../mwgui/dialogue.hpp" #include "../mwscript/compilercontext.hpp" #include "../mwscript/interpretercontext.hpp" #include "../mwscript/extensions.hpp" -#include "../mwclass/npc.hpp" +#include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/npcstats.hpp" +#include "filter.hpp" + namespace { +<<<<<<< HEAD template bool selectCompare (char comp, T1 value1, T2 value2) { @@ -122,6 +124,8 @@ namespace return false; } +======= +>>>>>>> 92623921add0d6e16a34973dcf6f2ee1f52dbbe7 //helper function std::string::size_type find_str_ci(const std::string& str, const std::string& substr,size_t pos) { @@ -131,6 +135,7 @@ namespace namespace MWDialogue { +<<<<<<< HEAD bool DialogueManager::functionFilter(const MWWorld::Ptr& actor, const ESM::DialInfo& info,bool choice) @@ -558,18 +563,31 @@ namespace MWDialogue } DialogueManager::DialogueManager (const Compiler::Extensions& extensions) : +======= + DialogueManager::DialogueManager (const Compiler::Extensions& extensions, bool scriptVerbose) : +>>>>>>> 92623921add0d6e16a34973dcf6f2ee1f52dbbe7 mCompilerContext (MWScript::CompilerContext::Type_Dialgoue), mErrorStream(std::cout.rdbuf()),mErrorHandler(mErrorStream) + , mTemporaryDispositionChange(0.f) + , mPermanentDispositionChange(0.f), mScriptVerbose (scriptVerbose) { mChoice = -1; mIsInChoice = false; mCompilerContext.setExtensions (&extensions); mDialogueMap.clear(); mActorKnownTopics.clear(); - ESMS::RecListCaseT::MapType dialogueList = MWBase::Environment::get().getWorld()->getStore().dialogs.list; - for(ESMS::RecListCaseT::MapType::iterator it = dialogueList.begin(); it!=dialogueList.end();it++) + + const MWWorld::Store &dialogs = + MWBase::Environment::get().getWorld()->getStore().get(); + + MWWorld::Store::iterator it = dialogs.begin(); + for (; it != dialogs.end(); ++it) { +<<<<<<< HEAD mDialogueMap[Misc::toLower(it->first)] = it->second; +======= + mDialogueMap[toLower(it->mId)] = *it; +>>>>>>> 92623921add0d6e16a34973dcf6f2ee1f52dbbe7 } } @@ -578,7 +596,7 @@ namespace MWDialogue mKnownTopics[Misc::toLower(topic)] = true; } - void DialogueManager::parseText (std::string text) + void DialogueManager::parseText (const std::string& text) { std::list::iterator it; for(it = mActorKnownTopics.begin();it != mActorKnownTopics.end();++it) @@ -586,14 +604,7 @@ namespace MWDialogue size_t pos = find_str_ci(text,*it,0); if(pos !=std::string::npos) { - if(pos==0) - { - mKnownTopics[*it] = true; - } - else if(text.substr(pos -1,1) == " ") - { - mKnownTopics[*it] = true; - } + mKnownTopics[*it] = true; } } updateTopics(); @@ -606,6 +617,10 @@ namespace MWDialogue mActor = actor; + MWMechanics::CreatureStats& creatureStats = MWWorld::Class::get (actor).getCreatureStats (actor); + mTalkedTo = creatureStats.hasTalkedToPlayer(); + creatureStats.talkedToPlayer(); + mActorKnownTopics.clear(); //initialise the GUI @@ -617,34 +632,30 @@ namespace MWDialogue updateTopics(); //greeting - bool greetingFound = false; - //ESMS::RecListT::MapType dialogueList = MWBase::Environment::get().getWorld()->getStore().dialogs.list; - ESMS::RecListCaseT::MapType dialogueList = MWBase::Environment::get().getWorld()->getStore().dialogs.list; - for(ESMS::RecListCaseT::MapType::iterator it = dialogueList.begin(); it!=dialogueList.end();it++) - { - ESM::Dialogue ndialogue = it->second; - if(ndialogue.mType == ESM::Dialogue::Greeting) - { - if (greetingFound) break; - for (std::vector::const_iterator iter (it->second.mInfo.begin()); - iter!=it->second.mInfo.end(); ++iter) - { - if (isMatching (actor, *iter) && functionFilter(mActor,*iter,true)) - { - if (!iter->mSound.empty()) - { - // TODO play sound - } + const MWWorld::Store &dialogs = + MWBase::Environment::get().getWorld()->getStore().get(); - std::string text = iter->mResponse; - parseText(text); - win->addText(iter->mResponse); - executeScript(iter->mResultScript); - greetingFound = true; - mLastTopic = it->first; - mLastDialogue = *iter; - break; + Filter filter (actor, mChoice, mTalkedTo); + + for (MWWorld::Store::iterator it = dialogs.begin(); it != dialogs.end(); ++it) + { + if(it->mType == ESM::Dialogue::Greeting) + { + if (const ESM::DialInfo *info = filter.search (*it)) + { + if (!info->mSound.empty()) + { + // TODO play sound } + + parseText (info->mResponse); + + MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); + win->addText (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); + executeScript (info->mResultScript); + mLastTopic = it->mId; + mLastDialogue = *info; + break; } } } @@ -652,6 +663,8 @@ namespace MWDialogue bool DialogueManager::compile (const std::string& cmd,std::vector& code) { + bool success = true; + try { mErrorHandler.reset(); @@ -673,26 +686,36 @@ namespace MWDialogue Compiler::ScriptParser parser(mErrorHandler,mCompilerContext, locals, false); scanner.scan (parser); - if(mErrorHandler.isGood()) - { - parser.getCode(code); - return true; - } - return false; + + if (!mErrorHandler.isGood()) + success = false; + + if (success) + parser.getCode (code); } catch (const Compiler::SourceException& /* error */) { // error has already been reported via error handler + success = false; } catch (const std::exception& error) { - printError (std::string ("An exception has been thrown: ") + error.what()); + std::cerr << std::string ("Dialogue error: An exception has been thrown: ") + error.what() << std::endl; + success = false; } - return false; + if (!success && mScriptVerbose) + { + std::cerr + << "compiling failed (dialogue script)" << std::endl + << cmd + << std::endl << std::endl; + } + + return success; } - void DialogueManager::executeScript(std::string script) + void DialogueManager::executeScript (const std::string& script) { std::vector code; if(compile(script,code)) @@ -706,29 +729,74 @@ namespace MWDialogue } catch (const std::exception& error) { - printError (std::string ("An exception has been thrown: ") + error.what()); + std::cerr << std::string ("Dialogue error: An exception has been thrown: ") + error.what(); } } } + void DialogueManager::executeTopic (const std::string& topic) + { + Filter filter (mActor, mChoice, mTalkedTo); + + const MWWorld::Store &dialogues = + MWBase::Environment::get().getWorld()->getStore().get(); + + const ESM::Dialogue& dialogue = *dialogues.find (topic); + + if (const ESM::DialInfo *info = filter.search (dialogue)) + { + parseText (info->mResponse); + + MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); + + if (dialogue.mType==ESM::Dialogue::Persuasion) + { + std::string modifiedTopic = "s" + topic; + + modifiedTopic.erase (std::remove (modifiedTopic.begin(), modifiedTopic.end(), ' '), modifiedTopic.end()); + + const MWWorld::Store& gmsts = + MWBase::Environment::get().getWorld()->getStore().get(); + + win->addTitle (gmsts.find (modifiedTopic)->getString()); + } + else + win->addTitle (topic); + + MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); + win->addText (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); + + executeScript (info->mResultScript); + + mLastTopic = topic; + mLastDialogue = *info; + } + } + void DialogueManager::updateTopics() { std::list keywordList; int choice = mChoice; mChoice = -1; mActorKnownTopics.clear(); - MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); - ESMS::RecListCaseT::MapType dialogueList = MWBase::Environment::get().getWorld()->getStore().dialogs.list; - for(ESMS::RecListCaseT::MapType::iterator it = dialogueList.begin(); it!=dialogueList.end();it++) + + const MWWorld::Store &dialogs = + MWBase::Environment::get().getWorld()->getStore().get(); + + Filter filter (mActor, mChoice, mTalkedTo); + + for (MWWorld::Store::iterator iter = dialogs.begin(); iter != dialogs.end(); ++iter) { - ESM::Dialogue ndialogue = it->second; - if(ndialogue.mType == ESM::Dialogue::Topic) + if (iter->mType == ESM::Dialogue::Topic) { - for (std::vector::const_iterator iter (it->second.mInfo.begin()); - iter!=it->second.mInfo.end(); ++iter) + if (filter.search (*iter)) { - if (isMatching (mActor, *iter) && functionFilter(mActor,*iter,true)) + mActorKnownTopics.push_back (toLower (iter->mId)); + + //does the player know the topic? + if (mKnownTopics.find (toLower (iter->mId)) != mKnownTopics.end()) { +<<<<<<< HEAD mActorKnownTopics.push_back(Misc::toLower(it->first)); //does the player know the topic? if(mKnownTopics.find(Misc::toLower(it->first)) != mKnownTopics.end()) @@ -736,6 +804,9 @@ namespace MWDialogue keywordList.push_back(it->first); break; } +======= + keywordList.push_back (iter->mId); +>>>>>>> 92623921add0d6e16a34973dcf6f2ee1f52dbbe7 } } } @@ -746,14 +817,14 @@ namespace MWDialogue if (mActor.getTypeName() == typeid(ESM::NPC).name()) { MWWorld::LiveCellRef* ref = mActor.get(); - if (ref->base->mHasAI) - services = ref->base->mAiData.mServices; + if (ref->mBase->mHasAI) + services = ref->mBase->mAiData.mServices; } else if (mActor.getTypeName() == typeid(ESM::Creature).name()) { MWWorld::LiveCellRef* ref = mActor.get(); - if (ref->base->mHasAI) - services = ref->base->mAiData.mServices; + if (ref->mBase->mHasAI) + services = ref->mBase->mAiData.mServices; } int windowServices = 0; @@ -771,7 +842,7 @@ namespace MWDialogue || services & ESM::NPC::Misc) windowServices |= MWGui::DialogueWindow::Service_Trade; - if( !mActor.get()->base->mTransport.empty()) + if(mActor.getTypeName() == typeid(ESM::NPC).name() && !mActor.get()->mBase->mTransport.empty()) windowServices |= MWGui::DialogueWindow::Service_Travel; if (services & ESM::NPC::Spells) @@ -786,6 +857,8 @@ namespace MWDialogue if (services & ESM::NPC::Enchanting) windowServices |= MWGui::DialogueWindow::Service_Enchant; + MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); + win->setServices (windowServices); // sort again, because the previous sort was case-sensitive @@ -802,29 +875,9 @@ namespace MWDialogue if(mDialogueMap.find(keyword) != mDialogueMap.end()) { ESM::Dialogue ndialogue = mDialogueMap[keyword]; - if(ndialogue.mType == ESM::Dialogue::Topic) + if (mDialogueMap[keyword].mType == ESM::Dialogue::Topic) { - for (std::vector::const_iterator iter = ndialogue.mInfo.begin(); - iter!=ndialogue.mInfo.end(); ++iter) - { - if (isMatching (mActor, *iter) && functionFilter(mActor,*iter,true)) - { - std::string text = iter->mResponse; - std::string script = iter->mResultScript; - - parseText(text); - - MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); - win->addTitle(keyword); - win->addText(iter->mResponse); - - executeScript(script); - - mLastTopic = keyword; - mLastDialogue = *iter; - break; - } - } + executeTopic (keyword); } } } @@ -835,45 +888,51 @@ namespace MWDialogue void DialogueManager::goodbyeSelected() { MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Dialogue); + + // Apply disposition change to NPC's base disposition + if (mActor.getTypeName() == typeid(ESM::NPC).name()) + { + MWMechanics::NpcStats& npcStats = MWWorld::Class::get(mActor).getNpcStats(mActor); + npcStats.setBaseDisposition(npcStats.getBaseDisposition() + mPermanentDispositionChange); + } + mPermanentDispositionChange = 0; + mTemporaryDispositionChange = 0; } void DialogueManager::questionAnswered (const std::string& answer) { - if(mChoiceMap.find(answer) != mChoiceMap.end()) + if (mChoiceMap.find(answer) != mChoiceMap.end()) { mChoice = mChoiceMap[answer]; - std::vector::const_iterator iter; - if(mDialogueMap.find(mLastTopic) != mDialogueMap.end()) + if (mDialogueMap.find(mLastTopic) != mDialogueMap.end()) { - ESM::Dialogue ndialogue = mDialogueMap[mLastTopic]; - if(ndialogue.mType == ESM::Dialogue::Topic) + if (mDialogueMap[mLastTopic].mType == ESM::Dialogue::Topic) { - for (std::vector::const_iterator iter = ndialogue.mInfo.begin(); - iter!=ndialogue.mInfo.end(); ++iter) + Filter filter (mActor, mChoice, mTalkedTo); + + if (const ESM::DialInfo *info = filter.search (mDialogueMap[mLastTopic])) { - if (isMatching (mActor, *iter) && functionFilter(mActor,*iter,true)) - { - mChoiceMap.clear(); - mChoice = -1; - mIsInChoice = false; - MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); - std::string text = iter->mResponse; - parseText(text); - win->addText(text); - executeScript(iter->mResultScript); - mLastTopic = mLastTopic; - mLastDialogue = *iter; - break; - } + mChoiceMap.clear(); + mChoice = -1; + mIsInChoice = false; + std::string text = info->mResponse; + parseText (text); + + MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); + MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addText (Interpreter::fixDefinesDialog(text, interpreterContext)); + executeScript (info->mResultScript); + mLastTopic = mLastTopic; + mLastDialogue = *info; } } } + updateTopics(); } } - void DialogueManager::printError (std::string error) + void DialogueManager::printError (const std::string& error) { MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); win->addText(error); @@ -887,22 +946,9 @@ namespace MWDialogue mIsInChoice = true; } - std::string DialogueManager::getFaction() const + MWWorld::Ptr DialogueManager::getActor() const { - if (mActor.getTypeName() != typeid(ESM::NPC).name()) - return ""; - - std::string factionID(""); - MWMechanics::NpcStats stats = MWWorld::Class::get(mActor).getNpcStats(mActor); - if(stats.getFactionRanks().empty()) - { - std::cout << "No faction for this actor!"; - } - else - { - factionID = stats.getFactionRanks().begin()->first; - } - return factionID; + return mActor; } void DialogueManager::goodbye() @@ -911,4 +957,49 @@ namespace MWDialogue win->goodbye(); } + + void DialogueManager::persuade(int type) + { + bool success; + float temp, perm; + MWBase::Environment::get().getMechanicsManager()->getPersuasionDispositionChange( + mActor, MWBase::MechanicsManager::PersuasionType(type), mTemporaryDispositionChange, + success, temp, perm); + mTemporaryDispositionChange += temp; + mPermanentDispositionChange += perm; + + // change temp disposition so that final disposition is between 0...100 + int curDisp = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mActor); + if (curDisp + mTemporaryDispositionChange < 0) + mTemporaryDispositionChange = -curDisp; + else if (curDisp + mTemporaryDispositionChange > 100) + mTemporaryDispositionChange = 100 - curDisp; + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWWorld::Class::get(player).skillUsageSucceeded(player, ESM::Skill::Speechcraft, success ? 0 : 1); + + std::string text; + + if (type == MWBase::MechanicsManager::PT_Admire) + text = "Admire"; + else if (type == MWBase::MechanicsManager::PT_Taunt) + text = "Taunt"; + else if (type == MWBase::MechanicsManager::PT_Intimidate) + text = "Intimidate"; + else{ + text = "Bribe"; + } + + executeTopic (text + (success ? " Success" : " Fail")); + } + + int DialogueManager::getTemporaryDispositionChange() const + { + return mTemporaryDispositionChange; + } + + void DialogueManager::applyTemporaryDispositionChange(int delta) + { + mTemporaryDispositionChange += delta; + } } diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index e3e9fd752..98b27f774 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -3,55 +3,54 @@ #include "../mwbase/dialoguemanager.hpp" -#include +#include +#include #include -#include "../mwscript/compilercontext.hpp" -#include "../mwscript/interpretercontext.hpp" -#include #include "../mwworld/ptr.hpp" -#include +#include "../mwscript/compilercontext.hpp" namespace MWDialogue { class DialogueManager : public MWBase::DialogueManager { - bool isMatching (const MWWorld::Ptr& actor, const ESM::DialInfo::SelectStruct& select) const; - - bool isMatching (const MWWorld::Ptr& actor, const ESM::DialInfo& info) const; - - bool functionFilter(const MWWorld::Ptr& actor, const ESM::DialInfo& info,bool choice); - - void parseText(std::string text); - - void updateTopics(); - - std::map mDialogueMap; - std::map mKnownTopics;// Those are the topics the player knows. + std::map mDialogueMap; + std::map mKnownTopics;// Those are the topics the player knows. std::list mActorKnownTopics; MWScript::CompilerContext mCompilerContext; std::ostream mErrorStream; Compiler::StreamErrorHandler mErrorHandler; - - bool compile (const std::string& cmd,std::vector& code); - void executeScript(std::string script); MWWorld::Ptr mActor; - - void printError(std::string error); + bool mTalkedTo; int mChoice; - std::map mChoiceMap; + std::map mChoiceMap; std::string mLastTopic; ESM::DialInfo mLastDialogue; bool mIsInChoice; + float mTemporaryDispositionChange; + float mPermanentDispositionChange; + bool mScriptVerbose; + + void parseText (const std::string& text); + + void updateTopics(); + + bool compile (const std::string& cmd,std::vector& code); + void executeScript (const std::string& script); + + void printError (const std::string& error); + + void executeTopic (const std::string& topic); + public: - DialogueManager (const Compiler::Extensions& extensions); + DialogueManager (const Compiler::Extensions& extensions, bool scriptVerbose); virtual void startDialogue (const MWWorld::Ptr& actor); @@ -61,14 +60,17 @@ namespace MWDialogue virtual void goodbye(); - ///get the faction of the actor you are talking with - virtual std::string getFaction() const; + virtual MWWorld::Ptr getActor() const; + ///< Return the actor the player is currently talking to. //calbacks for the GUI virtual void keywordSelected (const std::string& keyword); virtual void goodbyeSelected(); virtual void questionAnswered (const std::string& answer); + virtual void persuade (int type); + virtual int getTemporaryDispositionChange () const; + virtual void applyTemporaryDispositionChange (int delta); }; } diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp new file mode 100644 index 000000000..0deef7fd0 --- /dev/null +++ b/apps/openmw/mwdialogue/filter.cpp @@ -0,0 +1,570 @@ + +#include "filter.hpp" + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/journal.hpp" +#include "../mwbase/mechanicsmanager.hpp" + +#include "../mwworld/class.hpp" +#include "../mwworld/player.hpp" +#include "../mwworld/containerstore.hpp" +#include "../mwworld/inventorystore.hpp" + +#include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/magiceffects.hpp" + +#include "selectwrapper.hpp" + +namespace +{ + std::string toLower (const std::string& name) + { + std::string lowerCase; + + std::transform (name.begin(), name.end(), std::back_inserter (lowerCase), + (int(*)(int)) std::tolower); + + return lowerCase; + } +} + +bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const +{ + // actor id + if (!info.mActor.empty()) + if (toLower (info.mActor)!=MWWorld::Class::get (mActor).getId (mActor)) + return false; + + bool isCreature = (mActor.getTypeName() != typeid (ESM::NPC).name()); + + // NPC race + if (!info.mRace.empty()) + { + if (isCreature) + return false; + + MWWorld::LiveCellRef *cellRef = mActor.get(); + + if (toLower (info.mRace)!=toLower (cellRef->mBase->mRace)) + return false; + } + + // NPC class + if (!info.mClass.empty()) + { + if (isCreature) + return false; + + MWWorld::LiveCellRef *cellRef = mActor.get(); + + if (toLower (info.mClass)!=toLower (cellRef->mBase->mClass)) + return false; + } + + // NPC faction + if (!info.mNpcFaction.empty()) + { + if (isCreature) + return false; + + MWMechanics::NpcStats& stats = MWWorld::Class::get (mActor).getNpcStats (mActor); + std::map::iterator iter = stats.getFactionRanks().find (toLower (info.mNpcFaction)); + + if (iter==stats.getFactionRanks().end()) + return false; + + // check rank + if (iter->second < info.mData.mRank) + return false; + } + + // Gender + if (!isCreature) + { + MWWorld::LiveCellRef* npc = mActor.get(); + if (info.mData.mGender==(npc->mBase->mFlags & npc->mBase->Female ? 0 : 1)) + return false; + } + + return true; +} + +bool MWDialogue::Filter::testPlayer (const ESM::DialInfo& info) const +{ + const MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + + // check player faction + if (!info.mPcFaction.empty()) + { + MWMechanics::NpcStats& stats = MWWorld::Class::get (player).getNpcStats (player); + std::map::iterator iter = stats.getFactionRanks().find (toLower (info.mPcFaction)); + + if(iter==stats.getFactionRanks().end()) + return false; + + // check rank + if (iter->second < info.mData.mPCrank) + return false; + } + + // check cell + if (!info.mCell.empty()) + if (toLower (player.getCell()->mCell->mName) != toLower (info.mCell)) + return false; + + return true; +} + +bool MWDialogue::Filter::testSelectStructs (const ESM::DialInfo& info) const +{ + for (std::vector::const_iterator iter (info.mSelects.begin()); + iter != info.mSelects.end(); ++iter) + if (!testSelectStruct (*iter)) + return false; + + return true; +} + +bool MWDialogue::Filter::testSelectStruct (const SelectWrapper& select) const +{ + if (select.isNpcOnly() && mActor.getTypeName()!=typeid (ESM::NPC).name()) + return select.isInverted(); + + switch (select.getType()) + { + case SelectWrapper::Type_None: return true; + case SelectWrapper::Type_Integer: return select.selectCompare (getSelectStructInteger (select)); + case SelectWrapper::Type_Numeric: return testSelectStructNumeric (select); + case SelectWrapper::Type_Boolean: return select.selectCompare (getSelectStructBoolean (select)); + } + + return true; +} + +bool MWDialogue::Filter::testSelectStructNumeric (const SelectWrapper& select) const +{ + switch (select.getFunction()) + { + case SelectWrapper::Function_Global: + + // internally all globals are float :( + return select.selectCompare ( + MWBase::Environment::get().getWorld()->getGlobalVariable (select.getName()).mFloat); + + case SelectWrapper::Function_Local: + { + std::string scriptName = MWWorld::Class::get (mActor).getScript (mActor); + + if (scriptName.empty()) + return false; // no script + + const ESM::Script *script = + MWBase::Environment::get().getWorld()->getStore().get().find (scriptName); + + std::string name = select.getName(); + + int i = 0; + + for (; i (script->mVarNames.size()); ++i) + if (script->mVarNames[i]==name) + break; + + if (i>=static_cast (script->mVarNames.size())) + return false; // script does not have a variable of this name + + const MWScript::Locals& locals = mActor.getRefData().getLocals(); + + if (imData.mNumShorts) + return select.selectCompare (static_cast (locals.mShorts[i])); + + i -= script->mData.mNumShorts; + + if (imData.mNumLongs) + return select.selectCompare (locals.mLongs[i]); + + i -= script->mData.mNumShorts; + + return select.selectCompare (locals.mFloats.at (i)); + } + + case SelectWrapper::Function_PcHealthPercent: + { + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + + float ratio = MWWorld::Class::get (player).getCreatureStats (player).getHealth().getCurrent() / + MWWorld::Class::get (player).getCreatureStats (player).getHealth().getModified(); + + return select.selectCompare (ratio); + } + + case SelectWrapper::Function_PcDynamicStat: + { + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + + float value = MWWorld::Class::get (player).getCreatureStats (player). + getDynamic (select.getArgument()).getCurrent(); + + return select.selectCompare (value); + } + + case SelectWrapper::Function_HealthPercent: + { + float ratio = MWWorld::Class::get (mActor).getCreatureStats (mActor).getHealth().getCurrent() / + MWWorld::Class::get (mActor).getCreatureStats (mActor).getHealth().getModified(); + + return select.selectCompare (ratio); + } + + default: + + throw std::runtime_error ("unknown numeric select function"); + } +} + +int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) const +{ + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + + switch (select.getFunction()) + { + case SelectWrapper::Function_Journal: + + return MWBase::Environment::get().getJournal()->getJournalIndex (select.getName()); + + case SelectWrapper::Function_Item: + { + MWWorld::ContainerStore& store = MWWorld::Class::get (player).getContainerStore (player); + + int sum = 0; + + std::string name = select.getName(); + + for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter) + if (toLower(iter->getCellRef().mRefID) == name) + sum += iter->getRefData().getCount(); + + return sum; + } + + case SelectWrapper::Function_Dead: + + return MWBase::Environment::get().getMechanicsManager()->countDeaths (select.getName()); + + case SelectWrapper::Function_Choice: + + return mChoice; + + case SelectWrapper::Function_AiSetting: + + return MWWorld::Class::get (mActor).getCreatureStats (mActor).getAiSetting (select.getArgument()); + + case SelectWrapper::Function_PcAttribute: + + return MWWorld::Class::get (player).getCreatureStats (player). + getAttribute (select.getArgument()).getModified(); + + case SelectWrapper::Function_PcSkill: + + return static_cast (MWWorld::Class::get (player). + getNpcStats (player).getSkill (select.getArgument()).getModified()); + + case SelectWrapper::Function_FriendlyHit: + { + int hits = MWWorld::Class::get (mActor).getCreatureStats (mActor).getFriendlyHits(); + + return hits>4 ? 4 : hits; + } + + case SelectWrapper::Function_PcLevel: + + return MWWorld::Class::get (player).getCreatureStats (player).getLevel(); + + case SelectWrapper::Function_PcGender: + + return player.get()->mBase->mFlags & ESM::NPC::Female ? 0 : 1; + + case SelectWrapper::Function_PcClothingModifier: + { + MWWorld::InventoryStore& store = MWWorld::Class::get (player).getInventoryStore (player); + + int value = 0; + + for (int i=0; i<=15; ++i) // everything except thigns held in hands and amunition + { + MWWorld::ContainerStoreIterator slot = store.getSlot (i); + + if (slot!=store.end()) + value += MWWorld::Class::get (*slot).getValue (*slot); + } + + return value; + } + + case SelectWrapper::Function_PcCrimeLevel: + + return MWWorld::Class::get (player).getNpcStats (player).getBounty(); + + case SelectWrapper::Function_RankRequirement: + { + if (MWWorld::Class::get (mActor).getNpcStats (mActor).getFactionRanks().empty()) + return 0; + + std::string faction = + MWWorld::Class::get (mActor).getNpcStats (mActor).getFactionRanks().begin()->first; + + int rank = getFactionRank (player, faction); + + if (rank>=9) + return 0; // max rank + + int result = 0; + + if (hasFactionRankSkillRequirements (player, faction, rank+1)) + result += 1; + + if (hasFactionRankReputationRequirements (player, faction, rank+1)) + result += 2; + + return result; + } + + case SelectWrapper::Function_Level: + + return MWWorld::Class::get (mActor).getCreatureStats (mActor).getLevel(); + + case SelectWrapper::Function_PCReputation: + + return MWWorld::Class::get (player).getNpcStats (player).getReputation(); + + case SelectWrapper::Function_Weather: + + return MWBase::Environment::get().getWorld()->getCurrentWeather(); + + case SelectWrapper::Function_Reputation: + + return MWWorld::Class::get (mActor).getNpcStats (mActor).getReputation(); + + case SelectWrapper::Function_FactionRankDiff: + { + if (MWWorld::Class::get (mActor).getNpcStats (mActor).getFactionRanks().empty()) + return 0; + + std::pair faction = + *MWWorld::Class::get (mActor).getNpcStats (mActor).getFactionRanks().begin(); + + int rank = getFactionRank (player, faction.first); + + return rank-faction.second; + } + + case SelectWrapper::Function_WerewolfKills: + + return MWWorld::Class::get (player).getNpcStats (player).getWerewolfKills(); + + case SelectWrapper::Function_RankLow: + case SelectWrapper::Function_RankHigh: + { + bool low = select.getFunction()==SelectWrapper::Function_RankLow; + + if (MWWorld::Class::get (mActor).getNpcStats (mActor).getFactionRanks().empty()) + return 0; + + std::string factionId = + MWWorld::Class::get (mActor).getNpcStats (mActor).getFactionRanks().begin()->first; + + int value = 0; + + const ESM::Faction& faction = + *MWBase::Environment::get().getWorld()->getStore().get().find (factionId); + + MWMechanics::NpcStats& playerStats = MWWorld::Class::get (player).getNpcStats (player); + + for (std::vector::const_iterator iter (faction.mReactions.begin()); + iter!=faction.mReactions.end(); ++iter) + if (playerStats.getFactionRanks().find (iter->mFaction)!=playerStats.getFactionRanks().end()) + if (low ? iter->mReactionmReaction>value) + value = iter->mReaction; + + return value; + } + + default: + + throw std::runtime_error ("unknown integer select function"); + } +} + +bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) const +{ + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + + switch (select.getFunction()) + { + case SelectWrapper::Function_False: + + return false; + + case SelectWrapper::Function_Id: + + return select.getName()==toLower (MWWorld::Class::get (mActor).getId (mActor)); + + case SelectWrapper::Function_Faction: + + return toLower (mActor.get()->mBase->mFaction)==select.getName(); + + case SelectWrapper::Function_Class: + + return toLower (mActor.get()->mBase->mClass)==select.getName(); + + case SelectWrapper::Function_Race: + + return toLower (mActor.get()->mBase->mRace)==select.getName(); + + case SelectWrapper::Function_Cell: + + return toLower (mActor.getCell()->mCell->mName)==select.getName(); + + case SelectWrapper::Function_SameGender: + + return (player.get()->mBase->mFlags & ESM::NPC::Female)== + (mActor.get()->mBase->mFlags & ESM::NPC::Female); + + case SelectWrapper::Function_SameRace: + + return toLower (mActor.get()->mBase->mRace)!= + toLower (player.get()->mBase->mRace); + + case SelectWrapper::Function_SameFaction: + + return MWWorld::Class::get (mActor).getNpcStats (mActor).isSameFaction ( + MWWorld::Class::get (player).getNpcStats (player)); + + case SelectWrapper::Function_PcCommonDisease: + + return MWWorld::Class::get (player).getCreatureStats (player).hasCommonDisease(); + + case SelectWrapper::Function_PcBlightDisease: + + return MWWorld::Class::get (player).getCreatureStats (player).hasBlightDisease(); + + case SelectWrapper::Function_PcCorprus: + + return MWWorld::Class::get (player).getCreatureStats (player). + getMagicEffects().get (132).mMagnitude!=0; + + case SelectWrapper::Function_PcExpelled: + { + if (MWWorld::Class::get (mActor).getNpcStats (mActor).getFactionRanks().empty()) + return false; + + std::string faction = + MWWorld::Class::get (mActor).getNpcStats (mActor).getFactionRanks().begin()->first; + + std::set& expelled = MWWorld::Class::get (player).getNpcStats (player).getExpelled(); + + return expelled.find (faction)!=expelled.end(); + } + + case SelectWrapper::Function_PcVampire: + + return MWWorld::Class::get (player).getNpcStats (player).isVampire(); + + case SelectWrapper::Function_TalkedToPc: + + return mTalkedToPlayer; + + case SelectWrapper::Function_Alarmed: + + return MWWorld::Class::get (mActor).getCreatureStats (mActor).isAlarmed(); + + case SelectWrapper::Function_Detected: + + return MWWorld::Class::get (mActor).hasDetected (mActor, player); + + case SelectWrapper::Function_Attacked: + + return MWWorld::Class::get (mActor).getCreatureStats (mActor).getAttacked(); + + case SelectWrapper::Function_ShouldAttack: + + return MWWorld::Class::get (mActor).getCreatureStats (mActor).isHostile(); + + case SelectWrapper::Function_CreatureTargetted: + + return MWWorld::Class::get (mActor).getCreatureStats (mActor).getCreatureTargetted(); + + case SelectWrapper::Function_PCWerewolf: + + return MWWorld::Class::get (player).getNpcStats (player).isWerewolf(); + + default: + + throw std::runtime_error ("unknown boolean select function"); + } +} + +int MWDialogue::Filter::getFactionRank (const MWWorld::Ptr& actor, const std::string& factionId) const +{ + MWMechanics::NpcStats& stats = MWWorld::Class::get (actor).getNpcStats (actor); + + std::map::const_iterator iter = stats.getFactionRanks().find (factionId); + + if (iter==stats.getFactionRanks().end()) + return -1; + + return iter->second; +} + +bool MWDialogue::Filter::hasFactionRankSkillRequirements (const MWWorld::Ptr& actor, + const std::string& factionId, int rank) const +{ + if (rank<0 || rank>=10) + throw std::runtime_error ("rank index out of range"); + + if (!MWWorld::Class::get (actor).getNpcStats (actor).hasSkillsForRank (factionId, rank)) + return false; + + const ESM::Faction& faction = + *MWBase::Environment::get().getWorld()->getStore().get().find (factionId); + + MWMechanics::CreatureStats& stats = MWWorld::Class::get (actor).getCreatureStats (actor); + + return stats.getAttribute (faction.mData.mAttribute1).getBase()>=faction.mData.mRankData[rank].mAttribute1 && + stats.getAttribute (faction.mData.mAttribute2).getBase()>=faction.mData.mRankData[rank].mAttribute2; +} + +bool MWDialogue::Filter::hasFactionRankReputationRequirements (const MWWorld::Ptr& actor, + const std::string& factionId, int rank) const +{ + if (rank<0 || rank>=10) + throw std::runtime_error ("rank index out of range"); + + MWMechanics::NpcStats& stats = MWWorld::Class::get (actor).getNpcStats (actor); + + const ESM::Faction& faction = + *MWBase::Environment::get().getWorld()->getStore().get().find (factionId); + + return stats.getFactionReputation (factionId)>=faction.mData.mRankData[rank].mFactReaction; +} + +MWDialogue::Filter::Filter (const MWWorld::Ptr& actor, int choice, bool talkedToPlayer) +: mActor (actor), mChoice (choice), mTalkedToPlayer (talkedToPlayer) +{} + +bool MWDialogue::Filter::operator() (const ESM::DialInfo& info) const +{ + return testActor (info) && testPlayer (info) && testSelectStructs (info); +} + +const ESM::DialInfo *MWDialogue::Filter::search (const ESM::Dialogue& dialogue) const +{ + for (std::vector::const_iterator iter = dialogue.mInfo.begin(); + iter!=dialogue.mInfo.end(); ++iter) + if ((*this) (*iter)) + return &*iter; + + return 0; +} + diff --git a/apps/openmw/mwdialogue/filter.hpp b/apps/openmw/mwdialogue/filter.hpp new file mode 100644 index 000000000..7c8f1116f --- /dev/null +++ b/apps/openmw/mwdialogue/filter.hpp @@ -0,0 +1,58 @@ +#ifndef GAME_MWDIALOGUE_FILTER_H +#define GAME_MWDIALOGUE_FILTER_H + +#include "../mwworld/ptr.hpp" + +namespace ESM +{ + struct DialInfo; + struct Dialogue; +} + +namespace MWDialogue +{ + class SelectWrapper; + + class Filter + { + MWWorld::Ptr mActor; + int mChoice; + bool mTalkedToPlayer; + + bool testActor (const ESM::DialInfo& info) const; + ///< Is this the right actor for this \a info? + + bool testPlayer (const ESM::DialInfo& info) const; + ///< Do the player and the cell the player is currently in match \a info? + + bool testSelectStructs (const ESM::DialInfo& info) const; + ///< Are all select structs matching? + + bool testSelectStruct (const SelectWrapper& select) const; + + bool testSelectStructNumeric (const SelectWrapper& select) const; + + int getSelectStructInteger (const SelectWrapper& select) const; + + bool getSelectStructBoolean (const SelectWrapper& select) const; + + int getFactionRank (const MWWorld::Ptr& actor, const std::string& factionId) const; + + bool hasFactionRankSkillRequirements (const MWWorld::Ptr& actor, const std::string& factionId, + int rank) const; + + bool hasFactionRankReputationRequirements (const MWWorld::Ptr& actor, const std::string& factionId, + int rank) const; + + public: + + Filter (const MWWorld::Ptr& actor, int choice, bool talkedToPlayer); + + bool operator() (const ESM::DialInfo& info) const; + ///< \return does the dialogue match? + + const ESM::DialInfo *search (const ESM::Dialogue& dialogue) const; + }; +} + +#endif diff --git a/apps/openmw/mwdialogue/journalentry.cpp b/apps/openmw/mwdialogue/journalentry.cpp index 1c6addb6e..e6141884c 100644 --- a/apps/openmw/mwdialogue/journalentry.cpp +++ b/apps/openmw/mwdialogue/journalentry.cpp @@ -3,11 +3,11 @@ #include -#include - #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" +#include "../mwworld/esmstore.hpp" + namespace MWDialogue { JournalEntry::JournalEntry() {} @@ -16,9 +16,10 @@ namespace MWDialogue : mTopic (topic), mInfoId (infoId) {} - std::string JournalEntry::getText (const ESMS::ESMStore& store) const + std::string JournalEntry::getText (const MWWorld::ESMStore& store) const { - const ESM::Dialogue *dialogue = store.dialogs.find (mTopic); + const ESM::Dialogue *dialogue = + store.get().find (mTopic); for (std::vector::const_iterator iter (dialogue->mInfo.begin()); iter!=dialogue->mInfo.end(); ++iter) @@ -35,7 +36,8 @@ namespace MWDialogue std::string JournalEntry::idFromIndex (const std::string& topic, int index) { - const ESM::Dialogue *dialogue = MWBase::Environment::get().getWorld()->getStore().dialogs.find (topic); + const ESM::Dialogue *dialogue = + MWBase::Environment::get().getWorld()->getStore().get().find (topic); for (std::vector::const_iterator iter (dialogue->mInfo.begin()); iter!=dialogue->mInfo.end(); ++iter) diff --git a/apps/openmw/mwdialogue/journalentry.hpp b/apps/openmw/mwdialogue/journalentry.hpp index 3e8640185..19a9f42b5 100644 --- a/apps/openmw/mwdialogue/journalentry.hpp +++ b/apps/openmw/mwdialogue/journalentry.hpp @@ -3,7 +3,7 @@ #include -namespace ESMS +namespace MWWorld { struct ESMStore; } @@ -20,7 +20,7 @@ namespace MWDialogue JournalEntry (const std::string& topic, const std::string& infoId); - std::string getText (const ESMS::ESMStore& store) const; + std::string getText (const MWWorld::ESMStore& store) const; static JournalEntry makeFromQuest (const std::string& topic, int index); diff --git a/apps/openmw/mwdialogue/journalimp.cpp b/apps/openmw/mwdialogue/journalimp.cpp index ac4b7a6de..2b2c60381 100644 --- a/apps/openmw/mwdialogue/journalimp.cpp +++ b/apps/openmw/mwdialogue/journalimp.cpp @@ -1,7 +1,7 @@ #include "journalimp.hpp" -#include +#include "../mwworld/esmstore.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwdialogue/quest.cpp b/apps/openmw/mwdialogue/quest.cpp index b4f02e128..5e2739be1 100644 --- a/apps/openmw/mwdialogue/quest.cpp +++ b/apps/openmw/mwdialogue/quest.cpp @@ -1,7 +1,7 @@ #include "quest.hpp" -#include +#include "../mwworld/esmstore.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -18,7 +18,8 @@ namespace MWDialogue const std::string Quest::getName() const { - const ESM::Dialogue *dialogue = MWBase::Environment::get().getWorld()->getStore().dialogs.find (mTopic); + const ESM::Dialogue *dialogue = + MWBase::Environment::get().getWorld()->getStore().get().find (mTopic); for (std::vector::const_iterator iter (dialogue->mInfo.begin()); iter!=dialogue->mInfo.end(); ++iter) @@ -35,7 +36,8 @@ namespace MWDialogue void Quest::setIndex (int index) { - const ESM::Dialogue *dialogue = MWBase::Environment::get().getWorld()->getStore().dialogs.find (mTopic); + const ESM::Dialogue *dialogue = + MWBase::Environment::get().getWorld()->getStore().get().find (mTopic); for (std::vector::const_iterator iter (dialogue->mInfo.begin()); iter!=dialogue->mInfo.end(); ++iter) @@ -63,7 +65,8 @@ namespace MWDialogue { int index = -1; - const ESM::Dialogue *dialogue = MWBase::Environment::get().getWorld()->getStore().dialogs.find (entry.mTopic); + const ESM::Dialogue *dialogue = + MWBase::Environment::get().getWorld()->getStore().get().find (entry.mTopic); for (std::vector::const_iterator iter (dialogue->mInfo.begin()); iter!=dialogue->mInfo.end(); ++iter) diff --git a/apps/openmw/mwdialogue/selectwrapper.cpp b/apps/openmw/mwdialogue/selectwrapper.cpp new file mode 100644 index 000000000..1462ee8ba --- /dev/null +++ b/apps/openmw/mwdialogue/selectwrapper.cpp @@ -0,0 +1,311 @@ + +#include "selectwrapper.hpp" + +#include + +#include +#include +#include +#include + +namespace +{ + std::string toLower (const std::string& name) + { + std::string lowerCase; + + std::transform (name.begin(), name.end(), std::back_inserter (lowerCase), + (int(*)(int)) std::tolower); + + return lowerCase; + } + + template + bool selectCompareImp (char comp, T1 value1, T2 value2) + { + switch (comp) + { + case '0': return value1==value2; + case '1': return value1!=value2; + case '2': return value1>value2; + case '3': return value1>=value2; + case '4': return value1 + bool selectCompareImp (const ESM::DialInfo::SelectStruct& select, T value1) + { + if (select.mType==ESM::VT_Short || select.mType==ESM::VT_Int || + select.mType==ESM::VT_Long) + { + return selectCompareImp (select.mSelectRule[4], value1, select.mI); + } + else if (select.mType==ESM::VT_Float) + { + return selectCompareImp (select.mSelectRule[4], value1, select.mF); + } + else + throw std::runtime_error ( + "unsupported variable type in dialogue info select"); + } +} + +MWDialogue::SelectWrapper::Function MWDialogue::SelectWrapper::decodeFunction() const +{ + int index = 0; + + std::istringstream (mSelect.mSelectRule.substr(2,2)) >> index; + + switch (index) + { + case 0: return Function_RankLow; + case 1: return Function_RankHigh; + case 2: return Function_RankRequirement; + case 3: return Function_Reputation; + case 4: return Function_HealthPercent; + case 5: return Function_PCReputation; + case 6: return Function_PcLevel; + case 7: return Function_PcHealthPercent; + case 8: case 9: return Function_PcDynamicStat; + case 10: return Function_PcAttribute; + case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 19: case 20: + case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28: case 29: case 30: + case 31: case 32: case 33: case 34: case 35: case 36: case 37: return Function_PcSkill; + case 38: return Function_PcGender; + case 39: return Function_PcExpelled; + case 40: return Function_PcCommonDisease; + case 41: return Function_PcBlightDisease; + case 42: return Function_PcClothingModifier; + case 43: return Function_PcCrimeLevel; + case 44: return Function_SameGender; + case 45: return Function_SameRace; + case 46: return Function_SameFaction; + case 47: return Function_FactionRankDiff; + case 48: return Function_Detected; + case 49: return Function_Alarmed; + case 50: return Function_Choice; + case 51: case 52: case 53: case 54: case 55: case 56: case 57: return Function_PcAttribute; + case 58: return Function_PcCorprus; + case 59: return Function_Weather; + case 60: return Function_PcVampire; + case 61: return Function_Level; + case 62: return Function_Attacked; + case 63: return Function_TalkedToPc; + case 64: return Function_PcDynamicStat; + case 65: return Function_CreatureTargetted; + case 66: return Function_FriendlyHit; + case 67: case 68: case 69: case 70: return Function_AiSetting; + case 71: return Function_ShouldAttack; + case 72: return Function_PCWerewolf; + case 73: return Function_WerewolfKills; + } + + return Function_False; +} + +MWDialogue::SelectWrapper::SelectWrapper (const ESM::DialInfo::SelectStruct& select) : mSelect (select) {} + +MWDialogue::SelectWrapper::Function MWDialogue::SelectWrapper::getFunction() const +{ + char type = mSelect.mSelectRule[1]; + + switch (type) + { + case '1': return decodeFunction(); + case '2': return Function_Global; + case '3': return Function_Local; + case '4': return Function_Journal; + case '5': return Function_Item; + case '6': return Function_Dead; + case '7': return Function_Id; + case '8': return Function_Faction; + case '9': return Function_Class; + case 'A': return Function_Race; + case 'B': return Function_Cell; + case 'C': return Function_Local; + } + + return Function_None; +} + +int MWDialogue::SelectWrapper::getArgument() const +{ + if (mSelect.mSelectRule[1]!='1') + return 0; + + int index = 0; + + std::istringstream (mSelect.mSelectRule.substr(2,2)) >> index; + + switch (index) + { + // AI settings + case 67: return 1; + case 68: return 0; + case 69: return 3; + case 70: return 2; + + // attributes + case 10: return 0; + case 51: return 1; + case 52: return 2; + case 53: return 3; + case 54: return 4; + case 55: return 5; + case 56: return 6; + case 57: return 7; + + // skills + case 11: return 0; + case 12: return 1; + case 13: return 2; + case 14: return 3; + case 15: return 4; + case 16: return 5; + case 17: return 6; + case 18: return 7; + case 19: return 8; + case 20: return 9; + case 21: return 10; + case 22: return 11; + case 23: return 12; + case 24: return 13; + case 25: return 14; + case 26: return 15; + case 27: return 16; + case 28: return 17; + case 29: return 18; + case 30: return 19; + case 31: return 20; + case 32: return 21; + case 33: return 22; + case 34: return 23; + case 35: return 24; + case 36: return 25; + case 37: return 26; + + // dynamic stats + case 8: return 1; + case 9: return 2; + case 64: return 0; + } + + return 0; +} + +MWDialogue::SelectWrapper::Type MWDialogue::SelectWrapper::getType() const +{ + static const Function integerFunctions[] = + { + Function_Journal, Function_Item, Function_Dead, + Function_Choice, + Function_AiSetting, + Function_PcAttribute, Function_PcSkill, + Function_FriendlyHit, + Function_PcLevel, Function_PcGender, Function_PcClothingModifier, + Function_PcCrimeLevel, + Function_RankRequirement, + Function_Level, Function_PCReputation, + Function_Weather, + Function_Reputation, Function_FactionRankDiff, + Function_WerewolfKills, + Function_RankLow, Function_RankHigh, + Function_None // end marker + }; + + static const Function numericFunctions[] = + { + Function_Global, Function_Local, + Function_PcDynamicStat, Function_PcHealthPercent, + Function_HealthPercent, + Function_None // end marker + }; + + static const Function booleanFunctions[] = + { + Function_False, + Function_Id, Function_Faction, Function_Class, Function_Race, Function_Cell, + Function_SameGender, Function_SameRace, Function_SameFaction, + Function_PcCommonDisease, Function_PcBlightDisease, Function_PcCorprus, + Function_PcExpelled, + Function_PcVampire, Function_TalkedToPc, + Function_Alarmed, Function_Detected, + Function_Attacked, Function_ShouldAttack, + Function_CreatureTargetted, + Function_PCWerewolf, + Function_None // end marker + }; + + Function function = getFunction(); + + for (int i=0; integerFunctions[i]!=Function_None; ++i) + if (integerFunctions[i]==function) + return Type_Integer; + + for (int i=0; numericFunctions[i]!=Function_None; ++i) + if (numericFunctions[i]==function) + return Type_Numeric; + + for (int i=0; booleanFunctions[i]!=Function_None; ++i) + if (booleanFunctions[i]==function) + return Type_Boolean; + + return Type_None; +} + +bool MWDialogue::SelectWrapper::isInverted() const +{ + char type = mSelect.mSelectRule[1]; + + return type=='7' || type=='8' || type=='9' || type=='A' || type=='B' || type=='C'; +} + +bool MWDialogue::SelectWrapper::isNpcOnly() const +{ + static const Function functions[] = + { + Function_Faction, SelectWrapper::Function_Class, SelectWrapper::Function_Race, + Function_SameGender, Function_SameRace, Function_SameFaction, + Function_PcSkill, + Function_PcExpelled, + Function_PcVampire, + Function_PcCrimeLevel, + Function_RankRequirement, + Function_Reputation, Function_FactionRankDiff, + Function_PCWerewolf, Function_WerewolfKills, + Function_RankLow, Function_RankHigh, + Function_None // end marker + }; + + Function function = getFunction(); + + for (int i=0; functions[i]!=Function_None; ++i) + if (functions[i]==function) + return true; + + return false; +} + +bool MWDialogue::SelectWrapper::selectCompare (int value) const +{ + return selectCompareImp (mSelect, value)!=isInverted(); // logic XOR +} + +bool MWDialogue::SelectWrapper::selectCompare (float value) const +{ + return selectCompareImp (mSelect, value)!=isInverted(); // logic XOR +} + +bool MWDialogue::SelectWrapper::selectCompare (bool value) const +{ + return selectCompareImp (mSelect, static_cast (value))!=isInverted(); // logic XOR +} + +std::string MWDialogue::SelectWrapper::getName() const +{ + return toLower (mSelect.mSelectRule.substr (5)); +} diff --git a/apps/openmw/mwdialogue/selectwrapper.hpp b/apps/openmw/mwdialogue/selectwrapper.hpp new file mode 100644 index 000000000..b77ed7985 --- /dev/null +++ b/apps/openmw/mwdialogue/selectwrapper.hpp @@ -0,0 +1,86 @@ +#ifndef GAME_MWDIALOGUE_SELECTWRAPPER_H +#define GAME_MWDIALOGUE_SELECTWRAPPER_H + +#include + +namespace MWDialogue +{ + class SelectWrapper + { + const ESM::DialInfo::SelectStruct& mSelect; + + public: + + enum Function + { + Function_None, Function_False, + Function_Journal, + Function_Item, + Function_Dead, + Function_Id, + Function_Faction, + Function_Class, + Function_Race, + Function_Cell, + Function_Local, + Function_Global, + Function_SameGender, Function_SameRace, Function_SameFaction, + Function_Choice, + Function_PcCommonDisease, Function_PcBlightDisease, Function_PcCorprus, + Function_AiSetting, + Function_PcAttribute, Function_PcSkill, + Function_PcExpelled, + Function_PcVampire, + Function_FriendlyHit, + Function_TalkedToPc, + Function_PcLevel, Function_PcHealthPercent, Function_PcDynamicStat, + Function_PcGender, Function_PcClothingModifier, Function_PcCrimeLevel, + Function_RankRequirement, + Function_HealthPercent, Function_Level, Function_PCReputation, + Function_Weather, + Function_Reputation, Function_Alarmed, Function_FactionRankDiff, Function_Detected, + Function_Attacked, Function_ShouldAttack, + Function_CreatureTargetted, + Function_PCWerewolf, Function_WerewolfKills, + Function_RankLow, Function_RankHigh + }; + + enum Type + { + Type_None, + Type_Integer, + Type_Numeric, + Type_Boolean + }; + + private: + + Function decodeFunction() const; + + public: + + SelectWrapper (const ESM::DialInfo::SelectStruct& select); + + Function getFunction() const; + + int getArgument() const; + + Type getType() const; + + bool isInverted() const; + + bool isNpcOnly() const; + ///< \attention Do not call any of the select functions for this select struct! + + bool selectCompare (int value) const; + + bool selectCompare (float value) const; + + bool selectCompare (bool value) const; + + std::string getName() const; + ///< Return case-smashed name. + }; +} + +#endif diff --git a/apps/openmw/mwdialogue/topic.cpp b/apps/openmw/mwdialogue/topic.cpp index 8c1dfafb8..b6e7c07ae 100644 --- a/apps/openmw/mwdialogue/topic.cpp +++ b/apps/openmw/mwdialogue/topic.cpp @@ -1,7 +1,7 @@ #include "topic.hpp" -#include +#include "../mwworld/esmstore.hpp" namespace MWDialogue { diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 56db47a0f..db1a81c2c 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -63,7 +63,7 @@ namespace MWGui void AlchemyWindow::onCancelButtonClicked(MyGUI::Widget* _sender) { mAlchemy.clear(); - + mWindowManager.removeGuiMode(GM_Alchemy); mWindowManager.removeGuiMode(GM_Inventory); } @@ -119,7 +119,6 @@ namespace MWGui if (mIngredients[i]->isUserString("ToolTipType")) { MWWorld::Ptr ingred = *mIngredients[i]->getUserData(); - ingred.getRefData().setCount(ingred.getRefData().getCount()-1); if (ingred.getRefData().getCount() == 0) removeIngredient(mIngredients[i]); } @@ -132,6 +131,8 @@ namespace MWGui openContainer (MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); // this sets mPtr setFilter (ContainerBase::Filter_Ingredients); + mNameEdit->setCaption(""); + mAlchemy.setAlchemist (mPtr); int index = 0; diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index e7862c4e7..4837821e0 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -3,7 +3,7 @@ #include #include -#include "components/esm_store/store.hpp" +#include "../mwworld/esmstore.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -130,19 +130,18 @@ void BirthDialog::updateBirths() { mBirthList->removeAllItems(); - const ESMS::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + const MWWorld::Store &signs = + MWBase::Environment::get().getWorld()->getStore().get(); - ESMS::RecListT::MapType::const_iterator it = store.birthSigns.list.begin(); - ESMS::RecListT::MapType::const_iterator end = store.birthSigns.list.end(); int index = 0; // sort by name std::vector < std::pair > birthSigns; - for (; it!=end; ++it) + + MWWorld::Store::iterator it = signs.begin(); + for (; it != signs.end(); ++it) { - std::string id = it->first; - const ESM::BirthSign* sign = &it->second; - birthSigns.push_back(std::make_pair(id, sign)); + birthSigns.push_back(std::make_pair(it->mId, &(*it))); } std::sort(birthSigns.begin(), birthSigns.end(), sortBirthSigns); @@ -170,8 +169,11 @@ void BirthDialog::updateSpells() const int lineHeight = 18; MyGUI::IntCoord coord(0, 0, mSpellArea->getWidth(), 18); - const ESMS::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - const ESM::BirthSign *birth = store.birthSigns.find(mCurrentBirthId); + const MWWorld::ESMStore &store = + MWBase::Environment::get().getWorld()->getStore(); + + const ESM::BirthSign *birth = + store.get().find(mCurrentBirthId); std::string texturePath = std::string("textures\\") + birth->mTexture; fixTexturePath(texturePath); @@ -184,7 +186,7 @@ void BirthDialog::updateSpells() for (; it != end; ++it) { const std::string &spellId = *it; - const ESM::Spell *spell = store.spells.search(spellId); + const ESM::Spell *spell = store.get().search(spellId); if (!spell) continue; // Skip spells which cannot be found ESM::Spell::SpellType type = static_cast(spell->mData.mType); @@ -200,11 +202,17 @@ void BirthDialog::updateSpells() } int i = 0; - struct{ const std::vector &spells; const char *label; } categories[3] = { + + struct { + const std::vector &spells; + const char *label; + } + categories[3] = { {abilities, "sBirthsignmenu1"}, {powers, "sPowers"}, {spells, "sBirthsignmenu2"} }; + for (int category = 0; category < 3; ++category) { if (!categories[category].spells.empty()) diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index cb142db60..bc3cd7b40 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -60,7 +60,7 @@ void BookWindow::open (MWWorld::Ptr book) MWWorld::LiveCellRef *ref = mBook.get(); BookTextParser parser; - std::vector results = parser.split(ref->base->mText, mLeftPage->getSize().width, mLeftPage->getSize().height); + std::vector results = parser.split(ref->mBase->mText, mLeftPage->getSize().width, mLeftPage->getSize().height); int i=0; for (std::vector::iterator it=results.begin(); diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index e4b77287c..1719c5768 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -7,6 +7,7 @@ #include "review.hpp" #include "dialogue.hpp" #include "mode.hpp" +#include "inventorywindow.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" @@ -357,7 +358,9 @@ void CharacterCreation::onPickClassDialogDone(WindowBase* parWindow) const std::string &classId = mPickClassDialog->getClassId(); if (!classId.empty()) MWBase::Environment::get().getMechanicsManager()->setPlayerClass(classId); - const ESM::Class *klass = MWBase::Environment::get().getWorld()->getStore().classes.find(classId); + + const ESM::Class *klass = + MWBase::Environment::get().getWorld()->getStore().get().find(classId); if (klass) { mPlayerClass = *klass; @@ -457,9 +460,16 @@ void CharacterCreation::onRaceDialogBack() { if (mRaceDialog) { - mPlayerRaceId = mRaceDialog->getRaceId(); - if (!mPlayerRaceId.empty()) - MWBase::Environment::get().getMechanicsManager()->setPlayerRace(mPlayerRaceId, mRaceDialog->getGender() == RaceDialog::GM_Male); + const ESM::NPC &data = mRaceDialog->getResult(); + mPlayerRaceId = data.mRace; + if (!mPlayerRaceId.empty()) { + MWBase::Environment::get().getMechanicsManager()->setPlayerRace( + data.mRace, + data.isMale(), + data.mHead, + data.mHair + ); + } mWM->removeDialog(mRaceDialog); mRaceDialog = 0; } @@ -472,10 +482,18 @@ void CharacterCreation::onRaceDialogDone(WindowBase* parWindow) { if (mRaceDialog) { - mPlayerRaceId = mRaceDialog->getRaceId(); - mWM->setValue("race", mPlayerRaceId); - if (!mPlayerRaceId.empty()) - MWBase::Environment::get().getMechanicsManager()->setPlayerRace(mPlayerRaceId, mRaceDialog->getGender() == RaceDialog::GM_Male); + const ESM::NPC &data = mRaceDialog->getResult(); + mPlayerRaceId = data.mRace; + if (!mPlayerRaceId.empty()) { + MWBase::Environment::get().getMechanicsManager()->setPlayerRace( + data.mRace, + data.isMale(), + data.mHead, + data.mHair + ); + } + mWM->getInventoryWindow()->rebuildAvatar(); + mWM->removeDialog(mRaceDialog); mRaceDialog = 0; } @@ -557,6 +575,7 @@ void CharacterCreation::onCreateClassDialogDone(WindowBase* parWindow) klass.mData.mSkills[i][1] = majorSkills[i]; klass.mData.mSkills[i][0] = minorSkills[i]; } + MWBase::Environment::get().getMechanicsManager()->setPlayerClass(klass); mPlayerClass = klass; mWM->setPlayerClass(klass); @@ -729,7 +748,10 @@ void CharacterCreation::onGenerateClassDone(WindowBase* parWindow) mGenerateClassResultDialog = 0; MWBase::Environment::get().getMechanicsManager()->setPlayerClass(mGenerateClass); - const ESM::Class *klass = MWBase::Environment::get().getWorld()->getStore().classes.find(mGenerateClass); + + const ESM::Class *klass = + MWBase::Environment::get().getWorld()->getStore().get().find(mGenerateClass); + mPlayerClass = *klass; mWM->setPlayerClass(mPlayerClass); diff --git a/apps/openmw/mwgui/charactercreation.hpp b/apps/openmw/mwgui/charactercreation.hpp index 28ced2e70..9653aeede 100644 --- a/apps/openmw/mwgui/charactercreation.hpp +++ b/apps/openmw/mwgui/charactercreation.hpp @@ -1,7 +1,7 @@ #ifndef CHARACTER_CREATION_HPP #define CHARACTER_CREATION_HPP -#include +#include "../mwworld/esmstore.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index f020010ec..c14c7f74b 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include "../mwworld/esmstore.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -50,7 +50,7 @@ void GenerateClassResultDialog::setClassId(const std::string &classId) { mCurrentClassId = classId; mClassImage->setImageTexture(std::string("textures\\levelup\\") + mCurrentClassId + ".dds"); - mClassName->setCaption(MWBase::Environment::get().getWorld()->getStore().classes.find(mCurrentClassId)->mName); + mClassName->setCaption(MWBase::Environment::get().getWorld()->getStore().get().find(mCurrentClassId)->mName); } // widget controls @@ -185,20 +185,18 @@ void PickClassDialog::updateClasses() { mClassList->removeAllItems(); - const ESMS::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - ESMS::RecListT::MapType::const_iterator it = store.classes.list.begin(); - ESMS::RecListT::MapType::const_iterator end = store.classes.list.end(); int index = 0; - for (; it != end; ++it) + MWWorld::Store::iterator it = store.get().begin(); + for (; it != store.get().end(); ++it) { - const ESM::Class &klass = it->second; - bool playable = (klass.mData.mIsPlayable != 0); + bool playable = (it->mData.mIsPlayable != 0); if (!playable) // Only display playable classes continue; - const std::string &id = it->first; - mClassList->addItem(klass.mName, id); + const std::string &id = it->mId; + mClassList->addItem(it->mName, id); if (boost::iequals(id, mCurrentClassId)) mClassList->setIndexSelected(index); ++index; @@ -209,8 +207,8 @@ void PickClassDialog::updateStats() { if (mCurrentClassId.empty()) return; - const ESMS::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - const ESM::Class *klass = store.classes.search(mCurrentClassId); + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + const ESM::Class *klass = store.get().search(mCurrentClassId); if (!klass) return; diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index b939284dd..b2281d87e 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -4,11 +4,10 @@ #include #include -#include -#include - #include +#include "../mwworld/esmstore.hpp" + #include "../mwscript/extensions.hpp" #include "../mwbase/environment.hpp" @@ -93,12 +92,12 @@ namespace MWGui scanner.listKeywords (mNames); // identifier - const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + const MWWorld::ESMStore& store = + MWBase::Environment::get().getWorld()->getStore(); - for (ESMS::RecListList::const_iterator iter (store.recLists.begin()); - iter!=store.recLists.end(); ++iter) + for (MWWorld::ESMStore::iterator it = store.begin(); it != store.end(); ++it) { - iter->second->listIdentifier (mNames); + it->second->listIdentifier (mNames); } // sort diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 5c202941f..20bc95445 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -127,10 +127,13 @@ void ContainerBase::onSelectedItem(MyGUI::Widget* _sender) if (isInventory()) { + const MWWorld::Store &gmst = + MWBase::Environment::get().getWorld()->getStore().get(); + // the player is trying to sell an item, check if the merchant accepts it // also, don't allow selling gold (let's be better than Morrowind at this, can we?) if (!MWBase::Environment::get().getWindowManager()->getTradeWindow()->npcAcceptsItem(object) || - MWWorld::Class::get(object).getName(object) == MWBase::Environment::get().getWorld()->getStore().gameSettings.find("sGold")->getString()) + MWWorld::Class::get(object).getName(object) == gmst.find("sGold")->getString()) { // user notification "i don't buy this item" MWBase::Environment::get().getWindowManager()-> @@ -274,7 +277,7 @@ void ContainerBase::onContainerClicked(MyGUI::Widget* _sender) if (mPtr.getTypeName() == typeid(ESM::Container).name()) { MWWorld::LiveCellRef* ref = mPtr.get(); - if (ref->base->mFlags & ESM::Container::Organic) + if (ref->mBase->mFlags & ESM::Container::Organic) { // user notification MWBase::Environment::get().getWindowManager()-> diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 27c3288ae..08d425032 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -1,7 +1,7 @@ #ifndef MGUI_CONTAINER_H #define MGUI_CONTAINER_H -#include +#include "../mwworld/esmstore.hpp" #include "window_base.hpp" #include "referenceinterface.hpp" diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 23d2197b7..2809e842a 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -6,12 +6,15 @@ #include #include -#include +#include "../mwworld/esmstore.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/dialoguemanager.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/mechanicsmanager.hpp" + +#include "../mwmechanics/npcstats.hpp" #include "dialogue_history.hpp" #include "widgets.hpp" @@ -45,17 +48,95 @@ std::string::size_type find_str_ci(const std::string& str, const std::string& su return lower_string(str).find(lower_string(substr),pos); } +bool sortByLength (const std::string& left, const std::string& right) +{ + return left.size() > right.size(); +} + } + +PersuasionDialog::PersuasionDialog(MWBase::WindowManager &parWindowManager) + : WindowModal("openmw_persuasion_dialog.layout", parWindowManager) +{ + getWidget(mCancelButton, "CancelButton"); + getWidget(mAdmireButton, "AdmireButton"); + getWidget(mIntimidateButton, "IntimidateButton"); + getWidget(mTauntButton, "TauntButton"); + getWidget(mBribe10Button, "Bribe10Button"); + getWidget(mBribe100Button, "Bribe100Button"); + getWidget(mBribe1000Button, "Bribe1000Button"); + getWidget(mGoldLabel, "GoldLabel"); + + mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onCancel); + mAdmireButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); + mIntimidateButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); + mTauntButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); + mBribe10Button->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); + mBribe100Button->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); + mBribe1000Button->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); +} + +void PersuasionDialog::onCancel(MyGUI::Widget *sender) +{ + setVisible(false); +} + +void PersuasionDialog::onPersuade(MyGUI::Widget *sender) +{ + MWBase::MechanicsManager::PersuasionType type; + if (sender == mAdmireButton) type = MWBase::MechanicsManager::PT_Admire; + else if (sender == mIntimidateButton) type = MWBase::MechanicsManager::PT_Intimidate; + else if (sender == mTauntButton) type = MWBase::MechanicsManager::PT_Taunt; + else if (sender == mBribe10Button) + { + mWindowManager.getTradeWindow()->addOrRemoveGold(-10); + type = MWBase::MechanicsManager::PT_Bribe10; + } + else if (sender == mBribe100Button) + { + mWindowManager.getTradeWindow()->addOrRemoveGold(-100); + type = MWBase::MechanicsManager::PT_Bribe100; + } + else /*if (sender == mBribe1000Button)*/ + { + mWindowManager.getTradeWindow()->addOrRemoveGold(-1000); + type = MWBase::MechanicsManager::PT_Bribe1000; + } + + MWBase::Environment::get().getDialogueManager()->persuade(type); + + setVisible(false); +} + +void PersuasionDialog::open() +{ + WindowModal::open(); + center(); + + int playerGold = mWindowManager.getInventoryWindow()->getPlayerGold(); + + mBribe10Button->setEnabled (playerGold >= 10); + mBribe100Button->setEnabled (playerGold >= 100); + mBribe1000Button->setEnabled (playerGold >= 1000); + + mGoldLabel->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast(playerGold)); +} + +// -------------------------------------------------------------------------------------------------- + DialogueWindow::DialogueWindow(MWBase::WindowManager& parWindowManager) : WindowBase("openmw_dialogue_window.layout", parWindowManager) - , mEnabled(true) + , mPersuasionDialog(parWindowManager) + , mEnabled(false) , mServices(0) { // Centre dialog center(); + mPersuasionDialog.setVisible(false); + //History view getWidget(mHistory, "History"); mHistory->setOverflowToTheLeft(true); @@ -127,33 +208,40 @@ void DialogueWindow::onSelectTopic(std::string topic) { if (!mEnabled) return; - if (topic == MWBase::Environment::get().getWorld()->getStore().gameSettings.find("sBarter")->getString()) + const MWWorld::Store &gmst = + MWBase::Environment::get().getWorld()->getStore().get(); + + if (topic == gmst.find("sBarter")->getString()) { /// \todo check if the player is allowed to trade with this actor (e.g. faction rank high enough)? mWindowManager.pushGuiMode(GM_Barter); mWindowManager.getTradeWindow()->startTrade(mPtr); } - else if (topic == MWBase::Environment::get().getWorld()->getStore().gameSettings.find("sSpells")->getString()) + if (topic == gmst.find("sPersuasion")->getString()) + { + mPersuasionDialog.setVisible(true); + } + else if (topic == gmst.find("sSpells")->getString()) { mWindowManager.pushGuiMode(GM_SpellBuying); mWindowManager.getSpellBuyingWindow()->startSpellBuying(mPtr); } - else if (topic == MWBase::Environment::get().getWorld()->getStore().gameSettings.find("sTravel")->getString()) + else if (topic == gmst.find("sTravel")->getString()) { mWindowManager.pushGuiMode(GM_Travel); mWindowManager.getTravelWindow()->startTravel(mPtr); } - else if (topic == MWBase::Environment::get().getWorld()->getStore().gameSettings.find("sSpellMakingMenuTitle")->getString()) + else if (topic == gmst.find("sSpellMakingMenuTitle")->getString()) { mWindowManager.pushGuiMode(GM_SpellCreation); mWindowManager.startSpellMaking (mPtr); } - else if (topic == MWBase::Environment::get().getWorld()->getStore().gameSettings.find("sEnchanting")->getString()) + else if (topic == gmst.find("sEnchanting")->getString()) { mWindowManager.pushGuiMode(GM_Enchanting); mWindowManager.startEnchanting (mPtr); } - else if (topic == MWBase::Environment::get().getWorld()->getStore().gameSettings.find("sServiceTrainingTitle")->getString()) + else if (topic == gmst.find("sServiceTrainingTitle")->getString()) { mWindowManager.pushGuiMode(GM_Training); mWindowManager.startTraining (mPtr); @@ -170,7 +258,7 @@ void DialogueWindow::startDialogue(MWWorld::Ptr actor, std::string npcName) setTitle(npcName); mTopicsList->clear(); - mHistory->eraseText(0,mHistory->getTextLength()); + mHistory->setCaption(""); updateOptions(); } @@ -180,25 +268,31 @@ void DialogueWindow::setKeywords(std::list keyWords) bool anyService = mServices > 0; + const MWWorld::Store &gmst = + MWBase::Environment::get().getWorld()->getStore().get(); + + if (mPtr.getTypeName() == typeid(ESM::NPC).name()) + mTopicsList->addItem(gmst.find("sPersuasion")->getString()); + if (mServices & Service_Trade) - mTopicsList->addItem(MWBase::Environment::get().getWorld()->getStore().gameSettings.find("sBarter")->getString()); + mTopicsList->addItem(gmst.find("sBarter")->getString()); if (mServices & Service_BuySpells) - mTopicsList->addItem(MWBase::Environment::get().getWorld()->getStore().gameSettings.find("sSpells")->getString()); + mTopicsList->addItem(gmst.find("sSpells")->getString()); if (mServices & Service_Travel) - mTopicsList->addItem(MWBase::Environment::get().getWorld()->getStore().gameSettings.find("sTravel")->getString()); + mTopicsList->addItem(gmst.find("sTravel")->getString()); if (mServices & Service_CreateSpells) - mTopicsList->addItem(MWBase::Environment::get().getWorld()->getStore().gameSettings.find("sSpellmakingMenuTitle")->getString()); + mTopicsList->addItem(gmst.find("sSpellmakingMenuTitle")->getString()); - if (mServices & Service_Enchant) - mTopicsList->addItem(MWBase::Environment::get().getWorld()->getStore().gameSettings.find("sEnchanting")->getString()); +// if (mServices & Service_Enchant) +// mTopicsList->addItem(gmst.find("sEnchanting")->getString()); if (mServices & Service_Training) - mTopicsList->addItem(MWBase::Environment::get().getWorld()->getStore().gameSettings.find("sServiceTrainingTitle")->getString()); + mTopicsList->addItem(gmst.find("sServiceTrainingTitle")->getString()); - if (anyService) + if (anyService || mPtr.getTypeName() == typeid(ESM::NPC).name()) mTopicsList->addSeparator(); for(std::list::iterator it = keyWords.begin(); it != keyWords.end(); ++it) @@ -222,43 +316,52 @@ void addColorInString(std::string& str, const std::string& keyword,std::string c size_t pos = 0; while((pos = find_str_ci(str,keyword, pos)) != std::string::npos) { - if(pos==0) + // do not add color if this portion of text is already colored. { - str.insert(pos,color1); - pos += color1.length(); - pos += keyword.length(); - str.insert(pos,color2); - pos+= color2.length(); - } - else - { - if(str.substr(pos -1,1) == " ") + MyGUI::TextIterator iterator (str); + MyGUI::UString colour; + while(iterator.moveNext()) { - str.insert(pos,color1); - pos += color1.length(); - pos += keyword.length(); - str.insert(pos,color2); - pos+= color2.length(); - } - else - { - pos += keyword.length(); + size_t iteratorPos = iterator.getPosition(); + iterator.getTagColour(colour); + if (iteratorPos == pos) + break; } + + if (colour == color1) + return; } + + str.insert(pos,color1); + pos += color1.length(); + pos += keyword.length(); + str.insert(pos,color2); + pos+= color2.length(); } } std::string DialogueWindow::parseText(std::string text) { bool separatorReached = false; // only parse topics that are below the separator (this prevents actions like "Barter" that are not topics from getting blue-colored) + + std::vector topics; + for(unsigned int i = 0;igetItemCount();i++) { std::string keyWord = mTopicsList->getItemNameAt(i); - if (separatorReached && keyWord != "") - addColorInString(text,keyWord,"#686EBA","#B29154"); - else + if (separatorReached) + topics.push_back(keyWord); + else if (keyWord == "") separatorReached = true; } + + // sort by length to make sure longer topics are replaced first + std::sort(topics.begin(), topics.end(), sortByLength); + + for(std::vector::const_iterator it = topics.begin(); it != topics.end(); ++it) + { + addColorInString(text,*it,"#686EBA","#B29154"); + } return text; } @@ -267,6 +370,11 @@ void DialogueWindow::addText(std::string text) mHistory->addDialogText("#B29154"+parseText(text)+"#B29154"); } +void DialogueWindow::addMessageBox(const std::string& text) +{ + mHistory->addDialogText("\n#FFFFFF"+text+"#B29154"); +} + void DialogueWindow::addTitle(std::string text) { // This is called from the dialogue manager, so text is @@ -293,15 +401,18 @@ void DialogueWindow::updateOptions() mTopicsList->clear(); mHistory->eraseText(0, mHistory->getTextLength()); - mDispositionBar->setProgressRange(100); - mDispositionBar->setProgressPosition(40); - mDispositionText->eraseText(0, mDispositionText->getTextLength()); - mDispositionText->addText("#B29154"+std::string("40/100")+"#B29154"); + if (mPtr.getTypeName() == typeid(ESM::NPC).name()) + { + mDispositionBar->setProgressRange(100); + mDispositionBar->setProgressPosition(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr)); + mDispositionText->eraseText(0, mDispositionText->getTextLength()); + mDispositionText->addText("#B29154"+boost::lexical_cast(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr))+std::string("/100")+"#B29154"); + } } void DialogueWindow::goodbye() { - mHistory->addDialogText("\n#572D21" + MWBase::Environment::get().getWorld()->getStore().gameSettings.find("sGoodbye")->getString()); + mHistory->addDialogText("\n#572D21" + MWBase::Environment::get().getWorld()->getStore().get().find("sGoodbye")->getString()); mTopicsList->setEnabled(false); mEnabled = false; } @@ -310,3 +421,17 @@ void DialogueWindow::onReferenceUnavailable() { mWindowManager.removeGuiMode(GM_Dialogue); } + +void DialogueWindow::onFrame() +{ + if(mEnabled && mPtr.getTypeName() == typeid(ESM::NPC).name()) + { + int disp = std::max(0, std::min(100, + MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr) + + MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange())); + mDispositionBar->setProgressRange(100); + mDispositionBar->setProgressPosition(disp); + mDispositionText->eraseText(0, mDispositionText->getTextLength()); + mDispositionText->addText("#B29154"+boost::lexical_cast(disp)+std::string("/100")+"#B29154"); + } +} diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 3a89409ca..72bb6d19a 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -26,6 +26,27 @@ namespace MWGui { class DialogueHistory; + class PersuasionDialog : public WindowModal + { + public: + PersuasionDialog(MWBase::WindowManager& parWindowManager); + + virtual void open(); + + private: + MyGUI::Button* mCancelButton; + MyGUI::Button* mAdmireButton; + MyGUI::Button* mIntimidateButton; + MyGUI::Button* mTauntButton; + MyGUI::Button* mBribe10Button; + MyGUI::Button* mBribe100Button; + MyGUI::Button* mBribe1000Button; + MyGUI::TextBox* mGoldLabel; + + void onCancel (MyGUI::Widget* sender); + void onPersuade (MyGUI::Widget* sender); + }; + class DialogueWindow: public WindowBase, public ReferenceInterface { public: @@ -44,9 +65,11 @@ namespace MWGui void setKeywords(std::list keyWord); void removeKeyword(std::string keyWord); void addText(std::string text); + void addMessageBox(const std::string& text); void addTitle(std::string text); void askQuestion(std::string question); void goodbye(); + void onFrame(); // make sure to call these before setKeywords() void setServices(int services) { mServices = services; } @@ -85,6 +108,8 @@ namespace MWGui Widgets::MWList* mTopicsList; MyGUI::ProgressPtr mDispositionBar; MyGUI::EditPtr mDispositionText; + + PersuasionDialog mPersuasionDialog; }; } #endif diff --git a/apps/openmw/mwgui/dialogue_history.cpp b/apps/openmw/mwgui/dialogue_history.cpp index 4ca764c82..13f72545e 100644 --- a/apps/openmw/mwgui/dialogue_history.cpp +++ b/apps/openmw/mwgui/dialogue_history.cpp @@ -3,7 +3,8 @@ #include "../mwbase/windowmanager.hpp" #include "widgets.hpp" -#include "components/esm_store/store.hpp" + +#include "../mwworld/esmstore.hpp" #include #include diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index 53c23c25d..4090b592d 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -1,5 +1,10 @@ #include "formatting.hpp" +#include + +#include "../mwscript/interpretercontext.hpp" +#include "../mwworld/ptr.hpp" + #include #include @@ -68,6 +73,9 @@ std::vector BookTextParser::split(std::string text, const int width { std::vector result; + MWScript::InterpreterContext interpreterContext(NULL, MWWorld::Ptr()); // empty arguments, because there is no locals or actor + text = Interpreter::fixDefinesBook(text, interpreterContext); + boost::algorithm::replace_all(text, "
", "\n"); boost::algorithm::replace_all(text, "

", "\n\n"); @@ -167,6 +175,10 @@ std::vector BookTextParser::split(std::string text, const int width MyGUI::IntSize BookTextParser::parse(std::string text, MyGUI::Widget* parent, const int width) { + MWScript::InterpreterContext interpreterContext(NULL, MWWorld::Ptr()); // empty arguments, because there is no locals or actor + text = Interpreter::fixDefinesBook(text, interpreterContext); + + mParent = parent; mWidth = width; mHeight = 0; diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 66cc6b21a..689baf488 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -319,7 +319,7 @@ void HUD::setCellName(const std::string& cellName) mCellNameTimer = 5.0f; mCellName = cellName; - mCellNameBox->setCaption(mCellName); + mCellNameBox->setCaptionWithReplacing("#{sCell=" + mCellName + "}"); mCellNameBox->setVisible(mMapVisible); } } @@ -341,7 +341,9 @@ void HUD::onResChange(int width, int height) void HUD::setSelectedSpell(const std::string& spellId, int successChancePercent) { - const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(spellId); + const ESM::Spell* spell = + MWBase::Environment::get().getWorld()->getStore().get().find(spellId); + std::string spellName = spell->mName; if (spellName != mSpellName && mSpellVisible) { @@ -361,7 +363,9 @@ void HUD::setSelectedSpell(const std::string& spellId, int successChancePercent) mSpellBox->setUserString("Spell", spellId); // use the icon of the first effect - const ESM::MagicEffect* effect = MWBase::Environment::get().getWorld()->getStore().magicEffects.find(spell->mEffects.mList.front().mEffectID); + const ESM::MagicEffect* effect = + MWBase::Environment::get().getWorld()->getStore().get().find(spell->mEffects.mList.front().mEffectID); + std::string icon = effect->mIcon; int slashPos = icon.find("\\"); icon.insert(slashPos+1, "b_"); diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 84b576a58..6b45a9980 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -28,6 +28,10 @@ namespace MWGui MWWorld::Ptr getAvatarSelectedItem(int x, int y); + void rebuildAvatar() { + mPreview.rebuild(); + } + protected: MyGUI::Widget* mAvatar; MyGUI::ImageBox* mAvatarImage; diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index 7dced94f5..45890b89f 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -8,14 +8,12 @@ #include "../mwworld/player.hpp" #include "../mwworld/class.hpp" +#include "../mwworld/esmstore.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/stat.hpp" -#include -#include - namespace MWGui { @@ -110,7 +108,8 @@ namespace MWGui void LevelupDialog::open() { - MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayer().getPlayer(); + MWBase::World *world = MWBase::Environment::get().getWorld(); + MWWorld::Ptr player = world->getPlayer().getPlayer(); MWMechanics::CreatureStats& creatureStats = MWWorld::Class::get(player).getCreatureStats (player); MWMechanics::NpcStats& pcStats = MWWorld::Class::get(player).getNpcStats (player); @@ -121,17 +120,13 @@ namespace MWGui setAttributeValues(); + const ESM::NPC *playerData = player.get()->mBase; + // set class image - const ESM::Class& playerClass = MWBase::Environment::get().getWorld ()->getPlayer ().getClass (); - // retrieve the ID to this class - std::string classId; - std::map list = MWBase::Environment::get().getWorld()->getStore ().classes.list; - for (std::map::iterator it = list.begin(); it != list.end(); ++it) - { - if (playerClass.mName == it->second.mName) - classId = it->first; - } - mClassImage->setImageTexture ("textures\\levelup\\" + classId + ".dds"); + const ESM::Class *cls = + world->getStore().get().find(playerData->mClass); + + mClassImage->setImageTexture ("textures\\levelup\\" + cls->mId + ".dds"); /// \todo replace this with INI-imported texts int level = creatureStats.getLevel ()+1; diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 8bcaa6ce0..d721e209a 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -226,9 +226,14 @@ namespace MWGui if (start == "splash") splash.push_back (*it); } - std::string randomSplash = splash[rand() % splash.size()]; + if (splash.size()) + { + std::string randomSplash = splash[rand() % splash.size()]; - Ogre::TexturePtr tex = Ogre::TextureManager::getSingleton ().load (randomSplash, "General"); - mBackgroundImage->setImageTexture (randomSplash); + Ogre::TexturePtr tex = Ogre::TextureManager::getSingleton ().load (randomSplash, "General"); + mBackgroundImage->setImageTexture (randomSplash); + } + else + std::cerr << "No loading screens found!" << std::endl; } } diff --git a/apps/openmw/mwgui/map_window.cpp b/apps/openmw/mwgui/map_window.cpp index 1913ed8dd..4e2ee517e 100644 --- a/apps/openmw/mwgui/map_window.cpp +++ b/apps/openmw/mwgui/map_window.cpp @@ -269,10 +269,12 @@ MapWindow::MapWindow(MWBase::WindowManager& parWindowManager, const std::string& getWidget(mLocalMap, "LocalMap"); getWidget(mGlobalMap, "GlobalMap"); getWidget(mGlobalMapImage, "GlobalMapImage"); + getWidget(mGlobalMapOverlay, "GlobalMapOverlay"); getWidget(mPlayerArrowLocal, "CompassLocal"); getWidget(mPlayerArrowGlobal, "CompassGlobal"); mGlobalMapImage->setImageTexture("GlobalMap.png"); + mGlobalMapOverlay->setImageTexture("GlobalMapOverlay"); mGlobalMap->setVisible (false); @@ -297,7 +299,7 @@ MapWindow::~MapWindow() void MapWindow::setCellName(const std::string& cellName) { - setTitle(cellName); + setTitle("#{sCell=" + cellName + "}"); } void MapWindow::addVisitedLocation(const std::string& name, int x, int y) @@ -328,6 +330,11 @@ void MapWindow::addVisitedLocation(const std::string& name, int x, int y) markerWidget->setUserString("Caption_Text", name); } +void MapWindow::cellExplored(int x, int y) +{ + mGlobalMapRender->exploreCell(x,y); +} + void MapWindow::onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) { if (_id!=MyGUI::MouseButton::Left) return; diff --git a/apps/openmw/mwgui/map_window.hpp b/apps/openmw/mwgui/map_window.hpp index 73eaad1cd..4e2dd6756 100644 --- a/apps/openmw/mwgui/map_window.hpp +++ b/apps/openmw/mwgui/map_window.hpp @@ -70,6 +70,7 @@ namespace MWGui void setCellName(const std::string& cellName); void addVisitedLocation(const std::string& name, int x, int y); // adds the marker to the global map + void cellExplored(int x, int y); virtual void open(); @@ -82,6 +83,7 @@ namespace MWGui MyGUI::ScrollView* mGlobalMap; MyGUI::ImageBox* mGlobalMapImage; + MyGUI::ImageBox* mGlobalMapOverlay; MyGUI::ImageBox* mPlayerArrowLocal; MyGUI::ImageBox* mPlayerArrowGlobal; MyGUI::Button* mButton; diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index e927af95d..02512425d 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -29,8 +29,11 @@ namespace bool sortSpells(const std::string& left, const std::string& right) { - const ESM::Spell* a = MWBase::Environment::get().getWorld()->getStore().spells.find(left); - const ESM::Spell* b = MWBase::Environment::get().getWorld()->getStore().spells.find(right); + const MWWorld::Store &spells = + MWBase::Environment::get().getWorld()->getStore().get(); + + const ESM::Spell* a = spells.find(left); + const ESM::Spell* b = spells.find(right); int cmp = a->mName.compare(b->mName); return cmp < 0; @@ -234,9 +237,15 @@ namespace MWGui MyGUI::ImageBox* image = frame->createWidget("ImageBox", MyGUI::IntCoord(5, 5, 32, 32), MyGUI::Align::Default); + const MWWorld::ESMStore &esmStore = + MWBase::Environment::get().getWorld()->getStore(); + // use the icon of the first effect - const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(spellId); - const ESM::MagicEffect* effect = MWBase::Environment::get().getWorld()->getStore().magicEffects.find(spell->mEffects.mList.front().mEffectID); + const ESM::Spell* spell = esmStore.get().find(spellId); + + const ESM::MagicEffect* effect = + esmStore.get().find(spell->mEffects.mList.front().mEffectID); + std::string path = effect->mIcon; int slashPos = path.find("\\"); path.insert(slashPos+1, "b_"); @@ -434,11 +443,14 @@ namespace MWGui spellList.push_back(*it); } + const MWWorld::ESMStore &esmStore = + MWBase::Environment::get().getWorld()->getStore(); + std::vector powers; std::vector::iterator it = spellList.begin(); while (it != spellList.end()) { - const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(*it); + const ESM::Spell* spell = esmStore.get().find(*it); if (spell->mData.mType == ESM::Spell::ST_Power) { powers.push_back(*it); @@ -465,7 +477,9 @@ namespace MWGui if (enchantId != "") { // only add items with "Cast once" or "Cast on use" - const ESM::Enchantment* enchant = MWBase::Environment::get().getWorld()->getStore().enchants.find(enchantId); + const ESM::Enchantment* enchant = + esmStore.get().find(enchantId); + int type = enchant->mData.mType; if (type != ESM::Enchantment::CastOnce && type != ESM::Enchantment::WhenUsed) @@ -487,7 +501,7 @@ namespace MWGui for (std::vector::const_iterator it = powers.begin(); it != powers.end(); ++it) { - const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(*it); + const ESM::Spell* spell = esmStore.get().find(*it); MyGUI::Button* t = mMagicList->createWidget("SpellText", MyGUI::IntCoord(4, mHeight, mWidth-8, spellHeight), MyGUI::Align::Left | MyGUI::Align::Top); t->setCaption(spell->mName); @@ -504,7 +518,7 @@ namespace MWGui addGroup("#{sSpells}", ""); for (std::vector::const_iterator it = spellList.begin(); it != spellList.end(); ++it) { - const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(*it); + const ESM::Spell* spell = esmStore.get().find(*it); MyGUI::Button* t = mMagicList->createWidget("SpellText", MyGUI::IntCoord(4, mHeight, mWidth-8, spellHeight), MyGUI::Align::Left | MyGUI::Align::Top); t->setCaption(spell->mName); diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index d681bc69d..d2714fb51 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -5,8 +5,9 @@ #include #include +#include -#include +#include "../mwworld/esmstore.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -108,6 +109,16 @@ void RaceDialog::open() MWBase::Environment::get().getWorld ()->setupExternalRendering (*mPreview); mPreview->update (0); + const ESM::NPC proto = mPreview->getPrototype(); + setRaceId(proto.mRace); + recountParts(); + + std::string index = proto.mHead.substr(proto.mHead.size() - 2, 2); + mFaceIndex = boost::lexical_cast(index) - 1; + + index = proto.mHair.substr(proto.mHair.size() - 2, 2); + mHairIndex = boost::lexical_cast(index) - 1; + mPreviewImage->setImageTexture ("CharacterHeadPreview"); } @@ -143,6 +154,35 @@ int wrap(int index, int max) return index; } +int countParts(const std::string &part, const std::string &race, bool male) +{ + const MWWorld::Store &store = + MWBase::Environment::get().getWorld()->getStore().get(); + + std::string prefix = + "b_n_" + race + ((male) ? "_m_" : "_f_") + part; + + std::string suffix; + suffix.reserve(prefix.size() + 3); + + int count = -1; + do { + ++count; + suffix = "_" + (boost::format("%02d") % (count + 1)).str(); + } + while (store.search(prefix + suffix) != 0); + + if (count == 0 && part == "hair") { + count = -1; + do { + ++count; + suffix = (boost::format("%02d") % (count + 1)).str(); + } + while (store.search(prefix + suffix) != 0); + } + return count; +} + void RaceDialog::close() { delete mPreview; @@ -174,31 +214,41 @@ void RaceDialog::onHeadRotate(MyGUI::ScrollBar*, size_t _position) void RaceDialog::onSelectPreviousGender(MyGUI::Widget*) { mGenderIndex = wrap(mGenderIndex - 1, 2); + + recountParts(); + updatePreview(); } void RaceDialog::onSelectNextGender(MyGUI::Widget*) { mGenderIndex = wrap(mGenderIndex + 1, 2); + + recountParts(); + updatePreview(); } void RaceDialog::onSelectPreviousFace(MyGUI::Widget*) { mFaceIndex = wrap(mFaceIndex - 1, mFaceCount); + updatePreview(); } void RaceDialog::onSelectNextFace(MyGUI::Widget*) { mFaceIndex = wrap(mFaceIndex + 1, mFaceCount); + updatePreview(); } void RaceDialog::onSelectPreviousHair(MyGUI::Widget*) { mHairIndex = wrap(mHairIndex - 1, mHairCount); + updatePreview(); } void RaceDialog::onSelectNextHair(MyGUI::Widget*) { - mHairIndex = wrap(mHairIndex - 1, mHairCount); + mHairIndex = wrap(mHairIndex + 1, mHairCount); + updatePreview(); } void RaceDialog::onSelectRace(MyGUI::ListBox* _sender, size_t _index) @@ -214,30 +264,67 @@ void RaceDialog::onSelectRace(MyGUI::ListBox* _sender, size_t _index) return; mCurrentRaceId = *raceId; + + recountParts(); + + updatePreview(); updateSkills(); updateSpellPowers(); } +void RaceDialog::recountParts() +{ + mFaceIndex = 0; + mHairIndex = 0; + + mFaceCount = countParts("head", mCurrentRaceId, mGenderIndex == 0); + mHairCount = countParts("hair", mCurrentRaceId, mGenderIndex == 0); +} + // update widget content +void RaceDialog::updatePreview() +{ + ESM::NPC record = mPreview->getPrototype(); + record.mRace = mCurrentRaceId; + record.setIsMale(mGenderIndex == 0); + + std::string prefix = + "b_n_" + mCurrentRaceId + ((record.isMale()) ? "_m_" : "_f_"); + + std::string headIndex = (boost::format("%02d") % (mFaceIndex + 1)).str(); + std::string hairIndex = (boost::format("%02d") % (mHairIndex + 1)).str(); + + record.mHead = prefix + "head_" + headIndex; + record.mHair = prefix + "hair_" + hairIndex; + + const MWWorld::Store &parts = + MWBase::Environment::get().getWorld()->getStore().get(); + + if (parts.search(record.mHair) == 0) { + record.mHair = prefix + "hair" + hairIndex; + } + mPreview->setPrototype(record); +} + void RaceDialog::updateRaces() { mRaceList->removeAllItems(); - const ESMS::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + const MWWorld::Store &races = + MWBase::Environment::get().getWorld()->getStore().get(); - ESMS::RecListT::MapType::const_iterator it = store.races.list.begin(); - ESMS::RecListT::MapType::const_iterator end = store.races.list.end(); + int index = 0; - for (; it != end; ++it) + MWWorld::Store::iterator it = races.begin(); + for (; it != races.end(); ++it) { - const ESM::Race &race = it->second; - bool playable = race.mData.mFlags & ESM::Race::Playable; + bool playable = it->mData.mFlags & ESM::Race::Playable; if (!playable) // Only display playable races continue; - mRaceList->addItem(race.mName, it->first); - if (boost::iequals(it->first, mCurrentRaceId)) + mRaceList->addItem(it->mName, it->mId); + if (boost::iequals(it->mId, mCurrentRaceId)) mRaceList->setIndexSelected(index); ++index; } @@ -258,8 +345,8 @@ void RaceDialog::updateSkills() const int lineHeight = 18; MyGUI::IntCoord coord1(0, 0, mSkillList->getWidth(), 18); - const ESMS::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - const ESM::Race *race = store.races.find(mCurrentRaceId); + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + const ESM::Race *race = store.get().find(mCurrentRaceId); int count = sizeof(race->mData.mBonus)/sizeof(race->mData.mBonus[0]); // TODO: Find a portable macro for this ARRAYSIZE? for (int i = 0; i < count; ++i) { @@ -296,8 +383,8 @@ void RaceDialog::updateSpellPowers() const int lineHeight = 18; MyGUI::IntCoord coord(0, 0, mSpellPowerList->getWidth(), 18); - const ESMS::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - const ESM::Race *race = store.races.find(mCurrentRaceId); + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + const ESM::Race *race = store.get().find(mCurrentRaceId); std::vector::const_iterator it = race->mPowers.mList.begin(); std::vector::const_iterator end = race->mPowers.mList.end(); diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index c4734eae8..e0dc3306a 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -4,7 +4,7 @@ #include -#include +#include "../mwworld/esmstore.hpp" #include "../mwrender/characterpreview.hpp" @@ -34,6 +34,7 @@ namespace MWGui GM_Female }; + const ESM::NPC &getResult() const { return mPreview->getPrototype(); } const std::string &getRaceId() const { return mCurrentRaceId; } Gender getGender() const { return mGenderIndex == 0 ? GM_Male : GM_Female; } // getFace() @@ -77,6 +78,8 @@ namespace MWGui void updateRaces(); void updateSkills(); void updateSpellPowers(); + void updatePreview(); + void recountParts(); MyGUI::ImageBox* mPreviewImage; MyGUI::ListBox* mRaceList; diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 984c7d1ae..45adb5383 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include "../mwworld/esmstore.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -108,7 +108,9 @@ void ReviewDialog::setPlayerName(const std::string &name) void ReviewDialog::setRace(const std::string &raceId) { mRaceId = raceId; - const ESM::Race *race = MWBase::Environment::get().getWorld()->getStore().races.search(mRaceId); + + const ESM::Race *race = + MWBase::Environment::get().getWorld()->getStore().get().search(mRaceId); if (race) { ToolTips::createRaceToolTip(mRaceWidget, race); @@ -126,7 +128,9 @@ void ReviewDialog::setClass(const ESM::Class& class_) void ReviewDialog::setBirthSign(const std::string& signId) { mBirthSignId = signId; - const ESM::BirthSign *sign = MWBase::Environment::get().getWorld()->getStore().birthSigns.search(mBirthSignId); + + const ESM::BirthSign *sign = + MWBase::Environment::get().getWorld()->getStore().get().search(mBirthSignId); if (sign) { mBirthSignWidget->setCaption(sign->mName); @@ -281,7 +285,7 @@ void ReviewDialog::addSkills(const SkillList &skills, const std::string &titleId if (skillId < 0 || skillId > ESM::Skill::Length) // Skip unknown skill indexes continue; assert(skillId >= 0 && skillId < ESM::Skill::Length); - const std::string &skillNameId = ESMS::Skill::sSkillNameIds[skillId]; + const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId]; const MWMechanics::Stat &stat = mSkillValues.find(skillId)->second; float base = stat.getBase(); float modified = stat.getModified(); diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index c839e9b73..8317025e0 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -36,7 +36,7 @@ void ScrollWindow::open (MWWorld::Ptr scroll) MWWorld::LiveCellRef *ref = mScroll.get(); BookTextParser parser; - MyGUI::IntSize size = parser.parse(ref->base->mText, mTextView, 390); + MyGUI::IntSize size = parser.parse(ref->mBase->mText, mTextView, 390); if (size.height > mTextView->getSize().height) mTextView->setCanvasSize(MyGUI::IntSize(410, size.height)); diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index ece19cdc3..a41f401a5 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -8,6 +8,7 @@ #include "../mwbase/world.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/player.hpp" #include "../mwworld/manualref.hpp" @@ -49,8 +50,12 @@ namespace MWGui void SpellBuyingWindow::addSpell(const std::string& spellId) { - const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(spellId); - int price = spell->mData.mCost*MWBase::Environment::get().getWorld()->getStore().gameSettings.find("fSpellValueMult")->getFloat(); + const MWWorld::ESMStore &store = + MWBase::Environment::get().getWorld()->getStore(); + + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(spellId); + int price = spell->mData.mCost*store.get().find("fSpellValueMult")->getFloat(); + price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr,price,true); MyGUI::Button* toAdd = mSpellsView->createWidget( @@ -63,7 +68,6 @@ namespace MWGui ); mCurrentY += sLineHeight; - /// \todo price adjustment depending on merchantile skill toAdd->setUserData(price); toAdd->setCaptionWithReplacing(spell->mName+" - "+boost::lexical_cast(price)+"#{sgp}"); @@ -97,7 +101,8 @@ namespace MWGui for (MWMechanics::Spells::TIterator iter = merchantSpells.begin(); iter!=merchantSpells.end(); ++iter) { - const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find (*iter); + const ESM::Spell* spell = + MWBase::Environment::get().getWorld()->getStore().get().find (*iter); if (spell->mData.mType!=ESM::Spell::ST_Spell) continue; // don't try to sell diseases, curses or powers diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 4ce056010..69d69519f 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -2,14 +2,14 @@ #include -#include - #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" +#include "../mwbase/mechanicsmanager.hpp" +#include "../mwworld/esmstore.hpp" #include "../mwworld/player.hpp" #include "../mwworld/class.hpp" @@ -29,8 +29,11 @@ namespace bool sortMagicEffects (short id1, short id2) { - return MWBase::Environment::get().getWorld ()->getStore ().gameSettings.find(ESM::MagicEffect::effectIdToString (id1))->getString() - < MWBase::Environment::get().getWorld ()->getStore ().gameSettings.find(ESM::MagicEffect::effectIdToString (id2))->getString(); + const MWWorld::Store &gmst = + MWBase::Environment::get().getWorld()->getStore().get(); + + return gmst.find(ESM::MagicEffect::effectIdToString (id1))->getString() + < gmst.find(ESM::MagicEffect::effectIdToString (id2))->getString(); } } @@ -106,7 +109,8 @@ namespace MWGui void EditEffectDialog::editEffect (ESM::ENAMstruct effect) { - const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().magicEffects.find(effect.mEffectID); + const ESM::MagicEffect* magicEffect = + MWBase::Environment::get().getWorld()->getStore().get().find(effect.mEffectID); setMagicEffect(magicEffect); @@ -291,6 +295,7 @@ namespace MWGui void SpellCreationDialog::startSpellMaking (MWWorld::Ptr actor) { mPtr = actor; + mNameEdit->setCaption(""); startEditing(); } @@ -332,12 +337,12 @@ namespace MWGui MWBase::Environment::get().getSoundManager()->playSound ("Item Gold Up", 1.0, 1.0); - std::pair result = MWBase::Environment::get().getWorld()->createRecord(mSpell); + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->createRecord(mSpell); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player); MWMechanics::Spells& spells = stats.getSpells(); - spells.add (result.first); + spells.add (spell->mId); MWBase::Environment::get().getSoundManager()->playSound ("Item Gold Up", 1.0, 1.0); @@ -359,16 +364,23 @@ namespace MWGui { float y = 0; + const MWWorld::ESMStore &store = + MWBase::Environment::get().getWorld()->getStore(); + for (std::vector::const_iterator it = mEffects.begin(); it != mEffects.end(); ++it) { float x = 0.5 * it->mMagnMin + it->mMagnMax; - const ESM::MagicEffect* effect = MWBase::Environment::get().getWorld()->getStore().magicEffects.find(it->mEffectID); + const ESM::MagicEffect* effect = + store.get().find(it->mEffectID); + x *= 0.1 * effect->mData.mBaseCost; x *= 1 + it->mDuration; x += 0.05 * std::max(1, it->mArea) * effect->mData.mBaseCost; - float fEffectCostMult = MWBase::Environment::get().getWorld()->getStore().gameSettings.find("fEffectCostMult")->getFloat(); + float fEffectCostMult = + store.get().find("fEffectCostMult")->getFloat(); + y += x * fEffectCostMult; y = std::max(1.f,y); @@ -385,10 +397,10 @@ namespace MWGui mMagickaCost->setCaption(boost::lexical_cast(int(y))); - float fSpellMakingValueMult = MWBase::Environment::get().getWorld()->getStore().gameSettings.find("fSpellMakingValueMult")->getFloat(); + float fSpellMakingValueMult = + store.get().find("fSpellMakingValueMult")->getFloat(); - /// \todo mercantile - int price = int(y) * fSpellMakingValueMult; + int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr,int(y) * fSpellMakingValueMult,true); mPriceLabel->setCaption(boost::lexical_cast(int(price))); @@ -423,7 +435,8 @@ namespace MWGui for (MWMechanics::Spells::TIterator it = spells.begin(); it != spells.end(); ++it) { - const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(*it); + const ESM::Spell* spell = + MWBase::Environment::get().getWorld()->getStore().get().find(*it); // only normal spells count if (spell->mData.mType != ESM::Spell::ST_Spell) @@ -443,14 +456,14 @@ namespace MWGui for (std::vector::const_iterator it = knownEffects.begin(); it != knownEffects.end(); ++it) { - mAvailableEffectsList->addItem(MWBase::Environment::get().getWorld ()->getStore ().gameSettings.find( + mAvailableEffectsList->addItem(MWBase::Environment::get().getWorld ()->getStore ().get().find( ESM::MagicEffect::effectIdToString (*it))->getString()); } mAvailableEffectsList->adjustSize (); for (std::vector::const_iterator it = knownEffects.begin(); it != knownEffects.end(); ++it) { - std::string name = MWBase::Environment::get().getWorld ()->getStore ().gameSettings.find( + std::string name = MWBase::Environment::get().getWorld ()->getStore ().get().find( ESM::MagicEffect::effectIdToString (*it))->getString(); MyGUI::Widget* w = mAvailableEffectsList->getItemWidget(name); w->setUserData(*it); @@ -516,7 +529,8 @@ namespace MWGui } } - const ESM::MagicEffect* effect = MWBase::Environment::get().getWorld()->getStore().magicEffects.find(effectId); + const ESM::MagicEffect* effect = + MWBase::Environment::get().getWorld()->getStore().get().find(effectId); mAddEffectDialog.newEffect (effect); diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index a203ac92b..d62b23de4 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include "../mwworld/esmstore.hpp" #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" @@ -26,8 +26,11 @@ namespace { bool sortSpells(const std::string& left, const std::string& right) { - const ESM::Spell* a = MWBase::Environment::get().getWorld()->getStore().spells.find(left); - const ESM::Spell* b = MWBase::Environment::get().getWorld()->getStore().spells.find(right); + const MWWorld::Store &spells = + MWBase::Environment::get().getWorld()->getStore().get(); + + const ESM::Spell* a = spells.find(left); + const ESM::Spell* b = spells.find(right); int cmp = a->mName.compare(b->mName); return cmp < 0; @@ -139,11 +142,15 @@ namespace MWGui spellList.push_back(*it); } + const MWWorld::ESMStore &esmStore = + MWBase::Environment::get().getWorld()->getStore(); + std::vector powers; std::vector::iterator it = spellList.begin(); while (it != spellList.end()) { - const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(*it); + const ESM::Spell* spell = esmStore.get().find(*it); + if (spell->mData.mType == ESM::Spell::ST_Power) { powers.push_back(*it); @@ -170,7 +177,9 @@ namespace MWGui if (enchantId != "") { // only add items with "Cast once" or "Cast on use" - const ESM::Enchantment* enchant = MWBase::Environment::get().getWorld()->getStore().enchants.find(enchantId); + const ESM::Enchantment* enchant = + esmStore.get().find(enchantId); + int type = enchant->mData.mType; if (type != ESM::Enchantment::CastOnce && type != ESM::Enchantment::WhenUsed) @@ -191,7 +200,7 @@ namespace MWGui for (std::vector::const_iterator it = powers.begin(); it != powers.end(); ++it) { - const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(*it); + const ESM::Spell* spell = esmStore.get().find(*it); MyGUI::Button* t = mSpellView->createWidget("SpellText", MyGUI::IntCoord(4, mHeight, mWidth-8, spellHeight), MyGUI::Align::Left | MyGUI::Align::Top); t->setCaption(spell->mName); @@ -211,7 +220,7 @@ namespace MWGui addGroup("#{sSpells}", "#{sCostChance}"); for (std::vector::const_iterator it = spellList.begin(); it != spellList.end(); ++it) { - const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(*it); + const ESM::Spell* spell = esmStore.get().find(*it); MyGUI::Button* t = mSpellView->createWidget("SpellText", MyGUI::IntCoord(4, mHeight, mWidth-8, spellHeight), MyGUI::Align::Left | MyGUI::Align::Top); t->setCaption(spell->mName); @@ -244,7 +253,8 @@ namespace MWGui { MWWorld::Ptr item = *it; - const ESM::Enchantment* enchant = MWBase::Environment::get().getWorld()->getStore().enchants.find(MWWorld::Class::get(item).getEnchantment(item)); + const ESM::Enchantment* enchant = + esmStore.get().find(MWWorld::Class::get(item).getEnchantment(item)); // check if the item is currently equipped (will display in a different color) bool equipped = false; @@ -378,7 +388,9 @@ namespace MWGui if (MyGUI::InputManager::getInstance().isShiftPressed()) { // delete spell, if allowed - const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(spellId); + const ESM::Spell* spell = + MWBase::Environment::get().getWorld()->getStore().get().find(spellId); + if (spell->mData.mFlags & ESM::Spell::F_Always || spell->mData.mType == ESM::Spell::ST_Power) { diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index 665caaae1..70ceed857 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -54,10 +54,10 @@ StatsWindow::StatsWindow (MWBase::WindowManager& parWindowManager) { 0, 0 } }; - const ESMS::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); for (int i=0; names[i][0]; ++i) { - setText (names[i][0], store.gameSettings.find (names[i][1])->getString()); + setText (names[i][0], store.get().find (names[i][1])->getString()); } getWidget(mSkillView, "SkillView"); @@ -252,8 +252,14 @@ void StatsWindow::onFrame () } setFactions(PCstats.getFactionRanks()); + setExpelled(PCstats.getExpelled ()); - setBirthSign(MWBase::Environment::get().getWorld()->getPlayer().getBirthsign()); + const std::string &signId = + MWBase::Environment::get().getWorld()->getPlayer().getBirthSign(); + + setBirthSign(signId); + setReputation (PCstats.getReputation ()); + setBounty (PCstats.getBounty ()); if (mChanged) updateSkillArea(); @@ -268,6 +274,15 @@ void StatsWindow::setFactions (const FactionList& factions) } } +void StatsWindow::setExpelled (const std::set& expelled) +{ + if (mExpelled != expelled) + { + mExpelled = expelled; + mChanged = true; + } +} + void StatsWindow::setBirthSign (const std::string& signId) { if (signId != mBirthSignId) @@ -357,18 +372,22 @@ void StatsWindow::addSkills(const SkillList &skills, const std::string &titleId, if (skillId < 0 || skillId > ESM::Skill::Length) // Skip unknown skill indexes continue; assert(skillId >= 0 && skillId < ESM::Skill::Length); - const std::string &skillNameId = ESMS::Skill::sSkillNameIds[skillId]; + const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId]; const MWMechanics::Stat &stat = mSkillValues.find(skillId)->second; float base = stat.getBase(); float modified = stat.getModified(); int progressPercent = (modified - float(static_cast(modified))) * 100; - const ESM::Skill* skill = MWBase::Environment::get().getWorld()->getStore().skills.search(skillId); + const MWWorld::ESMStore &esmStore = + MWBase::Environment::get().getWorld()->getStore(); + + const ESM::Skill* skill = esmStore.get().find(skillId); assert(skill); std::string icon = "icons\\k\\" + ESM::Skill::sIconNames[skillId]; - const ESM::Attribute* attr = MWBase::Environment::get().getWorld()->getStore().attributes.search(skill->mData.mAttribute); + const ESM::Attribute* attr = + esmStore.get().find(skill->mData.mAttribute); assert(attr); std::string state = "normal"; @@ -422,10 +441,14 @@ void StatsWindow::updateSkillArea() if (!mMiscSkills.empty()) addSkills(mMiscSkills, "sSkillClassMisc", "Misc Skills", coord1, coord2); - const ESMS::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + MWBase::World *world = MWBase::Environment::get().getWorld(); + const MWWorld::ESMStore &store = world->getStore(); + const ESM::NPC *player = + world->getPlayer().getPlayer().get()->mBase; // race tooltip - const ESM::Race* playerRace = store.races.find (MWBase::Environment::get().getWorld()->getPlayer().getRace()); + const ESM::Race* playerRace = store.get().find(player->mRace); + MyGUI::Widget* raceWidget; getWidget(raceWidget, "RaceText"); ToolTips::createRaceToolTip(raceWidget, playerRace); @@ -434,11 +457,14 @@ void StatsWindow::updateSkillArea() // class tooltip MyGUI::Widget* classWidget; - const ESM::Class& playerClass = MWBase::Environment::get().getWorld()->getPlayer().getClass(); + + const ESM::Class *playerClass = + store.get().find(player->mClass); + getWidget(classWidget, "ClassText"); - ToolTips::createClassToolTip(classWidget, playerClass); + ToolTips::createClassToolTip(classWidget, *playerClass); getWidget(classWidget, "Class_str"); - ToolTips::createClassToolTip(classWidget, playerClass); + ToolTips::createClassToolTip(classWidget, *playerClass); if (!mFactions.empty()) { @@ -446,46 +472,57 @@ void StatsWindow::updateSkillArea() if (!mSkillWidgets.empty()) addSeparator(coord1, coord2); + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWMechanics::NpcStats PCstats = MWWorld::Class::get(player).getNpcStats(player); + std::set& expelled = PCstats.getExpelled (); + addGroup(mWindowManager.getGameSettingString("sFaction", "Faction"), coord1, coord2); FactionList::const_iterator end = mFactions.end(); for (FactionList::const_iterator it = mFactions.begin(); it != end; ++it) { - const ESM::Faction *faction = store.factions.find(it->first); + const ESM::Faction *faction = + store.get().find(it->first); MyGUI::Widget* w = addItem(faction->mName, coord1, coord2); std::string text; text += std::string("#DDC79E") + faction->mName; - text += std::string("\n#BF9959") + faction->mRanks[it->second]; - if (it->second < 9) + if (expelled.find(it->first) != expelled.end()) + text += "\n#{sExpelled}"; + else { - // player doesn't have max rank yet - text += std::string("\n\n#DDC79E#{sNextRank} ") + faction->mRanks[it->second+1]; + text += std::string("\n#BF9959") + faction->mRanks[it->second]; - ESM::RankData rankData = faction->mData.mRankData[it->second+1]; - const ESM::Attribute* attr1 = MWBase::Environment::get().getWorld()->getStore().attributes.search(faction->mData.mAttribute1); - const ESM::Attribute* attr2 = MWBase::Environment::get().getWorld()->getStore().attributes.search(faction->mData.mAttribute2); - assert(attr1 && attr2); - - text += "\n#BF9959#{" + attr1->mName + "}: " + boost::lexical_cast(rankData.mAttribute1) - + ", #{" + attr2->mName + "}: " + boost::lexical_cast(rankData.mAttribute2); - - text += "\n\n#DDC79E#{sFavoriteSkills}"; - text += "\n#BF9959"; - for (int i=0; i<6; ++i) + if (it->second < 9) { - text += "#{"+ESM::Skill::sSkillNameIds[faction->mData.mSkillID[i]]+"}"; - if (i<5) - text += ", "; + // player doesn't have max rank yet + text += std::string("\n\n#DDC79E#{sNextRank} ") + faction->mRanks[it->second+1]; + + ESM::RankData rankData = faction->mData.mRankData[it->second+1]; + const ESM::Attribute* attr1 = store.get().find(faction->mData.mAttribute1); + const ESM::Attribute* attr2 = store.get().find(faction->mData.mAttribute2); + assert(attr1 && attr2); + + text += "\n#BF9959#{" + attr1->mName + "}: " + boost::lexical_cast(rankData.mAttribute1) + + ", #{" + attr2->mName + "}: " + boost::lexical_cast(rankData.mAttribute2); + + text += "\n\n#DDC79E#{sFavoriteSkills}"; + text += "\n#BF9959"; + for (int i=0; i<6; ++i) + { + text += "#{"+ESM::Skill::sSkillNameIds[faction->mData.mSkillID[i]]+"}"; + if (i<5) + text += ", "; + } + + text += "\n"; + + if (rankData.mSkill1 > 0) + text += "\n#{sNeedOneSkill} " + boost::lexical_cast(rankData.mSkill1); + if (rankData.mSkill2 > 0) + text += "\n#{sNeedTwoSkills} " + boost::lexical_cast(rankData.mSkill2); } - - text += "\n"; - - if (rankData.mSkill1 > 0) - text += "\n#{sNeedOneSkill} " + boost::lexical_cast(rankData.mSkill1); - if (rankData.mSkill2 > 0) - text += "\n#{sNeedTwoSkills} " + boost::lexical_cast(rankData.mSkill2); } w->setUserString("ToolTipType", "Layout"); @@ -501,7 +538,8 @@ void StatsWindow::updateSkillArea() addSeparator(coord1, coord2); addGroup(mWindowManager.getGameSettingString("sBirthSign", "Sign"), coord1, coord2); - const ESM::BirthSign *sign = store.birthSigns.find(mBirthSignId); + const ESM::BirthSign *sign = + store.get().find(mBirthSignId); MyGUI::Widget* w = addItem(sign->mName, coord1, coord2); ToolTips::createBirthsignToolTip(w, mBirthSignId); diff --git a/apps/openmw/mwgui/stats_window.hpp b/apps/openmw/mwgui/stats_window.hpp index 75f8c568b..6619680fa 100644 --- a/apps/openmw/mwgui/stats_window.hpp +++ b/apps/openmw/mwgui/stats_window.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_STATS_WINDOW_H #define MWGUI_STATS_WINDOW_H -#include +#include "../mwworld/esmstore.hpp" #include #include @@ -38,8 +38,8 @@ namespace MWGui void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat& value); void configureSkills (const SkillList& major, const SkillList& minor); - void setReputation (int reputation) { this->mReputation = reputation; } - void setBounty (int bounty) { this->mBounty = bounty; } + void setReputation (int reputation) { if (reputation != mReputation) mChanged = true; this->mReputation = reputation; } + void setBounty (int bounty) { if (bounty != mBounty) mChanged = true; this->mBounty = bounty; } void updateSkillArea(); private: @@ -50,6 +50,7 @@ namespace MWGui MyGUI::Widget* addItem(const std::string& text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void setFactions (const FactionList& factions); + void setExpelled (const std::set& expelled); void setBirthSign (const std::string &signId); void onWindowResize(MyGUI::Window* window); @@ -71,6 +72,7 @@ namespace MWGui std::string mBirthSignId; int mReputation, mBounty; std::vector mSkillWidgets; //< Skills and other information + std::set mExpelled; bool mChanged; diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 35224613c..97df211ac 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -31,6 +31,7 @@ ToolTips::ToolTips(MWBase::WindowManager* windowManager) : , mRemainingDelay(0.0) , mLastMouseX(0) , mLastMouseY(0) + , mHorizontalScrollIndex(0) { getWidget(mDynamicToolTipBox, "DynamicToolTipBox"); @@ -52,6 +53,7 @@ void ToolTips::setEnabled(bool enabled) void ToolTips::onFrame(float frameDuration) { + while (mDynamicToolTipBox->getChildCount()) { MyGUI::Gui::getInstance().destroyWidget(mDynamicToolTipBox->getChildAt(0)); @@ -103,7 +105,7 @@ void ToolTips::onFrame(float frameDuration) else { - const MyGUI::IntPoint& lastPressed = InputManager::getInstance().getLastPressedPosition(MyGUI::MouseButton::Left); + const MyGUI::IntPoint& lastPressed = InputManager::getInstance().getLastPressedPosition(MyGUI::MouseButton::Left); if (mousePos == lastPressed) // mouseclick makes tooltip disappear return; @@ -114,11 +116,13 @@ void ToolTips::onFrame(float frameDuration) } else { + mHorizontalScrollIndex = 0; mRemainingDelay = mDelay; } mLastMouseX = mousePos.left; mLastMouseY = mousePos.top; + if (mRemainingDelay > 0) return; @@ -148,7 +152,8 @@ void ToolTips::onFrame(float frameDuration) { return; } - + + // special handling for markers on the local map: the tooltip should only be visible // if the marker is not hidden due to the fog of war. if (focus->getUserString ("IsMarker") == "true") @@ -179,7 +184,9 @@ void ToolTips::onFrame(float frameDuration) else if (type == "Spell") { ToolTipInfo info; - const ESM::Spell *spell = MWBase::Environment::get().getWorld()->getStore().spells.find(focus->getUserString("Spell")); + + const ESM::Spell *spell = + MWBase::Environment::get().getWorld()->getStore().get().find(focus->getUserString("Spell")); info.caption = spell->mName; Widgets::SpellEffectList effects; std::vector::const_iterator end = spell->mEffects.mList.end(); @@ -352,7 +359,7 @@ void ToolTips::findImageExtension(std::string& image) } IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) -{ +{ mDynamicToolTipBox->setVisible(true); std::string caption = info.caption; @@ -364,11 +371,14 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) if (text.size() > 0 && text[0] == '\n') text.erase(0, 1); + if(caption.size() > 0 && isalnum(caption[0])) + caption[0] = toupper(caption[0]); + const ESM::Enchantment* enchant = 0; - const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); if (info.enchant != "") { - enchant = store.enchants.search(info.enchant); + enchant = store.get().find(info.enchant); if (enchant->mData.mType == ESM::Enchantment::CastOnce) text += "\n#{sItemCastOnce}"; else if (enchant->mData.mType == ESM::Enchantment::WhenStrikes) @@ -383,6 +393,8 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) setCoord(0, 0, 300, 300); const IntPoint padding(8, 8); + + const int maximumWidth = 500; const int imageCaptionHPadding = (caption != "" ? 8 : 0); const int imageCaptionVPadding = (caption != "" ? 4 : 0); @@ -406,7 +418,7 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) IntSize textSize = textWidget->getTextSize(); captionSize += IntSize(imageSize, 0); // adjust for image - IntSize totalSize = IntSize( std::max(textSize.width, captionSize.width + ((image != "") ? imageCaptionHPadding : 0)), + IntSize totalSize = IntSize( std::min(std::max(textSize.width,captionSize.width + ((image != "") ? imageCaptionHPadding : 0)),maximumWidth), ((text != "") ? textSize.height + imageCaptionVPadding : 0) + captionHeight ); if (!info.effects.empty()) @@ -494,8 +506,24 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) (captionHeight-captionSize.height)/2, captionSize.width-imageSize, captionSize.height); + + //if its too long we do hscroll with the caption + if (captionSize.width > maximumWidth){ + mHorizontalScrollIndex = mHorizontalScrollIndex + 2; + if (mHorizontalScrollIndex > captionSize.width){ + mHorizontalScrollIndex = -totalSize.width; + } + int horizontal_scroll = mHorizontalScrollIndex; + if (horizontal_scroll < 40){ + horizontal_scroll = 40; + }else{ + horizontal_scroll = 80 - mHorizontalScrollIndex; + } + captionWidget->setPosition (IntPoint(horizontal_scroll, captionWidget->getPosition().top + padding.top)); + } else { + captionWidget->setPosition (captionWidget->getPosition() + padding); + } - captionWidget->setPosition (captionWidget->getPosition() + padding); textWidget->setPosition (textWidget->getPosition() + IntPoint(0, padding.top)); // only apply vertical padding, the horizontal works automatically due to Align::HCenter if (image != "") @@ -571,10 +599,15 @@ void ToolTips::createSkillToolTip(MyGUI::Widget* widget, int skillId) if (skillId == -1) return; - const std::string &skillNameId = ESMS::Skill::sSkillNameIds[skillId]; - const ESM::Skill* skill = MWBase::Environment::get().getWorld()->getStore().skills.search(skillId); + const MWWorld::ESMStore &store = + MWBase::Environment::get().getWorld()->getStore(); + + const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId]; + const ESM::Skill* skill = store.get().find(skillId); assert(skill); - const ESM::Attribute* attr = MWBase::Environment::get().getWorld()->getStore().attributes.search(skill->mData.mAttribute); + + const ESM::Attribute* attr = + store.get().find(skill->mData.mAttribute); assert(attr); std::string icon = "icons\\k\\" + ESM::Skill::sIconNames[skillId]; @@ -607,12 +640,14 @@ void ToolTips::createSpecializationToolTip(MyGUI::Widget* widget, const std::str widget->setUserString("Caption_CenteredCaption", name); std::string specText; // get all skills of this specialisation - std::map skills = MWBase::Environment::get().getWorld()->getStore().skills.list; - for (std::map::const_iterator it = skills.begin(); - it != skills.end(); ++it) + const MWWorld::Store &skills = + MWBase::Environment::get().getWorld()->getStore().get(); + + MWWorld::Store::iterator it = skills.begin(); + for (; it != skills.end(); ++it) { - if (it->second.mData.mSpecialization == specId) - specText += std::string("\n#{") + ESM::Skill::sSkillNameIds[it->second.mIndex] + "}"; + if (it->mData.mSpecialization == specId) + specText += std::string("\n#{") + ESM::Skill::sSkillNameIds[it->mIndex] + "}"; } widget->setUserString("Caption_CenteredCaptionText", specText); widget->setUserString("ToolTipLayout", "TextWithCenteredCaptionToolTip"); @@ -621,7 +656,10 @@ void ToolTips::createSpecializationToolTip(MyGUI::Widget* widget, const std::str void ToolTips::createBirthsignToolTip(MyGUI::Widget* widget, const std::string& birthsignId) { - const ESM::BirthSign *sign = MWBase::Environment::get().getWorld()->getStore().birthSigns.find(birthsignId); + const MWWorld::ESMStore &store = + MWBase::Environment::get().getWorld()->getStore(); + + const ESM::BirthSign *sign = store.get().find(birthsignId); widget->setUserString("ToolTipType", "Layout"); widget->setUserString("ToolTipLayout", "BirthSignToolTip"); @@ -640,7 +678,7 @@ void ToolTips::createBirthsignToolTip(MyGUI::Widget* widget, const std::string& for (; it != end; ++it) { const std::string &spellId = *it; - const ESM::Spell *spell = MWBase::Environment::get().getWorld()->getStore().spells.search(spellId); + const ESM::Spell *spell = store.get().search(spellId); if (!spell) continue; // Skip spells which cannot be found ESM::Spell::SpellType type = static_cast(spell->mData.mType); @@ -655,7 +693,11 @@ void ToolTips::createBirthsignToolTip(MyGUI::Widget* widget, const std::string& spells.push_back(spellId); } - struct{ const std::vector &spells; std::string label; } categories[3] = { + struct { + const std::vector &spells; + std::string label; + } + categories[3] = { {abilities, "sBirthsignmenu1"}, {powers, "sPowers"}, {spells, "sBirthsignmenu2"} @@ -672,7 +714,7 @@ void ToolTips::createBirthsignToolTip(MyGUI::Widget* widget, const std::string& const std::string &spellId = *it; - const ESM::Spell *spell = MWBase::Environment::get().getWorld()->getStore().spells.search(spellId); + const ESM::Spell *spell = store.get().find(spellId); text += "\n#BF9959" + spell->mName; } } @@ -711,7 +753,8 @@ void ToolTips::createClassToolTip(MyGUI::Widget* widget, const ESM::Class& playe void ToolTips::createMagicEffectToolTip(MyGUI::Widget* widget, short id) { - const ESM::MagicEffect* effect = MWBase::Environment::get().getWorld ()->getStore ().magicEffects.find(id); + const ESM::MagicEffect* effect = + MWBase::Environment::get().getWorld ()->getStore ().get().find(id); const std::string &name = ESM::MagicEffect::effectIdToString (id); std::string icon = effect->mIcon; diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index 270df4ae2..4048d0d5a 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -90,6 +90,9 @@ namespace MWGui float mFocusToolTipX; float mFocusToolTipY; + + int mHorizontalScrollIndex; + float mDelay; float mRemainingDelay; // remaining time until tooltip will show diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 64710c279..a005c618f 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -6,10 +6,17 @@ #include "../mwbase/world.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/dialoguemanager.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/manualref.hpp" +#include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/npcstats.hpp" + +#include "../mwworld/player.hpp" + #include "inventorywindow.hpp" namespace MWGui @@ -52,6 +59,8 @@ namespace MWGui mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onCancelButtonClicked); mOfferButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onOfferButtonClicked); + mIncreaseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onIncreaseButtonClicked); + mDecreaseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onDecreaseButtonClicked); setCoord(400, 0, 400, 300); @@ -63,6 +72,7 @@ namespace MWGui setTitle(MWWorld::Class::get(actor).getName(actor)); mCurrentBalance = 0; + mCurrentMerchantOffer = 0; mWindowManager.getInventoryWindow()->startTrade(); @@ -107,10 +117,14 @@ namespace MWGui bool goldFound = false; MWWorld::Ptr gold; MWWorld::ContainerStore& playerStore = mWindowManager.getInventoryWindow()->getContainerStore(); + + const MWWorld::Store &gmst = + MWBase::Environment::get().getWorld()->getStore().get(); + for (MWWorld::ContainerStoreIterator it = playerStore.begin(); it != playerStore.end(); ++it) { - if (MWWorld::Class::get(*it).getName(*it) == MWBase::Environment::get().getWorld()->getStore().gameSettings.find("sGold")->getString()) + if (MWWorld::Class::get(*it).getName(*it) == gmst.find("sGold")->getString()) { goldFound = true; gold = *it; @@ -131,6 +145,9 @@ namespace MWGui void TradeWindow::onOfferButtonClicked(MyGUI::Widget* _sender) { + const MWWorld::Store &gmst = + MWBase::Environment::get().getWorld()->getStore().get(); + // were there any items traded at all? MWWorld::ContainerStore& playerBought = mWindowManager.getInventoryWindow()->getBoughtItems(); MWWorld::ContainerStore& merchantBought = getBoughtItems(); @@ -156,15 +173,15 @@ namespace MWGui if (mPtr.getTypeName() == typeid(ESM::NPC).name()) { MWWorld::LiveCellRef* ref = mPtr.get(); - if (ref->base->mNpdt52.mGold == -10) - merchantgold = ref->base->mNpdt12.mGold; + if (ref->mBase->mNpdt52.mGold == -10) + merchantgold = ref->mBase->mNpdt12.mGold; else - merchantgold = ref->base->mNpdt52.mGold; + merchantgold = ref->mBase->mNpdt52.mGold; } else // ESM::Creature { MWWorld::LiveCellRef* ref = mPtr.get(); - merchantgold = ref->base->mData.mGold; + merchantgold = ref->mBase->mData.mGold; } if (mCurrentBalance > 0 && merchantgold < mCurrentBalance) { @@ -174,6 +191,62 @@ namespace MWGui return; } + if(mCurrentBalance > mCurrentMerchantOffer) + { + //if npc is a creature: reject (no haggle) + if (mPtr.getTypeName() != typeid(ESM::NPC).name()) + { + MWBase::Environment::get().getWindowManager()-> + messageBox("#{sNotifyMessage9}", std::vector()); + return; + } + + int a = abs(mCurrentMerchantOffer); + int b = abs(mCurrentBalance); + int d = 0; + if (mCurrentMerchantOffer<0) d = int(100 * (a - b) / a); + else d = int(100 * (b - a) / a); + + float clampedDisposition = std::max(0,std::min(int(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr) + + MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange()),100)); + + MWMechanics::NpcStats sellerSkill = MWWorld::Class::get(mPtr).getNpcStats(mPtr); + MWMechanics::CreatureStats sellerStats = MWWorld::Class::get(mPtr).getCreatureStats(mPtr); + MWWorld::Ptr playerPtr = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWMechanics::NpcStats playerSkill = MWWorld::Class::get(playerPtr).getNpcStats(playerPtr); + MWMechanics::CreatureStats playerStats = MWWorld::Class::get(playerPtr).getCreatureStats(playerPtr); + + float a1 = std::min(playerSkill.getSkill(ESM::Skill::Mercantile).getModified(), 100.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 d1 = std::min(sellerSkill.getSkill(ESM::Skill::Mercantile).getModified(), 100.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 pcTerm = (clampedDisposition - 50 + a1 + b1 + c1) * playerStats.getFatigueTerm(); + float npcTerm = (d1 + e1 + f1) * sellerStats.getFatigueTerm(); + float x = gmst.find("fBargainOfferMulti")->getFloat() * d + gmst.find("fBargainOfferBase")->getFloat(); + if (mCurrentMerchantOffer<0) x += abs(int(pcTerm - npcTerm)); + else x += abs(int(npcTerm - pcTerm)); + + int roll = std::rand()%100 + 1; + if(roll > x) //trade refused + { + MWBase::Environment::get().getWindowManager()-> + messageBox("#{sNotifyMessage9}", std::vector()); + + int iBarterFailDisposition = gmst.find("iBarterFailDisposition")->getInt(); + MWBase::Environment::get().getDialogueManager()->applyTemporaryDispositionChange(iBarterFailDisposition); + return; + } + + //skill use! + MWWorld::Class::get(playerPtr).skillUsageSucceeded(playerPtr, ESM::Skill::Mercantile, 0); + } + + int iBarterSuccessDisposition = gmst.find("iBarterSuccessDisposition")->getInt(); + MWBase::Environment::get().getDialogueManager()->applyTemporaryDispositionChange(iBarterSuccessDisposition); + // success! make the item transfer. transferBoughtItems(); mWindowManager.getInventoryWindow()->transferBoughtItems(); @@ -198,6 +271,20 @@ namespace MWGui mWindowManager.removeGuiMode(GM_Barter); } + void TradeWindow::onIncreaseButtonClicked(MyGUI::Widget* _sender) + { + if(mCurrentBalance<=-1) mCurrentBalance -= 1; + if(mCurrentBalance>=1) mCurrentBalance += 1; + updateLabels(); + } + + void TradeWindow::onDecreaseButtonClicked(MyGUI::Widget* _sender) + { + if(mCurrentBalance<-1) mCurrentBalance += 1; + if(mCurrentBalance>1) mCurrentBalance -= 1; + updateLabels(); + } + void TradeWindow::updateLabels() { mPlayerGold->setCaptionWithReplacing("#{sYourGold} " + boost::lexical_cast(mWindowManager.getInventoryWindow()->getPlayerGold())); @@ -217,15 +304,15 @@ namespace MWGui if (mPtr.getTypeName() == typeid(ESM::NPC).name()) { MWWorld::LiveCellRef* ref = mPtr.get(); - if (ref->base->mNpdt52.mGold == -10) - merchantgold = ref->base->mNpdt12.mGold; + if (ref->mBase->mNpdt52.mGold == -10) + merchantgold = ref->mBase->mNpdt12.mGold; else - merchantgold = ref->base->mNpdt52.mGold; + merchantgold = ref->mBase->mNpdt52.mGold; } else // ESM::Creature { MWWorld::LiveCellRef* ref = mPtr.get(); - merchantgold = ref->base->mData.mGold; + merchantgold = ref->mBase->mData.mGold; } mMerchantGold->setCaptionWithReplacing("#{sSellerGold} " + boost::lexical_cast(merchantgold)); @@ -261,14 +348,14 @@ namespace MWGui if (mPtr.getTypeName() == typeid(ESM::NPC).name()) { MWWorld::LiveCellRef* ref = mPtr.get(); - if (ref->base->mHasAI) - services = ref->base->mAiData.mServices; + if (ref->mBase->mHasAI) + services = ref->mBase->mAiData.mServices; } else if (mPtr.getTypeName() == typeid(ESM::Creature).name()) { MWWorld::LiveCellRef* ref = mPtr.get(); - if (ref->base->mHasAI) - services = ref->base->mAiData.mServices; + if (ref->mBase->mHasAI) + services = ref->mBase->mAiData.mServices; } /// \todo what about potions, there doesn't seem to be a flag for them?? @@ -316,19 +403,17 @@ namespace MWGui void TradeWindow::sellToNpc(MWWorld::Ptr item, int count) { - /// \todo price adjustment depending on merchantile skill - - mCurrentBalance -= MWWorld::Class::get(item).getValue(item) * count; + mCurrentBalance -= MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, MWWorld::Class::get(item).getValue(item) * count,true); + mCurrentMerchantOffer -= MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, MWWorld::Class::get(item).getValue(item) * count,true); updateLabels(); } void TradeWindow::buyFromNpc(MWWorld::Ptr item, int count) { - /// \todo price adjustment depending on merchantile skill - - mCurrentBalance += MWWorld::Class::get(item).getValue(item) * count; + mCurrentBalance += MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, MWWorld::Class::get(item).getValue(item) * count,false); + mCurrentMerchantOffer += MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, MWWorld::Class::get(item).getValue(item) * count,false); updateLabels(); } diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 4ec55045c..db386d8b6 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -55,11 +55,14 @@ namespace MWGui MyGUI::TextBox* mMerchantGold; int mCurrentBalance; + int mCurrentMerchantOffer; void onWindowResize(MyGUI::Window* _sender); void onFilterChanged(MyGUI::Widget* _sender); void onOfferButtonClicked(MyGUI::Widget* _sender); void onCancelButtonClicked(MyGUI::Widget* _sender); + void onIncreaseButtonClicked(MyGUI::Widget* _sender); + void onDecreaseButtonClicked(MyGUI::Widget* _sender); // don't show items that the NPC has equipped in his trade-window. virtual bool ignoreEquippedItems() { return true; } diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index af61b3487..ba39ee601 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -7,6 +7,7 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/player.hpp" @@ -73,10 +74,13 @@ namespace MWGui MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer (); MWMechanics::NpcStats& pcStats = MWWorld::Class::get(player).getNpcStats (player); + const MWWorld::Store &gmst = + MWBase::Environment::get().getWorld()->getStore().get(); + for (int i=0; i<3; ++i) { - /// \todo mercantile skill - int price = pcStats.getSkill (bestSkills[i].first).getBase() * MWBase::Environment::get().getWorld ()->getStore ().gameSettings.find("iTrainingMod")->getInt (); + int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer + (mPtr,pcStats.getSkill (bestSkills[i].first).getBase() * gmst.find("iTrainingMod")->getInt (),true); std::string skin = (price > mWindowManager.getInventoryWindow ()->getPlayerGold ()) ? "SandTextGreyedOut" : "SandTextButton"; @@ -113,8 +117,11 @@ namespace MWGui MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer (); MWMechanics::NpcStats& pcStats = MWWorld::Class::get(player).getNpcStats (player); - /// \todo mercantile skill - int price = pcStats.getSkill (skillId).getBase() * MWBase::Environment::get().getWorld ()->getStore ().gameSettings.find("iTrainingMod")->getInt (); + const MWWorld::ESMStore &store = + MWBase::Environment::get().getWorld()->getStore(); + + int price = pcStats.getSkill (skillId).getBase() * store.get().find("iTrainingMod")->getInt (); + price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr,price,true); if (mWindowManager.getInventoryWindow()->getPlayerGold() *playerRef = player.get(); - const ESM::Class *class_ = MWBase::Environment::get().getWorld()->getStore().classes.find ( - playerRef->base->mClass); + + const ESM::Class *class_ = + store.get().find(playerRef->mBase->mClass); pcStats.increaseSkill (skillId, *class_, true); // remove gold diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index c19639aa6..abbc6172f 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -54,21 +54,25 @@ namespace MWGui { int price = 0; + const MWWorld::Store &gmst = + MWBase::Environment::get().getWorld()->getStore().get(); + if(interior) { - price = MWBase::Environment::get().getWorld()->getStore().gameSettings.find("fMagesGuildTravel")->getFloat(); + price = gmst.find("fMagesGuildTravel")->getFloat(); } else { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); 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) ); - price = d/MWBase::Environment::get().getWorld()->getStore().gameSettings.find("fTravelMult")->getFloat(); + price = d/gmst.find("fTravelMult")->getFloat(); } + price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr,price,true); + MyGUI::Button* toAdd = mDestinationsView->createWidget((price>mWindowManager.getInventoryWindow()->getPlayerGold()) ? "SandTextGreyedOut" : "SandTextButton", 0, mCurrentY, 200, sLineHeight, MyGUI::Align::Default); mCurrentY += sLineHeight; - /// \todo price adjustment depending on merchantile skill if(interior) toAdd->setUserString("interior","y"); else @@ -104,15 +108,15 @@ namespace MWGui MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - for(unsigned int i = 0;i()->base->mTransport.size();i++) + for(unsigned int i = 0;i()->mBase->mTransport.size();i++) { - std::string cellname = mPtr.get()->base->mTransport[i].mCellName; + std::string cellname = mPtr.get()->mBase->mTransport[i].mCellName; bool interior = true; int x,y; - MWBase::Environment::get().getWorld()->positionToIndex(mPtr.get()->base->mTransport[i].mPos.pos[0], - mPtr.get()->base->mTransport[i].mPos.pos[1],x,y); - if(cellname == "") {cellname = MWBase::Environment::get().getWorld()->getExterior(x,y)->cell->mName; interior= false;} - addDestination(cellname,mPtr.get()->base->mTransport[i].mPos,interior); + MWBase::Environment::get().getWorld()->positionToIndex(mPtr.get()->mBase->mTransport[i].mPos.pos[0], + mPtr.get()->mBase->mTransport[i].mPos.pos[1],x,y); + if(cellname == "") {cellname = MWBase::Environment::get().getWorld()->getExterior(x,y)->mCell->mName; interior= false;} + addDestination(cellname,mPtr.get()->mBase->mTransport[i].mPos,interior); } updateLabels(); @@ -142,7 +146,7 @@ namespace MWGui cell = MWBase::Environment::get().getWorld()->getExterior(x,y); 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) ); - int time = int(d /MWBase::Environment::get().getWorld()->getStore().gameSettings.find("fTravelTimeMult")->getFloat()); + int time = int(d /MWBase::Environment::get().getWorld()->getStore().get().find("fTravelTimeMult")->getFloat()); for(int i = 0;i < time;i++) { MWBase::Environment::get().getMechanicsManager ()->restoreDynamicStats (); diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 380fb8dd5..4f2c98c08 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -120,9 +120,10 @@ namespace MWGui int hour = MWBase::Environment::get().getWorld ()->getTimeStamp ().getHour (); bool pm = hour >= 12; if (hour >= 13) hour -= 12; + if (hour == 0) hour = 12; std::string dateTimeText = - boost::lexical_cast(MWBase::Environment::get().getWorld ()->getDay ()+1) + " " + boost::lexical_cast(MWBase::Environment::get().getWorld ()->getDay ()) + " " + month + " (#{sDay} " + boost::lexical_cast(MWBase::Environment::get().getWorld ()->getTimeStamp ().getDay ()+1) + ") " + boost::lexical_cast(hour) + " " + (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}"); @@ -203,6 +204,7 @@ namespace MWGui MWBase::Environment::get().getWorld ()->getFader ()->fadeIn(0.2); mProgressBar.setVisible (false); mWindowManager.removeGuiMode (GM_Rest); + mWindowManager.removeGuiMode (GM_RestBed); mWaiting = false; MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index ed09b9805..82e112826 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -2,12 +2,12 @@ #include -#include "components/esm_store/store.hpp" - #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwworld/esmstore.hpp" + #undef min #undef max @@ -228,8 +228,10 @@ void MWSpell::setSpellId(const std::string &spellId) void MWSpell::createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord, int flags) { - const ESMS::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - const ESM::Spell *spell = store.spells.search(mId); + const MWWorld::ESMStore &store = + MWBase::Environment::get().getWorld()->getStore(); + + const ESM::Spell *spell = store.get().search(mId); MYGUI_ASSERT(spell, "spell with id '" << mId << "' not found"); MWSpellEffectPtr effect = nullptr; @@ -259,8 +261,10 @@ void MWSpell::updateWidgets() { if (mSpellNameWidget && mWindowManager) { - const ESMS::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - const ESM::Spell *spell = store.spells.search(mId); + const MWWorld::ESMStore &store = + MWBase::Environment::get().getWorld()->getStore(); + + const ESM::Spell *spell = store.get().search(mId); if (spell) static_cast(mSpellNameWidget)->setCaption(spell->mName); else @@ -386,8 +390,14 @@ void MWSpellEffect::setSpellEffect(const SpellEffectParams& params) void MWSpellEffect::updateWidgets() { - const ESMS::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - const ESM::MagicEffect *magicEffect = store.magicEffects.search(mEffectParams.mEffectID); + if (!mWindowManager) + return; + + const MWWorld::ESMStore &store = + MWBase::Environment::get().getWorld()->getStore(); + + const ESM::MagicEffect *magicEffect = + store.get().search(mEffectParams.mEffectID); assert(magicEffect); assert(mWindowManager); diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index a41e1f123..4ac5383f7 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_WIDGETS_H #define MWGUI_WIDGETS_H -#include +#include "../mwworld/esmstore.hpp" #include diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 0350581e4..fe3cb7b11 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -9,6 +9,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" @@ -55,7 +56,8 @@ using namespace MWGui; WindowManager::WindowManager( const Compiler::Extensions& extensions, int fpsLevel, bool newGame, OEngine::Render::OgreRenderer *mOgre, - const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts) + const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, + Translation::Storage& translationDataStorage) : mGuiManager(NULL) , mHud(NULL) , mMap(NULL) @@ -83,7 +85,6 @@ WindowManager::WindowManager( , mSpellCreationDialog(NULL) , mEnchantingDialog(NULL) , mTrainingWindow(NULL) - , mPlayerClass() , mPlayerName() , mPlayerRaceId() , mPlayerAttributes() @@ -105,6 +106,7 @@ WindowManager::WindowManager( , mCrosshairEnabled(Settings::Manager::getBool ("crosshair", "HUD")) , mSubtitlesEnabled(Settings::Manager::getBool ("subtitles", "GUI")) , mHudEnabled(true) + , mTranslationDataStorage (translationDataStorage) { // Set up the GUI system @@ -499,8 +501,7 @@ void WindowManager::setValue (const std::string& id, int value) void WindowManager::setPlayerClass (const ESM::Class &class_) { - mPlayerClass = class_; - mStatsWindow->setValue("class", mPlayerClass.mName); + mStatsWindow->setValue("class", class_.mName); } void WindowManager::configureSkills (const SkillList& major, const SkillList& minor) @@ -536,10 +537,15 @@ void WindowManager::removeDialog(OEngine::GUI::Layout*dialog) void WindowManager::messageBox (const std::string& message, const std::vector& buttons) { - if (buttons.empty()) - { - mMessageBoxManager->createMessageBox(message); + if(buttons.empty()){ + /* If there are no buttons, and there is a dialogue window open, messagebox goes to the dialogue window */ + if(std::find(mGuiModes.begin(), mGuiModes.end(), GM_Dialogue) != mGuiModes.end()) + mDialogueWindow->addMessageBox(MyGUI::LanguageManager::getInstance().replaceTags(message)); + + else + mMessageBoxManager->createMessageBox(message); } + else { mMessageBoxManager->createInteractiveMessageBox(message, buttons); @@ -554,7 +560,9 @@ int WindowManager::readPressedButton () std::string WindowManager::getGameSettingString(const std::string &id, const std::string &default_) { - const ESM::GameSetting *setting = MWBase::Environment::get().getWorld()->getStore().gameSettings.search(id); + const ESM::GameSetting *setting = + MWBase::Environment::get().getWorld()->getStore().get().search(id); + if (setting && setting->mType == ESM::VT_String) return setting->getString(); return default_; @@ -582,6 +590,8 @@ void WindowManager::onFrame (float frameDuration) mDragAndDrop->mDraggedWidget->setPosition(MyGUI::InputManager::getInstance().getMousePosition()); } + mDialogueWindow->onFrame(); + mInventoryWindow->onFrame(); mStatsWindow->onFrame(); @@ -604,37 +614,40 @@ void WindowManager::onFrame (float frameDuration) void WindowManager::changeCell(MWWorld::Ptr::CellStore* cell) { - if (!(cell->cell->mData.mFlags & ESM::Cell::Interior)) + if (cell->mCell->isExterior()) { std::string name; - if (cell->cell->mName != "") + if (cell->mCell->mName != "") { - name = cell->cell->mName; - mMap->addVisitedLocation (name, cell->cell->getGridX (), cell->cell->getGridY ()); + name = cell->mCell->mName; + mMap->addVisitedLocation ("#{sCell=" + name + "}", cell->mCell->getGridX (), cell->mCell->getGridY ()); } else { - const ESM::Region* region = MWBase::Environment::get().getWorld()->getStore().regions.search(cell->cell->mRegion); + const ESM::Region* region = + MWBase::Environment::get().getWorld()->getStore().get().search(cell->mCell->mRegion); if (region) name = region->mName; else name = getGameSettingString("sDefaultCellname", "Wilderness"); } + mMap->cellExplored(cell->mCell->getGridX(), cell->mCell->getGridY()); + mMap->setCellName( name ); mHud->setCellName( name ); mMap->setCellPrefix("Cell"); mHud->setCellPrefix("Cell"); - mMap->setActiveCell( cell->cell->mData.mX, cell->cell->mData.mY ); - mHud->setActiveCell( cell->cell->mData.mX, cell->cell->mData.mY ); + mMap->setActiveCell( cell->mCell->getGridX(), cell->mCell->getGridY() ); + mHud->setActiveCell( cell->mCell->getGridX(), cell->mCell->getGridY() ); } else { - mMap->setCellName( cell->cell->mName ); - mHud->setCellName( cell->cell->mName ); - mMap->setCellPrefix( cell->cell->mName ); - mHud->setCellPrefix( cell->cell->mName ); + mMap->setCellName( cell->mCell->mName ); + mHud->setCellName( cell->mCell->mName ); + mMap->setCellPrefix( cell->mCell->mName ); + mHud->setCellPrefix( cell->mCell->mName ); } } @@ -717,11 +730,25 @@ void WindowManager::setDragDrop(bool dragDrop) void WindowManager::onRetrieveTag(const MyGUI::UString& _tag, MyGUI::UString& _result) { - const ESM::GameSetting *setting = MWBase::Environment::get().getWorld()->getStore().gameSettings.find(_tag); - if (setting && setting->mType == ESM::VT_String) - _result = setting->getString(); + std::string tag(_tag); + + std::string tokenToFind = "sCell="; + size_t tokenLength = tokenToFind.length(); + + if (tag.substr(0, tokenLength) == tokenToFind) + { + _result = mTranslationDataStorage.translateCellName(tag.substr(tokenLength)); + } else - _result = _tag; + { + const ESM::GameSetting *setting = + MWBase::Environment::get().getWorld()->getStore().get().find(tag); + + if (setting && setting->mType == ESM::VT_String) + _result = setting->getString(); + else + _result = tag; + } } void WindowManager::processChangedSettings(const Settings::CategorySettingVector& changed) @@ -769,6 +796,13 @@ void WindowManager::pushGuiMode(GuiMode mode) if (mode==GM_Inventory && mAllowed==GW_None) return; + + // If this mode already exists somewhere in the stack, just bring it to the front. + if (std::find(mGuiModes.begin(), mGuiModes.end(), mode) != mGuiModes.end()) + { + mGuiModes.erase(std::find(mGuiModes.begin(), mGuiModes.end(), mode)); + } + mGuiModes.push_back(mode); bool gameMode = !isGuiMode(); @@ -808,7 +842,10 @@ void WindowManager::removeGuiMode(GuiMode mode) void WindowManager::setSelectedSpell(const std::string& spellId, int successChancePercent) { mHud->setSelectedSpell(spellId, successChancePercent); - const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(spellId); + + const ESM::Spell* spell = + MWBase::Environment::get().getWorld()->getStore().get().find(spellId); + mSpellWindow->setTitle(spell->mName); } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index aa796343e..aaa856aef 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -29,6 +29,11 @@ namespace Compiler class Extensions; } +namespace Translation +{ + class Storage; +} + namespace OEngine { namespace GUI @@ -76,7 +81,8 @@ namespace MWGui WindowManager(const Compiler::Extensions& extensions, int fpsLevel, bool newGame, OEngine::Render::OgreRenderer *mOgre, const std::string& logpath, - const std::string& cacheDir, bool consoleOnlyScripts); + const std::string& cacheDir, bool consoleOnlyScripts, + Translation::Storage& translationDataStorage); virtual ~WindowManager(); /** @@ -250,6 +256,7 @@ namespace MWGui SpellCreationDialog* mSpellCreationDialog; EnchantingDialog* mEnchantingDialog; TrainingWindow* mTrainingWindow; + Translation::Storage& mTranslationDataStorage; CharacterCreation* mCharGen; @@ -261,7 +268,6 @@ namespace MWGui /// \todo get rid of this stuff. Move it to the respective UI element classes, if needed. // Various stats about player as needed by window manager - ESM::Class mPlayerClass; std::string mPlayerName; std::string mPlayerRaceId; std::map > mPlayerAttributes; diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index c3e131440..6a1c3aa9b 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -9,7 +9,7 @@ #include -#include +#include #include #include @@ -624,7 +624,9 @@ namespace MWInput void InputManager::toggleAutoMove() { if (mWindows.isGuiMode()) return; - mPlayer.setAutoMove (!mPlayer.getAutoMove()); + + if (mControlSwitch["playercontrols"]) + mPlayer.setAutoMove (!mPlayer.getAutoMove()); } void InputManager::toggleWalking() diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 5e6169f68..718d6b76f 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -42,8 +42,8 @@ namespace OIS class InputManager; } -#include -#include +#include +#include #include #include diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index df5ea7c3f..f53ccdce3 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -3,13 +3,15 @@ #include +#include + #include #include #include #include #include -#include +#include "../mwworld/esmstore.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -86,7 +88,7 @@ namespace MWMechanics if (effects.second) { const ESM::MagicEffect *magicEffect = - MWBase::Environment::get().getWorld()->getStore().magicEffects.find ( + MWBase::Environment::get().getWorld()->getStore().get().find ( iter->mEffectID); if (iter->mDuration==0) @@ -114,18 +116,18 @@ namespace MWMechanics std::pair ActiveSpells::getEffectList (const std::string& id) const { if (const ESM::Spell *spell = - MWBase::Environment::get().getWorld()->getStore().spells.search (id)) + MWBase::Environment::get().getWorld()->getStore().get().search (id)) return std::make_pair (spell->mEffects, false); if (const ESM::Potion *potion = - MWBase::Environment::get().getWorld()->getStore().potions.search (id)) + MWBase::Environment::get().getWorld()->getStore().get().search (id)) return std::make_pair (potion->mEffects, false); if (const ESM::Ingredient *ingredient = - MWBase::Environment::get().getWorld()->getStore().ingreds.search (id)) + MWBase::Environment::get().getWorld()->getStore().get().search (id)) { const ESM::MagicEffect *magicEffect = - MWBase::Environment::get().getWorld()->getStore().magicEffects.find ( + MWBase::Environment::get().getWorld()->getStore().get().find ( ingredient->mData.mEffectID[0]); ESM::ENAMstruct effect; @@ -258,4 +260,18 @@ namespace MWMechanics return scaledDuration-usedUp; } + + bool ActiveSpells::isSpellActive(std::string id) const + { + boost::algorithm::to_lower(id); + for (TContainer::iterator iter = mSpells.begin(); iter != mSpells.end(); ++iter) + { + std::string left = iter->first; + boost::algorithm::to_lower(left); + + if (iter->first == id) + return true; + } + return false; + } } diff --git a/apps/openmw/mwmechanics/activespells.hpp b/apps/openmw/mwmechanics/activespells.hpp index e7a239854..6b832f4cd 100644 --- a/apps/openmw/mwmechanics/activespells.hpp +++ b/apps/openmw/mwmechanics/activespells.hpp @@ -58,6 +58,9 @@ namespace MWMechanics void removeSpell (const std::string& id); + bool isSpellActive (std::string id) const; + ///< case insensitive + const MagicEffects& getMagicEffects() const; TIterator begin() const; diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index f3b6b1616..d541baea9 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -7,7 +7,7 @@ #include -#include +#include "../mwworld/esmstore.hpp" #include "../mwworld/class.hpp" #include "../mwworld/inventorystore.hpp" @@ -101,11 +101,11 @@ namespace MWMechanics health.setCurrent (health.getCurrent() + 0.1 * endurance); stats.setHealth (health); - const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); - float fFatigueReturnBase = store.gameSettings.find("fFatigueReturnBase")->getFloat (); - float fFatigueReturnMult = store.gameSettings.find("fFatigueReturnMult")->getFloat (); - float fEndFatigueMult = store.gameSettings.find("fEndFatigueMult")->getFloat (); + float fFatigueReturnBase = store.get().find("fFatigueReturnBase")->getFloat (); + float fFatigueReturnMult = store.get().find("fFatigueReturnMult")->getFloat (); + float fEndFatigueMult = store.get().find("fEndFatigueMult")->getFloat (); float capacity = MWWorld::Class::get(ptr).getCapacity(ptr); float encumbrance = MWWorld::Class::get(ptr).getEncumbrance(ptr); @@ -122,7 +122,7 @@ namespace MWMechanics if (!stunted) { - float fRestMagicMult = store.gameSettings.find("fRestMagicMult")->getFloat (); + float fRestMagicMult = store.get().find("fRestMagicMult")->getFloat (); DynamicStat magicka = stats.getMagicka(); magicka.setCurrent (magicka.getCurrent() diff --git a/apps/openmw/mwmechanics/aiactivate.cpp b/apps/openmw/mwmechanics/aiactivate.cpp new file mode 100644 index 000000000..b94c8c259 --- /dev/null +++ b/apps/openmw/mwmechanics/aiactivate.cpp @@ -0,0 +1,21 @@ +#include "aiactivate.hpp" +#include + +MWMechanics::AiActivate::AiActivate(const std::string &objectId) +: mObjectId(objectId) +{ +} +MWMechanics::AiActivate *MWMechanics::AiActivate::clone() const +{ + return new AiActivate(*this); +} +bool MWMechanics::AiActivate::execute (const MWWorld::Ptr& actor) +{ + std::cout << "AiActivate completed.\n"; + return true; +} + +int MWMechanics::AiActivate::getTypeId() const +{ + return 4; +} diff --git a/apps/openmw/mwmechanics/aiactivate.hpp b/apps/openmw/mwmechanics/aiactivate.hpp new file mode 100644 index 000000000..7f3d4016d --- /dev/null +++ b/apps/openmw/mwmechanics/aiactivate.hpp @@ -0,0 +1,23 @@ +#ifndef GAME_MWMECHANICS_AIACTIVATE_H +#define GAME_MWMECHANICS_AIACTIVATE_H + +#include "aipackage.hpp" +#include + +namespace MWMechanics +{ + + class AiActivate : public AiPackage + { + public: + AiActivate(const std::string &objectId); + virtual AiActivate *clone() const; + virtual bool execute (const MWWorld::Ptr& actor); + ///< \return Package completed? + virtual int getTypeId() const; + + private: + std::string mObjectId; + }; +} +#endif // GAME_MWMECHANICS_AIACTIVATE_H diff --git a/apps/openmw/mwmechanics/aiescort.cpp b/apps/openmw/mwmechanics/aiescort.cpp new file mode 100644 index 000000000..27cd9095d --- /dev/null +++ b/apps/openmw/mwmechanics/aiescort.cpp @@ -0,0 +1,24 @@ +#include "aiescort.hpp" +#include + +MWMechanics::AiEscort::AiEscort(const std::string &actorId,int duration, float x, float y, float z) +: mActorId(actorId), mX(x), mY(y), mZ(z), mDuration(duration) +{ +} + +MWMechanics::AiEscort *MWMechanics::AiEscort::clone() const +{ + return new AiEscort(*this); +} + +bool MWMechanics::AiEscort::execute (const MWWorld::Ptr& actor) +{ + std::cout << "AiEscort completed. \n"; + return true; +} + +int MWMechanics::AiEscort::getTypeId() const +{ + return 2; +} + diff --git a/apps/openmw/mwmechanics/aiescort.hpp b/apps/openmw/mwmechanics/aiescort.hpp new file mode 100644 index 000000000..fef70f508 --- /dev/null +++ b/apps/openmw/mwmechanics/aiescort.hpp @@ -0,0 +1,29 @@ +#ifndef GAME_MWMECHANICS_AIESCORT_H +#define GAME_MWMECHANICS_AIESCORT_H + +#include "aipackage.hpp" +#include + +namespace MWMechanics +{ + class AiEscort : public AiPackage + { + public: + AiEscort(const std::string &actorId,int duration, float x, float y, float z); + virtual AiEscort *clone() const; + + virtual bool execute (const MWWorld::Ptr& actor); + ///< \return Package completed? + + virtual int getTypeId() const; + + private: + std::string mActorId; + float mX; + float mY; + float mZ; + int mDuration; + + }; +} +#endif diff --git a/apps/openmw/mwmechanics/aifollow.cpp b/apps/openmw/mwmechanics/aifollow.cpp new file mode 100644 index 000000000..3fee6d98c --- /dev/null +++ b/apps/openmw/mwmechanics/aifollow.cpp @@ -0,0 +1,22 @@ +#include "aifollow.hpp" +#include + +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) +{ +} +MWMechanics::AiFollow *MWMechanics::AiFollow::clone() const +{ + return new AiFollow(*this); +} + + bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor) +{ + std::cout << "AiFollow completed.\n"; + return true; +} + + int MWMechanics::AiFollow::getTypeId() const +{ + return 3; +} diff --git a/apps/openmw/mwmechanics/aifollow.hpp b/apps/openmw/mwmechanics/aifollow.hpp new file mode 100644 index 000000000..ded13d780 --- /dev/null +++ b/apps/openmw/mwmechanics/aifollow.hpp @@ -0,0 +1,27 @@ +#ifndef GAME_MWMECHANICS_AIFALLOW_H +#define GAME_MWMECHANICS_AIFALLOW_H + +#include "aipackage.hpp" +#include + +namespace MWMechanics +{ + + class AiFollow : public AiPackage + { + public: + AiFollow(const std::string &ActorId,float duration, float X, float Y, float Z); + virtual AiFollow *clone() const; + virtual bool execute (const MWWorld::Ptr& actor); + ///< \return Package completed? + virtual int getTypeId() const; + + private: + float mDuration; + float mX; + float mY; + float mZ; + std::string mActorId; + }; +} +#endif diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp new file mode 100644 index 000000000..897dd1748 --- /dev/null +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -0,0 +1,25 @@ +#include "aitravel.hpp" +#include + +MWMechanics::AiTravel::AiTravel(float x, float y, float z) +: mX(x),mY(y),mZ(z) +{ +} + +MWMechanics::AiTravel * MWMechanics::AiTravel::clone() const +{ + return new AiTravel(*this); +} + +bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) +{ + std::cout << "AiTravel completed.\n"; + return true; +} + +int MWMechanics::AiTravel::getTypeId() const +{ + return 1; +} + + diff --git a/apps/openmw/mwmechanics/aitravel.hpp b/apps/openmw/mwmechanics/aitravel.hpp new file mode 100644 index 000000000..1c6abbf27 --- /dev/null +++ b/apps/openmw/mwmechanics/aitravel.hpp @@ -0,0 +1,27 @@ +#ifndef GAME_MWMECHANICS_AITRAVEL_H +#define GAME_MWMECHANICS_AITRAVEL_H + +#include "aipackage.hpp" + +namespace MWMechanics +{ + class AiTravel : public AiPackage + { + public: + AiTravel(float x, float y, float z); + virtual AiTravel *clone() const; + + virtual bool execute (const MWWorld::Ptr& actor); + ///< \return Package completed? + + virtual int getTypeId() const; + + private: + float mX; + float mY; + float mZ; + + }; +} + +#endif diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp new file mode 100644 index 000000000..e9db6d212 --- /dev/null +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -0,0 +1,23 @@ +#include "aiwander.hpp" +#include + +MWMechanics::AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector& idle): + mDistance(distance), mDuration(duration), mTimeOfDay(timeOfDay), mIdle(idle) +{ +} + +MWMechanics::AiPackage * MWMechanics::AiWander::clone() const +{ + return new AiWander(*this); +} + +bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor) +{ + std::cout << "AiWadner completed.\n"; + return true; +} + +int MWMechanics::AiWander::getTypeId() const +{ + return 0; +} diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp new file mode 100644 index 000000000..a71858feb --- /dev/null +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -0,0 +1,29 @@ +#ifndef GAME_MWMECHANICS_AIWANDER_H +#define GAME_MWMECHANICS_AIWANDER_H + +#include "aipackage.hpp" +#include + +namespace MWMechanics +{ + + class AiWander : public AiPackage + { + public: + + AiWander(int distance, int duration, int timeOfDay, const std::vector& idle); + virtual AiPackage *clone() const; + virtual bool execute (const MWWorld::Ptr& actor); + ///< \return Package completed? + virtual int getTypeId() const; + ///< 0: Wander + + private: + int mDistance; + int mDuration; + int mTimeOfDay; + std::vector mIdle; + }; + } + +#endif diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index 962350472..8ab81bfdf 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -13,11 +13,11 @@ #include #include -#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" +#include "../mwworld/esmstore.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/class.hpp" #include "../mwworld/cellstore.hpp" @@ -38,11 +38,11 @@ std::set MWMechanics::Alchemy::listEffects() const const MWWorld::LiveCellRef *ingredient = iter->get(); for (int i=0; i<4; ++i) - if (ingredient->base->mData.mEffectID[i]!=-1) + if (ingredient->mBase->mData.mEffectID[i]!=-1) { EffectKey key ( - ingredient->base->mData.mEffectID[i], ingredient->base->mData.mSkills[i]!=-1 ? - ingredient->base->mData.mSkills[i] : ingredient->base->mData.mAttributes[i]); + ingredient->mBase->mData.mEffectID[i], ingredient->mBase->mData.mSkills[i]!=-1 ? + ingredient->mBase->mData.mSkills[i] : ingredient->mBase->mData.mAttributes[i]); ++effects[key]; } @@ -77,9 +77,9 @@ void MWMechanics::Alchemy::applyTools (int flags, float& value) const else return; - float toolQuality = setup==1 || setup==2 ? mTools[tool].get()->base->mData.mQuality : 0; + float toolQuality = setup==1 || setup==2 ? mTools[tool].get()->mBase->mData.mQuality : 0; float calcinatorQuality = setup==1 || setup==3 ? - mTools[ESM::Apparatus::Calcinator].get()->base->mData.mQuality : 0; + mTools[ESM::Apparatus::Calcinator].get()->mBase->mData.mQuality : 0; float quality = 1; @@ -130,30 +130,30 @@ void MWMechanics::Alchemy::updateEffects() // general alchemy factor float x = getChance(); - x *= mTools[ESM::Apparatus::MortarPestle].get()->base->mData.mQuality; - x *= MWBase::Environment::get().getWorld()->getStore().gameSettings.find ("fPotionStrengthMult")->getFloat(); + x *= mTools[ESM::Apparatus::MortarPestle].get()->mBase->mData.mQuality; + x *= MWBase::Environment::get().getWorld()->getStore().get().find ("fPotionStrengthMult")->getFloat(); // value mValue = static_cast ( - x * MWBase::Environment::get().getWorld()->getStore().gameSettings.find ("iAlchemyMod")->getFloat()); + x * MWBase::Environment::get().getWorld()->getStore().get().find ("iAlchemyMod")->getFloat()); // build quantified effect list for (std::set::const_iterator iter (effects.begin()); iter!=effects.end(); ++iter) { const ESM::MagicEffect *magicEffect = - MWBase::Environment::get().getWorld()->getStore().magicEffects.find (iter->mId); + MWBase::Environment::get().getWorld()->getStore().get().find (iter->mId); if (magicEffect->mData.mBaseCost<=0) throw std::runtime_error ("invalid base cost for magic effect " + iter->mId); float fPotionT1MagMul = - MWBase::Environment::get().getWorld()->getStore().gameSettings.find ("fPotionT1MagMult")->getFloat(); + MWBase::Environment::get().getWorld()->getStore().get().find ("fPotionT1MagMult")->getFloat(); if (fPotionT1MagMul<=0) throw std::runtime_error ("invalid gmst: fPotionT1MagMul"); float fPotionT1DurMult = - MWBase::Environment::get().getWorld()->getStore().gameSettings.find ("fPotionT1DurMult")->getFloat(); + MWBase::Environment::get().getWorld()->getStore().get().find ("fPotionT1DurMult")->getFloat(); if (fPotionT1DurMult<=0) throw std::runtime_error ("invalid gmst: fPotionT1DurMult"); @@ -192,18 +192,20 @@ void MWMechanics::Alchemy::updateEffects() const ESM::Potion *MWMechanics::Alchemy::getRecord() const { - for (ESMS::RecListWithIDT::MapType::const_iterator iter ( - MWBase::Environment::get().getWorld()->getStore().potions.list.begin()); - iter!=MWBase::Environment::get().getWorld()->getStore().potions.list.end(); ++iter) + const MWWorld::Store &potions = + MWBase::Environment::get().getWorld()->getStore().get(); + + MWWorld::Store::iterator iter = potions.begin(); + for (; iter != potions.end(); ++iter) { - if (iter->second.mEffects.mList.size()!=mEffects.size()) + if (iter->mEffects.mList.size() != mEffects.size()) continue; bool mismatch = false; - for (int i=0; i (iter->second.mEffects.mList.size()); ++iter) + for (int i=0; i (iter->mEffects.mList.size()); ++i) { - const ESM::ENAMstruct& first = iter->second.mEffects.mList[i]; + const ESM::ENAMstruct& first = iter->mEffects.mList[i]; const ESM::ENAMstruct& second = mEffects[i]; if (first.mEffectID!=second.mEffectID || @@ -221,7 +223,7 @@ const ESM::Potion *MWMechanics::Alchemy::getRecord() const } if (!mismatch) - return &iter->second; + return &(*iter); } return 0; @@ -258,7 +260,7 @@ void MWMechanics::Alchemy::addPotion (const std::string& name) for (TIngredientsIterator iter (beginIngredients()); iter!=endIngredients(); ++iter) if (!iter->isEmpty()) - newRecord.mData.mWeight += iter->get()->base->mData.mWeight; + newRecord.mData.mWeight += iter->get()->mBase->mData.mWeight; newRecord.mData.mWeight /= countIngredients(); @@ -277,7 +279,7 @@ void MWMechanics::Alchemy::addPotion (const std::string& name) newRecord.mEffects.mList = mEffects; - record = MWBase::Environment::get().getWorld()->createRecord (newRecord).second; + record = MWBase::Environment::get().getWorld()->createRecord (newRecord); } MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), record->mId); @@ -332,13 +334,13 @@ void MWMechanics::Alchemy::setAlchemist (const MWWorld::Ptr& npc) { MWWorld::LiveCellRef* ref = iter->get(); - int type = ref->base->mData.mType; + int type = ref->mBase->mData.mType; if (type<0 || type>=static_cast (mTools.size())) throw std::runtime_error ("invalid apparatus type"); if (!mTools[type].isEmpty()) - if (ref->base->mData.mQuality<=mTools[type].get()->base->mData.mQuality) + if (ref->mBase->mData.mQuality<=mTools[type].get()->mBase->mData.mQuality) continue; mTools[type] = *iter; diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index 1e57ba313..4be5d55b2 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -2,16 +2,19 @@ #include -#include +#include "../mwworld/esmstore.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" namespace MWMechanics -{ +{ CreatureStats::CreatureStats() - : mLevel (0), mHello (0), mFight (0), mFlee (0), mAlarm (0), mLevelHealthBonus(0.f), mDead (false) + : mLevel (0), mLevelHealthBonus(0.f), mDead (false), mFriendlyHits (0), mTalkedTo (false), mAlarmed (false), + mAttacked (false), mHostile (false) { + for (int i=0; i<4; ++i) + mAiSettings[i] = 0; } void CreatureStats::increaseLevelHealthBonus (float value) @@ -28,25 +31,26 @@ namespace MWMechanics { return mAiSequence; } - + AiSequence& CreatureStats::getAiSequence() { - return mAiSequence; + return mAiSequence; } - - float CreatureStats::getFatigueTerm() const + + float CreatureStats::getFatigueTerm() const { int max = getFatigue().getModified(); int current = getFatigue().getCurrent(); - + float normalised = max==0 ? 1 : std::max (0.0f, static_cast (current)/max); - const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); - - return store.gameSettings.find ("fFatigueBase")->getFloat() - - store.gameSettings.find ("fFatigueMult")->getFloat() * (1-normalised); + const MWWorld::Store &gmst = + MWBase::Environment::get().getWorld()->getStore().get(); + + return gmst.find ("fFatigueBase")->getFloat() + - gmst.find ("fFatigueMult")->getFloat() * (1-normalised); } - + const Stat &CreatureStats::getAttribute(int index) const { if (index < 0 || index > 7) { @@ -89,25 +93,11 @@ namespace MWMechanics { return mLevel; } - - int CreatureStats::getHello() const - { - return mHello; - } - int CreatureStats::getFight() const + int CreatureStats::getAiSetting (int index) const { - return mFight; - } - - int CreatureStats::getFlee() const - { - return mFlee; - } - - int CreatureStats::getAlarm() const - { - return mAlarm; + assert (index>=0 && index<4); + return mAiSettings[index]; } Stat &CreatureStats::getAttribute(int index) @@ -179,7 +169,7 @@ namespace MWMechanics if (index==0 && mDynamic[index].getCurrent()<1) mDead = true; } - + void CreatureStats::setLevel(int level) { mLevel = level; @@ -195,40 +185,91 @@ namespace MWMechanics mMagicEffects = effects; } - void CreatureStats::setHello(int value) + void CreatureStats::setAiSetting (int index, int value) { - mHello = value; + assert (index>=0 && index<4); + mAiSettings[index] = value; } - void CreatureStats::setFight(int value) - { - mFight = value; - } - - void CreatureStats::setFlee(int value) - { - mFlee = value; - } - - void CreatureStats::setAlarm(int value) - { - mAlarm = value; - } - bool CreatureStats::isDead() const { return mDead; } - + void CreatureStats::resurrect() { if (mDead) { if (mDynamic[0].getCurrent()<1) mDynamic[0].setCurrent (1); - + if (mDynamic[0].getCurrent()>=1) mDead = false; } } + + bool CreatureStats::hasCommonDisease() const + { + return mSpells.hasCommonDisease(); + } + + bool CreatureStats::hasBlightDisease() const + { + return mSpells.hasBlightDisease(); + } + + int CreatureStats::getFriendlyHits() const + { + return mFriendlyHits; + } + + void CreatureStats::friendlyHit() + { + ++mFriendlyHits; + } + + bool CreatureStats::hasTalkedToPlayer() const + { + return mTalkedTo; + } + + void CreatureStats::talkedToPlayer() + { + mTalkedTo = true; + } + + bool CreatureStats::isAlarmed() const + { + return mAlarmed; + } + + void CreatureStats::setAlarmed (bool alarmed) + { + mAlarmed = alarmed; + } + + bool CreatureStats::getAttacked() const + { + return mAttacked; + } + + void CreatureStats::setAttacked (bool attacked) + { + mAttacked = attacked; + } + + bool CreatureStats::isHostile() const + { + return mHostile; + } + + void CreatureStats::setHostile (bool hostile) + { + mHostile = hostile; + } + + bool CreatureStats::getCreatureTargetted() const + { + return false; + } } diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index 671dcd439..3375c1af8 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -24,13 +24,15 @@ namespace MWMechanics Spells mSpells; ActiveSpells mActiveSpells; MagicEffects mMagicEffects; - int mHello; - int mFight; - int mFlee; - int mAlarm; + int mAiSettings[4]; AiSequence mAiSequence; float mLevelHealthBonus; - bool mDead; + bool mDead; + int mFriendlyHits; + bool mTalkedTo; + bool mAlarmed; + bool mAttacked; + bool mHostile; public: CreatureStats(); @@ -53,13 +55,8 @@ namespace MWMechanics int getLevel() const; - int getHello() const; - - int getFight() const; - - int getFlee() const; - - int getAlarm() const; + int getAiSetting (int index) const; + ///< 0: hello, 1 fight, 2 flee, 3 alarm Stat & getAttribute(int index); @@ -87,18 +84,13 @@ namespace MWMechanics void setLevel(int level); - void setHello(int value); + void setAiSetting (int index, int value); + ///< 0: hello, 1 fight, 2 flee, 3 alarm - void setFight(int value); - - void setFlee(int value); - - void setAlarm(int value); - const AiSequence& getAiSequence() const; - + AiSequence& getAiSequence(); - + float getFatigueTerm() const; ///< Return effective fatigue @@ -107,8 +99,37 @@ namespace MWMechanics float getLevelHealthBonus() const; bool isDead() const; - + void resurrect(); + + bool hasCommonDisease() const; + + bool hasBlightDisease() const; + + int getFriendlyHits() const; + ///< Number of friendly hits received. + + void friendlyHit(); + ///< Increase number of friendly hits by one. + + bool hasTalkedToPlayer() const; + ///< Has this creature talked with the player before? + + void talkedToPlayer(); + + bool isAlarmed() const; + + void setAlarmed (bool alarmed); + + bool getAttacked() const; + + void setAttacked (bool attacked); + + bool isHostile() const; + + void setHostile (bool hostile); + + bool getCreatureTargetted() const; }; } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 873dd9498..079f8520b 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1,11 +1,12 @@ #include "mechanicsmanagerimp.hpp" -#include +#include "../mwworld/esmstore.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/dialoguemanager.hpp" #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" @@ -19,7 +20,7 @@ namespace MWMechanics MWMechanics::CreatureStats& creatureStats = MWWorld::Class::get (ptr).getCreatureStats (ptr); MWMechanics::NpcStats& npcStats = MWWorld::Class::get (ptr).getNpcStats (ptr); - const ESM::NPC *player = ptr.get()->base; + const ESM::NPC *player = ptr.get()->mBase; // reset creatureStats.setLevel(player->mNpdt52.mLevel); @@ -38,14 +39,16 @@ namespace MWMechanics creatureStats.getAttribute(6).setBase (player->mNpdt52.mPersonality); creatureStats.getAttribute(7).setBase (player->mNpdt52.mLuck); + const MWWorld::ESMStore &esmStore = + MWBase::Environment::get().getWorld()->getStore(); + // race if (mRaceSelected) { const ESM::Race *race = - MWBase::Environment::get().getWorld()->getStore().races.find ( - MWBase::Environment::get().getWorld()->getPlayer().getRace()); + esmStore.get().find(player->mRace); - bool male = MWBase::Environment::get().getWorld()->getPlayer().isMale(); + bool male = (player->mFlags & ESM::NPC::Female) == 0; for (int i=0; i<8; ++i) { @@ -69,14 +72,14 @@ namespace MWMechanics for (int i=0; i<27; ++i) { int bonus = 0; - + for (int i2=0; i2<7; ++i2) if (race->mData.mBonus[i2].mSkill==i) { bonus = race->mData.mBonus[i2].mBonus; break; } - + npcStats.getSkill (i).setBase (5 + bonus); } @@ -88,11 +91,13 @@ namespace MWMechanics } // birthsign - if (!MWBase::Environment::get().getWorld()->getPlayer().getBirthsign().empty()) + const std::string &signId = + MWBase::Environment::get().getWorld()->getPlayer().getBirthSign(); + + if (!signId.empty()) { const ESM::BirthSign *sign = - MWBase::Environment::get().getWorld()->getStore().birthSigns.find ( - MWBase::Environment::get().getWorld()->getPlayer().getBirthsign()); + esmStore.get().find(signId); for (std::vector::const_iterator iter (sign->mPowers.mList.begin()); iter!=sign->mPowers.mList.end(); ++iter) @@ -104,11 +109,12 @@ namespace MWMechanics // class if (mClassSelected) { - const ESM::Class& class_ = MWBase::Environment::get().getWorld()->getPlayer().getClass(); + const ESM::Class *class_ = + esmStore.get().find(player->mClass); for (int i=0; i<2; ++i) { - int attribute = class_.mData.mAttribute[i]; + int attribute = class_->mData.mAttribute[i]; if (attribute>=0 && attribute<8) { creatureStats.getAttribute(attribute).setBase ( @@ -122,7 +128,7 @@ namespace MWMechanics for (int i2=0; i2<5; ++i2) { - int index = class_.mData.mSkills[i2][i]; + int index = class_->mData.mSkills[i2][i]; if (index>=0 && index<27) { @@ -132,14 +138,15 @@ namespace MWMechanics } } - typedef ESMS::IndexListT::MapType ContainerType; - const ContainerType& skills = MWBase::Environment::get().getWorld()->getStore().skills.list; + const MWWorld::Store &skills = + esmStore.get(); - for (ContainerType::const_iterator iter (skills.begin()); iter!=skills.end(); ++iter) + MWWorld::Store::iterator iter = skills.begin(); + for (; iter != skills.end(); ++iter) { - if (iter->second.mData.mSpecialization==class_.mData.mSpecialization) + if (iter->mData.mSpecialization==class_->mData.mSpecialization) { - int index = iter->first; + int index = iter->mIndex; if (index>=0 && index<27) { @@ -261,12 +268,22 @@ namespace MWMechanics if (mUpdatePlayer) { // basic player profile; should not change anymore after the creation phase is finished. - MWBase::Environment::get().getWindowManager()->setValue ("name", MWBase::Environment::get().getWorld()->getPlayer().getName()); - MWBase::Environment::get().getWindowManager()->setValue ("race", - MWBase::Environment::get().getWorld()->getStore().races.find (MWBase::Environment::get().getWorld()->getPlayer(). - getRace())->mName); - MWBase::Environment::get().getWindowManager()->setValue ("class", - MWBase::Environment::get().getWorld()->getPlayer().getClass().mName); + MWBase::WindowManager *winMgr = + MWBase::Environment::get().getWindowManager(); + + MWBase::World *world = MWBase::Environment::get().getWorld(); + const ESM::NPC *player = + world->getPlayer().getPlayer().get()->mBase; + + const ESM::Race *race = + world->getStore().get().find(player->mRace); + const ESM::Class *cls = + world->getStore().get().find(player->mClass); + + winMgr->setValue ("name", player->mName); + winMgr->setValue ("race", race->mName); + winMgr->setValue ("class", cls->mName); + mUpdatePlayer = false; MWBase::WindowManager::SkillList majorSkills (5); @@ -274,11 +291,11 @@ namespace MWMechanics for (int i=0; i<5; ++i) { - minorSkills[i] = MWBase::Environment::get().getWorld()->getPlayer().getClass().mData.mSkills[i][0]; - majorSkills[i] = MWBase::Environment::get().getWorld()->getPlayer().getClass().mData.mSkills[i][1]; + minorSkills[i] = cls->mData.mSkills[i][0]; + majorSkills[i] = cls->mData.mSkills[i][1]; } - MWBase::Environment::get().getWindowManager()->configureSkills (majorSkills, minorSkills); + winMgr->configureSkills (majorSkills, minorSkills); } mActors.update (movement, duration, paused); @@ -291,14 +308,31 @@ namespace MWMechanics void MechanicsManager::setPlayerName (const std::string& name) { - MWBase::Environment::get().getWorld()->getPlayer().setName (name); + MWBase::World *world = MWBase::Environment::get().getWorld(); + + ESM::NPC player = + *world->getPlayer().getPlayer().get()->mBase; + player.mName = name; + + world->createRecord(player); + mUpdatePlayer = true; } - void MechanicsManager::setPlayerRace (const std::string& race, bool male) + void MechanicsManager::setPlayerRace (const std::string& race, bool male, const std::string &head, const std::string &hair) { - MWBase::Environment::get().getWorld()->getPlayer().setGender (male); - MWBase::Environment::get().getWorld()->getPlayer().setRace (race); + MWBase::World *world = MWBase::Environment::get().getWorld(); + + ESM::NPC player = + *world->getPlayer().getPlayer().get()->mBase; + + player.mRace = race; + player.mHead = head; + player.mHair = hair; + player.setIsMale(male); + + world->createRecord(player); + mRaceSelected = true; buildPlayer(); mUpdatePlayer = true; @@ -306,29 +340,303 @@ namespace MWMechanics void MechanicsManager::setPlayerBirthsign (const std::string& id) { - MWBase::Environment::get().getWorld()->getPlayer().setBirthsign (id); + MWBase::Environment::get().getWorld()->getPlayer().setBirthSign(id); buildPlayer(); mUpdatePlayer = true; } void MechanicsManager::setPlayerClass (const std::string& id) { - MWBase::Environment::get().getWorld()->getPlayer().setClass (*MWBase::Environment::get().getWorld()->getStore().classes.find (id)); + MWBase::World *world = MWBase::Environment::get().getWorld(); + + ESM::NPC player = + *world->getPlayer().getPlayer().get()->mBase; + player.mClass = id; + + world->createRecord(player); + mClassSelected = true; buildPlayer(); mUpdatePlayer = true; } - void MechanicsManager::setPlayerClass (const ESM::Class& class_) + void MechanicsManager::setPlayerClass (const ESM::Class &cls) { - MWBase::Environment::get().getWorld()->getPlayer().setClass (class_); + MWBase::World *world = MWBase::Environment::get().getWorld(); + + const ESM::Class *ptr = world->createRecord(cls); + + ESM::NPC player = + *world->getPlayer().getPlayer().get()->mBase; + player.mClass = ptr->mId; + + world->createRecord(player); + mClassSelected = true; buildPlayer(); mUpdatePlayer = true; } - + + std::string toLower (const std::string& name) + { + std::string lowerCase; + + std::transform (name.begin(), name.end(), std::back_inserter (lowerCase), + (int(*)(int)) std::tolower); + + return lowerCase; + } + + int MechanicsManager::getDerivedDisposition(const MWWorld::Ptr& ptr) + { + MWMechanics::NpcStats npcSkill = MWWorld::Class::get(ptr).getNpcStats(ptr); + float x = npcSkill.getBaseDisposition(); + + MWWorld::LiveCellRef* npc = ptr.get(); + MWWorld::Ptr playerPtr = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWWorld::LiveCellRef* player = playerPtr.get(); + MWMechanics::CreatureStats playerStats = MWWorld::Class::get(playerPtr).getCreatureStats(playerPtr); + MWMechanics::NpcStats playerNpcStats = MWWorld::Class::get(playerPtr).getNpcStats(playerPtr); + + if (toLower(npc->mBase->mRace) == toLower(player->mBase->mRace)) x += MWBase::Environment::get().getWorld()->getStore().get().find("fDispRaceMod")->getFloat(); + + x += MWBase::Environment::get().getWorld()->getStore().get().find("fDispPersonalityMult")->getFloat() + * (playerStats.getAttribute(ESM::Attribute::Personality).getModified() - MWBase::Environment::get().getWorld()->getStore().get().find("fDispPersonalityBase")->getFloat()); + + float reaction = 0; + int rank = 0; + std::string npcFaction = ""; + if(!npcSkill.getFactionRanks().empty()) npcFaction = npcSkill.getFactionRanks().begin()->first; + + if (playerNpcStats.getFactionRanks().find(toLower(npcFaction)) != playerNpcStats.getFactionRanks().end()) + { + for(std::vector::const_iterator it = MWBase::Environment::get().getWorld()->getStore().get().find(toLower(npcFaction))->mReactions.begin(); + it != MWBase::Environment::get().getWorld()->getStore().get().find(toLower(npcFaction))->mReactions.end(); it++) + { + if(toLower(it->mFaction) == toLower(npcFaction)) reaction = it->mReaction; + } + rank = playerNpcStats.getFactionRanks().find(toLower(npcFaction))->second; + } + else if (npcFaction != "") + { + for(std::vector::const_iterator it = MWBase::Environment::get().getWorld()->getStore().get().find(toLower(npcFaction))->mReactions.begin(); + it != MWBase::Environment::get().getWorld()->getStore().get().find(toLower(npcFaction))->mReactions.end();it++) + { + if(playerNpcStats.getFactionRanks().find(toLower(it->mFaction)) != playerNpcStats.getFactionRanks().end() ) + { + if(it->mReactionmReaction; + } + } + rank = 0; + } + else + { + reaction = 0; + rank = 0; + } + x += (MWBase::Environment::get().getWorld()->getStore().get().find("fDispFactionRankMult")->getFloat() * rank + + MWBase::Environment::get().getWorld()->getStore().get().find("fDispFactionRankBase")->getFloat()) + * MWBase::Environment::get().getWorld()->getStore().get().find("fDispFactionMod")->getFloat() * reaction; + + x -= MWBase::Environment::get().getWorld()->getStore().get().find("fDispCrimeMod")->getFloat() * playerNpcStats.getBounty(); + if (playerStats.hasCommonDisease() || playerStats.hasBlightDisease()) + x += MWBase::Environment::get().getWorld()->getStore().get().find("fDispDiseaseMod")->getFloat(); + + if (playerNpcStats.getDrawState() == MWMechanics::DrawState_Weapon) + x += MWBase::Environment::get().getWorld()->getStore().get().find("fDispWeaponDrawn")->getFloat(); + + int effective_disposition = std::max(0,std::min(int(x),100));//, normally clamped to [0..100] when used + return effective_disposition; + } + + int MechanicsManager::getBarterOffer(const MWWorld::Ptr& ptr,int basePrice, bool buying) + { + if (ptr.getTypeName() == typeid(ESM::Creature).name()) + return basePrice; + + MWMechanics::NpcStats sellerSkill = MWWorld::Class::get(ptr).getNpcStats(ptr); + MWMechanics::CreatureStats sellerStats = MWWorld::Class::get(ptr).getCreatureStats(ptr); + + MWWorld::Ptr playerPtr = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWMechanics::NpcStats playerSkill = MWWorld::Class::get(playerPtr).getNpcStats(playerPtr); + MWMechanics::CreatureStats playerStats = MWWorld::Class::get(playerPtr).getCreatureStats(playerPtr); + + // I suppose the temporary disposition change _has_ to be considered here, + // otherwise one would get different prices when exiting and re-entering the dialogue window... + int clampedDisposition = std::max(0, std::min(getDerivedDisposition(ptr) + + MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange(),100)); + float a = std::min(playerSkill.getSkill(ESM::Skill::Mercantile).getModified(), 100.f); + float b = std::min(0.1f * playerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f); + float c = std::min(0.2f * playerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f); + float d = std::min(sellerSkill.getSkill(ESM::Skill::Mercantile).getModified(), 100.f); + float e = std::min(0.1f * sellerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f); + float f = std::min(0.2f * sellerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f); + + float pcTerm = (clampedDisposition - 50 + a + b + c) * playerStats.getFatigueTerm(); + float npcTerm = (d + e + f) * sellerStats.getFatigueTerm(); + float buyTerm = 0.01 * (100 - 0.5 * (pcTerm - npcTerm)); + float sellTerm = 0.01 * (50 - 0.5 * (npcTerm - pcTerm)); + + float x; + if(buying) x = buyTerm; + else x = std::min(buyTerm, sellTerm); + int offerPrice; + if (x < 1) offerPrice = int(x * basePrice); + if (x >= 1) offerPrice = basePrice + int((x - 1) * basePrice); + offerPrice = std::max(1, offerPrice); + return offerPrice; + } + int MechanicsManager::countDeaths (const std::string& id) const { return mActors.countDeaths (id); } + + + void MechanicsManager::getPersuasionDispositionChange (const MWWorld::Ptr& npc, PersuasionType type, + float currentTemporaryDispositionDelta, bool& success, float& tempChange, float& permChange) + { + const MWWorld::Store &gmst = + MWBase::Environment::get().getWorld()->getStore().get(); + + MWWorld::Ptr playerPtr = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWMechanics::NpcStats playerSkill = MWWorld::Class::get(playerPtr).getNpcStats(playerPtr); + MWMechanics::CreatureStats playerStats = MWWorld::Class::get(playerPtr).getCreatureStats(playerPtr); + + MWMechanics::NpcStats npcSkill = MWWorld::Class::get(npc).getNpcStats(npc); + MWMechanics::CreatureStats npcStats = MWWorld::Class::get(npc).getCreatureStats(npc); + + + float persTerm = playerStats.getAttribute(ESM::Attribute::Personality).getModified() + / gmst.find("fPersonalityMod")->getFloat(); + + float luckTerm = playerStats.getAttribute(ESM::Attribute::Luck).getModified() + / gmst.find("fLuckMod")->getFloat(); + + float repTerm = playerSkill.getReputation() * gmst.find("fReputationMod")->getFloat(); + + float levelTerm = playerStats.getLevel() * gmst.find("fLevelMod")->getFloat(); + + float fatigueTerm = playerStats.getFatigueTerm(); + + float playerRating1 = (repTerm + luckTerm + persTerm + playerSkill.getSkill(ESM::Skill::Speechcraft).getModified()) * fatigueTerm; + float playerRating2 = playerRating1 + levelTerm; + float playerRating3 = (playerSkill.getSkill(ESM::Skill::Mercantile).getModified() + luckTerm + persTerm) * fatigueTerm; + + float npcRating1 = (repTerm + luckTerm + persTerm + playerSkill.getSkill(ESM::Skill::Speechcraft).getModified()) * fatigueTerm; + float npcRating2 = (levelTerm + repTerm + luckTerm + persTerm + npcSkill.getSkill(ESM::Skill::Speechcraft).getModified()) * fatigueTerm; + float npcRating3 = (playerSkill.getSkill(ESM::Skill::Mercantile).getModified() + repTerm + luckTerm + persTerm) * fatigueTerm; + + int currentDisposition = std::min(100, std::max(0, int(getDerivedDisposition(npc) + currentTemporaryDispositionDelta))); + + float d = 1 - 0.02 * abs(currentDisposition - 50); + float target1 = d * (playerRating1 - npcRating1 + 50); + float target2 = d * (playerRating2 - npcRating2 + 50); + + float bribeMod; + if (type == PT_Bribe10) bribeMod = gmst.find("fBribe10Mod")->getFloat(); + if (type == PT_Bribe100) bribeMod = gmst.find("fBribe100Mod")->getFloat(); + else bribeMod = gmst.find("fBribe1000Mod")->getFloat(); + + float target3 = d * (playerRating3 - npcRating3 + 50) + bribeMod; + + float iPerMinChance = gmst.find("iPerMinChance")->getInt(); + float iPerMinChange = gmst.find("iPerMinChange")->getInt(); + float fPerDieRollMult = gmst.find("fPerDieRollMult")->getFloat(); + float fPerTempMult = gmst.find("fPerTempMult")->getFloat(); + + float x,y; + + float roll = static_cast (std::rand()) / RAND_MAX * 100; + + if (type == PT_Admire) + { + target1 = std::max(iPerMinChance, target1); + success = (roll <= target1); + float c = int(fPerDieRollMult * (target1 - roll)); + x = success ? std::max(iPerMinChange, c) : c; + } + else if (type == PT_Intimidate) + { + target2 = std::max(iPerMinChance, target2); + + success = (roll <= target2); + + float r; + if (roll != target2) + r = int(target2 - roll); + else + r = 1; + + if (roll <= target2) + { + float s = int(r * fPerDieRollMult * fPerTempMult); + + npcStats.setAiSetting (2, std::max(0, std::min(100, npcStats.getAiSetting (2) + int(std::max(iPerMinChange, s))))); + npcStats.setAiSetting (1, std::max(0, std::min(100, npcStats.getAiSetting (1) + int(std::min(-iPerMinChange, -s))))); + } + + float c = -std::abs(int(r * fPerDieRollMult)); + if (success) + { + if (std::abs(c) < iPerMinChange) + { + x = 0; + y = -iPerMinChange; + } + else + { + x = -int(c * fPerTempMult); + y = c; + } + } + else + { + x = int(c * fPerTempMult); + y = c; + } + } + else if (type == PT_Taunt) + { + target1 = std::max(iPerMinChance, target1); + success = (roll <= target1); + + float c = std::abs(int(target1 - roll)); + + if (roll <= target1) + { + float s = c * fPerDieRollMult * fPerTempMult; + + npcStats.setAiSetting (2, std::max(0, std::min(100, npcStats.getAiSetting (2) + std::min(-int(iPerMinChange), int(-s))))); + npcStats.setAiSetting (1, std::max(0, std::min(100, npcStats.getAiSetting (1) + std::max(int(iPerMinChange), int(s))))); + } + x = int(-c * fPerDieRollMult); + + if (success && std::abs(x) < iPerMinChange) + x = -iPerMinChange; + } + else // Bribe + { + target3 = std::max(iPerMinChance, target3); + success = (roll <= target3); + float c = int((target3 - roll) * fPerDieRollMult); + + x = success ? std::max(iPerMinChange, c) : c; + } + + tempChange = type == PT_Intimidate ? x : int(x * fPerTempMult); + + + float cappedDispositionChange = tempChange; + if (currentDisposition + tempChange > 100.f) + cappedDispositionChange = 100 - currentDisposition; + if (currentDisposition + tempChange < 0.f) + cappedDispositionChange = -currentDisposition; + + permChange = int(cappedDispositionChange / fPerTempMult); + if (type == PT_Intimidate) + { + permChange = success ? -int(cappedDispositionChange/ fPerTempMult) : y; + } + } } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 38536d3bd..f8d470a4e 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -64,7 +64,7 @@ namespace MWMechanics virtual void setPlayerName (const std::string& name); ///< Set player name. - virtual void setPlayerRace (const std::string& id, bool male); + virtual void setPlayerRace (const std::string& id, bool male, const std::string &head, const std::string &hair); ///< Set player race. virtual void setPlayerBirthsign (const std::string& id); @@ -79,9 +79,18 @@ namespace MWMechanics virtual void restoreDynamicStats(); ///< If the player is sleeping, this should be called every hour. + virtual int getBarterOffer(const MWWorld::Ptr& ptr,int basePrice, bool buying); + ///< This is used by every service to determine the price of objects given the trading skills of the player and NPC. + + virtual int getDerivedDisposition(const MWWorld::Ptr& ptr); + ///< Calculate the diposition of an NPC toward the player. + virtual int countDeaths (const std::string& id) const; ///< Return the number of deaths for actors with the given ID. + virtual void getPersuasionDispositionChange (const MWWorld::Ptr& npc, PersuasionType type, + float currentTemporaryDispositionDelta, bool& success, float& tempChange, float& permChange); + ///< Perform a persuasion action on NPC }; } diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index bbd42c147..26c4c8e9a 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -3,14 +3,17 @@ #include #include +#include +#include #include #include #include #include +#include -#include +#include "../mwworld/esmstore.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -18,8 +21,8 @@ #include "../mwbase/soundmanager.hpp" MWMechanics::NpcStats::NpcStats() -: mMovementFlags (0), mDrawState (DrawState_Nothing) -, mLevelProgress(0) +: mMovementFlags (0), mDrawState (DrawState_Nothing), mBounty (0) +, mLevelProgress(0), mDisposition(0), mVampire (0), mReputation(0), mWerewolf (false), mWerewolfKills (0) { mSkillIncreases.resize (ESM::Attribute::Length); for (int i=0; i& MWMechanics::NpcStats::getFactionRanks() return mFactionRank; } +std::set& MWMechanics::NpcStats::getExpelled() +{ + return mExpelled; +} + const std::map& MWMechanics::NpcStats::getFactionRanks() const { return mFactionRank; } +bool MWMechanics::NpcStats::isSameFaction (const NpcStats& npcStats) const +{ + for (std::map::const_iterator iter (mFactionRank.begin()); iter!=mFactionRank.end(); + ++iter) + if (npcStats.mFactionRank.find (iter->first)!=npcStats.mFactionRank.end()) + return true; + + return false; +} + float MWMechanics::NpcStats::getSkillGain (int skillIndex, const ESM::Class& class_, int usageType, int level) const { if (level<0) level = static_cast (getSkill (skillIndex).getBase()); - const ESM::Skill *skill = MWBase::Environment::get().getWorld()->getStore().skills.find (skillIndex); + const ESM::Skill *skill = + MWBase::Environment::get().getWorld()->getStore().get().find (skillIndex); float skillFactor = 1; if (usageType>=4) throw std::runtime_error ("skill usage type out of range"); - if (usageType>0) + if (usageType>=0) { skillFactor = skill->mData.mUseValue[usageType]; - if (skillFactor<=0) + if (skillFactor<0) throw std::runtime_error ("invalid skill gain factor"); + + if (skillFactor==0) + return 0; } - float typeFactor = - MWBase::Environment::get().getWorld()->getStore().gameSettings.find ("fMiscSkillBonus")->getFloat(); + const MWWorld::Store &gmst = + MWBase::Environment::get().getWorld()->getStore().get(); + + float typeFactor = gmst.find ("fMiscSkillBonus")->getFloat(); for (int i=0; i<5; ++i) if (class_.mData.mSkills[i][0]==skillIndex) { - typeFactor = - MWBase::Environment::get().getWorld()->getStore().gameSettings.find ("fMinorSkillBonus")->getFloat(); + typeFactor = gmst.find ("fMinorSkillBonus")->getFloat(); break; } @@ -111,8 +144,7 @@ float MWMechanics::NpcStats::getSkillGain (int skillIndex, const ESM::Class& cla for (int i=0; i<5; ++i) if (class_.mData.mSkills[i][1]==skillIndex) { - typeFactor = - MWBase::Environment::get().getWorld()->getStore().gameSettings.find ("fMajorSkillBonus")->getFloat(); + typeFactor = gmst.find ("fMajorSkillBonus")->getFloat(); break; } @@ -124,8 +156,7 @@ float MWMechanics::NpcStats::getSkillGain (int skillIndex, const ESM::Class& cla if (skill->mData.mSpecialization==class_.mData.mSpecialization) { - specialisationFactor = - MWBase::Environment::get().getWorld()->getStore().gameSettings.find ("fSpecialSkillBonus")->getFloat(); + specialisationFactor = gmst.find ("fSpecialSkillBonus")->getFloat(); if (specialisationFactor<=0) throw std::runtime_error ("invalid skill specialisation factor"); @@ -178,7 +209,8 @@ void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &clas mLevelProgress += levelProgress; // check the attribute this skill belongs to - const ESM::Skill* skill = MWBase::Environment::get().getWorld ()->getStore ().skills.find(skillIndex); + const ESM::Skill* skill = + MWBase::Environment::get().getWorld ()->getStore ().get().find(skillIndex); ++mSkillIncreases[skill->mData.mAttribute]; // Play sound & skill progress notification @@ -188,7 +220,7 @@ void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &clas std::stringstream message; message << boost::format(MWBase::Environment::get().getWindowManager ()->getGameSettingString ("sNotifyMessage39", "")) % std::string("#{" + ESM::Skill::sSkillNameIds[skillIndex] + "}") - % base; + % static_cast (base); MWBase::Environment::get().getWindowManager ()->messageBox(message.str(), std::vector()); if (mLevelProgress >= 10) @@ -237,3 +269,88 @@ bool MWMechanics::NpcStats::hasBeenUsed (const std::string& id) const { return mUsedIds.find (id)!=mUsedIds.end(); } + +int MWMechanics::NpcStats::getBounty() const +{ + return mBounty; +} + +void MWMechanics::NpcStats::setBounty (int bounty) +{ + mBounty = bounty; +} + +int MWMechanics::NpcStats::getFactionReputation (const std::string& faction) const +{ + std::map::const_iterator iter = mFactionReputation.find (faction); + + if (iter==mFactionReputation.end()) + return 0; + + return iter->second; +} + +void MWMechanics::NpcStats::setFactionReputation (const std::string& faction, int value) +{ + mFactionReputation[faction] = value; +} + +bool MWMechanics::NpcStats::isVampire() const +{ + return mVampire; +} + +void MWMechanics::NpcStats::setVampire (bool set) +{ + mVampire = set; +} + +int MWMechanics::NpcStats::getReputation() const +{ + return mReputation; +} + +void MWMechanics::NpcStats::setReputation(int reputation) +{ + mReputation = reputation; +} + +bool MWMechanics::NpcStats::hasSkillsForRank (const std::string& factionId, int rank) const +{ + if (rank<0 || rank>=10) + throw std::runtime_error ("rank index out of range"); + + const ESM::Faction& faction = + *MWBase::Environment::get().getWorld()->getStore().get().find (factionId); + + std::vector skills; + + for (int i=0; i<6; ++i) + skills.push_back (static_cast (getSkill (faction.mData.mSkillID[i]).getModified())); + + std::sort (skills.begin(), skills.end()); + + std::vector::const_reverse_iterator iter = skills.rbegin(); + + const ESM::RankData& rankData = faction.mData.mRankData[rank]; + + if (*iter=rankData.mSkill2; +} + +bool MWMechanics::NpcStats::isWerewolf() const +{ + return mWerewolf; +} + +void MWMechanics::NpcStats::setWerewolf (bool set) +{ + mWerewolf = set; +} + +int MWMechanics::NpcStats::getWerewolfKills() const +{ + return mWerewolfKills; +} diff --git a/apps/openmw/mwmechanics/npcstats.hpp b/apps/openmw/mwmechanics/npcstats.hpp index 48e63d7b6..af32bd294 100644 --- a/apps/openmw/mwmechanics/npcstats.hpp +++ b/apps/openmw/mwmechanics/npcstats.hpp @@ -43,8 +43,16 @@ namespace MWMechanics std::map mFactionRank; DrawState_ mDrawState; + int mDisposition; unsigned int mMovementFlags; Stat mSkill[27]; + int mBounty; + std::set mExpelled; + std::map mFactionReputation; + bool mVampire; + int mReputation; + bool mWerewolf; + int mWerewolfKills; int mLevelProgress; // 0-10 @@ -60,6 +68,14 @@ namespace MWMechanics void setDrawState (DrawState_ state); + int getBaseDisposition() const; + + void setBaseDisposition(int disposition); + + int getReputation() const; + + void setReputation(int reputation); + bool getMovementFlag (Flag flag) const; void setMovementFlag (Flag flag, bool state); @@ -70,6 +86,11 @@ namespace MWMechanics std::map& getFactionRanks(); + std::set& getExpelled(); + + bool isSameFaction (const NpcStats& npcStats) const; + ///< Do *this and \a npcStats share a faction? + const std::map& getFactionRanks() const; float getSkillGain (int skillIndex, const ESM::Class& class_, int usageType = -1, @@ -88,10 +109,30 @@ namespace MWMechanics int getLevelupAttributeMultiplier(int attribute) const; void levelUp(); - + void flagAsUsed (const std::string& id); - + bool hasBeenUsed (const std::string& id) const; + + int getBounty() const; + + void setBounty (int bounty); + + int getFactionReputation (const std::string& faction) const; + + void setFactionReputation (const std::string& faction, int value); + + bool isVampire() const; + + void setVampire (bool set); + + bool hasSkillsForRank (const std::string& factionId, int rank) const; + + bool isWerewolf() const; + + void setWerewolf (bool set); + + int getWerewolfKills() const; }; } diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index adfb35cd9..ef084f479 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -1,7 +1,7 @@ #include "spells.hpp" -#include +#include "../mwworld/esmstore.hpp" #include @@ -50,7 +50,8 @@ namespace MWMechanics for (TIterator iter = mSpells.begin(); iter!=mSpells.end(); ++iter) { - const ESM::Spell *spell = MWBase::Environment::get().getWorld()->getStore().spells.find (*iter); + const ESM::Spell *spell = + MWBase::Environment::get().getWorld()->getStore().get().find (*iter); if (spell->mData.mType==ESM::Spell::ST_Ability || spell->mData.mType==ESM::Spell::ST_Blight || spell->mData.mType==ESM::Spell::ST_Disease || spell->mData.mType==ESM::Spell::ST_Curse) @@ -74,4 +75,32 @@ namespace MWMechanics { return mSelectedSpell; } + + bool Spells::hasCommonDisease() const + { + for (TIterator iter = mSpells.begin(); iter!=mSpells.end(); ++iter) + { + const ESM::Spell *spell = + MWBase::Environment::get().getWorld()->getStore().get().find (*iter); + + if (spell->mData.mFlags & ESM::Spell::ST_Disease) + return true; + } + + return false; + } + + bool Spells::hasBlightDisease() const + { + for (TIterator iter = mSpells.begin(); iter!=mSpells.end(); ++iter) + { + const ESM::Spell *spell = + MWBase::Environment::get().getWorld()->getStore().get().find (*iter); + + if (spell->mData.mFlags & ESM::Spell::ST_Blight) + return true; + } + + return false; + } } diff --git a/apps/openmw/mwmechanics/spells.hpp b/apps/openmw/mwmechanics/spells.hpp index d90f5b502..12308661b 100644 --- a/apps/openmw/mwmechanics/spells.hpp +++ b/apps/openmw/mwmechanics/spells.hpp @@ -55,6 +55,10 @@ namespace MWMechanics const std::string getSelectedSpell() const; ///< May return an empty string. + + bool hasCommonDisease() const; + + bool hasBlightDisease() const; }; } diff --git a/apps/openmw/mwmechanics/spellsuccess.hpp b/apps/openmw/mwmechanics/spellsuccess.hpp index a46667cdc..57c600df5 100644 --- a/apps/openmw/mwmechanics/spellsuccess.hpp +++ b/apps/openmw/mwmechanics/spellsuccess.hpp @@ -8,7 +8,7 @@ #include "../mwworld/class.hpp" #include "../mwmechanics/creaturestats.hpp" -#include +#include "../mwworld/esmstore.hpp" #include "npcstats.hpp" @@ -40,7 +40,8 @@ namespace MWMechanics for (std::vector::const_iterator it = effects.begin(); it != effects.end(); ++it) { - const ESM::MagicEffect* effect = MWBase::Environment::get().getWorld()->getStore().magicEffects.find(it->mEffectID); + const ESM::MagicEffect* effect = + MWBase::Environment::get().getWorld()->getStore().get().find(it->mEffectID); int _school = effect->mData.mSchool; int _skillLevel = stats.getSkill (spellSchoolToSkill(_school)).getModified(); @@ -61,7 +62,8 @@ namespace MWMechanics inline int getSpellSchool(const std::string& spellId, const MWWorld::Ptr& actor) { - const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(spellId); + const ESM::Spell* spell = + MWBase::Environment::get().getWorld()->getStore().get().find(spellId); return getSpellSchool(spell, actor); } @@ -107,7 +109,8 @@ namespace MWMechanics inline float getSpellSuccessChance (const std::string& spellId, const MWWorld::Ptr& actor) { - const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(spellId); + const ESM::Spell* spell = + MWBase::Environment::get().getWorld()->getStore().get().find(spellId); return getSpellSuccessChance(spell, actor); } } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index ef92497e5..2a3b8cf43 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -7,7 +7,6 @@ #include #include - namespace MWRender { diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 017062baa..0a11dc281 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -48,8 +48,9 @@ namespace MWRender mNode->setVisible (false); - mCamera->setPosition(mPosition); - mCamera->lookAt(mLookAt); + Ogre::Vector3 scale = mNode->getScale(); + mCamera->setPosition(mPosition * scale); + mCamera->lookAt(mLookAt * scale); mCamera->setNearClipDistance (0.01); mCamera->setFarClipDistance (1000); @@ -80,6 +81,22 @@ namespace MWRender delete mAnimation; } + void CharacterPreview::rebuild() + { + assert(mAnimation); + delete mAnimation; + + mAnimation = new NpcAnimation(mCharacter, mNode, + MWWorld::Class::get(mCharacter).getInventoryStore (mCharacter), RV_PlayerPreview); + + mNode->setVisible (false); + + Ogre::Vector3 scale = mNode->getScale(); + mCamera->setPosition(mPosition * scale); + mCamera->lookAt(mLookAt * scale); + + onSetup(); + } // -------------------------------------------------------------------------------------------------- @@ -128,8 +145,10 @@ namespace MWRender RaceSelectionPreview::RaceSelectionPreview() : CharacterPreview(MWBase::Environment::get().getWorld()->getPlayer().getPlayer(), 512, 512, "CharacterHeadPreview", Ogre::Vector3(0, 120, -35), Ogre::Vector3(0,125,0)) + , mRef(&mBase) { - + mBase = *mCharacter.get()->mBase; + mCharacter = MWWorld::Ptr(&mRef, mCharacter.getCell()); } void RaceSelectionPreview::update(float angle) @@ -141,4 +160,11 @@ namespace MWRender mNode->setVisible (false); } + void RaceSelectionPreview::setPrototype(const ESM::NPC &proto) + { + mBase = proto; + mBase.mId = "player"; + rebuild(); + update(0); + } } diff --git a/apps/openmw/mwrender/characterpreview.hpp b/apps/openmw/mwrender/characterpreview.hpp index 2a6b12b9e..18362d1db 100644 --- a/apps/openmw/mwrender/characterpreview.hpp +++ b/apps/openmw/mwrender/characterpreview.hpp @@ -4,6 +4,7 @@ #include #include +#include #include "externalrendering.hpp" @@ -32,6 +33,7 @@ namespace MWRender virtual void setup (Ogre::SceneManager *sceneManager); virtual void onSetup(); + virtual void rebuild(); protected: Ogre::TexturePtr mTexture; @@ -77,10 +79,19 @@ namespace MWRender class RaceSelectionPreview : public CharacterPreview { + ESM::NPC mBase; + MWWorld::LiveCellRef mRef; + public: RaceSelectionPreview(); void update(float angle); + + const ESM::NPC &getPrototype() const { + return mBase; + } + + void setPrototype(const ESM::NPC &proto); }; } diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index afd114972..7ee361a6f 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -21,10 +21,10 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr): Animation() mInsert = ptr.getRefData().getBaseNode(); MWWorld::LiveCellRef *ref = ptr.get(); - assert (ref->base != NULL); - if(!ref->base->mModel.empty()) + assert (ref->mBase != NULL); + if(!ref->mBase->mModel.empty()) { - std::string mesh = "meshes\\" + ref->base->mModel; + std::string mesh = "meshes\\" + ref->mBase->mModel; mEntityList = NifOgre::NIFLoader::createEntities(mInsert, &mTextKeys, mesh); for(size_t i = 0;i < mEntityList.mEntities.size();i++) diff --git a/apps/openmw/mwrender/debugging.cpp b/apps/openmw/mwrender/debugging.cpp index 4f7150754..1548cc1b0 100644 --- a/apps/openmw/mwrender/debugging.cpp +++ b/apps/openmw/mwrender/debugging.cpp @@ -11,7 +11,7 @@ #include #include -#include +#include "../mwworld/esmstore.hpp" #include "../mwbase/world.hpp" // these includes can be removed once the static-hack is gone #include "../mwbase/environment.hpp" @@ -228,22 +228,23 @@ void Debugging::togglePathgrid() void Debugging::enableCellPathgrid(MWWorld::Ptr::CellStore *store) { - ESM::Pathgrid *pathgrid = MWBase::Environment::get().getWorld()->getStore().pathgrids.search(*store->cell); + const ESM::Pathgrid *pathgrid = + MWBase::Environment::get().getWorld()->getStore().get().search(*store->mCell); if (!pathgrid) return; Vector3 cellPathGridPos(0, 0, 0); - if (store->cell->isExterior()) + if (store->mCell->isExterior()) { - cellPathGridPos.x = store->cell->mData.mX * ESM::Land::REAL_SIZE; - cellPathGridPos.y = store->cell->mData.mY * ESM::Land::REAL_SIZE; + cellPathGridPos.x = store->mCell->mData.mX * ESM::Land::REAL_SIZE; + cellPathGridPos.y = store->mCell->mData.mY * ESM::Land::REAL_SIZE; } SceneNode *cellPathGrid = mPathGridRoot->createChildSceneNode(cellPathGridPos); cellPathGrid->attachObject(createPathgridLines(pathgrid)); cellPathGrid->attachObject(createPathgridPoints(pathgrid)); - if (store->cell->isExterior()) + if (store->mCell->isExterior()) { - mExteriorPathgridNodes[std::make_pair(store->cell->mData.mX, store->cell->mData.mY)] = cellPathGrid; + mExteriorPathgridNodes[std::make_pair(store->mCell->getGridX(), store->mCell->getGridY())] = cellPathGrid; } else { @@ -254,10 +255,10 @@ void Debugging::enableCellPathgrid(MWWorld::Ptr::CellStore *store) void Debugging::disableCellPathgrid(MWWorld::Ptr::CellStore *store) { - if (store->cell->isExterior()) + if (store->mCell->isExterior()) { ExteriorPathgridNodes::iterator it = - mExteriorPathgridNodes.find(std::make_pair(store->cell->mData.mX, store->cell->mData.mY)); + mExteriorPathgridNodes.find(std::make_pair(store->mCell->getGridX(), store->mCell->getGridY())); if (it != mExteriorPathgridNodes.end()) { destroyCellPathgridNode(it->second); diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 7a799a2e4..072015f9a 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -1,18 +1,19 @@ #include "globalmap.hpp" #include +#include #include #include #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" -#include -#include +#include "../mwworld/esmstore.hpp" namespace MWRender { @@ -29,24 +30,28 @@ namespace MWRender { Ogre::TexturePtr tex; + const MWWorld::ESMStore &esmStore = + MWBase::Environment::get().getWorld()->getStore(); + // get the size of the world - const ESMS::CellList::ExtCells& extCells = MWBase::Environment::get().getWorld ()->getStore ().cells.extCells; - for (ESMS::CellList::ExtCells::const_iterator it = extCells.begin(); it != extCells.end(); ++it) + MWWorld::Store::iterator it = esmStore.get().extBegin(); + for (; it != esmStore.get().extEnd(); ++it) { - if (it->first.first < mMinX) - mMinX = it->first.first; - if (it->first.first > mMaxX) - mMaxX = it->first.first; - if (it->first.second < mMinY) - mMinY = it->first.second; - if (it->first.second > mMaxY) - mMaxY = it->first.second; + if (it->getGridX() < mMinX) + mMinX = it->getGridX(); + if (it->getGridX() > mMaxX) + mMaxX = it->getGridX(); + if (it->getGridY() < mMinY) + mMinY = it->getGridY(); + if (it->getGridY() > mMaxY) + mMaxY = it->getGridY(); } int cellSize = 24; mWidth = cellSize*(mMaxX-mMinX+1); mHeight = cellSize*(mMaxY-mMinY+1); + mExploredBuffer.resize((mMaxX-mMinX+1) * (mMaxY-mMinY+1) * 4); //if (!boost::filesystem::exists(mCacheDir + "/GlobalMap.png")) if (1) @@ -59,7 +64,7 @@ namespace MWRender { for (int y = mMinY; y <= mMaxY; ++y) { - ESM::Land* land = MWBase::Environment::get().getWorld ()->getStore ().lands.search (x,y); + ESM::Land* land = esmStore.get().search (x,y); if (land) { @@ -155,13 +160,30 @@ namespace MWRender //image.save (mCacheDir + "/GlobalMap.png"); tex = Ogre::TextureManager::getSingleton ().createManual ("GlobalMap.png", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - Ogre::TEX_TYPE_2D, mWidth, mHeight, 0, Ogre::PF_B8G8R8, Ogre::TU_DEFAULT); + Ogre::TEX_TYPE_2D, mWidth, mHeight, 0, Ogre::PF_B8G8R8, Ogre::TU_STATIC); tex->loadImage(image); } else tex = Ogre::TextureManager::getSingleton ().getByName ("GlobalMap.png"); tex->load(); + + + + + mOverlayTexture = Ogre::TextureManager::getSingleton().createManual("GlobalMapOverlay", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, + Ogre::TEX_TYPE_2D, mWidth, mHeight, 0, Ogre::PF_A8B8G8R8, Ogre::TU_DYNAMIC_WRITE_ONLY); + + + std::vector buffer; + buffer.resize(mWidth * mHeight); + + // initialize to (0, 0, 0, 0) + for (int p=0; pgetBuffer()->lock(Ogre::HardwareBuffer::HBL_DISCARD), &buffer[0], mWidth*mHeight*4); + mOverlayTexture->getBuffer()->unlock(); } void GlobalMap::worldPosToImageSpace(float x, float z, float& imageX, float& imageY) @@ -179,5 +201,32 @@ namespace MWRender imageY = 1.f-float(y - mMinY + 1) / (mMaxY - mMinY + 1); } + void GlobalMap::exploreCell(int cellX, int cellY) + { + float originX = (cellX - mMinX) * 24; + // NB y + 1, because we want the top left corner, not bottom left where the origin of the cell is + float originY = mHeight - (cellY+1 - mMinY) * 24; + if (cellX > mMaxX || cellX < mMinX || cellY > mMaxY || cellY < mMinY) + return; + + Ogre::TexturePtr localMapTexture = Ogre::TextureManager::getSingleton().getByName("Cell_" + + boost::lexical_cast(cellX) + "_" + boost::lexical_cast(cellY)); + + // mipmap version - can't get ogre to generate automips.. + /*if (!localMapTexture.isNull()) + { + assert(localMapTexture->getBuffer(0, 4)->getWidth() == 64); // 1024 / 2^4 + + mOverlayTexture->getBuffer()->blit(localMapTexture->getBuffer(0, 4), Ogre::Image::Box(0,0,64, 64), + Ogre::Image::Box(originX,originY,originX+24,originY+24)); + }*/ + + if (!localMapTexture.isNull()) + { + + mOverlayTexture->getBuffer()->blit(localMapTexture->getBuffer(), Ogre::Image::Box(0,0,512,512), + Ogre::Image::Box(originX,originY,originX+24,originY+24)); + } + } } diff --git a/apps/openmw/mwrender/globalmap.hpp b/apps/openmw/mwrender/globalmap.hpp index 01f5fdb9e..c01182c5b 100644 --- a/apps/openmw/mwrender/globalmap.hpp +++ b/apps/openmw/mwrender/globalmap.hpp @@ -3,6 +3,8 @@ #include +#include + namespace MWRender { @@ -22,9 +24,16 @@ namespace MWRender void cellTopLeftCornerToImageSpace(int x, int y, float& imageX, float& imageY); + void exploreCell (int cellX, int cellY); + private: std::string mCacheDir; + std::vector< std::pair > mExploredCells; + + Ogre::TexturePtr mOverlayTexture; + std::vector mExploredBuffer; + int mWidth; int mHeight; diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 1bdbce6d9..d878cb86e 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include "../mwworld/esmstore.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -108,10 +108,10 @@ void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell) mCameraRotNode->setOrientation(Quaternion::IDENTITY); - std::string name = "Cell_"+coordStr(cell->cell->mData.mX, cell->cell->mData.mY); + int x = cell->mCell->getGridX(); + int y = cell->mCell->getGridY(); - int x = cell->cell->mData.mX; - int y = cell->cell->mData.mY; + std::string name = "Cell_"+coordStr(x, y); mCameraPosNode->setPosition(Vector3(0,0,0)); @@ -163,7 +163,7 @@ void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell, const int segsX = std::ceil( length.x / sSize ); const int segsY = std::ceil( length.y / sSize ); - mInteriorName = cell->cell->mName; + mInteriorName = cell->mCell->mName; for (int x=0; xcell->mName + "_" + coordStr(x,y)); + cell->mCell->mName + "_" + coordStr(x,y)); } } } diff --git a/apps/openmw/mwrender/localmap.hpp b/apps/openmw/mwrender/localmap.hpp index 056d2498a..1aedf1325 100644 --- a/apps/openmw/mwrender/localmap.hpp +++ b/apps/openmw/mwrender/localmap.hpp @@ -58,7 +58,6 @@ namespace MWRender */ void saveFogOfWar(MWWorld::CellStore* cell); - /** * Get the interior map texture index and normalized position * on this texture, given a world position (in ogre coordinates) @@ -75,7 +74,7 @@ namespace MWRender MWRender::RenderingManager* mRenderingManager; // 1024*1024 pixels for a cell - static const int sMapResolution = 1024; + static const int sMapResolution = 512; // the dynamic texture is a bottleneck, so don't set this too high static const int sFogOfWarResolution = 32; diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 5c2b05aca..e6a8006e2 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include "../mwworld/esmstore.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -17,44 +17,54 @@ using namespace NifOgre; namespace MWRender{ NpcAnimation::~NpcAnimation() { - removeEntities(head); - removeEntities(hair); - removeEntities(neck); - removeEntities(chest); - removeEntities(groin); - removeEntities(skirt); - removeEntities(rHand); - removeEntities(lHand); - removeEntities(rWrist); - removeEntities(lWrist); - removeEntities(rForearm); - removeEntities(lForearm); - removeEntities(rupperArm); - removeEntities(lupperArm); - removeEntities(rfoot); - removeEntities(lfoot); - removeEntities(rAnkle); - removeEntities(lAnkle); - removeEntities(rKnee); - removeEntities(lKnee); - removeEntities(rUpperLeg); - removeEntities(lUpperLeg); - removeEntities(rclavicle); - removeEntities(lclavicle); - removeEntities(tail); + removeEntities(mHead); + removeEntities(mHair); + removeEntities(mNeck); + removeEntities(mChest); + removeEntities(mGroin); + removeEntities(mSkirt); + removeEntities(mHandL); + removeEntities(mHandR); + removeEntities(mWristL); + removeEntities(mWristR); + removeEntities(mForearmL); + removeEntities(mForearmR); + removeEntities(mUpperArmL); + removeEntities(mUpperArmR); + removeEntities(mFootL); + removeEntities(mFootR); + removeEntities(mAnkleL); + removeEntities(mAnkleR); + removeEntities(mKneeL); + removeEntities(mKneeR); + removeEntities(mUpperLegL); + removeEntities(mUpperLegR); + removeEntities(mClavicleL); + removeEntities(mClavicleR); + removeEntities(mTail); } -NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWorld::InventoryStore& _inv, int visibilityFlags) - : Animation(), mStateID(-1), mInv(_inv), timeToChange(0), mVisibilityFlags(visibilityFlags), - robe(mInv.end()), helmet(mInv.end()), shirt(mInv.end()), - cuirass(mInv.end()), greaves(mInv.end()), - leftpauldron(mInv.end()), rightpauldron(mInv.end()), - boots(mInv.end()), - leftglove(mInv.end()), rightglove(mInv.end()), skirtiter(mInv.end()), - pants(mInv.end()) +NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWorld::InventoryStore& inv, int visibilityFlags) + : Animation(), + mStateID(-1), + mInv(inv), + mTimeToChange(0), + mVisibilityFlags(visibilityFlags), + mRobe(mInv.end()), + mHelmet(mInv.end()), + mShirt(mInv.end()), + mCuirass(mInv.end()), + mGreaves(mInv.end()), + mPauldronL(mInv.end()), + mPauldronR(mInv.end()), + mBoots(mInv.end()), + mPants(mInv.end()), + mGloveL(mInv.end()), + mGloveR(mInv.end()), + mSkirtIter(mInv.end()) { - MWWorld::LiveCellRef *ref = ptr.get(); + mNpc = ptr.get()->mBase; for (int init = 0; init < 27; init++) { @@ -62,25 +72,20 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor mPartPriorities[init] = 0; } - const ESMS::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - const ESM::Race *race = store.races.find(ref->base->mRace); + const MWWorld::ESMStore &store = + MWBase::Environment::get().getWorld()->getStore(); + const ESM::Race *race = store.get().find(mNpc->mRace); - std::string hairID = ref->base->mHair; - std::string headID = ref->base->mHead; - headModel = "meshes\\" + store.bodyParts.find(headID)->mModel; - hairModel = "meshes\\" + store.bodyParts.find(hairID)->mModel; - npcName = ref->base->mName; - - isFemale = !!(ref->base->mFlags&ESM::NPC::Female); - isBeast = !!(race->mData.mFlags&ESM::Race::Beast); - - bodyRaceID = "b_n_"+ref->base->mRace; - std::transform(bodyRaceID.begin(), bodyRaceID.end(), bodyRaceID.begin(), ::tolower); + mHeadModel = "meshes\\" + store.get().find(mNpc->mHead)->mModel; + mHairModel = "meshes\\" + store.get().find(mNpc->mHair)->mModel; + mBodyPrefix = "b_n_" + mNpc->mRace; + std::transform(mBodyPrefix.begin(), mBodyPrefix.end(), mBodyPrefix.begin(), ::tolower); mInsert = node; assert(mInsert); + bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0; std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif"); mEntityList = NifOgre::NIFLoader::createEntities(mInsert, &mTextKeys, smodel); @@ -124,7 +129,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor } float scale = race->mData.mHeight.mMale; - if (isFemale) { + if (!mNpc->isMale()) { scale = race->mData.mHeight.mFemale; } mInsert->scale(scale, scale, scale); @@ -140,18 +145,18 @@ void NpcAnimation::updateParts() MWWorld::ContainerStoreIterator *iter; int slot; } slotlist[] = { - { &robe, MWWorld::InventoryStore::Slot_Robe }, - { &skirtiter, MWWorld::InventoryStore::Slot_Skirt }, - { &helmet, MWWorld::InventoryStore::Slot_Helmet }, - { &cuirass, MWWorld::InventoryStore::Slot_Cuirass }, - { &greaves, MWWorld::InventoryStore::Slot_Greaves }, - { &leftpauldron, MWWorld::InventoryStore::Slot_LeftPauldron }, - { &rightpauldron, MWWorld::InventoryStore::Slot_RightPauldron }, - { &boots, MWWorld::InventoryStore::Slot_Boots }, - { &leftglove, MWWorld::InventoryStore::Slot_LeftGauntlet }, - { &rightglove, MWWorld::InventoryStore::Slot_RightGauntlet }, - { &shirt, MWWorld::InventoryStore::Slot_Shirt }, - { &pants, MWWorld::InventoryStore::Slot_Pants }, + { &mRobe, MWWorld::InventoryStore::Slot_Robe }, + { &mSkirtIter, MWWorld::InventoryStore::Slot_Skirt }, + { &mHelmet, MWWorld::InventoryStore::Slot_Helmet }, + { &mCuirass, MWWorld::InventoryStore::Slot_Cuirass }, + { &mGreaves, MWWorld::InventoryStore::Slot_Greaves }, + { &mPauldronL, MWWorld::InventoryStore::Slot_LeftPauldron }, + { &mPauldronR, MWWorld::InventoryStore::Slot_RightPauldron }, + { &mBoots, MWWorld::InventoryStore::Slot_Boots }, + { &mGloveL, MWWorld::InventoryStore::Slot_LeftGauntlet }, + { &mGloveR, MWWorld::InventoryStore::Slot_RightGauntlet }, + { &mShirt, MWWorld::InventoryStore::Slot_Shirt }, + { &mPants, MWWorld::InventoryStore::Slot_Pants }, }; for(size_t i = 0;i < sizeof(slotlist)/sizeof(slotlist[0]);i++) { @@ -166,11 +171,11 @@ void NpcAnimation::updateParts() if(apparelChanged) { - if(robe != mInv.end()) + if(mRobe != mInv.end()) { - MWWorld::Ptr ptr = *robe; + MWWorld::Ptr ptr = *mRobe; - const ESM::Clothing *clothes = (ptr.get())->base; + const ESM::Clothing *clothes = (ptr.get())->mBase; std::vector parts = clothes->mParts.mParts; addPartGroup(MWWorld::InventoryStore::Slot_Robe, 5, parts); reserveIndividualPart(ESM::PRT_Groin, MWWorld::InventoryStore::Slot_Robe, 5); @@ -186,11 +191,11 @@ void NpcAnimation::updateParts() reserveIndividualPart(ESM::PRT_RPauldron, MWWorld::InventoryStore::Slot_Robe, 5); reserveIndividualPart(ESM::PRT_LPauldron, MWWorld::InventoryStore::Slot_Robe, 5); } - if(skirtiter != mInv.end()) + if(mSkirtIter != mInv.end()) { - MWWorld::Ptr ptr = *skirtiter; + MWWorld::Ptr ptr = *mSkirtIter; - const ESM::Clothing *clothes = (ptr.get())->base; + const ESM::Clothing *clothes = (ptr.get())->mBase; std::vector parts = clothes->mParts.mParts; addPartGroup(MWWorld::InventoryStore::Slot_Skirt, 4, parts); reserveIndividualPart(ESM::PRT_Groin, MWWorld::InventoryStore::Slot_Skirt, 4); @@ -198,103 +203,103 @@ void NpcAnimation::updateParts() reserveIndividualPart(ESM::PRT_LLeg, MWWorld::InventoryStore::Slot_Skirt, 4); } - if(helmet != mInv.end()) + if(mHelmet != mInv.end()) { removeIndividualPart(ESM::PRT_Hair); - const ESM::Armor *armor = (helmet->get())->base; + const ESM::Armor *armor = (mHelmet->get())->mBase; std::vector parts = armor->mParts.mParts; addPartGroup(MWWorld::InventoryStore::Slot_Helmet, 3, parts); } - if(cuirass != mInv.end()) + if(mCuirass != mInv.end()) { - const ESM::Armor *armor = (cuirass->get())->base; + const ESM::Armor *armor = (mCuirass->get())->mBase; std::vector parts = armor->mParts.mParts; addPartGroup(MWWorld::InventoryStore::Slot_Cuirass, 3, parts); } - if(greaves != mInv.end()) + if(mGreaves != mInv.end()) { - const ESM::Armor *armor = (greaves->get())->base; + const ESM::Armor *armor = (mGreaves->get())->mBase; std::vector parts = armor->mParts.mParts; addPartGroup(MWWorld::InventoryStore::Slot_Greaves, 3, parts); } - if(leftpauldron != mInv.end()) + if(mPauldronL != mInv.end()) { - const ESM::Armor *armor = (leftpauldron->get())->base; + const ESM::Armor *armor = (mPauldronL->get())->mBase; std::vector parts = armor->mParts.mParts; addPartGroup(MWWorld::InventoryStore::Slot_LeftPauldron, 3, parts); } - if(rightpauldron != mInv.end()) + if(mPauldronR != mInv.end()) { - const ESM::Armor *armor = (rightpauldron->get())->base; + const ESM::Armor *armor = (mPauldronR->get())->mBase; std::vector parts = armor->mParts.mParts; addPartGroup(MWWorld::InventoryStore::Slot_RightPauldron, 3, parts); } - if(boots != mInv.end()) + if(mBoots != mInv.end()) { - if(boots->getTypeName() == typeid(ESM::Clothing).name()) + if(mBoots->getTypeName() == typeid(ESM::Clothing).name()) { - const ESM::Clothing *clothes = (boots->get())->base; + const ESM::Clothing *clothes = (mBoots->get())->mBase; std::vector parts = clothes->mParts.mParts; addPartGroup(MWWorld::InventoryStore::Slot_Boots, 2, parts); } - else if(boots->getTypeName() == typeid(ESM::Armor).name()) + else if(mBoots->getTypeName() == typeid(ESM::Armor).name()) { - const ESM::Armor *armor = (boots->get())->base; + const ESM::Armor *armor = (mBoots->get())->mBase; std::vector parts = armor->mParts.mParts; addPartGroup(MWWorld::InventoryStore::Slot_Boots, 3, parts); } } - if(leftglove != mInv.end()) + if(mGloveL != mInv.end()) { - if(leftglove->getTypeName() == typeid(ESM::Clothing).name()) + if(mGloveL->getTypeName() == typeid(ESM::Clothing).name()) { - const ESM::Clothing *clothes = (leftglove->get())->base; + const ESM::Clothing *clothes = (mGloveL->get())->mBase; std::vector parts = clothes->mParts.mParts; addPartGroup(MWWorld::InventoryStore::Slot_LeftGauntlet, 2, parts); } else { - const ESM::Armor *armor = (leftglove->get())->base; + const ESM::Armor *armor = (mGloveL->get())->mBase; std::vector parts = armor->mParts.mParts; addPartGroup(MWWorld::InventoryStore::Slot_LeftGauntlet, 3, parts); } } - if(rightglove != mInv.end()) + if(mGloveR != mInv.end()) { - if(rightglove->getTypeName() == typeid(ESM::Clothing).name()) + if(mGloveR->getTypeName() == typeid(ESM::Clothing).name()) { - const ESM::Clothing *clothes = (rightglove->get())->base; + const ESM::Clothing *clothes = (mGloveR->get())->mBase; std::vector parts = clothes->mParts.mParts; addPartGroup(MWWorld::InventoryStore::Slot_RightGauntlet, 2, parts); } else { - const ESM::Armor *armor = (rightglove->get())->base; + const ESM::Armor *armor = (mGloveR->get())->mBase; std::vector parts = armor->mParts.mParts; addPartGroup(MWWorld::InventoryStore::Slot_RightGauntlet, 3, parts); } } - if(shirt != mInv.end()) + if(mShirt != mInv.end()) { - const ESM::Clothing *clothes = (shirt->get())->base; + const ESM::Clothing *clothes = (mShirt->get())->mBase; std::vector parts = clothes->mParts.mParts; addPartGroup(MWWorld::InventoryStore::Slot_Shirt, 2, parts); } - if(pants != mInv.end()) + if(mPants != mInv.end()) { - const ESM::Clothing *clothes = (pants->get())->base; + const ESM::Clothing *clothes = (mPants->get())->mBase; std::vector parts = clothes->mParts.mParts; addPartGroup(MWWorld::InventoryStore::Slot_Pants, 2, parts); } } if(mPartPriorities[ESM::PRT_Head] < 1) - addOrReplaceIndividualPart(ESM::PRT_Head, -1,1, headModel); + addOrReplaceIndividualPart(ESM::PRT_Head, -1,1, mHeadModel); if(mPartPriorities[ESM::PRT_Hair] < 1 && mPartPriorities[ESM::PRT_Head] <= 1) - addOrReplaceIndividualPart(ESM::PRT_Hair, -1,1, hairModel); + addOrReplaceIndividualPart(ESM::PRT_Hair, -1,1, mHairModel); static const struct { ESM::PartReferenceType type; @@ -322,26 +327,27 @@ void NpcAnimation::updateParts() { ESM::PRT_Tail, { "tail", "" } } }; - const ESMS::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); for(size_t i = 0;i < sizeof(PartTypeList)/sizeof(PartTypeList[0]);i++) { if(mPartPriorities[PartTypeList[i].type] < 1) { const ESM::BodyPart *part = NULL; - bool tryfemale = isFemale; - int ni = 0; - do { - part = store.bodyParts.search(bodyRaceID+(tryfemale?"_f_":"_m_")+PartTypeList[i].name[ni]); - if(part) break; + const MWWorld::Store &partStore = + store.get(); - ni ^= 1; - if(ni == 0) - { - if(!tryfemale) - break; - tryfemale = false; + if (!mNpc->isMale()) { + part = partStore.search(mBodyPrefix + "_f_" + PartTypeList[i].name[0]); + if (part == 0) { + part = partStore.search(mBodyPrefix + "_f_" + PartTypeList[i].name[1]); } - } while(1); + } + if (part == 0) { + part = partStore.search(mBodyPrefix + "_m_" + PartTypeList[i].name[0]); + } + if (part == 0) { + part = partStore.search(mBodyPrefix + "_m_" + PartTypeList[i].name[1]); + } if(part) addOrReplaceIndividualPart(PartTypeList[i].type, -1,1, "meshes\\"+part->mModel); @@ -364,12 +370,12 @@ NifOgre::EntityList NpcAnimation::insertBoundedPart(const std::string &mesh, int void NpcAnimation::runAnimation(float timepassed) { - if(timeToChange > .2) + if(mTimeToChange > .2) { - timeToChange = 0; + mTimeToChange = 0; updateParts(); } - timeToChange += timepassed; + mTimeToChange += timepassed; Animation::runAnimation(timepassed); } @@ -394,61 +400,61 @@ void NpcAnimation::removeIndividualPart(int type) mPartslots[type] = -1; if(type == ESM::PRT_Head) //0 - removeEntities(head); + removeEntities(mHead); else if(type == ESM::PRT_Hair) //1 - removeEntities(hair); + removeEntities(mHair); else if(type == ESM::PRT_Neck) //2 - removeEntities(neck); + removeEntities(mNeck); else if(type == ESM::PRT_Cuirass)//3 - removeEntities(chest); + removeEntities(mChest); else if(type == ESM::PRT_Groin)//4 - removeEntities(groin); + removeEntities(mGroin); else if(type == ESM::PRT_Skirt)//5 - removeEntities(skirt); + removeEntities(mSkirt); else if(type == ESM::PRT_RHand)//6 - removeEntities(rHand); + removeEntities(mHandR); else if(type == ESM::PRT_LHand)//7 - removeEntities(lHand); + removeEntities(mHandL); else if(type == ESM::PRT_RWrist)//8 - removeEntities(rWrist); + removeEntities(mWristR); else if(type == ESM::PRT_LWrist) //9 - removeEntities(lWrist); + removeEntities(mWristL); else if(type == ESM::PRT_Shield) //10 { } else if(type == ESM::PRT_RForearm) //11 - removeEntities(rForearm); + removeEntities(mForearmR); else if(type == ESM::PRT_LForearm) //12 - removeEntities(lForearm); + removeEntities(mForearmL); else if(type == ESM::PRT_RUpperarm) //13 - removeEntities(rupperArm); + removeEntities(mUpperArmR); else if(type == ESM::PRT_LUpperarm) //14 - removeEntities(lupperArm); + removeEntities(mUpperArmL); else if(type == ESM::PRT_RFoot) //15 - removeEntities(rfoot); + removeEntities(mFootR); else if(type == ESM::PRT_LFoot) //16 - removeEntities(lfoot); + removeEntities(mFootL); else if(type == ESM::PRT_RAnkle) //17 - removeEntities(rAnkle); + removeEntities(mAnkleR); else if(type == ESM::PRT_LAnkle) //18 - removeEntities(lAnkle); + removeEntities(mAnkleL); else if(type == ESM::PRT_RKnee) //19 - removeEntities(rKnee); + removeEntities(mKneeR); else if(type == ESM::PRT_LKnee) //20 - removeEntities(lKnee); + removeEntities(mKneeL); else if(type == ESM::PRT_RLeg) //21 - removeEntities(rUpperLeg); + removeEntities(mUpperLegR); else if(type == ESM::PRT_LLeg) //22 - removeEntities(lUpperLeg); + removeEntities(mUpperLegL); else if(type == ESM::PRT_RPauldron) //23 - removeEntities(rclavicle); + removeEntities(mClavicleR); else if(type == ESM::PRT_LPauldron) //24 - removeEntities(lclavicle); + removeEntities(mClavicleL); else if(type == ESM::PRT_Weapon) //25 { } else if(type == ESM::PRT_Tail) //26 - removeEntities(tail); + removeEntities(mTail); } void NpcAnimation::reserveIndividualPart(int type, int group, int priority) @@ -481,83 +487,83 @@ bool NpcAnimation::addOrReplaceIndividualPart(int type, int group, int priority, switch(type) { case ESM::PRT_Head: //0 - head = insertBoundedPart(mesh, group, "Head"); + mHead = insertBoundedPart(mesh, group, "Head"); break; case ESM::PRT_Hair: //1 - hair = insertBoundedPart(mesh, group, "Head"); + mHair = insertBoundedPart(mesh, group, "Head"); break; case ESM::PRT_Neck: //2 - neck = insertBoundedPart(mesh, group, "Neck"); + mNeck = insertBoundedPart(mesh, group, "Neck"); break; case ESM::PRT_Cuirass: //3 - chest = insertBoundedPart(mesh, group, "Chest"); + mChest = insertBoundedPart(mesh, group, "Chest"); break; case ESM::PRT_Groin: //4 - groin = insertBoundedPart(mesh, group, "Groin"); + mGroin = insertBoundedPart(mesh, group, "Groin"); break; case ESM::PRT_Skirt: //5 - skirt = insertBoundedPart(mesh, group, "Groin"); + mSkirt = insertBoundedPart(mesh, group, "Groin"); break; case ESM::PRT_RHand: //6 - rHand = insertBoundedPart(mesh, group, "Right Hand"); + mHandR = insertBoundedPart(mesh, group, "Right Hand"); break; case ESM::PRT_LHand: //7 - lHand = insertBoundedPart(mesh, group, "Left Hand"); + mHandL = insertBoundedPart(mesh, group, "Left Hand"); break; case ESM::PRT_RWrist: //8 - rWrist = insertBoundedPart(mesh, group, "Right Wrist"); + mWristR = insertBoundedPart(mesh, group, "Right Wrist"); break; case ESM::PRT_LWrist: //9 - lWrist = insertBoundedPart(mesh, group, "Left Wrist"); + mWristL = insertBoundedPart(mesh, group, "Left Wrist"); break; case ESM::PRT_Shield: //10 break; case ESM::PRT_RForearm: //11 - rForearm = insertBoundedPart(mesh, group, "Right Forearm"); + mForearmR = insertBoundedPart(mesh, group, "Right Forearm"); break; case ESM::PRT_LForearm: //12 - lForearm = insertBoundedPart(mesh, group, "Left Forearm"); + mForearmL = insertBoundedPart(mesh, group, "Left Forearm"); break; case ESM::PRT_RUpperarm: //13 - rupperArm = insertBoundedPart(mesh, group, "Right Upper Arm"); + mUpperArmR = insertBoundedPart(mesh, group, "Right Upper Arm"); break; case ESM::PRT_LUpperarm: //14 - lupperArm = insertBoundedPart(mesh, group, "Left Upper Arm"); + mUpperArmL = insertBoundedPart(mesh, group, "Left Upper Arm"); break; case ESM::PRT_RFoot: //15 - rfoot = insertBoundedPart(mesh, group, "Right Foot"); + mFootR = insertBoundedPart(mesh, group, "Right Foot"); break; case ESM::PRT_LFoot: //16 - lfoot = insertBoundedPart(mesh, group, "Left Foot"); + mFootL = insertBoundedPart(mesh, group, "Left Foot"); break; case ESM::PRT_RAnkle: //17 - rAnkle = insertBoundedPart(mesh, group, "Right Ankle"); + mAnkleR = insertBoundedPart(mesh, group, "Right Ankle"); break; case ESM::PRT_LAnkle: //18 - lAnkle = insertBoundedPart(mesh, group, "Left Ankle"); + mAnkleL = insertBoundedPart(mesh, group, "Left Ankle"); break; case ESM::PRT_RKnee: //19 - rKnee = insertBoundedPart(mesh, group, "Right Knee"); + mKneeR = insertBoundedPart(mesh, group, "Right Knee"); break; case ESM::PRT_LKnee: //20 - lKnee = insertBoundedPart(mesh, group, "Left Knee"); + mKneeL = insertBoundedPart(mesh, group, "Left Knee"); break; case ESM::PRT_RLeg: //21 - rUpperLeg = insertBoundedPart(mesh, group, "Right Upper Leg"); + mUpperLegR = insertBoundedPart(mesh, group, "Right Upper Leg"); break; case ESM::PRT_LLeg: //22 - lUpperLeg = insertBoundedPart(mesh, group, "Left Upper Leg"); + mUpperLegL = insertBoundedPart(mesh, group, "Left Upper Leg"); break; case ESM::PRT_RPauldron: //23 - rclavicle = insertBoundedPart(mesh , group, "Right Clavicle"); + mClavicleR = insertBoundedPart(mesh , group, "Right Clavicle"); break; case ESM::PRT_LPauldron: //24 - lclavicle = insertBoundedPart(mesh, group, "Left Clavicle"); + mClavicleL = insertBoundedPart(mesh, group, "Left Clavicle"); break; case ESM::PRT_Weapon: //25 break; case ESM::PRT_Tail: //26 - tail = insertBoundedPart(mesh, group, "Tail"); + mTail = insertBoundedPart(mesh, group, "Tail"); break; } return true; @@ -569,11 +575,14 @@ void NpcAnimation::addPartGroup(int group, int priority, std::vector &partStore = + MWBase::Environment::get().getWorld()->getStore().get(); + const ESM::BodyPart *bodypart = 0; - if(isFemale) - bodypart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search(part.mFemale); + if(!mNpc->isMale()) + bodypart = partStore.search(part.mFemale); if(!bodypart) - bodypart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search(part.mMale); + bodypart = partStore.search(part.mMale); if(bodypart) addOrReplaceIndividualPart(part.mPart, group, priority,"meshes\\" + bodypart->mModel); diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 21edb3be4..ca76dcc22 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -8,6 +8,11 @@ #include "../mwclass/npc.hpp" #include "../mwworld/containerstore.hpp" +namespace ESM +{ + struct NPC; +} + namespace MWRender{ class NpcAnimation: public Animation{ @@ -19,57 +24,57 @@ private: int mPartPriorities[27]; //Bounded Parts - NifOgre::EntityList lclavicle; - NifOgre::EntityList rclavicle; - NifOgre::EntityList rupperArm; - NifOgre::EntityList lupperArm; - NifOgre::EntityList rUpperLeg; - NifOgre::EntityList lUpperLeg; - NifOgre::EntityList lForearm; - NifOgre::EntityList rForearm; - NifOgre::EntityList lWrist; - NifOgre::EntityList rWrist; - NifOgre::EntityList rKnee; - NifOgre::EntityList lKnee; - NifOgre::EntityList neck; - NifOgre::EntityList rAnkle; - NifOgre::EntityList lAnkle; - NifOgre::EntityList groin; - NifOgre::EntityList skirt; - NifOgre::EntityList lfoot; - NifOgre::EntityList rfoot; - NifOgre::EntityList hair; - NifOgre::EntityList rHand; - NifOgre::EntityList lHand; - NifOgre::EntityList head; - NifOgre::EntityList chest; - NifOgre::EntityList tail; + NifOgre::EntityList mClavicleL; + NifOgre::EntityList mClavicleR; + NifOgre::EntityList mUpperArmL; + NifOgre::EntityList mUpperArmR; + NifOgre::EntityList mUpperLegL; + NifOgre::EntityList mUpperLegR; + NifOgre::EntityList mForearmL; + NifOgre::EntityList mForearmR; + NifOgre::EntityList mWristL; + NifOgre::EntityList mWristR; + NifOgre::EntityList mKneeR; + NifOgre::EntityList mKneeL; + NifOgre::EntityList mNeck; + NifOgre::EntityList mAnkleL; + NifOgre::EntityList mAnkleR; + NifOgre::EntityList mGroin; + NifOgre::EntityList mSkirt; + NifOgre::EntityList mFootL; + NifOgre::EntityList mFootR; + NifOgre::EntityList mHair; + NifOgre::EntityList mHandL; + NifOgre::EntityList mHandR; + NifOgre::EntityList mHead; + NifOgre::EntityList mChest; + NifOgre::EntityList mTail; - bool isBeast; - bool isFemale; - std::string headModel; - std::string hairModel; - std::string npcName; - std::string bodyRaceID; - float timeToChange; - MWWorld::ContainerStoreIterator robe; - MWWorld::ContainerStoreIterator helmet; - MWWorld::ContainerStoreIterator shirt; - MWWorld::ContainerStoreIterator cuirass; - MWWorld::ContainerStoreIterator greaves; - MWWorld::ContainerStoreIterator leftpauldron; - MWWorld::ContainerStoreIterator rightpauldron; - MWWorld::ContainerStoreIterator boots; - MWWorld::ContainerStoreIterator pants; - MWWorld::ContainerStoreIterator leftglove; - MWWorld::ContainerStoreIterator rightglove; - MWWorld::ContainerStoreIterator skirtiter; + const ESM::NPC *mNpc; + std::string mHeadModel; + std::string mHairModel; + std::string mBodyPrefix; + + + float mTimeToChange; + MWWorld::ContainerStoreIterator mRobe; + MWWorld::ContainerStoreIterator mHelmet; + MWWorld::ContainerStoreIterator mShirt; + MWWorld::ContainerStoreIterator mCuirass; + MWWorld::ContainerStoreIterator mGreaves; + MWWorld::ContainerStoreIterator mPauldronL; + MWWorld::ContainerStoreIterator mPauldronR; + MWWorld::ContainerStoreIterator mBoots; + MWWorld::ContainerStoreIterator mPants; + MWWorld::ContainerStoreIterator mGloveL; + MWWorld::ContainerStoreIterator mGloveR; + MWWorld::ContainerStoreIterator mSkirtIter; int mVisibilityFlags; public: NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, - MWWorld::InventoryStore& _inv, int visibilityFlags); + MWWorld::InventoryStore& inv, int visibilityFlags); virtual ~NpcAnimation(); NifOgre::EntityList insertBoundedPart(const std::string &mesh, int group, const std::string &bonename); virtual void runAnimation(float timepassed); diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 69c853d86..36f09e6d9 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -219,18 +219,18 @@ void Objects::insertLight (const MWWorld::Ptr& ptr, float r, float g, float b, f info.radius = radius; info.colour = Ogre::ColourValue(r, g, b); - if (ref->base->mData.mFlags & ESM::Light::Negative) + if (ref->mBase->mData.mFlags & ESM::Light::Negative) info.colour *= -1; - info.interior = (ptr.getCell()->cell->mData.mFlags & ESM::Cell::Interior); + info.interior = !ptr.getCell()->mCell->isExterior(); - if (ref->base->mData.mFlags & ESM::Light::Flicker) + if (ref->mBase->mData.mFlags & ESM::Light::Flicker) info.type = LT_Flicker; - else if (ref->base->mData.mFlags & ESM::Light::FlickerSlow) + else if (ref->mBase->mData.mFlags & ESM::Light::FlickerSlow) info.type = LT_FlickerSlow; - else if (ref->base->mData.mFlags & ESM::Light::Pulse) + else if (ref->mBase->mData.mFlags & ESM::Light::Pulse) info.type = LT_Pulse; - else if (ref->base->mData.mFlags & ESM::Light::PulseSlow) + else if (ref->mBase->mData.mFlags & ESM::Light::PulseSlow) info.type = LT_PulseSlow; else info.type = LT_Normal; diff --git a/apps/openmw/mwrender/player.cpp b/apps/openmw/mwrender/player.cpp index bbc75cade..0e4c76b0e 100644 --- a/apps/openmw/mwrender/player.cpp +++ b/apps/openmw/mwrender/player.cpp @@ -23,7 +23,8 @@ namespace MWRender mFreeLook(true), mHeight(128.f), mCameraDistance(300.f), - mDistanceAdjusted(false) + mDistanceAdjusted(false), + mAnimation(NULL) { mVanity.enabled = false; mVanity.allowed = true; @@ -309,7 +310,13 @@ namespace MWRender void Player::setAnimation(NpcAnimation *anim) { + delete mAnimation; mAnimation = anim; + + mPlayerNode->setVisible( + mVanity.enabled || mPreviewMode || !mFirstPersonView, + false + ); } void Player::setHeight(float height) diff --git a/apps/openmw/mwrender/player.hpp b/apps/openmw/mwrender/player.hpp index b4d8983e4..29a68ca69 100644 --- a/apps/openmw/mwrender/player.hpp +++ b/apps/openmw/mwrender/player.hpp @@ -48,16 +48,6 @@ namespace MWRender /// Updates sound manager listener data void updateListener(); - void rotateCamera(const Ogre::Vector3 &rot, bool adjust); - - float getYaw(); - void setYaw(float angle); - - float getPitch(); - void setPitch(float angle); - - void compensateYaw(float diff); - void setLowHeight(bool low = true); public: @@ -69,7 +59,17 @@ namespace MWRender /// \param rot Rotation angles in radians /// \return true if player object needs to bo rotated physically bool rotate(const Ogre::Vector3 &rot, bool adjust); + + void rotateCamera(const Ogre::Vector3 &rot, bool adjust); + float getYaw(); + void setYaw(float angle); + + float getPitch(); + void setPitch(float angle); + + void compensateYaw(float diff); + std::string getHandle() const; /// Attach camera to object diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 5b5fdce68..8cb8e9fa8 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -13,12 +13,13 @@ #include #include #include +#include #include #include #include -#include +#include "../mwworld/esmstore.hpp" #include #include "../mwbase/world.hpp" // these includes can be removed once the static-hack is gone @@ -206,7 +207,7 @@ void RenderingManager::removeCell (MWWorld::Ptr::CellStore *store) mObjects.removeCell(store); mActors.removeCell(store); mDebugging->cellRemoved(store); - if (store->cell->isExterior()) + if (store->mCell->isExterior()) mTerrainManager->cellRemoved(store); } @@ -227,7 +228,7 @@ void RenderingManager::cellAdded (MWWorld::Ptr::CellStore *store) { mObjects.buildStaticGeometry (*store); mDebugging->cellAdded(store); - if (store->cell->isExterior()) + if (store->mCell->isExterior()) mTerrainManager->cellAdded(store); waterAdded(store); } @@ -236,18 +237,12 @@ void RenderingManager::addObject (const MWWorld::Ptr& ptr){ const MWWorld::Class& class_ = MWWorld::Class::get (ptr); class_.insertObjectRendering(ptr, *this); - } + void RenderingManager::removeObject (const MWWorld::Ptr& ptr) { if (!mObjects.deleteObject (ptr)) - { - /// \todo delete non-object MW-references - } - if (!mActors.deleteObject (ptr)) - { - /// \todo delete non-object MW-references - } + mActors.deleteObject (ptr); } void RenderingManager::moveObject (const MWWorld::Ptr& ptr, const Ogre::Vector3& position) @@ -257,39 +252,46 @@ void RenderingManager::moveObject (const MWWorld::Ptr& ptr, const Ogre::Vector3& setPosition (position); } -void RenderingManager::scaleObject (const MWWorld::Ptr& ptr, const Ogre::Vector3& scale){ - +void RenderingManager::scaleObject (const MWWorld::Ptr& ptr, const Ogre::Vector3& scale) +{ + ptr.getRefData().getBaseNode()->setScale(scale); } -bool -RenderingManager::rotateObject( - const MWWorld::Ptr &ptr, - Ogre::Vector3 &rot, - bool adjust) +bool RenderingManager::rotateObject( const MWWorld::Ptr &ptr, Ogre::Vector3 &rot, bool adjust) { bool isActive = ptr.getRefData().getBaseNode() != 0; bool isPlayer = isActive && ptr.getRefData().getHandle() == "player"; bool force = true; - if (isPlayer) { + if (isPlayer) force = mPlayer->rotate(rot, adjust); - } + MWWorld::Class::get(ptr).adjustRotation(ptr, rot.x, rot.y, rot.z); - if (adjust) { - /// \note Stored and passed in radians - float *f = ptr.getRefData().getPosition().rot; - rot.x += f[0], rot.y += f[1], rot.z += f[2]; - } - - if (!isPlayer && isActive) { + if (!isPlayer && isActive) + { Ogre::Quaternion xr(Ogre::Radian(rot.x), Ogre::Vector3::UNIT_X); Ogre::Quaternion yr(Ogre::Radian(rot.y), Ogre::Vector3::UNIT_Y); Ogre::Quaternion zr(Ogre::Radian(rot.z), Ogre::Vector3::UNIT_Z); - - ptr.getRefData().getBaseNode()->setOrientation(xr * yr * zr); + Ogre::Quaternion newo = adjust ? (xr * yr * zr) * ptr.getRefData().getBaseNode()->getOrientation() : xr * yr * zr; + rot.x = newo.x; + rot.y = newo.y; + rot.z = newo.z; + ptr.getRefData().getBaseNode()->setOrientation(newo); + } + else if(isPlayer) + { + rot.x = mPlayer->getPitch(); + rot.z = mPlayer->getYaw(); + } + else if (adjust) + { + // Stored and passed in radians + float *f = ptr.getRefData().getPosition().rot; + rot.x += f[0]; + rot.y += f[1]; + rot.z += f[2]; } - return force; } @@ -313,7 +315,7 @@ RenderingManager::moveObjectToCell( child->setPosition(pos); } -void RenderingManager::update (float duration) +void RenderingManager::update (float duration, bool paused) { Ogre::Vector3 orig, dest; mPlayer->setCameraDistance(); @@ -328,19 +330,28 @@ void RenderingManager::update (float duration) mPlayer->setCameraDistance(test.second * orig.distance(dest), false, false); } } + mOcclusionQuery->update(duration); + + mRendering.update(duration); + + if(paused) + { + Ogre::ControllerManager::getSingleton().setTimeFactor(0.f); + return; + } + Ogre::ControllerManager::getSingleton().setTimeFactor( + MWBase::Environment::get().getWorld()->getTimeScaleFactor()/30.f); + mPlayer->update(duration); mActors.update (duration); mObjects.update (duration); - mOcclusionQuery->update(duration); mSkyManager->update(duration); mSkyManager->setGlare(mOcclusionQuery->getSunVisibility()); - mRendering.update(duration); - MWWorld::RefData &data = MWBase::Environment::get() .getWorld() @@ -350,7 +361,7 @@ void RenderingManager::update (float duration) float *fpos = data.getPosition().pos; - /// \note only for LocalMap::updatePlayer() + // only for LocalMap::updatePlayer() Ogre::Vector3 pos(fpos[0], -fpos[2], -fpos[1]); Ogre::SceneNode *node = data.getBaseNode(); @@ -366,22 +377,26 @@ void RenderingManager::update (float duration) mWater->updateUnderwater( world->isUnderwater( - *world->getPlayer().getPlayer().getCell()->cell, + *world->getPlayer().getPlayer().getCell()->mCell, Ogre::Vector3(cam.x, -cam.z, cam.y)) ); mWater->update(duration); } } -void RenderingManager::waterAdded (MWWorld::Ptr::CellStore *store){ - if(store->cell->mData.mFlags & store->cell->HasWater - || ((!(store->cell->mData.mFlags & ESM::Cell::Interior)) - && !MWBase::Environment::get().getWorld()->getStore().lands.search(store->cell->mData.mX,store->cell->mData.mY) )) // always use water, if the cell does not have land. +void RenderingManager::waterAdded (MWWorld::Ptr::CellStore *store) +{ + const MWWorld::Store &lands = + MWBase::Environment::get().getWorld()->getStore().get(); + + if(store->mCell->mData.mFlags & ESM::Cell::HasWater + || ((store->mCell->isExterior()) + && !lands.search(store->mCell->getGridX(),store->mCell->getGridY()) )) // always use water, if the cell does not have land. { if(mWater == 0) - mWater = new MWRender::Water(mRendering.getCamera(), this, store->cell); + mWater = new MWRender::Water(mRendering.getCamera(), this, store->mCell); else - mWater->changeCell(store->cell); + mWater->changeCell(store->mCell); mWater->setActive(true); } else @@ -458,7 +473,13 @@ bool RenderingManager::toggleRenderMode(int mode) return false; } } - else //if (mode == MWWorld::World::Render_Compositors) + else if (mode == MWBase::World::Render_BoundingBoxes) + { + bool show = !mRendering.getScene()->getShowBoundingBoxes(); + mRendering.getScene()->showBoundingBoxes(show); + return show; + } + else //if (mode == MWBase::World::Render_Compositors) { return mCompositors->toggle(); } @@ -467,9 +488,9 @@ bool RenderingManager::toggleRenderMode(int mode) void RenderingManager::configureFog(MWWorld::Ptr::CellStore &mCell) { Ogre::ColourValue color; - color.setAsABGR (mCell.cell->mAmbi.mFog); + color.setAsABGR (mCell.mCell->mAmbi.mFog); - configureFog(mCell.cell->mAmbi.mFogDensity, color); + configureFog(mCell.mCell->mAmbi.mFogDensity, color); if (mWater) mWater->setViewportBackground (Ogre::ColourValue(0.8f, 0.9f, 1.0f)); @@ -519,7 +540,7 @@ void RenderingManager::setAmbientMode() void RenderingManager::configureAmbient(MWWorld::Ptr::CellStore &mCell) { - mAmbientColor.setAsABGR (mCell.cell->mAmbi.mAmbient); + mAmbientColor.setAsABGR (mCell.mCell->mAmbi.mAmbient); setAmbientMode(); // Create a "sun" that shines light downwards. It doesn't look @@ -529,7 +550,7 @@ void RenderingManager::configureAmbient(MWWorld::Ptr::CellStore &mCell) mSun = mRendering.getScene()->createLight(); } Ogre::ColourValue colour; - colour.setAsABGR (mCell.cell->mAmbi.mSunlight); + colour.setAsABGR (mCell.mCell->mAmbi.mSunlight); mSun->setDiffuseColour (colour); mSun->setType(Ogre::Light::LT_DIRECTIONAL); mSun->setDirection(0,-1,0); @@ -613,7 +634,7 @@ void RenderingManager::setGlare(bool glare) void RenderingManager::requestMap(MWWorld::Ptr::CellStore* cell) { - if (!(cell->cell->mData.mFlags & ESM::Cell::Interior)) + if (cell->mCell->isExterior()) mLocalMap->requestMap(cell); else mLocalMap->requestMap(cell, mObjects.getDimensions(cell)); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 359809b71..86346d1d6 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -125,7 +125,7 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList /// \param store Cell the object was in previously (\a ptr has already been updated to the new cell). void moveObjectToCell (const MWWorld::Ptr& ptr, const Ogre::Vector3& position, MWWorld::CellStore *store); - void update (float duration); + void update (float duration, bool paused); void setAmbientColour(const Ogre::ColourValue& colour); void setSunColour(const Ogre::ColourValue& colour); diff --git a/apps/openmw/mwrender/terrain.cpp b/apps/openmw/mwrender/terrain.cpp index 114a9bc37..e5a1362d7 100644 --- a/apps/openmw/mwrender/terrain.cpp +++ b/apps/openmw/mwrender/terrain.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include "../mwworld/esmstore.hpp" #include @@ -92,10 +92,11 @@ namespace MWRender void TerrainManager::cellAdded(MWWorld::Ptr::CellStore *store) { - const int cellX = store->cell->getGridX(); - const int cellY = store->cell->getGridY(); + const int cellX = store->mCell->getGridX(); + const int cellY = store->mCell->getGridY(); - ESM::Land* land = MWBase::Environment::get().getWorld()->getStore().lands.search(cellX, cellY); + ESM::Land* land = + MWBase::Environment::get().getWorld()->getStore().get().search(cellX, cellY); if (land == NULL) // no land data means we're not going to create any terrain. return; @@ -188,8 +189,8 @@ namespace MWRender { for ( int y = 0; y < 2; y++ ) { - int terrainX = store->cell->getGridX() * 2 + x; - int terrainY = store->cell->getGridY() * 2 + y; + int terrainX = store->mCell->getGridX() * 2 + x; + int terrainY = store->mCell->getGridY() * 2 + y; if (mTerrainGroup.getTerrain(terrainX, terrainY) != NULL) mTerrainGroup.unloadTerrain(terrainX, terrainY); } @@ -245,7 +246,10 @@ namespace MWRender { //NB: All vtex ids are +1 compared to the ltex ids - assert( (int)MWBase::Environment::get().getWorld()->getStore().landTexts.getSize() >= (int)ltexIndex - 1 && + const MWWorld::Store <exStore = + MWBase::Environment::get().getWorld()->getStore().get(); + + assert( (int)ltexStore.getSize() >= (int)ltexIndex - 1 && "LAND.VTEX must be within the bounds of the LTEX array"); std::string texture; @@ -255,7 +259,7 @@ namespace MWRender } else { - texture = MWBase::Environment::get().getWorld()->getStore().landTexts.search(ltexIndex-1)->mTexture; + texture = ltexStore.search(ltexIndex-1)->mTexture; //TODO this is needed due to MWs messed up texture handling texture = texture.substr(0, texture.rfind(".")) + ".dds"; } @@ -411,7 +415,8 @@ namespace MWRender } - ESM::Land* land = MWBase::Environment::get().getWorld()->getStore().lands.search(cellX, cellY); + ESM::Land* land = + MWBase::Environment::get().getWorld()->getStore().get().search(cellX, cellY); if ( land != NULL ) { if (!land->isDataLoaded(ESM::Land::DATA_VTEX)) diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index 9d70c28bd..aa1d2d030 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -114,71 +114,56 @@ namespace MWScript // discard additional arguments (reset), because we have no idea what they mean. for (unsigned int i=0; i - class OpSetHello : public Interpreter::Opcode0 + class OpGetAiSetting : public Interpreter::Opcode0 { + int mIndex; public: + OpGetAiSetting(int index) : mIndex(index) {} virtual void execute (Interpreter::Runtime& runtime) { MWWorld::Ptr ptr = R()(runtime); - Interpreter::Type_Integer value = runtime[0].mInteger; - runtime.pop(); - - MWWorld::Class::get (ptr).getCreatureStats (ptr).setHello(value); + runtime.push(MWWorld::Class::get (ptr).getCreatureStats (ptr).getAiSetting (mIndex)); } }; - template - class OpSetFight : public Interpreter::Opcode0 + class OpModAiSetting : public Interpreter::Opcode0 { + int mIndex; public: + OpModAiSetting(int index) : mIndex(index) {} virtual void execute (Interpreter::Runtime& runtime) { MWWorld::Ptr ptr = R()(runtime); - Interpreter::Type_Integer value = runtime[0].mInteger; runtime.pop(); - MWWorld::Class::get (ptr).getCreatureStats (ptr).setFight(value); + MWWorld::Class::get (ptr).getCreatureStats (ptr).setAiSetting (mIndex, + MWWorld::Class::get (ptr).getCreatureStats (ptr).getAiSetting (mIndex) + value); } }; - template - class OpSetFlee : public Interpreter::Opcode0 + class OpSetAiSetting : public Interpreter::Opcode0 { + int mIndex; public: + OpSetAiSetting(int index) : mIndex(index) {} virtual void execute (Interpreter::Runtime& runtime) { MWWorld::Ptr ptr = R()(runtime); - Interpreter::Type_Integer value = runtime[0].mInteger; runtime.pop(); - MWWorld::Class::get (ptr).getCreatureStats (ptr).setFlee(value); - } - }; - - template - class OpSetAlarm : public Interpreter::Opcode0 - { - public: - - virtual void execute (Interpreter::Runtime& runtime) - { - MWWorld::Ptr ptr = R()(runtime); - - Interpreter::Type_Integer value = runtime[0].mInteger; - runtime.pop(); - - MWWorld::Class::get (ptr).getCreatureStats (ptr).setAlarm(value); + MWWorld::Class::get (ptr).getCreatureStats (ptr).setAiSetting (mIndex, + value); } }; @@ -199,6 +184,22 @@ namespace MWScript const int opcodeSetFleeExplicit = 0x2000161; const int opcodeSetAlarm = 0x2000162; const int opcodeSetAlarmExplicit = 0x2000163; + const int opcodeModHello = 0x20001b7; + const int opcodeModHelloExplicit = 0x20001b8; + const int opcodeModFight = 0x20001b9; + const int opcodeModFightExplicit = 0x20001ba; + const int opcodeModFlee = 0x20001bb; + const int opcodeModFleeExplicit = 0x20001bc; + const int opcodeModAlarm = 0x20001bd; + const int opcodeModAlarmExplicit = 0x20001be; + const int opcodeGetHello = 0x20001bf; + const int opcodeGetHelloExplicit = 0x20001c0; + const int opcodeGetFight = 0x20001c1; + const int opcodeGetFightExplicit = 0x20001c2; + const int opcodeGetFlee = 0x20001c3; + const int opcodeGetFleeExplicit = 0x20001c4; + const int opcodeGetAlarm = 0x20001c5; + const int opcodeGetAlarmExplicit = 0x20001c6; void registerExtensions (Compiler::Extensions& extensions) { @@ -216,6 +217,14 @@ namespace MWScript extensions.registerInstruction ("setfight", "l", opcodeSetFight, opcodeSetFightExplicit); extensions.registerInstruction ("setflee", "l", opcodeSetFlee, opcodeSetFleeExplicit); extensions.registerInstruction ("setalarm", "l", opcodeSetAlarm, opcodeSetAlarmExplicit); + extensions.registerInstruction ("modhello", "l", opcodeModHello, opcodeModHelloExplicit); + extensions.registerInstruction ("modfight", "l", opcodeModFight, opcodeModFightExplicit); + extensions.registerInstruction ("modflee", "l", opcodeModFlee, opcodeModFleeExplicit); + extensions.registerInstruction ("modalarm", "l", opcodeModAlarm, opcodeModAlarmExplicit); + extensions.registerFunction ("gethello", 'l', "", opcodeGetHello, opcodeGetHelloExplicit); + extensions.registerFunction ("getfight", 'l', "", opcodeGetFight, opcodeGetFightExplicit); + extensions.registerFunction ("getflee", 'l', "", opcodeGetFlee, opcodeGetFleeExplicit); + extensions.registerFunction ("getalarm", 'l', "", opcodeGetAlarm, opcodeGetAlarmExplicit); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -229,14 +238,32 @@ namespace MWScript interpreter.installSegment5 (opcodeGetAiPackageDone, new OpGetAiPackageDone); interpreter.installSegment5 (opcodeGetAiPackageDoneExplicit, new OpGetAiPackageDone); - interpreter.installSegment5 (opcodeSetHello, new OpSetHello); - interpreter.installSegment5 (opcodeSetHelloExplicit, new OpSetHello); - interpreter.installSegment5 (opcodeSetFight, new OpSetFight); - interpreter.installSegment5 (opcodeSetFightExplicit, new OpSetFight); - interpreter.installSegment5 (opcodeSetFlee, new OpSetFlee); - interpreter.installSegment5 (opcodeSetFleeExplicit, new OpSetFlee); - interpreter.installSegment5 (opcodeSetAlarm, new OpSetAlarm); - interpreter.installSegment5 (opcodeSetAlarmExplicit, new OpSetAlarm); + interpreter.installSegment5 (opcodeSetHello, new OpSetAiSetting(0)); + interpreter.installSegment5 (opcodeSetHelloExplicit, new OpSetAiSetting(0)); + interpreter.installSegment5 (opcodeSetFight, new OpSetAiSetting(1)); + interpreter.installSegment5 (opcodeSetFightExplicit, new OpSetAiSetting(1)); + interpreter.installSegment5 (opcodeSetFlee, new OpSetAiSetting(2)); + interpreter.installSegment5 (opcodeSetFleeExplicit, new OpSetAiSetting(2)); + interpreter.installSegment5 (opcodeSetAlarm, new OpSetAiSetting(3)); + interpreter.installSegment5 (opcodeSetAlarmExplicit, new OpSetAiSetting(3)); + + interpreter.installSegment5 (opcodeModHello, new OpModAiSetting(0)); + interpreter.installSegment5 (opcodeModHelloExplicit, new OpModAiSetting(0)); + interpreter.installSegment5 (opcodeModFight, new OpModAiSetting(1)); + interpreter.installSegment5 (opcodeModFightExplicit, new OpModAiSetting(1)); + interpreter.installSegment5 (opcodeModFlee, new OpModAiSetting(2)); + interpreter.installSegment5 (opcodeModFleeExplicit, new OpModAiSetting(2)); + interpreter.installSegment5 (opcodeModAlarm, new OpModAiSetting(3)); + interpreter.installSegment5 (opcodeModAlarmExplicit, new OpModAiSetting(3)); + + interpreter.installSegment5 (opcodeGetHello, new OpGetAiSetting(0)); + interpreter.installSegment5 (opcodeGetHelloExplicit, new OpGetAiSetting(0)); + interpreter.installSegment5 (opcodeGetFight, new OpGetAiSetting(1)); + interpreter.installSegment5 (opcodeGetFightExplicit, new OpGetAiSetting(1)); + interpreter.installSegment5 (opcodeGetFlee, new OpGetAiSetting(2)); + interpreter.installSegment5 (opcodeGetFleeExplicit, new OpGetAiSetting(2)); + interpreter.installSegment5 (opcodeGetAlarm, new OpGetAiSetting(3)); + interpreter.installSegment5 (opcodeGetAlarmExplicit, new OpGetAiSetting(3)); } } } diff --git a/apps/openmw/mwscript/cellextensions.cpp b/apps/openmw/mwscript/cellextensions.cpp index 57dd7962b..a4a738ca7 100644 --- a/apps/openmw/mwscript/cellextensions.cpp +++ b/apps/openmw/mwscript/cellextensions.cpp @@ -1,7 +1,7 @@ #include "cellextensions.hpp" -#include +#include "../mwworld/esmstore.hpp" #include @@ -87,8 +87,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { bool interior = - MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell()->cell->mData.mFlags & - ESM::Cell::Interior; + !MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell()->mCell->isExterior(); runtime.push (interior ? 1 : 0); } @@ -103,14 +102,14 @@ namespace MWScript std::string name = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - const ESM::Cell *cell = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell()->cell; + const ESM::Cell *cell = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell()->mCell; std::string current = cell->mName; if (!(cell->mData.mFlags & ESM::Cell::Interior) && current.empty()) { const ESM::Region *region = - MWBase::Environment::get().getWorld()->getStore().regions.find (cell->mRegion); + MWBase::Environment::get().getWorld()->getStore().get().find (cell->mRegion); current = region->mName; } @@ -143,7 +142,7 @@ namespace MWScript MWWorld::Ptr::CellStore *cell = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell(); - if (!(cell->cell->mData.mFlags & ESM::Cell::Interior)) + if (cell->mCell->isExterior()) throw std::runtime_error("Can't set water level in exterior cell"); cell->mWaterLevel = level; @@ -161,7 +160,7 @@ namespace MWScript MWWorld::Ptr::CellStore *cell = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell(); - if (!(cell->cell->mData.mFlags & ESM::Cell::Interior)) + if (cell->mCell->isExterior()) throw std::runtime_error("Can't set water level in exterior cell"); cell->mWaterLevel +=level; diff --git a/apps/openmw/mwscript/compilercontext.cpp b/apps/openmw/mwscript/compilercontext.cpp index 139a5cc6c..57d93512f 100644 --- a/apps/openmw/mwscript/compilercontext.cpp +++ b/apps/openmw/mwscript/compilercontext.cpp @@ -1,7 +1,7 @@ #include "compilercontext.hpp" -#include +#include "../mwworld/esmstore.hpp" #include @@ -42,26 +42,29 @@ namespace MWScript bool CompilerContext::isId (const std::string& name) const { + const MWWorld::ESMStore &store = + MWBase::Environment::get().getWorld()->getStore(); + return - MWBase::Environment::get().getWorld()->getStore().activators.search (name) || - MWBase::Environment::get().getWorld()->getStore().potions.search (name) || - MWBase::Environment::get().getWorld()->getStore().appas.search (name) || - MWBase::Environment::get().getWorld()->getStore().armors.search (name) || - MWBase::Environment::get().getWorld()->getStore().books.search (name) || - MWBase::Environment::get().getWorld()->getStore().clothes.search (name) || - MWBase::Environment::get().getWorld()->getStore().containers.search (name) || - MWBase::Environment::get().getWorld()->getStore().creatures.search (name) || - MWBase::Environment::get().getWorld()->getStore().doors.search (name) || - MWBase::Environment::get().getWorld()->getStore().ingreds.search (name) || - MWBase::Environment::get().getWorld()->getStore().creatureLists.search (name) || - MWBase::Environment::get().getWorld()->getStore().itemLists.search (name) || - MWBase::Environment::get().getWorld()->getStore().lights.search (name) || - MWBase::Environment::get().getWorld()->getStore().lockpicks.search (name) || - MWBase::Environment::get().getWorld()->getStore().miscItems.search (name) || - MWBase::Environment::get().getWorld()->getStore().npcs.search (name) || - MWBase::Environment::get().getWorld()->getStore().probes.search (name) || - MWBase::Environment::get().getWorld()->getStore().repairs.search (name) || - MWBase::Environment::get().getWorld()->getStore().statics.search (name) || - MWBase::Environment::get().getWorld()->getStore().weapons.search (name); + store.get().search (name) || + store.get().search (name) || + store.get().search (name) || + store.get().search (name) || + store.get().search (name) || + store.get().search (name) || + store.get().search (name) || + store.get().search (name) || + store.get().search (name) || + store.get().search (name) || + store.get().search (name) || + store.get().search (name) || + store.get().search (name) || + store.get().search (name) || + store.get().search (name) || + store.get().search (name) || + store.get().search (name) || + store.get().search (name) || + store.get().search (name) || + store.get().search (name); } } diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 725885e41..114704388 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -3,6 +3,10 @@ #include +#include + +#include + #include #include @@ -10,10 +14,13 @@ #include #include "../mwbase/environment.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" +#include "../mwworld/actionequip.hpp" +#include "../mwworld/inventorystore.hpp" #include "interpretercontext.hpp" #include "ref.hpp" @@ -86,17 +93,22 @@ namespace MWScript Interpreter::Type_Integer count = runtime[0].mInteger; runtime.pop(); - + if (count<0) throw std::runtime_error ("second argument for RemoveItem must be non-negative"); MWWorld::ContainerStore& store = MWWorld::Class::get (ptr).getContainerStore (ptr); + + std::string itemName = ""; + Interpreter::Type_Integer originalCount = count; for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end() && count; ++iter) { if (Misc::toLower(iter->getCellRef().mRefID) == Misc::toLower(item)) { + itemName = MWWorld::Class::get(*iter).getName(*iter); + if (iter->getRefData().getCount()<=count) { count -= iter->getRefData().getCount(); @@ -109,18 +121,222 @@ namespace MWScript } } } + + /* The two GMST entries below expand to strings informing the player of what, and how many of it has been removed from their inventory */ + std::string msgBox; + if(originalCount - count > 1) + { + msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage63}"); + std::stringstream temp; + temp << boost::format(msgBox) % (originalCount - count) % itemName; + msgBox = temp.str(); + } + else + { + msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage62}"); + std::stringstream temp; + temp << boost::format(msgBox) % itemName; + msgBox = temp.str(); + } + + if(originalCount - count > 0) + MWBase::Environment::get().getWindowManager()->messageBox(msgBox, std::vector()); // To be fully compatible with original Morrowind, we would need to check if // count is >= 0 here and throw an exception. But let's be tollerant instead. } }; + template + class OpEquip : public Interpreter::Opcode0 + { + public: + + virtual void execute(Interpreter::Runtime &runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string item = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + MWWorld::InventoryStore& invStore = MWWorld::Class::get(ptr).getInventoryStore (ptr); + MWWorld::ContainerStoreIterator it = invStore.begin(); + for (; it != invStore.end(); ++it) + { + if (toLower(it->getCellRef().mRefID) == toLower(item)) + break; + } + if (it == invStore.end()) + throw std::runtime_error("Item to equip not found"); + + MWWorld::ActionEquip action (*it); + action.execute(ptr); + } + }; + + template + class OpGetArmorType : public Interpreter::Opcode0 + { + public: + + virtual void execute(Interpreter::Runtime &runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + Interpreter::Type_Integer location = runtime[0].mInteger; + runtime.pop(); + + int slot; + switch (location) + { + case 0: + slot = MWWorld::InventoryStore::Slot_Helmet; + break; + case 1: + slot = MWWorld::InventoryStore::Slot_Cuirass; + break; + case 2: + slot = MWWorld::InventoryStore::Slot_LeftPauldron; + break; + case 3: + slot = MWWorld::InventoryStore::Slot_RightPauldron; + break; + case 4: + slot = MWWorld::InventoryStore::Slot_Greaves; + break; + case 5: + slot = MWWorld::InventoryStore::Slot_Boots; + break; + case 6: + slot = MWWorld::InventoryStore::Slot_LeftGauntlet; + break; + case 7: + slot = MWWorld::InventoryStore::Slot_RightGauntlet; + break; + case 8: + slot = MWWorld::InventoryStore::Slot_CarriedLeft; // shield + break; + case 9: + slot = MWWorld::InventoryStore::Slot_LeftGauntlet; + break; + case 10: + slot = MWWorld::InventoryStore::Slot_RightGauntlet; + break; + default: + throw std::runtime_error ("armor index out of range"); + } + + MWWorld::InventoryStore& invStore = MWWorld::Class::get(ptr).getInventoryStore (ptr); + + MWWorld::ContainerStoreIterator it = invStore.getSlot (slot); + if (it == invStore.end() || it->getTypeName () != typeid(ESM::Armor).name()) + { + runtime.push(-1); + return; + } + + int skill = MWWorld::Class::get(*it).getEquipmentSkill (*it) ; + if (skill == ESM::Skill::HeavyArmor) + runtime.push(2); + else if (skill == ESM::Skill::MediumArmor) + runtime.push(1); + else if (skill == ESM::Skill::LightArmor) + runtime.push(0); + else + runtime.push(-1); + } + }; + + template + class OpHasItemEquipped : public Interpreter::Opcode0 + { + public: + + virtual void execute(Interpreter::Runtime &runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string item = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + MWWorld::InventoryStore& invStore = MWWorld::Class::get(ptr).getInventoryStore (ptr); + for (int slot = 0; slot < MWWorld::InventoryStore::Slots; ++slot) + { + MWWorld::ContainerStoreIterator it = invStore.getSlot (slot); + if (it != invStore.end() && toLower(it->getCellRef().mRefID) == toLower(item)) + { + runtime.push(1); + return; + } + } + runtime.push(0); + } + }; + + template + class OpHasSoulGem : public Interpreter::Opcode0 + { + public: + + virtual void execute(Interpreter::Runtime &runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string creatureName = toLower (runtime.getStringLiteral (runtime[0].mInteger)); + runtime.pop(); + + MWWorld::InventoryStore& invStore = MWWorld::Class::get(ptr).getInventoryStore (ptr); + for (MWWorld::ContainerStoreIterator it = invStore.begin(MWWorld::ContainerStore::Type_Miscellaneous); + it != invStore.end(); ++it) + { + + if (toLower(it->getCellRef().mSoul) == toLower(creatureName)) + { + runtime.push(1); + return; + } + } + runtime.push(0); + } + }; + + template + class OpGetWeaponType : public Interpreter::Opcode0 + { + public: + + virtual void execute(Interpreter::Runtime &runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + MWWorld::InventoryStore& invStore = MWWorld::Class::get(ptr).getInventoryStore (ptr); + MWWorld::ContainerStoreIterator it = invStore.getSlot (MWWorld::InventoryStore::Slot_CarriedRight); + if (it == invStore.end() || it->getTypeName () != typeid(ESM::Weapon).name()) + { + runtime.push(-1); + return; + } + + runtime.push(it->get()->mBase->mData.mType); + } + }; + const int opcodeAddItem = 0x2000076; const int opcodeAddItemExplicit = 0x2000077; const int opcodeGetItemCount = 0x2000078; const int opcodeGetItemCountExplicit = 0x2000079; const int opcodeRemoveItem = 0x200007a; const int opcodeRemoveItemExplicit = 0x200007b; + const int opcodeEquip = 0x20001b3; + const int opcodeEquipExplicit = 0x20001b4; + const int opcodeGetArmorType = 0x20001d1; + const int opcodeGetArmorTypeExplicit = 0x20001d2; + const int opcodeHasItemEquipped = 0x20001d5; + const int opcodeHasItemEquippedExplicit = 0x20001d6; + const int opcodeHasSoulGem = 0x20001de; + const int opcodeHasSoulGemExplicit = 0x20001df; + const int opcodeGetWeaponType = 0x20001e0; + const int opcodeGetWeaponTypeExplicit = 0x20001e1; void registerExtensions (Compiler::Extensions& extensions) { @@ -129,6 +345,11 @@ namespace MWScript opcodeGetItemCountExplicit); extensions.registerInstruction ("removeitem", "cl", opcodeRemoveItem, opcodeRemoveItemExplicit); + extensions.registerInstruction ("equip", "c", opcodeEquip, opcodeEquipExplicit); + extensions.registerFunction ("getarmortype", 'l', "l", opcodeGetArmorType, opcodeGetArmorTypeExplicit); + extensions.registerFunction ("hasitemequipped", 'l', "c", opcodeHasItemEquipped, opcodeHasItemEquippedExplicit); + extensions.registerFunction ("hassoulgem", 'l', "c", opcodeHasSoulGem, opcodeHasSoulGemExplicit); + extensions.registerFunction ("getweapontype", 'l', "", opcodeGetWeaponType, opcodeGetWeaponTypeExplicit); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -139,6 +360,16 @@ namespace MWScript interpreter.installSegment5 (opcodeGetItemCountExplicit, new OpGetItemCount); interpreter.installSegment5 (opcodeRemoveItem, new OpRemoveItem); interpreter.installSegment5 (opcodeRemoveItemExplicit, new OpRemoveItem); + interpreter.installSegment5 (opcodeEquip, new OpEquip); + interpreter.installSegment5 (opcodeEquipExplicit, new OpEquip); + interpreter.installSegment5 (opcodeGetArmorType, new OpGetArmorType); + interpreter.installSegment5 (opcodeGetArmorTypeExplicit, new OpGetArmorType); + interpreter.installSegment5 (opcodeHasItemEquipped, new OpHasItemEquipped); + interpreter.installSegment5 (opcodeHasItemEquippedExplicit, new OpHasItemEquipped); + interpreter.installSegment5 (opcodeHasSoulGem, new OpHasSoulGem); + interpreter.installSegment5 (opcodeHasSoulGemExplicit, new OpHasSoulGem); + interpreter.installSegment5 (opcodeGetWeaponType, new OpGetWeaponType); + interpreter.installSegment5 (opcodeGetWeaponTypeExplicit, new OpGetWeaponType); } } } diff --git a/apps/openmw/mwscript/controlextensions.cpp b/apps/openmw/mwscript/controlextensions.cpp index 0096c69ab..8d65dfdd5 100644 --- a/apps/openmw/mwscript/controlextensions.cpp +++ b/apps/openmw/mwscript/controlextensions.cpp @@ -106,6 +106,58 @@ namespace MWScript } }; + template + class OpGetForceRun : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + MWMechanics::NpcStats& npcStats = MWWorld::Class::get(ptr).getNpcStats (ptr); + + runtime.push (npcStats.getMovementFlag (MWMechanics::NpcStats::Flag_ForceRun)); + } + }; + + template + class OpGetForceSneak : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + MWMechanics::NpcStats& npcStats = MWWorld::Class::get(ptr).getNpcStats (ptr); + + runtime.push (npcStats.getMovementFlag (MWMechanics::NpcStats::Flag_ForceSneak)); + } + }; + + class OpGetPcRunning : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer(); + runtime.push (MWWorld::Class::get(ptr).getStance (ptr, MWWorld::Class::Run)); + } + }; + + class OpGetPcSneaking : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer(); + runtime.push (MWWorld::Class::get(ptr).getStance (ptr, MWWorld::Class::Sneak)); + } + }; + const int numberOfControls = 7; const int opcodeEnable = 0x200007e; @@ -120,6 +172,12 @@ namespace MWScript const int opcodeForceSneak = 0x200015a; const int opcodeForceSneakExplicit = 0x200015b; const int opcodeGetDisabled = 0x2000175; + const int opcodeGetPcRunning = 0x20001c9; + const int opcodeGetPcSneaking = 0x20001ca; + const int opcodeGetForceRun = 0x20001cb; + const int opcodeGetForceSneak = 0x20001cc; + const int opcodeGetForceRunExplicit = 0x20001cd; + const int opcodeGetForceSneakExplicit = 0x20001ce; const char *controls[numberOfControls] = { @@ -151,6 +209,10 @@ namespace MWScript opcodeClearForceSneakExplicit); extensions.registerInstruction ("forcesneak", "", opcodeForceSneak, opcodeForceSneakExplicit); + extensions.registerFunction ("getpcrunning", 'l', "", opcodeGetPcRunning); + extensions.registerFunction ("getpcsneaking", 'l', "", opcodeGetPcSneaking); + extensions.registerFunction ("getforcerun", 'l', "", opcodeGetForceRun, opcodeGetForceRunExplicit); + extensions.registerFunction ("getforcesneak", 'l', "", opcodeGetForceSneak, opcodeGetForceSneakExplicit); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -181,6 +243,12 @@ namespace MWScript new OpClearMovementFlag (MWMechanics::NpcStats::Flag_ForceSneak)); interpreter.installSegment5 (opcodeForceSneakExplicit, new OpSetMovementFlag (MWMechanics::NpcStats::Flag_ForceSneak)); + interpreter.installSegment5 (opcodeGetPcRunning, new OpGetPcRunning); + interpreter.installSegment5 (opcodeGetPcSneaking, new OpGetPcSneaking); + interpreter.installSegment5 (opcodeGetForceRun, new OpGetForceRun); + interpreter.installSegment5 (opcodeGetForceRunExplicit, new OpGetForceRun); + interpreter.installSegment5 (opcodeGetForceSneak, new OpGetForceSneak); + interpreter.installSegment5 (opcodeGetForceSneakExplicit, new OpGetForceSneak); } } } diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index 21c21acf0..f63623275 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -11,6 +11,10 @@ #include "../mwbase/dialoguemanager.hpp" #include "../mwbase/journal.hpp" +#include "../mwworld/class.hpp" +#include "../mwworld/player.hpp" +#include "../mwmechanics/npcstats.hpp" + #include "interpretercontext.hpp" #include "ref.hpp" @@ -126,6 +130,64 @@ namespace MWScript } }; + template + class OpModReputation : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + Interpreter::Type_Integer value = runtime[0].mInteger; + runtime.pop(); + + MWWorld::Class::get(ptr).getNpcStats (ptr).setReputation (MWWorld::Class::get(ptr).getNpcStats (ptr).getReputation () + value); + } + }; + + template + class OpSetReputation : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + Interpreter::Type_Integer value = runtime[0].mInteger; + runtime.pop(); + + MWWorld::Class::get(ptr).getNpcStats (ptr).setReputation (value); + } + }; + + template + class OpGetReputation : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + runtime.push (MWWorld::Class::get(ptr).getNpcStats (ptr).getReputation ()); + } + }; + + template + class OpSameFaction : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer(); + + runtime.push (MWWorld::Class::get(ptr).getNpcStats (ptr).isSameFaction (MWWorld::Class::get(player).getNpcStats (player))); + } + }; + const int opcodeJournal = 0x2000133; const int opcodeSetJournalIndex = 0x2000134; const int opcodeGetJournalIndex = 0x2000135; @@ -134,6 +196,14 @@ namespace MWScript const int opcodeForceGreeting = 0x200014f; const int opcodeForceGreetingExplicit = 0x2000150; const int opcodeGoodbye = 0x2000152; + const int opcodeSetReputation = 0x20001ad; + const int opcodeModReputation = 0x20001ae; + const int opcodeSetReputationExplicit = 0x20001af; + const int opcodeModReputationExplicit = 0x20001b0; + const int opcodeGetReputation = 0x20001b1; + const int opcodeGetReputationExplicit = 0x20001b2; + const int opcodeSameFaction = 0x20001b5; + const int opcodeSameFactionExplicit = 0x20001b6; void registerExtensions (Compiler::Extensions& extensions) { @@ -146,6 +216,14 @@ namespace MWScript extensions.registerInstruction("forcegreeting","",opcodeForceGreeting, opcodeForceGreetingExplicit); extensions.registerInstruction("goodbye", "", opcodeGoodbye); + extensions.registerInstruction("setreputation", "l", opcodeSetReputation, + opcodeSetReputationExplicit); + extensions.registerInstruction("modreputation", "l", opcodeModReputation, + opcodeModReputationExplicit); + extensions.registerFunction("getreputation", 'l', "", opcodeGetReputation, + opcodeGetReputationExplicit); + extensions.registerFunction("samefaction", 'l', "", opcodeSameFaction, + opcodeSameFactionExplicit); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -158,6 +236,14 @@ namespace MWScript interpreter.installSegment5 (opcodeForceGreeting, new OpForceGreeting); interpreter.installSegment5 (opcodeForceGreetingExplicit, new OpForceGreeting); interpreter.installSegment5 (opcodeGoodbye, new OpGoodbye); + interpreter.installSegment5 (opcodeGetReputation, new OpGetReputation); + interpreter.installSegment5 (opcodeSetReputation, new OpSetReputation); + interpreter.installSegment5 (opcodeModReputation, new OpModReputation); + interpreter.installSegment5 (opcodeSetReputationExplicit, new OpSetReputation); + interpreter.installSegment5 (opcodeModReputationExplicit, new OpModReputation); + interpreter.installSegment5 (opcodeGetReputationExplicit, new OpGetReputation); + interpreter.installSegment5 (opcodeSameFaction, new OpSameFaction); + interpreter.installSegment5 (opcodeSameFactionExplicit, new OpSameFaction); } } diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index cb984e257..df1a52329 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -31,7 +31,19 @@ op 0x2000e: PCGetRank implicit op 0x2000f: PCGetRank explicit op 0x20010: AiWander op 0x20011: AiWander, explicit reference -op s 0x20012-0x3ffff unused +op 0x20012: GetPCFacRep +op 0x20013: GetPCFacRep, explicit reference +op 0x20014: SetPCFacRep +op 0x20015: SetPCFacRep, explicit reference +op 0x20016: ModPCFacRep +op 0x20017: ModPCFacRep, explicit reference +op 0x20018: PcExpelled +op 0x20019: PcExpelled, explicit +op 0x2001a: PcExpell +op 0x2001b: PcExpell, explicit +op 0x2001c: PcClearExpelled +op 0x2001d: PcClearExpelled, explicit +op s 0x2001e-0x3ffff unused Segment 4: (not implemented yet) @@ -198,14 +210,92 @@ op 0x2000197: Position Explicit op 0x2000198: PositionCell op 0x2000199: PositionCell Explicit op 0x200019a: PlaceItemCell -op 0x200019b: PlaceItem +op 0x200019b: PlaceItem op 0x200019c: PlaceAtPc -op 0x200019d: PlaceAtMe +op 0x200019d: PlaceAtMe op 0x200019e: PlaceAtMe Explicit op 0x200019f: GetPcSleep op 0x20001a0: ShowMap op 0x20001a1: FillMap op 0x20001a2: WakeUpPc op 0x20001a3: GetDeadCount -opcodes 0x20001a4-0x3ffffff unused +op 0x20001a4: SetDisposition +op 0x20001a5: SetDisposition, Explicit +op 0x20001a6: GetDisposition +op 0x20001a7: GetDisposition, Explicit +op 0x20001a8: CommonDisease +op 0x20001a9: CommonDisease, explicit reference +op 0x20001aa: BlightDisease +op 0x20001ab: BlightDisease, explicit reference +op 0x20001ac: ToggleCollisionBoxes +op 0x20001ad: SetReputation +op 0x20001ae: ModReputation +op 0x20001af: SetReputation, explicit +op 0x20001b0: ModReputation, explicit +op 0x20001b1: GetReputation +op 0x20001b2: GetReputation, explicit +op 0x20001b3: Equip +op 0x20001b4: Equip, explicit +op 0x20001b5: SameFaction +op 0x20001b6: SameFaction, explicit +op 0x20001b7: ModHello +op 0x20001b8: ModHello, explicit reference +op 0x20001b9: ModFight +op 0x20001ba: ModFight, explicit reference +op 0x20001bb: ModFlee +op 0x20001bc: ModFlee, explicit reference +op 0x20001bd: ModAlarm +op 0x20001be: ModAlarm, explicit reference +op 0x20001bf: GetHello +op 0x20001c0: GetHello, explicit reference +op 0x20001c1: GetFight +op 0x20001c2: GetFight, explicit reference +op 0x20001c3: GetFlee +op 0x20001c4: GetFlee, explicit reference +op 0x20001c5: GetAlarm +op 0x20001c6: GetAlarm, explicit reference +op 0x20001c7: GetLocked +op 0x20001c8: GetLocked, explicit reference +op 0x20001c9: GetPcRunning +op 0x20001ca: GetPcSneaking +op 0x20001cb: GetForceRun +op 0x20001cc: GetForceSneak +op 0x20001cd: GetForceRun, explicit +op 0x20001ce: GetForceSneak, explicit +op 0x20001cf: GetEffect +op 0x20001d0: GetEffect, explicit +op 0x20001d1: GetArmorType +op 0x20001d2: GetArmorType, explicit +op 0x20001d3: GetAttacked +op 0x20001d4: GetAttacked, explicit +op 0x20001d5: HasItemEquipped +op 0x20001d6: HasItemEquipped, explicit +op 0x20001d7: GetWeaponDrawn +op 0x20001d8: GetWeaponDrawn, explicit +op 0x20001d9: GetRace +op 0x20001da: GetRace, explicit +op 0x20001db: GetSpellEffects +op 0x20001dc: GetSpellEffects, explicit +op 0x20001dd: GetCurrentTime +op 0x20001de: HasSoulGem +op 0x20001df: HasSoulGem, explicit +op 0x20001e0: GetWeaponType +op 0x20001e1: GetWeaponType, explicit +op 0x20001e2: GetWerewolfKills +op 0x20001e3: ModScale +op 0x20001e4: ModScale, explicit +op 0x20001e5: SetDelete +op 0x20001e6: SetDelete, explicit +op 0x20001e7: GetSquareRoot +op 0x20001e8: RaiseRank +op 0x20001e9: RaiseRank, explicit +op 0x20001ea: LowerRank +op 0x20001eb: LowerRank, explicit +op 0x20001ec: GetPCCrimeLevel +op 0x20001ed: SetPCCrimeLevel +op 0x20001ee: SetPCCrimeLevel + +opcodes 0x20001ef-0x3ffffff unused + + diff --git a/apps/openmw/mwscript/globalscripts.cpp b/apps/openmw/mwscript/globalscripts.cpp index 37cf34127..3ef138432 100644 --- a/apps/openmw/mwscript/globalscripts.cpp +++ b/apps/openmw/mwscript/globalscripts.cpp @@ -3,8 +3,7 @@ #include -#include -#include +#include "../mwworld/esmstore.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/scriptmanager.hpp" @@ -13,21 +12,23 @@ namespace MWScript { - GlobalScripts::GlobalScripts (const ESMS::ESMStore& store) + GlobalScripts::GlobalScripts (const MWWorld::ESMStore& store) : mStore (store) { addScript ("Main"); - for (ESMS::RecListT::MapType::const_iterator iter - (store.startScripts.list.begin()); - iter != store.startScripts.list.end(); ++iter) - addScript (iter->second.mScript); + MWWorld::Store::iterator iter = + store.get().begin(); + + for (; iter != store.get().end(); ++iter) { + addScript (iter->mScript); + } } void GlobalScripts::addScript (const std::string& name) { if (mScripts.find (name)==mScripts.end()) - if (const ESM::Script *script = mStore.scripts.find (name)) + if (const ESM::Script *script = mStore.get().find (name)) { Locals locals; diff --git a/apps/openmw/mwscript/globalscripts.hpp b/apps/openmw/mwscript/globalscripts.hpp index cc2f7ffdd..f9f9b7ae3 100644 --- a/apps/openmw/mwscript/globalscripts.hpp +++ b/apps/openmw/mwscript/globalscripts.hpp @@ -6,7 +6,7 @@ #include "locals.hpp" -namespace ESMS +namespace MWWorld { struct ESMStore; } @@ -15,12 +15,12 @@ namespace MWScript { class GlobalScripts { - const ESMS::ESMStore& mStore; + const MWWorld::ESMStore& mStore; std::map > mScripts; // running, local variables public: - GlobalScripts (const ESMS::ESMStore& store); + GlobalScripts (const MWWorld::ESMStore& store); void addScript (const std::string& name); diff --git a/apps/openmw/mwscript/guiextensions.cpp b/apps/openmw/mwscript/guiextensions.cpp index 66bb4e043..7d437f3c0 100644 --- a/apps/openmw/mwscript/guiextensions.cpp +++ b/apps/openmw/mwscript/guiextensions.cpp @@ -9,8 +9,7 @@ #include #include -#include -#include +#include "../mwworld/esmstore.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" @@ -109,13 +108,20 @@ namespace MWScript // "Will match complete or partial cells, so ShowMap, "Vivec" will show cells Vivec and Vivec, Fred's House as well." // http://www.uesp.net/wiki/Tes3Mod:ShowMap - const ESMS::CellList::ExtCells& extCells = MWBase::Environment::get().getWorld ()->getStore ().cells.extCells; - for (ESMS::CellList::ExtCells::const_iterator it = extCells.begin(); it != extCells.end(); ++it) + const MWWorld::Store &cells = + MWBase::Environment::get().getWorld()->getStore().get(); + + MWWorld::Store::iterator it = cells.extBegin(); + for (; it != cells.extEnd(); ++it) { - std::string name = it->second->mName; + std::string name = it->mName; boost::algorithm::to_lower(name); if (name.find(cell) != std::string::npos) - MWBase::Environment::get().getWindowManager()->addVisitedLocation (it->second->mName, it->first.first, it->first.second); + MWBase::Environment::get().getWindowManager()->addVisitedLocation ( + it->mName, + it->getGridX(), + it->getGridY() + ); } } }; @@ -126,12 +132,19 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - const ESMS::CellList::ExtCells& extCells = MWBase::Environment::get().getWorld ()->getStore ().cells.extCells; - for (ESMS::CellList::ExtCells::const_iterator it = extCells.begin(); it != extCells.end(); ++it) + const MWWorld::Store &cells = + MWBase::Environment::get().getWorld ()->getStore().get(); + + MWWorld::Store::iterator it = cells.extBegin(); + for (; it != cells.extEnd(); ++it) { - std::string name = it->second->mName; + std::string name = it->mName; if (name != "") - MWBase::Environment::get().getWindowManager()->addVisitedLocation (name, it->first.first, it->first.second); + MWBase::Environment::get().getWindowManager()->addVisitedLocation ( + name, + it->getGridX(), + it->getGridY() + ); } } }; @@ -168,7 +181,7 @@ opcodeEnableStatsReviewMenu); extensions.registerInstruction ("enablemapmenu", "", opcodeEnableMapMenu); extensions.registerInstruction ("enablestatsmenu", "", opcodeEnableStatsMenu); - extensions.registerInstruction ("enablerestmenu", "", opcodeEnableRest); + extensions.registerInstruction ("enablerest", "", opcodeEnableRest); extensions.registerInstruction ("enablelevelupmenu", "", opcodeEnableRest); extensions.registerInstruction ("showrestmenu", "", opcodeShowRestMenu); diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index 075ac5646..cb0e4a7f9 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -5,16 +5,19 @@ #include #include -#include +#include "../mwworld/esmstore.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/scriptmanager.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/inputmanager.hpp" #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" +#include "../mwmechanics/npcstats.hpp" + #include "locals.hpp" #include "globalscripts.hpp" @@ -174,6 +177,146 @@ namespace MWScript MWBase::Environment::get().getWorld()->getGlobalVariable (name).mFloat = value; } + std::vector InterpreterContext::getGlobals () const + { + MWBase::World *world = MWBase::Environment::get().getWorld(); + return world->getGlobals(); + + } + + char InterpreterContext::getGlobalType (const std::string& name) const + { + MWBase::World *world = MWBase::Environment::get().getWorld(); + return world->getGlobalVariableType(name); + } + + std::string InterpreterContext::getActionBinding(const std::string& action) const + { + std::vector actions = MWBase::Environment::get().getInputManager()->getActionSorting (); + for (std::vector::const_iterator it = actions.begin(); it != actions.end(); ++it) + { + std::string desc = MWBase::Environment::get().getInputManager()->getActionDescription (*it); + if(desc == "") + continue; + + if(desc == action) + return MWBase::Environment::get().getInputManager()->getActionBindingName (*it); + } + + return "None"; + } + + std::string InterpreterContext::getNPCName() const + { + ESM::NPC npc = *mReference.get()->mBase; + return npc.mName; + } + + std::string InterpreterContext::getNPCRace() const + { + ESM::NPC npc = *mReference.get()->mBase; + return npc.mRace; + } + + std::string InterpreterContext::getNPCClass() const + { + ESM::NPC npc = *mReference.get()->mBase; + return npc.mClass; + } + + std::string InterpreterContext::getNPCFaction() const + { + ESM::NPC npc = *mReference.get()->mBase; + return npc.mFaction; + } + + std::string InterpreterContext::getNPCRank() const + { + std::map ranks = MWWorld::Class::get (mReference).getNpcStats (mReference).getFactionRanks(); + std::map::const_iterator it = ranks.begin(); + + MWBase::World *world = MWBase::Environment::get().getWorld(); + const MWWorld::ESMStore &store = world->getStore(); + const ESM::Faction *faction = store.get().find(it->first); + + return faction->mRanks[it->second]; + } + + std::string InterpreterContext::getPCName() const + { + MWBase::World *world = MWBase::Environment::get().getWorld(); + ESM::NPC player = *world->getPlayer().getPlayer().get()->mBase; + return player.mName; + } + + std::string InterpreterContext::getPCRace() const + { + MWBase::World *world = MWBase::Environment::get().getWorld(); + ESM::NPC player = *world->getPlayer().getPlayer().get()->mBase; + return player.mRace; + } + + std::string InterpreterContext::getPCClass() const + { + MWBase::World *world = MWBase::Environment::get().getWorld(); + ESM::NPC player = *world->getPlayer().getPlayer().get()->mBase; + return player.mClass; + } + + std::string InterpreterContext::getPCRank() const + { + MWBase::World *world = MWBase::Environment::get().getWorld(); + MWWorld::Ptr player = world->getPlayer().getPlayer(); + + std::string factionId = MWWorld::Class::get (mReference).getNpcStats (mReference).getFactionRanks().begin()->first; + + std::map ranks = MWWorld::Class::get (player).getNpcStats (player).getFactionRanks(); + std::map::const_iterator it = ranks.begin(); + + const MWWorld::ESMStore &store = world->getStore(); + const ESM::Faction *faction = store.get().find(factionId); + + if(it->second < 0 || it->second > 9) // there are only 10 ranks + return ""; + + return faction->mRanks[it->second]; + } + + std::string InterpreterContext::getPCNextRank() const + { + MWBase::World *world = MWBase::Environment::get().getWorld(); + MWWorld::Ptr player = world->getPlayer().getPlayer(); + + std::string factionId = MWWorld::Class::get (mReference).getNpcStats (mReference).getFactionRanks().begin()->first; + + std::map ranks = MWWorld::Class::get (player).getNpcStats (player).getFactionRanks(); + std::map::const_iterator it = ranks.begin(); + + const MWWorld::ESMStore &store = world->getStore(); + const ESM::Faction *faction = store.get().find(factionId); + + if(it->second < 0 || it->second > 9) + return ""; + + if(it->second <= 8) // If player is at max rank, there is no next rank + return faction->mRanks[it->second + 1]; + else + return faction->mRanks[it->second]; + } + + int InterpreterContext::getPCBounty() const + { + MWBase::World *world = MWBase::Environment::get().getWorld(); + MWWorld::Ptr player = world->getPlayer().getPlayer(); + return MWWorld::Class::get (player).getNpcStats (player).getBounty(); + } + + std::string InterpreterContext::getCurrentCellName() const + { + MWBase::World *world = MWBase::Environment::get().getWorld(); + return world->getCurrentCellName(); + } + bool InterpreterContext::isScriptRunning (const std::string& name) const { return MWBase::Environment::get().getScriptManager()->getGlobalScripts().isRunning (name); @@ -278,7 +421,7 @@ namespace MWScript int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 's'); ptr.getRefData().setLocals ( - *MWBase::Environment::get().getWorld()->getStore().scripts.find (scriptId)); + *MWBase::Environment::get().getWorld()->getStore().get().find (scriptId)); return ptr.getRefData().getLocals().mShorts[index]; } @@ -291,7 +434,7 @@ namespace MWScript int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'l'); ptr.getRefData().setLocals ( - *MWBase::Environment::get().getWorld()->getStore().scripts.find (scriptId)); + *MWBase::Environment::get().getWorld()->getStore().get().find (scriptId)); return ptr.getRefData().getLocals().mLongs[index]; } @@ -304,7 +447,7 @@ namespace MWScript int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'f'); ptr.getRefData().setLocals ( - *MWBase::Environment::get().getWorld()->getStore().scripts.find (scriptId)); + *MWBase::Environment::get().getWorld()->getStore().get().find (scriptId)); return ptr.getRefData().getLocals().mFloats[index]; } @@ -317,7 +460,7 @@ namespace MWScript int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 's'); ptr.getRefData().setLocals ( - *MWBase::Environment::get().getWorld()->getStore().scripts.find (scriptId)); + *MWBase::Environment::get().getWorld()->getStore().get().find (scriptId)); ptr.getRefData().getLocals().mShorts[index] = value; } @@ -330,7 +473,7 @@ namespace MWScript int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'l'); ptr.getRefData().setLocals ( - *MWBase::Environment::get().getWorld()->getStore().scripts.find (scriptId)); + *MWBase::Environment::get().getWorld()->getStore().get().find (scriptId)); ptr.getRefData().getLocals().mLongs[index] = value; } @@ -343,7 +486,7 @@ namespace MWScript int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'f'); ptr.getRefData().setLocals ( - *MWBase::Environment::get().getWorld()->getStore().scripts.find (scriptId)); + *MWBase::Environment::get().getWorld()->getStore().get().find (scriptId)); ptr.getRefData().getLocals().mFloats[index] = value; } diff --git a/apps/openmw/mwscript/interpretercontext.hpp b/apps/openmw/mwscript/interpretercontext.hpp index 6d97f7949..f0b2758d9 100644 --- a/apps/openmw/mwscript/interpretercontext.hpp +++ b/apps/openmw/mwscript/interpretercontext.hpp @@ -75,6 +75,36 @@ namespace MWScript virtual void setGlobalLong (const std::string& name, int value); virtual void setGlobalFloat (const std::string& name, float value); + + virtual std::vector getGlobals () const; + + virtual char getGlobalType (const std::string& name) const; + + virtual std::string getActionBinding(const std::string& action) const; + + virtual std::string getNPCName() const; + + virtual std::string getNPCRace() const; + + virtual std::string getNPCClass() const; + + virtual std::string getNPCFaction() const; + + virtual std::string getNPCRank() const; + + virtual std::string getPCName() const; + + virtual std::string getPCRace() const; + + virtual std::string getPCClass() const; + + virtual std::string getPCRank() const; + + virtual std::string getPCNextRank() const; + + virtual int getPCBounty() const; + + virtual std::string getCurrentCellName() const; virtual bool isScriptRunning (const std::string& name) const; diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 674548cd6..b687471aa 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -13,6 +13,10 @@ #include "../mwbase/windowmanager.hpp" #include "../mwworld/class.hpp" +#include "../mwworld/player.hpp" + +#include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/creaturestats.hpp" #include "interpretercontext.hpp" #include "ref.hpp" @@ -132,6 +136,24 @@ namespace MWScript } }; + + class OpToggleCollisionBoxes : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + InterpreterContext& context = + static_cast (runtime.getContext()); + + bool enabled = + MWBase::Environment::get().getWorld()->toggleRenderMode (MWBase::World::Render_BoundingBoxes); + + context.report (enabled ? + "Bounding Box Rendering -> On" : "Bounding Box Rendering -> Off"); + } + }; + class OpToggleWireframe : public Interpreter::Opcode0 { public: @@ -254,6 +276,121 @@ namespace MWScript }; bool OpToggleVanityMode::sActivate = true; + template + class OpGetLocked : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + runtime.push (ptr.getCellRef ().mLockLevel > 0); + } + }; + + template + class OpGetEffect : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + int key = runtime[0].mInteger; + runtime.pop(); + + runtime.push (MWWorld::Class::get(ptr).getCreatureStats (ptr).getMagicEffects ().get ( + MWMechanics::EffectKey(key)).mMagnitude > 0); + } + }; + + template + class OpGetAttacked : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + runtime.push(MWWorld::Class::get(ptr).getCreatureStats (ptr).getAttacked ()); + } + }; + + template + class OpGetWeaponDrawn : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + runtime.push(MWWorld::Class::get(ptr).getNpcStats (ptr).getDrawState () == MWMechanics::DrawState_Weapon); + } + }; + + template + class OpGetSpellEffects : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + std::string id = runtime.getStringLiteral(runtime[0].mInteger); + runtime.pop(); + + runtime.push(MWWorld::Class::get(ptr).getCreatureStats(ptr).getActiveSpells().isSpellActive(id)); + } + }; + + class OpGetCurrentTime : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + runtime.push(MWBase::Environment::get().getWorld()->getTimeStamp().getHour()); + } + }; + + template + class OpSetDelete : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + int parameter = runtime[0].mInteger; + runtime.pop(); + + if (parameter == 1) + { + if (ptr.isInCell()) + MWBase::Environment::get().getWorld()->deleteObject (ptr); + else + ptr.getRefData().setCount(0); + } + } + }; + + class OpGetSquareRoot : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + float param = runtime[0].mFloat; + runtime.pop(); + + runtime.push(std::sqrt (param)); + } + }; + const int opcodeXBox = 0x200000c; const int opcodeOnActivate = 0x200000d; const int opcodeActivate = 0x2000075; @@ -262,6 +399,7 @@ namespace MWScript const int opcodeUnlock = 0x200008c; const int opcodeUnlockExplicit = 0x200008d; const int opcodeToggleCollisionDebug = 0x2000132; + const int opcodeToggleCollisionBoxes = 0x20001ac; const int opcodeToggleWireframe = 0x200013b; const int opcodeFadeIn = 0x200013c; const int opcodeFadeOut = 0x200013d; @@ -272,6 +410,20 @@ namespace MWScript const int opcodeToggleVanityMode = 0x2000174; const int opcodeGetPcSleep = 0x200019f; const int opcodeWakeUpPc = 0x20001a2; + const int opcodeGetLocked = 0x20001c7; + const int opcodeGetLockedExplicit = 0x20001c8; + const int opcodeGetEffect = 0x20001cf; + const int opcodeGetEffectExplicit = 0x20001d0; + const int opcodeGetAttacked = 0x20001d3; + const int opcodeGetAttackedExplicit = 0x20001d4; + const int opcodeGetWeaponDrawn = 0x20001d7; + const int opcodeGetWeaponDrawnExplicit = 0x20001d8; + const int opcodeGetSpellEffects = 0x20001db; + const int opcodeGetSpellEffectsExplicit = 0x20001dc; + const int opcodeGetCurrentTime = 0x20001dd; + const int opcodeSetDelete = 0x20001e5; + const int opcodeSetDeleteExplicit = 0x20001e6; + const int opcodeGetSquareRoot = 0x20001e7; void registerExtensions (Compiler::Extensions& extensions) { @@ -280,9 +432,9 @@ namespace MWScript extensions.registerInstruction ("activate", "", opcodeActivate); extensions.registerInstruction ("lock", "/l", opcodeLock, opcodeLockExplicit); extensions.registerInstruction ("unlock", "", opcodeUnlock, opcodeUnlockExplicit); - extensions.registerInstruction ("togglecollisionboxes", "", opcodeToggleCollisionDebug); + extensions.registerInstruction ("togglecollisionboxes", "", opcodeToggleCollisionBoxes); extensions.registerInstruction ("togglecollisiongrid", "", opcodeToggleCollisionDebug); - extensions.registerInstruction ("tcb", "", opcodeToggleCollisionDebug); + extensions.registerInstruction ("tcb", "", opcodeToggleCollisionBoxes); extensions.registerInstruction ("tcg", "", opcodeToggleCollisionDebug); extensions.registerInstruction ("twf", "", opcodeToggleWireframe); extensions.registerInstruction ("togglewireframe", "", opcodeToggleWireframe); @@ -298,6 +450,14 @@ namespace MWScript extensions.registerInstruction ("tvm", "", opcodeToggleVanityMode); extensions.registerFunction ("getpcsleep", 'l', "", opcodeGetPcSleep); extensions.registerInstruction ("wakeuppc", "", opcodeWakeUpPc); + extensions.registerFunction ("getlocked", 'l', "", opcodeGetLocked, opcodeGetLockedExplicit); + extensions.registerFunction ("geteffect", 'l', "l", opcodeGetEffect, opcodeGetEffectExplicit); + extensions.registerFunction ("getattacked", 'l', "", opcodeGetAttacked, opcodeGetAttackedExplicit); + extensions.registerFunction ("getweapondrawn", 'l', "", opcodeGetWeaponDrawn, opcodeGetWeaponDrawnExplicit); + extensions.registerFunction ("getspelleffects", 'l', "c", opcodeGetSpellEffects, opcodeGetSpellEffectsExplicit); + extensions.registerFunction ("getcurrenttime", 'f', "", opcodeGetCurrentTime); + extensions.registerInstruction ("setdelete", "l", opcodeSetDelete, opcodeSetDeleteExplicit); + extensions.registerFunction ("getsquareroot", 'f', "f", opcodeGetSquareRoot); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -310,6 +470,7 @@ namespace MWScript interpreter.installSegment5 (opcodeUnlock, new OpUnlock); interpreter.installSegment5 (opcodeUnlockExplicit, new OpUnlock); interpreter.installSegment5 (opcodeToggleCollisionDebug, new OpToggleCollisionDebug); + interpreter.installSegment5 (opcodeToggleCollisionBoxes, new OpToggleCollisionBoxes); interpreter.installSegment5 (opcodeToggleWireframe, new OpToggleWireframe); interpreter.installSegment5 (opcodeFadeIn, new OpFadeIn); interpreter.installSegment5 (opcodeFadeOut, new OpFadeOut); @@ -320,6 +481,20 @@ namespace MWScript interpreter.installSegment5 (opcodeToggleVanityMode, new OpToggleVanityMode); interpreter.installSegment5 (opcodeGetPcSleep, new OpGetPcSleep); interpreter.installSegment5 (opcodeWakeUpPc, new OpWakeUpPc); + interpreter.installSegment5 (opcodeGetLocked, new OpGetLocked); + interpreter.installSegment5 (opcodeGetLockedExplicit, new OpGetLocked); + interpreter.installSegment5 (opcodeGetEffect, new OpGetEffect); + interpreter.installSegment5 (opcodeGetEffectExplicit, new OpGetEffect); + interpreter.installSegment5 (opcodeGetAttacked, new OpGetAttacked); + interpreter.installSegment5 (opcodeGetAttackedExplicit, new OpGetAttacked); + interpreter.installSegment5 (opcodeGetWeaponDrawn, new OpGetWeaponDrawn); + interpreter.installSegment5 (opcodeGetWeaponDrawnExplicit, new OpGetWeaponDrawn); + interpreter.installSegment5 (opcodeGetSpellEffects, new OpGetSpellEffects); + interpreter.installSegment5 (opcodeGetSpellEffectsExplicit, new OpGetSpellEffects); + interpreter.installSegment5 (opcodeGetCurrentTime, new OpGetCurrentTime); + interpreter.installSegment5 (opcodeSetDelete, new OpSetDelete); + interpreter.installSegment5 (opcodeSetDeleteExplicit, new OpSetDelete); + interpreter.installSegment5 (opcodeGetSquareRoot, new OpGetSquareRoot); } } } diff --git a/apps/openmw/mwscript/scriptmanagerimp.cpp b/apps/openmw/mwscript/scriptmanagerimp.cpp index 883d3dfd3..1f338edbd 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.cpp +++ b/apps/openmw/mwscript/scriptmanagerimp.cpp @@ -7,7 +7,7 @@ #include #include -#include +#include "../mwworld/esmstore.hpp" #include #include @@ -17,7 +17,7 @@ namespace MWScript { - ScriptManager::ScriptManager (const ESMS::ESMStore& store, bool verbose, + ScriptManager::ScriptManager (const MWWorld::ESMStore& store, bool verbose, Compiler::Context& compilerContext) : mErrorHandler (std::cerr), mStore (store), mVerbose (verbose), mCompilerContext (compilerContext), mParser (mErrorHandler, mCompilerContext), @@ -31,7 +31,7 @@ namespace MWScript bool Success = true; - if (const ESM::Script *script = mStore.scripts.find (name)) + if (const ESM::Script *script = mStore.get().find (name)) { if (mVerbose) std::cout << "compiling script: " << name << std::endl; @@ -125,15 +125,14 @@ namespace MWScript std::pair ScriptManager::compileAll() { - typedef ESMS::ScriptListT::MapType Container; - - const Container& scripts = mStore.scripts.list; - int count = 0; int success = 0; - for (Container::const_iterator iter (scripts.begin()); iter!=scripts.end(); ++iter, ++count) - if (compile (iter->first)) + const MWWorld::Store& scripts = mStore.get(); + MWWorld::Store::iterator it = scripts.begin(); + + for (; it != scripts.end(); ++it, ++count) + if (compile (it->mId)) ++success; return std::make_pair (count, success); @@ -170,7 +169,7 @@ namespace MWScript int ScriptManager::getLocalIndex (const std::string& scriptId, const std::string& variable, char type) { - const ESM::Script *script = mStore.scripts.find (scriptId); + const ESM::Script *script = mStore.get().find (scriptId); int offset = 0; int size = 0; diff --git a/apps/openmw/mwscript/scriptmanagerimp.hpp b/apps/openmw/mwscript/scriptmanagerimp.hpp index a97310ae5..c4a016eb7 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.hpp +++ b/apps/openmw/mwscript/scriptmanagerimp.hpp @@ -14,7 +14,7 @@ #include "globalscripts.hpp" -namespace ESMS +namespace MWWorld { struct ESMStore; } @@ -35,7 +35,7 @@ namespace MWScript class ScriptManager : public MWBase::ScriptManager { Compiler::StreamErrorHandler mErrorHandler; - const ESMS::ESMStore& mStore; + const MWWorld::ESMStore& mStore; bool mVerbose; Compiler::Context& mCompilerContext; Compiler::FileParser mParser; @@ -50,7 +50,7 @@ namespace MWScript public: - ScriptManager (const ESMS::ESMStore& store, bool verbose, + ScriptManager (const MWWorld::ESMStore& store, bool verbose, Compiler::Context& compilerContext); virtual void run (const std::string& name, Interpreter::Context& interpreterContext); diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 0d69608e1..9e630aedf 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -7,7 +7,7 @@ #include -#include +#include "../mwworld/esmstore.hpp" #include @@ -28,6 +28,21 @@ #include "interpretercontext.hpp" #include "ref.hpp" +namespace +{ + std::string getDialogueActorFaction() + { + MWWorld::Ptr actor = MWBase::Environment::get().getDialogueManager()->getActor(); + + MWMechanics::NpcStats stats = MWWorld::Class::get (actor).getNpcStats (actor); + + if (stats.getFactionRanks().empty()) + throw std::runtime_error ( + "failed to determine dialogue actors faction (because actor is factionless)"); + + return stats.getFactionRanks().begin()->first; + } +} namespace MWScript { @@ -193,7 +208,7 @@ namespace MWScript .getDynamic (mIndex)); stat.setModified (value, 0); - + MWWorld::Class::get (ptr).getCreatureStats (ptr).setDynamic (mIndex, stat); } }; @@ -328,7 +343,7 @@ namespace MWScript assert (ref); const ESM::Class& class_ = - *MWBase::Environment::get().getWorld()->getStore().classes.find (ref->base->mClass); + *MWBase::Environment::get().getWorld()->getStore().get().find (ref->mBase->mClass); float level = 0; float progress = std::modf (stats.getSkill (mIndex).getBase(), &level); @@ -377,6 +392,46 @@ namespace MWScript } }; + class OpGetPCCrimeLevel : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWBase::World *world = MWBase::Environment::get().getWorld(); + MWWorld::Ptr player = world->getPlayer().getPlayer(); + runtime.push (static_cast (MWWorld::Class::get (player).getNpcStats (player).getBounty())); + } + }; + + class OpSetPCCrimeLevel : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWBase::World *world = MWBase::Environment::get().getWorld(); + MWWorld::Ptr player = world->getPlayer().getPlayer(); + + MWWorld::Class::get (player).getNpcStats (player).setBounty(runtime[0].mFloat); + runtime.pop(); + } + }; + + class OpModPCCrimeLevel : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWBase::World *world = MWBase::Environment::get().getWorld(); + MWWorld::Ptr player = world->getPlayer().getPlayer(); + + MWWorld::Class::get (player).getNpcStats (player).setBounty(runtime[0].mFloat + MWWorld::Class::get (player).getNpcStats (player).getBounty()); + runtime.pop(); + } + }; + template class OpAddSpell : public Interpreter::Opcode0 { @@ -390,7 +445,7 @@ namespace MWScript runtime.pop(); // make sure a spell with this ID actually exists. - MWBase::Environment::get().getWorld()->getStore().spells.find (id); + MWBase::Environment::get().getWorld()->getStore().get().find (id); MWWorld::Class::get (ptr).getCreatureStats (ptr).getSpells().add (id); } @@ -450,7 +505,7 @@ namespace MWScript if(arg0==0) { - factionID = MWBase::Environment::get().getDialogueManager()->getFaction(); + factionID = getDialogueActorFaction(); } else { @@ -479,7 +534,7 @@ namespace MWScript if(arg0==0) { - factionID = MWBase::Environment::get().getDialogueManager()->getFaction(); + factionID = getDialogueActorFaction(); } else { @@ -512,7 +567,7 @@ namespace MWScript if(arg0==0) { - factionID = MWBase::Environment::get().getDialogueManager()->getFaction(); + factionID = getDialogueActorFaction(); } else { @@ -550,7 +605,7 @@ namespace MWScript { if(MWWorld::Class::get(ptr).getNpcStats(ptr).getFactionRanks().empty()) { - //throw exception? + factionID = ""; } else { @@ -586,13 +641,43 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); -// Interpreter::Type_Integer value = runtime[0].mInteger; + Interpreter::Type_Integer value = runtime[0].mInteger; runtime.pop(); - /// \todo modify disposition towards the player + MWWorld::Class::get (ptr).getNpcStats (ptr).setBaseDisposition + (MWWorld::Class::get (ptr).getNpcStats (ptr).getBaseDisposition() + value); } }; - + + template + class OpSetDisposition : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + Interpreter::Type_Integer value = runtime[0].mInteger; + runtime.pop(); + + MWWorld::Class::get (ptr).getNpcStats (ptr).setBaseDisposition (value); + } + }; + + template + class OpGetDisposition : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + runtime.push (MWWorld::Class::get (ptr).getNpcStats (ptr).getBaseDisposition()); + } + }; + class OpGetDeadCount : public Interpreter::Opcode0 { public: @@ -602,8 +687,343 @@ namespace MWScript std::string id = runtime.getStringLiteral (runtime[0].mInteger); runtime[0].mInteger = MWBase::Environment::get().getMechanicsManager()->countDeaths (id); } - }; + }; + template + class OpGetPCFacRep : public Interpreter::Opcode1 + { + public: + + virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) + { + std::string factionId; + + if (arg0==1) + { + factionId = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + } + else + { + MWWorld::Ptr ptr = R()(runtime); + + if (!MWWorld::Class::get (ptr).getNpcStats (ptr).getFactionRanks().empty()) + factionId = MWWorld::Class::get (ptr).getNpcStats (ptr).getFactionRanks().begin()->first; + } + + if (factionId.empty()) + throw std::runtime_error ("failed to determine faction"); + + boost::algorithm::to_lower (factionId); + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + runtime.push ( + MWWorld::Class::get (player).getNpcStats (player).getFactionReputation (factionId)); + } + }; + + template + class OpSetPCFacRep : public Interpreter::Opcode1 + { + public: + + virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) + { + Interpreter::Type_Integer value = runtime[0].mInteger; + runtime.pop(); + + std::string factionId; + + if (arg0==1) + { + factionId = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + } + else + { + MWWorld::Ptr ptr = R()(runtime); + + if (!MWWorld::Class::get (ptr).getNpcStats (ptr).getFactionRanks().empty()) + factionId = MWWorld::Class::get (ptr).getNpcStats (ptr).getFactionRanks().begin()->first; + } + + if (factionId.empty()) + throw std::runtime_error ("failed to determine faction"); + + boost::algorithm::to_lower (factionId); + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWWorld::Class::get (player).getNpcStats (player).setFactionReputation (factionId, value); + } + }; + + template + class OpModPCFacRep : public Interpreter::Opcode1 + { + public: + + virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) + { + Interpreter::Type_Integer value = runtime[0].mInteger; + runtime.pop(); + + std::string factionId; + + if (arg0==1) + { + factionId = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + } + else + { + MWWorld::Ptr ptr = R()(runtime); + + if (!MWWorld::Class::get (ptr).getNpcStats (ptr).getFactionRanks().empty()) + factionId = MWWorld::Class::get (ptr).getNpcStats (ptr).getFactionRanks().begin()->first; + } + + if (factionId.empty()) + throw std::runtime_error ("failed to determine faction"); + + boost::algorithm::to_lower (factionId); + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWWorld::Class::get (player).getNpcStats (player).setFactionReputation (factionId, + MWWorld::Class::get (player).getNpcStats (player).getFactionReputation (factionId)+ + value); + } + }; + + template + class OpGetCommonDisease : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + runtime.push (MWWorld::Class::get (ptr).getCreatureStats (ptr).hasCommonDisease()); + } + }; + + template + class OpGetBlightDisease : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + runtime.push (MWWorld::Class::get (ptr).getCreatureStats (ptr).hasBlightDisease()); + } + }; + + template + class OpGetRace : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string race = runtime.getStringLiteral(runtime[0].mInteger); + boost::algorithm::to_lower(race); + runtime.pop(); + + std::string npcRace = ptr.get()->mBase->mRace; + boost::algorithm::to_lower(npcRace); + + runtime.push (npcRace == race); + } + }; + + class OpGetWerewolfKills : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer (); + + runtime.push (MWWorld::Class::get(ptr).getNpcStats (ptr).getWerewolfKills ()); + } + }; + + template + class OpPcExpelled : public Interpreter::Opcode1 + { + public: + + virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string factionID = ""; + if(arg0 >0 ) + { + factionID = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + } + else + { + if(MWWorld::Class::get(ptr).getNpcStats(ptr).getFactionRanks().empty()) + { + factionID = ""; + } + else + { + factionID = MWWorld::Class::get(ptr).getNpcStats(ptr).getFactionRanks().begin()->first; + } + } + boost::algorithm::to_lower(factionID); + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + if(factionID!="") + { + std::set& expelled = MWWorld::Class::get(player).getNpcStats(player).getExpelled (); + if (expelled.find (factionID) != expelled.end()) + { + runtime.push(1); + } + else + { + runtime.push(0); + } + } + else + { + runtime.push(0); + } + } + }; + + template + class OpPcExpell : public Interpreter::Opcode1 + { + public: + + virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string factionID = ""; + if(arg0 >0 ) + { + factionID = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + } + else + { + if(MWWorld::Class::get(ptr).getNpcStats(ptr).getFactionRanks().empty()) + { + factionID = ""; + } + else + { + factionID = MWWorld::Class::get(ptr).getNpcStats(ptr).getFactionRanks().begin()->first; + } + } + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + if(factionID!="") + { + std::set& expelled = MWWorld::Class::get(player).getNpcStats(player).getExpelled (); + boost::algorithm::to_lower(factionID); + expelled.insert(factionID); + } + } + }; + + template + class OpPcClearExpelled : public Interpreter::Opcode1 + { + public: + + virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string factionID = ""; + if(arg0 >0 ) + { + factionID = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + } + else + { + if(MWWorld::Class::get(ptr).getNpcStats(ptr).getFactionRanks().empty()) + { + factionID = ""; + } + else + { + factionID = MWWorld::Class::get(ptr).getNpcStats(ptr).getFactionRanks().begin()->first; + } + } + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + if(factionID!="") + { + std::set& expelled = MWWorld::Class::get(player).getNpcStats(player).getExpelled (); + boost::algorithm::to_lower(factionID); + expelled.erase (factionID); + } + } + }; + + template + class OpRaiseRank : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string factionID = ""; + if(MWWorld::Class::get(ptr).getNpcStats(ptr).getFactionRanks().empty()) + return; + else + { + factionID = MWWorld::Class::get(ptr).getNpcStats(ptr).getFactionRanks().begin()->first; + } + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + + // no-op when executed on the player + if (ptr == player) + return; + + std::map& ranks = MWWorld::Class::get(ptr).getNpcStats(ptr).getFactionRanks (); + ranks[factionID] = ranks[factionID]+1; + } + }; + + template + class OpLowerRank : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string factionID = ""; + if(MWWorld::Class::get(ptr).getNpcStats(ptr).getFactionRanks().empty()) + return; + else + { + factionID = MWWorld::Class::get(ptr).getNpcStats(ptr).getFactionRanks().begin()->first; + } + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + + // no-op when executed on the player + if (ptr == player) + return; + + std::map& ranks = MWWorld::Class::get(ptr).getNpcStats(ptr).getFactionRanks (); + ranks[factionID] = ranks[factionID]-1; + } + }; const int numberOfAttributes = 8; @@ -636,6 +1056,10 @@ namespace MWScript const int opcodeModSkill = 0x20000fa; const int opcodeModSkillExplicit = 0x2000115; + const int opcodeGetPCCrimeLevel = 0x20001ec; + const int opcodeSetPCCrimeLevel = 0x20001ed; + const int opcodeModPCCrimeLevel = 0x20001ee; + const int opcodeAddSpell = 0x2000147; const int opcodeAddSpellExplicit = 0x2000148; const int opcodeRemoveSpell = 0x2000149; @@ -650,14 +1074,46 @@ namespace MWScript const int opcodeGetPCRankExplicit = 0x2000f; const int opcodeModDisposition = 0x200014d; const int opcodeModDispositionExplicit = 0x200014e; + const int opcodeSetDisposition = 0x20001a4; + const int opcodeSetDispositionExplicit = 0x20001a5; + const int opcodeGetDisposition = 0x20001a6; + const int opcodeGetDispositionExplicit = 0x20001a7; const int opcodeGetLevel = 0x200018c; const int opcodeGetLevelExplicit = 0x200018d; const int opcodeSetLevel = 0x200018e; const int opcodeSetLevelExplicit = 0x200018f; - + const int opcodeGetDeadCount = 0x20001a3; + const int opcodeGetPCFacRep = 0x20012; + const int opcodeGetPCFacRepExplicit = 0x20013; + const int opcodeSetPCFacRep = 0x20014; + const int opcodeSetPCFacRepExplicit = 0x20015; + const int opcodeModPCFacRep = 0x20016; + const int opcodeModPCFacRepExplicit = 0x20017; + + const int opcodeGetCommonDisease = 0x20001a8; + const int opcodeGetCommonDiseaseExplicit = 0x20001a9; + const int opcodeGetBlightDisease = 0x20001aa; + const int opcodeGetBlightDiseaseExplicit = 0x20001ab; + + const int opcodeGetRace = 0x20001d9; + const int opcodeGetRaceExplicit = 0x20001da; + + const int opcodeGetWerewolfKills = 0x20001e2; + + const int opcodePcExpelled = 0x20018; + const int opcodePcExpelledExplicit = 0x20019; + const int opcodePcExpell = 0x2001a; + const int opcodePcExpellExplicit = 0x2001b; + const int opcodePcClearExpelled = 0x2001c; + const int opcodePcClearExpelledExplicit = 0x2001d; + const int opcodeRaiseRank = 0x20001e8; + const int opcodeRaiseRankExplicit = 0x20001e9; + const int opcodeLowerRank = 0x20001ea; + const int opcodeLowerRankExplicit = 0x20001eb; + void registerExtensions (Compiler::Extensions& extensions) { static const char *attributes[numberOfAttributes] = @@ -678,7 +1134,7 @@ namespace MWScript "alteration", "illusion", "conjuration", "mysticism", "restoration", "alchemy", "unarmored", "security", "sneak", "acrobatics", "lightarmor", "shortblade", "marksman", - "merchantile", "speechcraft", "handtohand" + "mercantile", "speechcraft", "handtohand" }; std::string get ("get"); @@ -729,6 +1185,10 @@ namespace MWScript opcodeModSkill+i, opcodeModSkillExplicit+i); } + extensions.registerFunction ("getpccrimelevel", 'f', "", opcodeGetPCCrimeLevel); + extensions.registerInstruction ("setpccrimelevel", "f", opcodeSetPCCrimeLevel); + extensions.registerInstruction ("modpccrimelevel", "f", opcodeModPCCrimeLevel); + extensions.registerInstruction ("addspell", "c", opcodeAddSpell, opcodeAddSpellExplicit); extensions.registerInstruction ("removespell", "c", opcodeRemoveSpell, opcodeRemoveSpellExplicit); @@ -737,14 +1197,36 @@ namespace MWScript extensions.registerInstruction("pcraiserank","/S",opcodePCRaiseRank); extensions.registerInstruction("pclowerrank","/S",opcodePCLowerRank); extensions.registerInstruction("pcjoinfaction","/S",opcodePCJoinFaction); - extensions.registerInstruction("moddisposition","l",opcodeModDisposition, + extensions.registerInstruction ("moddisposition","l",opcodeModDisposition, opcodeModDispositionExplicit); + extensions.registerInstruction ("setdisposition","l",opcodeSetDisposition, + opcodeSetDispositionExplicit); + extensions.registerFunction ("getdisposition",'l', "",opcodeGetDisposition, + opcodeGetDispositionExplicit); extensions.registerFunction("getpcrank",'l',"/S",opcodeGetPCRank,opcodeGetPCRankExplicit); extensions.registerInstruction("setlevel", "l", opcodeSetLevel, opcodeSetLevelExplicit); extensions.registerFunction("getlevel", 'l', "", opcodeGetLevel, opcodeGetLevelExplicit); - extensions.registerFunction("getdeadcount", 'l', "c", opcodeGetDeadCount); + extensions.registerFunction ("getdeadcount", 'l', "c", opcodeGetDeadCount); + + extensions.registerFunction ("getpcfacrep", 'l', "/c", opcodeGetPCFacRep, opcodeGetPCFacRepExplicit); + extensions.registerInstruction ("setpcfacrep", "l/c", opcodeSetPCFacRep, opcodeSetPCFacRepExplicit); + extensions.registerInstruction ("modpcfacrep", "l/c", opcodeModPCFacRep, opcodeModPCFacRepExplicit); + + extensions.registerFunction ("getcommondisease", 'l', "", opcodeGetCommonDisease, + opcodeGetCommonDiseaseExplicit); + extensions.registerFunction ("getblightdisease", 'l', "", opcodeGetBlightDisease, + opcodeGetBlightDiseaseExplicit); + + extensions.registerFunction ("getrace", 'l', "c", opcodeGetRace, + opcodeGetRaceExplicit); + extensions.registerFunction ("getwerewolfkills", 'f', "", opcodeGetWerewolfKills); + extensions.registerFunction ("pcexpelled", 'l', "/S", opcodePcExpelled, opcodePcExpelledExplicit); + extensions.registerInstruction ("pcexpell", "/S", opcodePcExpell, opcodePcExpellExplicit); + extensions.registerInstruction ("pcclearexpelled", "/S", opcodePcClearExpelled, opcodePcClearExpelledExplicit); + extensions.registerInstruction ("raiserank", "", opcodeRaiseRank, opcodeRaiseRankExplicit); + extensions.registerInstruction ("lowerrank", "", opcodeLowerRank, opcodeLowerRankExplicit); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -801,6 +1283,10 @@ namespace MWScript interpreter.installSegment5 (opcodeModSkillExplicit+i, new OpModSkill (i)); } + interpreter.installSegment5 (opcodeGetPCCrimeLevel, new OpGetPCCrimeLevel); + interpreter.installSegment5 (opcodeSetPCCrimeLevel, new OpSetPCCrimeLevel); + interpreter.installSegment5 (opcodeModPCCrimeLevel, new OpModPCCrimeLevel); + interpreter.installSegment5 (opcodeAddSpell, new OpAddSpell); interpreter.installSegment5 (opcodeAddSpellExplicit, new OpAddSpell); interpreter.installSegment5 (opcodeRemoveSpell, new OpRemoveSpell); @@ -812,17 +1298,49 @@ namespace MWScript interpreter.installSegment3(opcodePCRaiseRank,new OpPCRaiseRank); interpreter.installSegment3(opcodePCLowerRank,new OpPCLowerRank); interpreter.installSegment3(opcodePCJoinFaction,new OpPCJoinFaction); - interpreter.installSegment5(opcodeModDisposition,new OpModDisposition); - interpreter.installSegment5(opcodeModDispositionExplicit,new OpModDisposition); interpreter.installSegment3(opcodeGetPCRank,new OpGetPCRank); interpreter.installSegment3(opcodeGetPCRankExplicit,new OpGetPCRank); + interpreter.installSegment5(opcodeModDisposition,new OpModDisposition); + interpreter.installSegment5(opcodeModDispositionExplicit,new OpModDisposition); + interpreter.installSegment5(opcodeSetDisposition,new OpSetDisposition); + interpreter.installSegment5(opcodeSetDispositionExplicit,new OpSetDisposition); + interpreter.installSegment5(opcodeGetDisposition,new OpGetDisposition); + interpreter.installSegment5(opcodeGetDispositionExplicit,new OpGetDisposition); + interpreter.installSegment5 (opcodeGetLevel, new OpGetLevel); interpreter.installSegment5 (opcodeGetLevelExplicit, new OpGetLevel); interpreter.installSegment5 (opcodeSetLevel, new OpSetLevel); interpreter.installSegment5 (opcodeSetLevelExplicit, new OpSetLevel); interpreter.installSegment5 (opcodeGetDeadCount, new OpGetDeadCount); + + interpreter.installSegment3 (opcodeGetPCFacRep, new OpGetPCFacRep); + interpreter.installSegment3 (opcodeGetPCFacRepExplicit, new OpGetPCFacRep); + interpreter.installSegment3 (opcodeSetPCFacRep, new OpSetPCFacRep); + interpreter.installSegment3 (opcodeSetPCFacRepExplicit, new OpSetPCFacRep); + interpreter.installSegment3 (opcodeModPCFacRep, new OpModPCFacRep); + interpreter.installSegment3 (opcodeModPCFacRepExplicit, new OpModPCFacRep); + + interpreter.installSegment5 (opcodeGetCommonDisease, new OpGetCommonDisease); + interpreter.installSegment5 (opcodeGetCommonDiseaseExplicit, new OpGetCommonDisease); + interpreter.installSegment5 (opcodeGetBlightDisease, new OpGetBlightDisease); + interpreter.installSegment5 (opcodeGetBlightDiseaseExplicit, new OpGetBlightDisease); + + interpreter.installSegment5 (opcodeGetRace, new OpGetRace); + interpreter.installSegment5 (opcodeGetRaceExplicit, new OpGetRace); + interpreter.installSegment5 (opcodeGetWerewolfKills, new OpGetWerewolfKills); + + interpreter.installSegment3 (opcodePcExpelled, new OpPcExpelled); + interpreter.installSegment3 (opcodePcExpelledExplicit, new OpPcExpelled); + interpreter.installSegment3 (opcodePcExpell, new OpPcExpell); + interpreter.installSegment3 (opcodePcExpellExplicit, new OpPcExpell); + interpreter.installSegment3 (opcodePcClearExpelled, new OpPcClearExpelled); + interpreter.installSegment3 (opcodePcClearExpelledExplicit, new OpPcClearExpelled); + interpreter.installSegment5 (opcodeRaiseRank, new OpRaiseRank); + interpreter.installSegment5 (opcodeRaiseRankExplicit, new OpRaiseRank); + interpreter.installSegment5 (opcodeLowerRank, new OpLowerRank); + interpreter.installSegment5 (opcodeLowerRankExplicit, new OpLowerRank); } } } diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 6e70f588e..2dd8f3e16 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include "../mwworld/esmstore.hpp" #include #include @@ -53,6 +53,23 @@ namespace MWScript } }; + template + class OpModScale : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + Interpreter::Type_Float scale = runtime[0].mFloat; + runtime.pop(); + + // add the parameter to the object's scale. + MWBase::Environment::get().getWorld()->scaleObject(ptr,ptr.getCellRef().mScale + scale); + } + }; + template class OpSetAngle : public Interpreter::Opcode0 { @@ -532,6 +549,8 @@ namespace MWScript const int opcodePlaceAtPc = 0x200019c; const int opcodePlaceAtMe = 0x200019d; const int opcodePlaceAtMeExplicit = 0x200019e; + const int opcodeModScale = 0x20001e3; + const int opcodeModScaleExplicit = 0x20001e4; void registerExtensions (Compiler::Extensions& extensions) { @@ -548,6 +567,7 @@ namespace MWScript extensions.registerInstruction("placeitem","cffff",opcodePlaceItem); extensions.registerInstruction("placeatpc","clfl",opcodePlaceAtPc); extensions.registerInstruction("placeatme","clfl",opcodePlaceAtMe,opcodePlaceAtMeExplicit); + extensions.registerInstruction("modscale","f",opcodeModScale,opcodeModScaleExplicit); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -574,7 +594,9 @@ namespace MWScript interpreter.installSegment5(opcodePlaceItem,new OpPlaceItem); interpreter.installSegment5(opcodePlaceAtPc,new OpPlaceAtPc); interpreter.installSegment5(opcodePlaceAtMe,new OpPlaceAtMe); - interpreter.installSegment5(opcodePlaceAtMeExplicit,new OpPlaceAtMe); + interpreter.installSegment5(opcodePlaceAtMeExplicit,new OpPlaceAtMe); + interpreter.installSegment5(opcodeModScale,new OpModScale); + interpreter.installSegment5(opcodeModScaleExplicit,new OpModScale); } } } diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index 9298bf848..5f61ab8f0 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -1,7 +1,12 @@ #ifdef OPENMW_USE_FFMPEG + #include "ffmpeg_decoder.hpp" +// auto_ptr +#include + +#include namespace MWSound { @@ -308,7 +313,12 @@ void FFmpeg_Decoder::close() mStreams.erase(mStreams.begin()); } if(mFormatCtx) + { + AVIOContext* context = mFormatCtx->pb; + av_free(context); + mFormatCtx->pb = NULL; av_close_input_file(mFormatCtx); + } mFormatCtx = NULL; mDataStream.setNull(); diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 5d5ef3d1d..8c4798c9d 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include "../mwworld/esmstore.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -116,9 +116,8 @@ namespace MWSound std::string SoundManager::lookup(const std::string &soundId, float &volume, float &min, float &max) { - const ESM::Sound *snd = MWBase::Environment::get().getWorld()->getStore().sounds.search(soundId); - if(snd == NULL) - throw std::runtime_error(std::string("Failed to lookup sound ")+soundId); + const ESM::Sound *snd = + MWBase::Environment::get().getWorld()->getStore().get().find(soundId); volume *= pow(10.0, (snd->mData.mVolume/255.0*3348.0 - 3348.0) / 2000.0); @@ -414,17 +413,19 @@ namespace MWSound //If the region has changed timePassed += duration; - if((current->cell->mData.mFlags & current->cell->Interior) || timePassed < 10) + if(!current->mCell->isExterior() || timePassed < 10) return; timePassed = 0; - if(regionName != current->cell->mRegion) + if(regionName != current->mCell->mRegion) { - regionName = current->cell->mRegion; + regionName = current->mCell->mRegion; total = 0; } - const ESM::Region *regn = MWBase::Environment::get().getWorld()->getStore().regions.search(regionName); + const ESM::Region *regn = + MWBase::Environment::get().getWorld()->getStore().get().search(regionName); + if (regn == NULL) return; @@ -477,7 +478,7 @@ namespace MWSound MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - const ESM::Cell *cell = player.getCell()->cell; + const ESM::Cell *cell = player.getCell()->mCell; Environment env = Env_Normal; if((cell->mData.mFlags&cell->HasWater) && mListenerPos.z < cell->mWater) diff --git a/apps/openmw/mwworld/actioneat.cpp b/apps/openmw/mwworld/actioneat.cpp index abd1ac4b9..63efff738 100644 --- a/apps/openmw/mwworld/actioneat.cpp +++ b/apps/openmw/mwworld/actioneat.cpp @@ -5,14 +5,13 @@ #include -#include - #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/npcstats.hpp" +#include "esmstore.hpp" #include "class.hpp" namespace MWWorld diff --git a/apps/openmw/mwworld/actionread.cpp b/apps/openmw/mwworld/actionread.cpp index 4ac613df7..6d5d9d8fd 100644 --- a/apps/openmw/mwworld/actionread.cpp +++ b/apps/openmw/mwworld/actionread.cpp @@ -4,15 +4,14 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" -#include "../mwworld/player.hpp" -#include "../mwworld/class.hpp" - #include "../mwmechanics/npcstats.hpp" #include "../mwgui/bookwindow.hpp" #include "../mwgui/scrollwindow.hpp" -#include +#include "player.hpp" +#include "class.hpp" +#include "esmstore.hpp" namespace MWWorld { @@ -24,7 +23,7 @@ namespace MWWorld { LiveCellRef *ref = getTarget().get(); - if (ref->base->mData.mIsScroll) + if (ref->mBase->mData.mIsScroll) { MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Scroll); MWBase::Environment::get().getWindowManager()->getScrollWindow()->open(getTarget()); @@ -39,16 +38,19 @@ namespace MWWorld MWMechanics::NpcStats& npcStats = MWWorld::Class::get(player).getNpcStats (player); // Skill gain from books - if (ref->base->mData.mSkillID >= 0 && ref->base->mData.mSkillID < ESM::Skill::Length - && !npcStats.hasBeenUsed (ref->base->mId)) + if (ref->mBase->mData.mSkillID >= 0 && ref->mBase->mData.mSkillID < ESM::Skill::Length + && !npcStats.hasBeenUsed (ref->mBase->mId)) { MWWorld::LiveCellRef *playerRef = player.get(); - const ESM::Class *class_ = MWBase::Environment::get().getWorld()->getStore().classes.find ( - playerRef->base->mClass); - npcStats.increaseSkill (ref->base->mData.mSkillID, *class_, true); + const ESM::Class *class_ = + MWBase::Environment::get().getWorld()->getStore().get().find ( + playerRef->mBase->mClass + ); - npcStats.flagAsUsed (ref->base->mId); + npcStats.increaseSkill (ref->mBase->mData.mSkillID, *class_, true); + + npcStats.flagAsUsed (ref->mBase->mId); } } diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index e5a38d4be..696a469f7 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -1,11 +1,10 @@ #include "cells.hpp" -#include - #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "class.hpp" +#include "esmstore.hpp" #include "containerstore.hpp" MWWorld::Ptr::CellStore *MWWorld::Cells::getCellStore (const ESM::Cell *cell) @@ -24,12 +23,12 @@ MWWorld::Ptr::CellStore *MWWorld::Cells::getCellStore (const ESM::Cell *cell) else { std::map, Ptr::CellStore>::iterator result = - mExteriors.find (std::make_pair (cell->mData.mX, cell->mData.mY)); + mExteriors.find (std::make_pair (cell->getGridX(), cell->getGridY())); if (result==mExteriors.end()) { result = mExteriors.insert (std::make_pair ( - std::make_pair (cell->mData.mX, cell->mData.mY), Ptr::CellStore (cell))).first; + std::make_pair (cell->getGridX(), cell->getGridY()), Ptr::CellStore (cell))).first; } @@ -40,33 +39,33 @@ MWWorld::Ptr::CellStore *MWWorld::Cells::getCellStore (const ESM::Cell *cell) void MWWorld::Cells::fillContainers (Ptr::CellStore& cellStore) { for (CellRefList::List::iterator iter ( - cellStore.containers.list.begin()); - iter!=cellStore.containers.list.end(); ++iter) + cellStore.mContainers.mList.begin()); + iter!=cellStore.mContainers.mList.end(); ++iter) { Ptr container (&*iter, &cellStore); Class::get (container).getContainerStore (container).fill ( - iter->base->mInventory, mStore); + iter->mBase->mInventory, mStore); } for (CellRefList::List::iterator iter ( - cellStore.creatures.list.begin()); - iter!=cellStore.creatures.list.end(); ++iter) + cellStore.mCreatures.mList.begin()); + iter!=cellStore.mCreatures.mList.end(); ++iter) { Ptr container (&*iter, &cellStore); Class::get (container).getContainerStore (container).fill ( - iter->base->mInventory, mStore); + iter->mBase->mInventory, mStore); } for (CellRefList::List::iterator iter ( - cellStore.npcs.list.begin()); - iter!=cellStore.npcs.list.end(); ++iter) + cellStore.mNpcs.mList.begin()); + iter!=cellStore.mNpcs.mList.end(); ++iter) { Ptr container (&*iter, &cellStore); Class::get (container).getContainerStore (container).fill ( - iter->base->mInventory, mStore); + iter->mBase->mInventory, mStore); } } @@ -85,7 +84,7 @@ MWWorld::Ptr MWWorld::Cells::getPtrAndCache (const std::string& name, Ptr::CellS return ptr; } -MWWorld::Cells::Cells (const ESMS::ESMStore& store, ESM::ESMReader& reader) +MWWorld::Cells::Cells (const MWWorld::ESMStore& store, ESM::ESMReader& reader) : mStore (store), mReader (reader), mIdCache (20, std::pair ("", (Ptr::CellStore*)0)), /// \todo make cache size configurable mIdCacheIndex (0) @@ -98,7 +97,7 @@ MWWorld::Ptr::CellStore *MWWorld::Cells::getExterior (int x, int y) if (result==mExteriors.end()) { - const ESM::Cell *cell = mStore.cells.searchExt (x, y); + const ESM::Cell *cell = mStore.get().search(x, y); if (!cell) { @@ -133,7 +132,7 @@ MWWorld::Ptr::CellStore *MWWorld::Cells::getInterior (const std::string& name) if (result==mInteriors.end()) { - const ESM::Cell *cell = mStore.cells.findInt (name); + const ESM::Cell *cell = mStore.get().find(name); result = mInteriors.insert (std::make_pair (name, Ptr::CellStore (cell))).first; } @@ -169,64 +168,64 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name, Ptr::CellStore& ce } MWWorld::Ptr ptr; - if (MWWorld::LiveCellRef *ref = cell.activators.find (name)) + if (MWWorld::LiveCellRef *ref = cell.mActivators.find (name)) ptr = Ptr (ref, &cell); - if (MWWorld::LiveCellRef *ref = cell.potions.find (name)) + if (MWWorld::LiveCellRef *ref = cell.mPotions.find (name)) ptr = Ptr (ref, &cell); - if (MWWorld::LiveCellRef *ref = cell.appas.find (name)) + if (MWWorld::LiveCellRef *ref = cell.mAppas.find (name)) ptr = Ptr (ref, &cell); - if (MWWorld::LiveCellRef *ref = cell.armors.find (name)) + if (MWWorld::LiveCellRef *ref = cell.mArmors.find (name)) ptr = Ptr (ref, &cell); - if (MWWorld::LiveCellRef *ref = cell.books.find (name)) + if (MWWorld::LiveCellRef *ref = cell.mBooks.find (name)) ptr = Ptr (ref, &cell); - if (MWWorld::LiveCellRef *ref = cell.clothes.find (name)) + if (MWWorld::LiveCellRef *ref = cell.mClothes.find (name)) ptr = Ptr (ref, &cell); - if (MWWorld::LiveCellRef *ref = cell.containers.find (name)) + if (MWWorld::LiveCellRef *ref = cell.mContainers.find (name)) ptr = Ptr (ref, &cell); - if (MWWorld::LiveCellRef *ref = cell.creatures.find (name)) + if (MWWorld::LiveCellRef *ref = cell.mCreatures.find (name)) ptr = Ptr (ref, &cell); - if (MWWorld::LiveCellRef *ref = cell.doors.find (name)) + if (MWWorld::LiveCellRef *ref = cell.mDoors.find (name)) ptr = Ptr (ref, &cell); - if (MWWorld::LiveCellRef *ref = cell.ingreds.find (name)) + if (MWWorld::LiveCellRef *ref = cell.mIngreds.find (name)) ptr = Ptr (ref, &cell); - if (MWWorld::LiveCellRef *ref = cell.creatureLists.find (name)) + if (MWWorld::LiveCellRef *ref = cell.mCreatureLists.find (name)) ptr = Ptr (ref, &cell); - if (MWWorld::LiveCellRef *ref = cell.itemLists.find (name)) + if (MWWorld::LiveCellRef *ref = cell.mItemLists.find (name)) ptr = Ptr (ref, &cell); - if (MWWorld::LiveCellRef *ref = cell.lights.find (name)) + if (MWWorld::LiveCellRef *ref = cell.mLights.find (name)) ptr = Ptr (ref, &cell); - if (MWWorld::LiveCellRef *ref = cell.lockpicks.find (name)) + if (MWWorld::LiveCellRef *ref = cell.mLockpicks.find (name)) ptr = Ptr (ref, &cell); - if (MWWorld::LiveCellRef *ref = cell.miscItems.find (name)) + if (MWWorld::LiveCellRef *ref = cell.mMiscItems.find (name)) ptr = Ptr (ref, &cell); - if (MWWorld::LiveCellRef *ref = cell.npcs.find (name)) + if (MWWorld::LiveCellRef *ref = cell.mNpcs.find (name)) ptr = Ptr (ref, &cell); - if (MWWorld::LiveCellRef *ref = cell.probes.find (name)) + if (MWWorld::LiveCellRef *ref = cell.mProbes.find (name)) ptr = Ptr (ref, &cell); - if (MWWorld::LiveCellRef *ref = cell.repairs.find (name)) + if (MWWorld::LiveCellRef *ref = cell.mRepairs.find (name)) ptr = Ptr (ref, &cell); - if (MWWorld::LiveCellRef *ref = cell.statics.find (name)) + if (MWWorld::LiveCellRef *ref = cell.mStatics.find (name)) ptr = Ptr (ref, &cell); - if (MWWorld::LiveCellRef *ref = cell.weapons.find (name)) + if (MWWorld::LiveCellRef *ref = cell.mWeapons.find (name)) ptr = Ptr (ref, &cell); if (!ptr.isEmpty() && ptr.getRefData().getCount() > 0) { @@ -265,10 +264,12 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name) } // Now try the other cells - for (ESMS::CellList::IntCells::const_iterator iter = mStore.cells.intCells.begin(); - iter!=mStore.cells.intCells.end(); ++iter) + const MWWorld::Store &cells = mStore.get(); + MWWorld::Store::iterator iter; + + for (iter = cells.intBegin(); iter != cells.intEnd(); ++iter) { - Ptr::CellStore *cellStore = getCellStore (iter->second); + Ptr::CellStore *cellStore = getCellStore (&(*iter)); Ptr ptr = getPtrAndCache (name, *cellStore); @@ -276,10 +277,9 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name) return ptr; } - for (ESMS::CellList::ExtCells::const_iterator iter = mStore.cells.extCells.begin(); - iter!=mStore.cells.extCells.end(); ++iter) + for (iter = cells.extBegin(); iter != cells.extEnd(); ++iter) { - Ptr::CellStore *cellStore = getCellStore (iter->second); + Ptr::CellStore *cellStore = getCellStore (&(*iter)); Ptr ptr = getPtrAndCache (name, *cellStore); diff --git a/apps/openmw/mwworld/cells.hpp b/apps/openmw/mwworld/cells.hpp index 3e1383166..edaf70055 100644 --- a/apps/openmw/mwworld/cells.hpp +++ b/apps/openmw/mwworld/cells.hpp @@ -11,17 +11,14 @@ namespace ESM class ESMReader; } -namespace ESM -{ - class ESMStore; -} - namespace MWWorld { + class ESMStore; + /// \brief Cell container class Cells { - const ESMS::ESMStore& mStore; + const MWWorld::ESMStore& mStore; ESM::ESMReader& mReader; std::map mInteriors; std::map, CellStore> mExteriors; @@ -39,7 +36,7 @@ namespace MWWorld public: - Cells (const ESMS::ESMStore& store, ESM::ESMReader& reader); + Cells (const MWWorld::ESMStore& store, ESM::ESMReader& reader); ///< \todo pass the dynamic part of the ESMStore isntead (once it is written) of the whole /// world diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index fcdec1e7f..1ef2d36a2 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -2,28 +2,28 @@ #include -#include - #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "ptr.hpp" +#include "esmstore.hpp" namespace MWWorld { - CellStore::CellStore (const ESM::Cell *cell_) : cell (cell_), mState (State_Unloaded) + CellStore::CellStore (const ESM::Cell *cell) + : mCell (cell), mState (State_Unloaded) { mWaterLevel = cell->mWater; } - void CellStore::load (const ESMS::ESMStore &store, ESM::ESMReader &esm) + void CellStore::load (const MWWorld::ESMStore &store, ESM::ESMReader &esm) { if (mState!=State_Loaded) { if (mState==State_Preloaded) mIds.clear(); - std::cout << "loading cell " << cell->getDescription() << std::endl; + std::cout << "loading cell " << mCell->getDescription() << std::endl; loadRefs (store, esm); @@ -31,7 +31,7 @@ namespace MWWorld } } - void CellStore::preload (const ESMS::ESMStore &store, ESM::ESMReader &esm) + void CellStore::preload (const MWWorld::ESMStore &store, ESM::ESMReader &esm) { if (mState==State_Unloaded) { @@ -41,20 +41,20 @@ namespace MWWorld } } - void CellStore::listRefs(const ESMS::ESMStore &store, ESM::ESMReader &esm) + void CellStore::listRefs(const MWWorld::ESMStore &store, ESM::ESMReader &esm) { - assert (cell); + assert (mCell); - if (cell->mContext.filename.empty()) + if (mCell->mContext.filename.empty()) return; // this is a dynamically generated cell -> skipping. // Reopen the ESM reader and seek to the right position. - cell->restore (esm); + mCell->restore (esm); ESM::CellRef ref; // Get each reference in turn - while (cell->getNextRef (esm, ref)) + while (mCell->getNextRef (esm, ref)) { std::string lowerCase; @@ -67,20 +67,20 @@ namespace MWWorld std::sort (mIds.begin(), mIds.end()); } - void CellStore::loadRefs(const ESMS::ESMStore &store, ESM::ESMReader &esm) + void CellStore::loadRefs(const MWWorld::ESMStore &store, ESM::ESMReader &esm) { - assert (cell); + assert (mCell); - if (cell->mContext.filename.empty()) + if (mCell->mContext.filename.empty()) return; // this is a dynamically generated cell -> skipping. // Reopen the ESM reader and seek to the right position. - cell->restore(esm); + mCell->restore(esm); ESM::CellRef ref; // Get each reference in turn - while(cell->getNextRef(esm, ref)) + while(mCell->getNextRef(esm, ref)) { std::string lowerCase; @@ -98,26 +98,26 @@ namespace MWWorld */ switch(rec) { - case ESM::REC_ACTI: activators.find(ref, store.activators); break; - case ESM::REC_ALCH: potions.find(ref, store.potions); break; - case ESM::REC_APPA: appas.find(ref, store.appas); break; - case ESM::REC_ARMO: armors.find(ref, store.armors); break; - case ESM::REC_BOOK: books.find(ref, store.books); break; - case ESM::REC_CLOT: clothes.find(ref, store.clothes); break; - case ESM::REC_CONT: containers.find(ref, store.containers); break; - case ESM::REC_CREA: creatures.find(ref, store.creatures); break; - case ESM::REC_DOOR: doors.find(ref, store.doors); break; - case ESM::REC_INGR: ingreds.find(ref, store.ingreds); break; - case ESM::REC_LEVC: creatureLists.find(ref, store.creatureLists); break; - case ESM::REC_LEVI: itemLists.find(ref, store.itemLists); break; - case ESM::REC_LIGH: lights.find(ref, store.lights); break; - case ESM::REC_LOCK: lockpicks.find(ref, store.lockpicks); break; - case ESM::REC_MISC: miscItems.find(ref, store.miscItems); break; - case ESM::REC_NPC_: npcs.find(ref, store.npcs); break; - case ESM::REC_PROB: probes.find(ref, store.probes); break; - case ESM::REC_REPA: repairs.find(ref, store.repairs); break; - case ESM::REC_STAT: statics.find(ref, store.statics); break; - case ESM::REC_WEAP: weapons.find(ref, store.weapons); break; + case ESM::REC_ACTI: mActivators.load(ref, store); break; + case ESM::REC_ALCH: mPotions.load(ref, store); break; + case ESM::REC_APPA: mAppas.load(ref, store); break; + case ESM::REC_ARMO: mArmors.load(ref, store); break; + case ESM::REC_BOOK: mBooks.load(ref, store); break; + case ESM::REC_CLOT: mClothes.load(ref, store); break; + case ESM::REC_CONT: mContainers.load(ref, store); break; + case ESM::REC_CREA: mCreatures.load(ref, store); break; + case ESM::REC_DOOR: mDoors.load(ref, store); break; + case ESM::REC_INGR: mIngreds.load(ref, store); break; + case ESM::REC_LEVC: mCreatureLists.load(ref, store); break; + case ESM::REC_LEVI: mItemLists.load(ref, store); break; + case ESM::REC_LIGH: mLights.load(ref, store); break; + case ESM::REC_LOCK: mLockpicks.load(ref, store); break; + case ESM::REC_MISC: mMiscItems.load(ref, store); break; + case ESM::REC_NPC_: mNpcs.load(ref, store); break; + case ESM::REC_PROB: mProbes.load(ref, store); break; + case ESM::REC_REPA: mRepairs.load(ref, store); break; + case ESM::REC_STAT: mStatics.load(ref, store); break; + case ESM::REC_WEAP: mWeapons.load(ref, store); break; case 0: std::cout << "Cell reference " + ref.mRefID + " not found!\n"; break; default: diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 32ab6e07b..ba3d24d7e 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -7,15 +7,12 @@ #include #include "refdata.hpp" - -namespace ESMS -{ - struct ESMStore; -} +#include "esmstore.hpp" namespace MWWorld { class Ptr; + class ESMStore; /// A reference to one object (of any type) in a cell. /// @@ -26,19 +23,21 @@ namespace MWWorld template struct LiveCellRef { - LiveCellRef(const ESM::CellRef& cref, const X* b = NULL) : base(b), ref(cref), - mData(ref) {} + LiveCellRef(const ESM::CellRef& cref, const X* b = NULL) + : mBase(b), mRef(cref), mData(mRef) + {} - - LiveCellRef(const X* b = NULL) : base(b), mData(ref) {} + LiveCellRef(const X* b = NULL) + : mBase(b), mData(mRef) + {} // The object that this instance is based on. - const X* base; + const X* mBase; /* Information about this instance, such as 3D location and rotation and individual type-dependent data. */ - ESM::CellRef ref; + ESM::CellRef mRef; /// runtime-data RefData mData; @@ -50,26 +49,29 @@ namespace MWWorld { typedef LiveCellRef LiveRef; typedef std::list List; - List list; + List mList; - // Search for the given reference in the given reclist from - // ESMStore. Insert the reference into the list if a match is - // found. If not, throw an exception. - template - void find(ESM::CellRef &ref, const Y& recList) + /// Searches for reference of appropriate type in given ESMStore. + /// If reference exists, loads it into container, throws an exception + /// on miss + void load(ESM::CellRef &ref, const MWWorld::ESMStore &esmStore) { - const X* obj = recList.find(ref.mRefID); - if(obj == NULL) - throw std::runtime_error("Error resolving cell reference " + ref.mRefID); + // for throwing exception on unhandled record type + const MWWorld::Store &store = esmStore.get(); + const X *ptr = store.find(ref.mRefID); - list.push_back(LiveRef(ref, obj)); + /// \note redundant because Store::find() throws exception on miss + if (ptr == NULL) { + throw std::runtime_error("Error resolving cell reference " + ref.mRefID); + } + mList.push_back(LiveRef(ref, ptr)); } LiveRef *find (const std::string& name) { - for (typename std::list::iterator iter (list.begin()); iter!=list.end(); ++iter) + for (typename std::list::iterator iter (mList.begin()); iter!=mList.end(); ++iter) { - if (iter->mData.getCount() > 0 && iter->ref.mRefID == name) + if (iter->mData.getCount() > 0 && iter->mRef.mRefID == name) return &*iter; } @@ -77,8 +79,8 @@ namespace MWWorld } LiveRef &insert(const LiveRef &item) { - list.push_back(item); - return list.back(); + mList.push_back(item); + return mList.back(); } }; @@ -94,37 +96,37 @@ namespace MWWorld CellStore (const ESM::Cell *cell_); - const ESM::Cell *cell; + const ESM::Cell *mCell; State mState; std::vector mIds; float mWaterLevel; // Lists for each individual object type - CellRefList activators; - CellRefList potions; - CellRefList appas; - CellRefList armors; - CellRefList books; - CellRefList clothes; - CellRefList containers; - CellRefList creatures; - CellRefList doors; - CellRefList ingreds; - CellRefList creatureLists; - CellRefList itemLists; - CellRefList lights; - CellRefList lockpicks; - CellRefList miscItems; - CellRefList npcs; - CellRefList probes; - CellRefList repairs; - CellRefList statics; - CellRefList weapons; + CellRefList mActivators; + CellRefList mPotions; + CellRefList mAppas; + CellRefList mArmors; + CellRefList mBooks; + CellRefList mClothes; + CellRefList mContainers; + CellRefList mCreatures; + CellRefList mDoors; + CellRefList mIngreds; + CellRefList mCreatureLists; + CellRefList mItemLists; + CellRefList mLights; + CellRefList mLockpicks; + CellRefList mMiscItems; + CellRefList mNpcs; + CellRefList mProbes; + CellRefList mRepairs; + CellRefList mStatics; + CellRefList mWeapons; - void load (const ESMS::ESMStore &store, ESM::ESMReader &esm); + void load (const MWWorld::ESMStore &store, ESM::ESMReader &esm); - void preload (const ESMS::ESMStore &store, ESM::ESMReader &esm); + void preload (const MWWorld::ESMStore &store, ESM::ESMReader &esm); /// Call functor (ref) for each reference. functor must return a bool. Returning /// false will abort the iteration. @@ -133,32 +135,32 @@ namespace MWWorld bool forEach (Functor& functor) { return - forEachImp (functor, activators) && - forEachImp (functor, potions) && - forEachImp (functor, appas) && - forEachImp (functor, armors) && - forEachImp (functor, books) && - forEachImp (functor, clothes) && - forEachImp (functor, containers) && - forEachImp (functor, creatures) && - forEachImp (functor, doors) && - forEachImp (functor, ingreds) && - forEachImp (functor, creatureLists) && - forEachImp (functor, itemLists) && - forEachImp (functor, lights) && - forEachImp (functor, lockpicks) && - forEachImp (functor, miscItems) && - forEachImp (functor, npcs) && - forEachImp (functor, probes) && - forEachImp (functor, repairs) && - forEachImp (functor, statics) && - forEachImp (functor, weapons); + forEachImp (functor, mActivators) && + forEachImp (functor, mPotions) && + forEachImp (functor, mAppas) && + forEachImp (functor, mArmors) && + forEachImp (functor, mBooks) && + forEachImp (functor, mClothes) && + forEachImp (functor, mContainers) && + forEachImp (functor, mCreatures) && + forEachImp (functor, mDoors) && + forEachImp (functor, mIngreds) && + forEachImp (functor, mCreatureLists) && + forEachImp (functor, mItemLists) && + forEachImp (functor, mLights) && + forEachImp (functor, mLockpicks) && + forEachImp (functor, mMiscItems) && + forEachImp (functor, mNpcs) && + forEachImp (functor, mProbes) && + forEachImp (functor, mRepairs) && + forEachImp (functor, mStatics) && + forEachImp (functor, mWeapons); } bool operator==(const CellStore &cell) { - return this->cell->mName == cell.cell->mName && - this->cell->mData.mX == cell.cell->mData.mX && - this->cell->mData.mY == cell.cell->mData.mY; + return mCell->mName == cell.mCell->mName && + mCell->mData.mX == cell.mCell->mData.mX && + mCell->mData.mY == cell.mCell->mData.mY; } bool operator!=(const CellStore &cell) { @@ -166,7 +168,7 @@ namespace MWWorld } bool isExterior() const { - return cell->isExterior(); + return mCell->isExterior(); } private: @@ -174,18 +176,18 @@ namespace MWWorld template bool forEachImp (Functor& functor, List& list) { - for (typename List::List::iterator iter (list.list.begin()); iter!=list.list.end(); + for (typename List::List::iterator iter (list.mList.begin()); iter!=list.mList.end(); ++iter) - if (!functor (iter->ref, iter->mData)) + if (!functor (iter->mRef, iter->mData)) return false; return true; } /// Run through references and store IDs - void listRefs(const ESMS::ESMStore &store, ESM::ESMReader &esm); + void listRefs(const MWWorld::ESMStore &store, ESM::ESMReader &esm); - void loadRefs(const ESMS::ESMStore &store, ESM::ESMReader &esm); + void loadRefs(const MWWorld::ESMStore &store, ESM::ESMReader &esm); }; } diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 8c639a874..c76019149 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -162,6 +162,11 @@ namespace MWWorld return false; } + bool Class::hasDetected (const MWWorld::Ptr& ptr, const MWWorld::Ptr& ptr2) const + { + return false; + } + const Class& Class::get (const std::string& key) { std::map >::const_iterator iter = sClasses.find (key); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 4662cbab6..07dcb8fe0 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -191,6 +191,11 @@ namespace MWWorld /// /// (default implementation: return false) + virtual bool hasDetected (const MWWorld::Ptr& ptr, const MWWorld::Ptr& ptr2) const; + ///< Has \æ ptr detected \a ptr2? + /// + /// (default implementation: return false) + static const Class& get (const std::string& key); ///< If there is no class for this \a key, an exception is thrown. diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 5c4dd03a4..e47f2191a 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -24,12 +24,12 @@ namespace float sum = 0; for (typename MWWorld::CellRefList::List::const_iterator iter ( - cellRefList.list.begin()); - iter!=cellRefList.list.end(); + cellRefList.mList.begin()); + iter!=cellRefList.mList.end(); ++iter) { if (iter->mData.getCount()>0) - sum += iter->mData.getCount()*iter->base->mData.mWeight; + sum += iter->mData.getCount()*iter->mBase->mData.mWeight; } return sum; @@ -74,26 +74,29 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& ptr) { int type = getType(ptr); + const MWWorld::ESMStore &esmStore = + MWBase::Environment::get().getWorld()->getStore(); + // gold needs special handling: when it is inserted into a container, the base object automatically becomes Gold_001 // this ensures that gold piles of different sizes stack with each other (also, several scripts rely on Gold_001 for detecting player gold) - if (MWWorld::Class::get(ptr).getName(ptr) == MWBase::Environment::get().getWorld()->getStore().gameSettings.find("sGold")->getString()) + if (MWWorld::Class::get(ptr).getName(ptr) == esmStore.get().find("sGold")->getString()) { MWWorld::LiveCellRef *gold = ptr.get(); - if (compare_string_ci(gold->ref.mRefID, "gold_001") - || compare_string_ci(gold->ref.mRefID, "gold_005") - || compare_string_ci(gold->ref.mRefID, "gold_010") - || compare_string_ci(gold->ref.mRefID, "gold_025") - || compare_string_ci(gold->ref.mRefID, "gold_100")) + if (compare_string_ci(gold->mRef.mRefID, "gold_001") + || compare_string_ci(gold->mRef.mRefID, "gold_005") + || compare_string_ci(gold->mRef.mRefID, "gold_010") + || compare_string_ci(gold->mRef.mRefID, "gold_025") + || compare_string_ci(gold->mRef.mRefID, "gold_100")) { - MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), "Gold_001"); + MWWorld::ManualRef ref(esmStore, "Gold_001"); - int count = (ptr.getRefData().getCount() == 1) ? gold->base->mData.mValue : ptr.getRefData().getCount(); + int count = (ptr.getRefData().getCount() == 1) ? gold->mBase->mData.mValue : ptr.getRefData().getCount(); ref.getPtr().getRefData().setCount(count); for (MWWorld::ContainerStoreIterator iter (begin(type)); iter!=end(); ++iter) { - if (compare_string_ci((*iter).get()->ref.mRefID, "gold_001")) + if (compare_string_ci((*iter).get()->mRef.mRefID, "gold_001")) { (*iter).getRefData().setCount( (*iter).getRefData().getCount() + count); flagAsModified(); @@ -127,25 +130,25 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImpl (const Ptr& ptr switch (getType(ptr)) { - case Type_Potion: potions.list.push_back (*ptr.get()); it = ContainerStoreIterator(this, --potions.list.end()); break; - case Type_Apparatus: appas.list.push_back (*ptr.get()); it = ContainerStoreIterator(this, --appas.list.end()); break; - case Type_Armor: armors.list.push_back (*ptr.get()); it = ContainerStoreIterator(this, --armors.list.end()); break; - case Type_Book: books.list.push_back (*ptr.get()); it = ContainerStoreIterator(this, --books.list.end()); break; - case Type_Clothing: clothes.list.push_back (*ptr.get()); it = ContainerStoreIterator(this, --clothes.list.end()); break; - case Type_Ingredient: ingreds.list.push_back (*ptr.get()); it = ContainerStoreIterator(this, --ingreds.list.end()); break; - case Type_Light: lights.list.push_back (*ptr.get()); it = ContainerStoreIterator(this, --lights.list.end()); break; - case Type_Lockpick: lockpicks.list.push_back (*ptr.get()); it = ContainerStoreIterator(this, --lockpicks.list.end()); break; - case Type_Miscellaneous: miscItems.list.push_back (*ptr.get()); it = ContainerStoreIterator(this, --miscItems.list.end()); break; - case Type_Probe: probes.list.push_back (*ptr.get()); it = ContainerStoreIterator(this, --probes.list.end()); break; - case Type_Repair: repairs.list.push_back (*ptr.get()); it = ContainerStoreIterator(this, --repairs.list.end()); break; - case Type_Weapon: weapons.list.push_back (*ptr.get()); it = ContainerStoreIterator(this, --weapons.list.end()); break; + case Type_Potion: potions.mList.push_back (*ptr.get()); it = ContainerStoreIterator(this, --potions.mList.end()); break; + case Type_Apparatus: appas.mList.push_back (*ptr.get()); it = ContainerStoreIterator(this, --appas.mList.end()); break; + case Type_Armor: armors.mList.push_back (*ptr.get()); it = ContainerStoreIterator(this, --armors.mList.end()); break; + case Type_Book: books.mList.push_back (*ptr.get()); it = ContainerStoreIterator(this, --books.mList.end()); break; + case Type_Clothing: clothes.mList.push_back (*ptr.get()); it = ContainerStoreIterator(this, --clothes.mList.end()); break; + case Type_Ingredient: ingreds.mList.push_back (*ptr.get()); it = ContainerStoreIterator(this, --ingreds.mList.end()); break; + case Type_Light: lights.mList.push_back (*ptr.get()); it = ContainerStoreIterator(this, --lights.mList.end()); break; + case Type_Lockpick: lockpicks.mList.push_back (*ptr.get()); it = ContainerStoreIterator(this, --lockpicks.mList.end()); break; + case Type_Miscellaneous: miscItems.mList.push_back (*ptr.get()); it = ContainerStoreIterator(this, --miscItems.mList.end()); break; + case Type_Probe: probes.mList.push_back (*ptr.get()); it = ContainerStoreIterator(this, --probes.mList.end()); break; + case Type_Repair: repairs.mList.push_back (*ptr.get()); it = ContainerStoreIterator(this, --repairs.mList.end()); break; + case Type_Weapon: weapons.mList.push_back (*ptr.get()); it = ContainerStoreIterator(this, --weapons.mList.end()); break; } flagAsModified(); return it; } -void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const ESMS::ESMStore& store) +void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const MWWorld::ESMStore& store) { for (std::vector::const_iterator iter (items.mList.begin()); iter!=items.mList.end(); ++iter) @@ -326,63 +329,63 @@ bool MWWorld::ContainerStoreIterator::resetIterator() { case ContainerStore::Type_Potion: - mPotion = mContainer->potions.list.begin(); - return mPotion!=mContainer->potions.list.end(); + mPotion = mContainer->potions.mList.begin(); + return mPotion!=mContainer->potions.mList.end(); case ContainerStore::Type_Apparatus: - mApparatus = mContainer->appas.list.begin(); - return mApparatus!=mContainer->appas.list.end(); + mApparatus = mContainer->appas.mList.begin(); + return mApparatus!=mContainer->appas.mList.end(); case ContainerStore::Type_Armor: - mArmor = mContainer->armors.list.begin(); - return mArmor!=mContainer->armors.list.end(); + mArmor = mContainer->armors.mList.begin(); + return mArmor!=mContainer->armors.mList.end(); case ContainerStore::Type_Book: - mBook = mContainer->books.list.begin(); - return mBook!=mContainer->books.list.end(); + mBook = mContainer->books.mList.begin(); + return mBook!=mContainer->books.mList.end(); case ContainerStore::Type_Clothing: - mClothing = mContainer->clothes.list.begin(); - return mClothing!=mContainer->clothes.list.end(); + mClothing = mContainer->clothes.mList.begin(); + return mClothing!=mContainer->clothes.mList.end(); case ContainerStore::Type_Ingredient: - mIngredient = mContainer->ingreds.list.begin(); - return mIngredient!=mContainer->ingreds.list.end(); + mIngredient = mContainer->ingreds.mList.begin(); + return mIngredient!=mContainer->ingreds.mList.end(); case ContainerStore::Type_Light: - mLight = mContainer->lights.list.begin(); - return mLight!=mContainer->lights.list.end(); + mLight = mContainer->lights.mList.begin(); + return mLight!=mContainer->lights.mList.end(); case ContainerStore::Type_Lockpick: - mLockpick = mContainer->lockpicks.list.begin(); - return mLockpick!=mContainer->lockpicks.list.end(); + mLockpick = mContainer->lockpicks.mList.begin(); + return mLockpick!=mContainer->lockpicks.mList.end(); case ContainerStore::Type_Miscellaneous: - mMiscellaneous = mContainer->miscItems.list.begin(); - return mMiscellaneous!=mContainer->miscItems.list.end(); + mMiscellaneous = mContainer->miscItems.mList.begin(); + return mMiscellaneous!=mContainer->miscItems.mList.end(); case ContainerStore::Type_Probe: - mProbe = mContainer->probes.list.begin(); - return mProbe!=mContainer->probes.list.end(); + mProbe = mContainer->probes.mList.begin(); + return mProbe!=mContainer->probes.mList.end(); case ContainerStore::Type_Repair: - mRepair = mContainer->repairs.list.begin(); - return mRepair!=mContainer->repairs.list.end(); + mRepair = mContainer->repairs.mList.begin(); + return mRepair!=mContainer->repairs.mList.end(); case ContainerStore::Type_Weapon: - mWeapon = mContainer->weapons.list.begin(); - return mWeapon!=mContainer->weapons.list.end(); + mWeapon = mContainer->weapons.mList.begin(); + return mWeapon!=mContainer->weapons.mList.end(); } return false; @@ -395,62 +398,62 @@ bool MWWorld::ContainerStoreIterator::incIterator() case ContainerStore::Type_Potion: ++mPotion; - return mPotion==mContainer->potions.list.end(); + return mPotion==mContainer->potions.mList.end(); case ContainerStore::Type_Apparatus: ++mApparatus; - return mApparatus==mContainer->appas.list.end(); + return mApparatus==mContainer->appas.mList.end(); case ContainerStore::Type_Armor: ++mArmor; - return mArmor==mContainer->armors.list.end(); + return mArmor==mContainer->armors.mList.end(); case ContainerStore::Type_Book: ++mBook; - return mBook==mContainer->books.list.end(); + return mBook==mContainer->books.mList.end(); case ContainerStore::Type_Clothing: ++mClothing; - return mClothing==mContainer->clothes.list.end(); + return mClothing==mContainer->clothes.mList.end(); case ContainerStore::Type_Ingredient: ++mIngredient; - return mIngredient==mContainer->ingreds.list.end(); + return mIngredient==mContainer->ingreds.mList.end(); case ContainerStore::Type_Light: ++mLight; - return mLight==mContainer->lights.list.end(); + return mLight==mContainer->lights.mList.end(); case ContainerStore::Type_Lockpick: ++mLockpick; - return mLockpick==mContainer->lockpicks.list.end(); + return mLockpick==mContainer->lockpicks.mList.end(); case ContainerStore::Type_Miscellaneous: ++mMiscellaneous; - return mMiscellaneous==mContainer->miscItems.list.end(); + return mMiscellaneous==mContainer->miscItems.mList.end(); case ContainerStore::Type_Probe: ++mProbe; - return mProbe==mContainer->probes.list.end(); + return mProbe==mContainer->probes.mList.end(); case ContainerStore::Type_Repair: ++mRepair; - return mRepair==mContainer->repairs.list.end(); + return mRepair==mContainer->repairs.mList.end(); case ContainerStore::Type_Weapon: ++mWeapon; - return mWeapon==mContainer->weapons.list.end(); + return mWeapon==mContainer->weapons.mList.end(); } return true; diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index ae27fad3d..1297fc53c 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -83,7 +83,7 @@ namespace MWWorld public: - void fill (const ESM::InventoryList& items, const ESMS::ESMStore& store); + void fill (const ESM::InventoryList& items, const MWWorld::ESMStore& store); ///< Insert items into *this. void clear(); diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp new file mode 100644 index 000000000..73f5185c9 --- /dev/null +++ b/apps/openmw/mwworld/esmstore.cpp @@ -0,0 +1,111 @@ +#include "esmstore.hpp" + +#include +#include + +namespace MWWorld +{ + +static bool isCacheableRecord(int id) +{ + if (id == ESM::REC_ACTI || id == ESM::REC_ALCH || id == ESM::REC_APPA || id == ESM::REC_ARMO || + id == ESM::REC_BOOK || id == ESM::REC_CLOT || id == ESM::REC_CONT || id == ESM::REC_CREA || + id == ESM::REC_DOOR || id == ESM::REC_INGR || id == ESM::REC_LEVC || id == ESM::REC_LEVI || + id == ESM::REC_LIGH || id == ESM::REC_LOCK || id == ESM::REC_MISC || id == ESM::REC_NPC_ || + id == ESM::REC_PROB || id == ESM::REC_REPA || id == ESM::REC_STAT || id == ESM::REC_WEAP) + { + return true; + } + return false; +} + +void ESMStore::load(ESM::ESMReader &esm) +{ + std::set missing; + + ESM::Dialogue *dialogue = 0; + + // Loop through all records + while(esm.hasMoreRecs()) + { + ESM::NAME n = esm.getRecName(); + esm.getRecHeader(); + + // Look up the record type. + std::map::iterator it = mStores.find(n.val); + + if (it == mStores.end()) { + if (n.val == ESM::REC_INFO) { + if (dialogue) { + dialogue->mInfo.push_back(ESM::DialInfo()); + dialogue->mInfo.back().load(esm); + } else { + std::cerr << "error: info record without dialog" << std::endl; + esm.skipRecord(); + } + } else if (n.val == ESM::REC_MGEF) { + mMagicEffects.load (esm); + } else if (n.val == ESM::REC_SKIL) { + mSkills.load (esm); + } else { + // Not found (this would be an error later) + esm.skipRecord(); + missing.insert(n.toString()); + } + } else { + // Load it + std::string id = esm.getHNOString("NAME"); + it->second->load(esm, id); + + if (n.val==ESM::REC_DIAL) { + // dirty hack, but it is better than non-const search() + // or friends + dialogue = &mDialogs.mStatic.back(); + assert (dialogue->mId == id); + } else { + dialogue = 0; + } + // Insert the reference into the global lookup + if (!id.empty() && isCacheableRecord(n.val)) { + mIds[id] = n.val; + } + } + } + + /* This information isn't needed on screen. But keep the code around + for debugging purposes later. + + cout << "\n" << mStores.size() << " record types:\n"; + for(RecListList::iterator it = mStores.begin(); it != mStores.end(); it++) + cout << " " << toStr(it->first) << ": " << it->second->getSize() << endl; + cout << "\nNot implemented yet: "; + for(set::iterator it = missing.begin(); + it != missing.end(); it++ ) + cout << *it << " "; + cout << endl; + */ + setUp(); +} + +void ESMStore::setUp() +{ + std::map::iterator it = mStores.begin(); + for (; it != mStores.end(); ++it) { + it->second->setUp(); + } + mSkills.setUp(); + mMagicEffects.setUp(); + mAttributes.setUp(); + + ESM::NPC item; + item.mId = "player"; + + std::vector::iterator pIt = + std::lower_bound(mNpcs.mStatic.begin(), mNpcs.mStatic.end(), item, RecordCmp()); + assert(pIt != mNpcs.mStatic.end() && pIt->mId == "player"); + + mNpcs.insert(*pIt); + mNpcs.mStatic.erase(pIt); +} + +} // end namespace diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp new file mode 100644 index 000000000..e14219aae --- /dev/null +++ b/apps/openmw/mwworld/esmstore.hpp @@ -0,0 +1,426 @@ +#ifndef OPENMW_MWWORLD_ESMSTORE_H +#define OPENMW_MWWORLD_ESMSTORE_H + +#include + +#include +#include "store.hpp" + +namespace MWWorld +{ + class ESMStore + { + Store mActivators; + Store mPotions; + Store mAppas; + Store mArmors; + Store mBodyParts; + Store mBooks; + Store mBirthSigns; + Store mClasses; + Store mClothes; + Store mContChange; + Store mContainers; + Store mCreatures; + Store mCreaChange; + Store mDialogs; + Store mDoors; + Store mEnchants; + Store mFactions; + Store mGlobals; + Store mIngreds; + Store mCreatureLists; + Store mItemLists; + Store mLights; + Store mLockpicks; + Store mMiscItems; + Store mNpcs; + Store mNpcChange; + Store mProbes; + Store mRaces; + Store mRegions; + Store mRepairs; + Store mSoundGens; + Store mSounds; + Store mSpells; + Store mStartScripts; + Store mStatics; + Store mWeapons; + + Store mGameSettings; + Store mScripts; + + // Lists that need special rules + Store mCells; + Store mLands; + Store mLandTextures; + Store mPathgrids; + + Store mMagicEffects; + Store mSkills; + + // Special entry which is hardcoded and not loaded from an ESM + Store mAttributes; + + // Lookup of all IDs. Makes looking up references faster. Just + // maps the id name to the record type. + std::map mIds; + std::map mStores; + + unsigned int mDynamicCount; + + public: + /// \todo replace with SharedIterator + typedef std::map::const_iterator iterator; + + iterator begin() const { + return mStores.begin(); + } + + iterator end() const { + return mStores.end(); + } + + // Look up the given ID in 'all'. Returns 0 if not found. + int find(const std::string &id) const + { + std::map::const_iterator it = mIds.find(id); + if (it == mIds.end()) { + return 0; + } + return it->second; + } + + ESMStore() + : mDynamicCount(0) + { + mStores[ESM::REC_ACTI] = &mActivators; + mStores[ESM::REC_ALCH] = &mPotions; + mStores[ESM::REC_APPA] = &mAppas; + mStores[ESM::REC_ARMO] = &mArmors; + mStores[ESM::REC_BODY] = &mBodyParts; + mStores[ESM::REC_BOOK] = &mBooks; + mStores[ESM::REC_BSGN] = &mBirthSigns; + mStores[ESM::REC_CELL] = &mCells; + mStores[ESM::REC_CLAS] = &mClasses; + mStores[ESM::REC_CLOT] = &mClothes; + mStores[ESM::REC_CNTC] = &mContChange; + mStores[ESM::REC_CONT] = &mContainers; + mStores[ESM::REC_CREA] = &mCreatures; + mStores[ESM::REC_CREC] = &mCreaChange; + mStores[ESM::REC_DIAL] = &mDialogs; + mStores[ESM::REC_DOOR] = &mDoors; + mStores[ESM::REC_ENCH] = &mEnchants; + mStores[ESM::REC_FACT] = &mFactions; + mStores[ESM::REC_GLOB] = &mGlobals; + mStores[ESM::REC_GMST] = &mGameSettings; + mStores[ESM::REC_INGR] = &mIngreds; + mStores[ESM::REC_LAND] = &mLands; + mStores[ESM::REC_LEVC] = &mCreatureLists; + mStores[ESM::REC_LEVI] = &mItemLists; + mStores[ESM::REC_LIGH] = &mLights; + mStores[ESM::REC_LOCK] = &mLockpicks; + mStores[ESM::REC_LTEX] = &mLandTextures; + mStores[ESM::REC_MISC] = &mMiscItems; + mStores[ESM::REC_NPC_] = &mNpcs; + mStores[ESM::REC_NPCC] = &mNpcChange; + mStores[ESM::REC_PGRD] = &mPathgrids; + mStores[ESM::REC_PROB] = &mProbes; + mStores[ESM::REC_RACE] = &mRaces; + mStores[ESM::REC_REGN] = &mRegions; + mStores[ESM::REC_REPA] = &mRepairs; + mStores[ESM::REC_SCPT] = &mScripts; + mStores[ESM::REC_SNDG] = &mSoundGens; + mStores[ESM::REC_SOUN] = &mSounds; + mStores[ESM::REC_SPEL] = &mSpells; + mStores[ESM::REC_SSCR] = &mStartScripts; + mStores[ESM::REC_STAT] = &mStatics; + mStores[ESM::REC_WEAP] = &mWeapons; + } + + void load(ESM::ESMReader &esm); + + template + const Store &get() const { + throw std::runtime_error("Storage for this type not exist"); + } + + template + const T *insert(const T &x) { + Store &store = const_cast &>(get()); + if (store.search(x.mId) != 0) { + std::ostringstream msg; + msg << "Try to override existing record '" << x.mId << "'"; + throw std::runtime_error(msg.str()); + } + T record = x; + + std::ostringstream id; + id << "$dynamic" << mDynamicCount++; + record.mId = id.str(); + + T *ptr = store.insert(record); + for (iterator it = mStores.begin(); it != mStores.end(); ++it) { + if (it->second == &store) { + mIds[ptr->mId] = it->first; + } + } + return ptr; + } + + private: + void setUp(); + }; + + template <> + inline const ESM::Cell *ESMStore::insert(const ESM::Cell &cell) { + return mCells.insert(cell); + } + + template <> + inline const ESM::NPC *ESMStore::insert(const ESM::NPC &npc) { + if (Misc::StringUtils::ciEqual(npc.mId, "player")) { + return mNpcs.insert(npc); + } else if (mNpcs.search(npc.mId) != 0) { + std::ostringstream msg; + msg << "Try to override existing record '" << npc.mId << "'"; + throw std::runtime_error(msg.str()); + } + ESM::NPC record = npc; + + std::ostringstream id; + id << "$dynamic" << mDynamicCount++; + record.mId = id.str(); + + ESM::NPC *ptr = mNpcs.insert(record); + mIds[ptr->mId] = ESM::REC_NPC_; + return ptr; + } + + template <> + inline const Store &ESMStore::get() const { + return mActivators; + } + + template <> + inline const Store &ESMStore::get() const { + return mPotions; + } + + template <> + inline const Store &ESMStore::get() const { + return mAppas; + } + + template <> + inline const Store &ESMStore::get() const { + return mArmors; + } + + template <> + inline const Store &ESMStore::get() const { + return mBodyParts; + } + + template <> + inline const Store &ESMStore::get() const { + return mBooks; + } + + template <> + inline const Store &ESMStore::get() const { + return mBirthSigns; + } + + template <> + inline const Store &ESMStore::get() const { + return mClasses; + } + + template <> + inline const Store &ESMStore::get() const { + return mClothes; + } + + template <> + inline const Store &ESMStore::get() const { + return mContChange; + } + + template <> + inline const Store &ESMStore::get() const { + return mContainers; + } + + template <> + inline const Store &ESMStore::get() const { + return mCreatures; + } + + template <> + inline const Store &ESMStore::get() const { + return mCreaChange; + } + + template <> + inline const Store &ESMStore::get() const { + return mDialogs; + } + + template <> + inline const Store &ESMStore::get() const { + return mDoors; + } + + template <> + inline const Store &ESMStore::get() const { + return mEnchants; + } + + template <> + inline const Store &ESMStore::get() const { + return mFactions; + } + + template <> + inline const Store &ESMStore::get() const { + return mGlobals; + } + + template <> + inline const Store &ESMStore::get() const { + return mIngreds; + } + + template <> + inline const Store &ESMStore::get() const { + return mCreatureLists; + } + + template <> + inline const Store &ESMStore::get() const { + return mItemLists; + } + + template <> + inline const Store &ESMStore::get() const { + return mLights; + } + + template <> + inline const Store &ESMStore::get() const { + return mLockpicks; + } + + template <> + inline const Store &ESMStore::get() const { + return mMiscItems; + } + + template <> + inline const Store &ESMStore::get() const { + return mNpcs; + } + + template <> + inline const Store &ESMStore::get() const { + return mNpcChange; + } + + template <> + inline const Store &ESMStore::get() const { + return mProbes; + } + + template <> + inline const Store &ESMStore::get() const { + return mRaces; + } + + template <> + inline const Store &ESMStore::get() const { + return mRegions; + } + + template <> + inline const Store &ESMStore::get() const { + return mRepairs; + } + + template <> + inline const Store &ESMStore::get() const { + return mSoundGens; + } + + template <> + inline const Store &ESMStore::get() const { + return mSounds; + } + + template <> + inline const Store &ESMStore::get() const { + return mSpells; + } + + template <> + inline const Store &ESMStore::get() const { + return mStartScripts; + } + + template <> + inline const Store &ESMStore::get() const { + return mStatics; + } + + template <> + inline const Store &ESMStore::get() const { + return mWeapons; + } + + template <> + inline const Store &ESMStore::get() const { + return mGameSettings; + } + + template <> + inline const Store &ESMStore::get() const { + return mScripts; + } + + template <> + inline const Store &ESMStore::get() const { + return mCells; + } + + template <> + inline const Store &ESMStore::get() const { + return mLands; + } + + template <> + inline const Store &ESMStore::get() const { + return mLandTextures; + } + + template <> + inline const Store &ESMStore::get() const { + return mPathgrids; + } + + template <> + inline const Store &ESMStore::get() const { + return mMagicEffects; + } + + template <> + inline const Store &ESMStore::get() const { + return mSkills; + } + + template <> + inline const Store &ESMStore::get() const { + return mAttributes; + } +} + +#endif diff --git a/apps/openmw/mwworld/failedaction.cpp b/apps/openmw/mwworld/failedaction.cpp index 8c64db69f..ec763dba0 100644 --- a/apps/openmw/mwworld/failedaction.cpp +++ b/apps/openmw/mwworld/failedaction.cpp @@ -9,11 +9,11 @@ namespace MWWorld { FailedAction::FailedAction (const std::string& msg) : Action (false), message(msg) { } - - + + void FailedAction::executeImp (const Ptr& actor) { - if ( actor.getRefData().getHandle()=="player" and !(message.empty())) + if ( actor.getRefData().getHandle()=="player" && !(message.empty())) { MWBase::Environment::get().getWindowManager() ->messageBox(message, std::vector()); } diff --git a/apps/openmw/mwworld/globals.cpp b/apps/openmw/mwworld/globals.cpp index 1430219d9..f010661b9 100644 --- a/apps/openmw/mwworld/globals.cpp +++ b/apps/openmw/mwworld/globals.cpp @@ -3,10 +3,21 @@ #include -#include +#include "esmstore.hpp" namespace MWWorld { + std::vector Globals::getGlobals () const + { + std::vector retval; + Collection::const_iterator it; + for(it = mVariables.begin(); it != mVariables.end(); ++it){ + retval.push_back(it->first); + } + + return retval; + } + Globals::Collection::const_iterator Globals::find (const std::string& name) const { Collection::const_iterator iter = mVariables.find (name); @@ -27,35 +38,36 @@ namespace MWWorld return iter; } - Globals::Globals (const ESMS::ESMStore& store) + Globals::Globals (const MWWorld::ESMStore& store) { - for (ESMS::RecListT::MapType::const_iterator iter - (store.globals.list.begin()); iter != store.globals.list.end(); ++iter) + const MWWorld::Store &globals = store.get(); + MWWorld::Store::iterator iter = globals.begin(); + for (; iter != globals.end(); ++iter) { char type = ' '; Data value; - switch (iter->second.mType) + switch (iter->mType) { case ESM::VT_Short: type = 's'; value.mShort = *reinterpret_cast ( - &iter->second.mValue); + &iter->mValue); break; case ESM::VT_Int: type = 'l'; value.mLong = *reinterpret_cast ( - &iter->second.mValue); + &iter->mValue); break; case ESM::VT_Float: type = 'f'; value.mFloat = *reinterpret_cast ( - &iter->second.mValue); + &iter->mValue); break; default: @@ -63,7 +75,7 @@ namespace MWWorld throw std::runtime_error ("unsupported global variable type"); } - mVariables.insert (std::make_pair (iter->first, std::make_pair (type, value))); + mVariables.insert (std::make_pair (iter->mId, std::make_pair (type, value))); } if (mVariables.find ("dayspassed")==mVariables.end()) diff --git a/apps/openmw/mwworld/globals.hpp b/apps/openmw/mwworld/globals.hpp index 6aa54ade2..681bd560e 100644 --- a/apps/openmw/mwworld/globals.hpp +++ b/apps/openmw/mwworld/globals.hpp @@ -1,18 +1,16 @@ #ifndef GAME_MWWORLD_GLOBALS_H #define GAME_MWWORLD_GLOBALS_H +#include #include #include #include -namespace ESMS -{ - struct ESMStore; -} - namespace MWWorld { + class ESMStore; + class Globals { public: @@ -36,7 +34,7 @@ namespace MWWorld public: - Globals (const ESMS::ESMStore& store); + Globals (const MWWorld::ESMStore& store); const Data& operator[] (const std::string& name) const; @@ -56,6 +54,8 @@ namespace MWWorld char getType (const std::string& name) const; ///< If there is no global variable with this name, ' ' is returned. + + std::vector getGlobals () const; }; } diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 179a484e9..dd518ff6a 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -6,13 +6,12 @@ #include -#include - #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwmechanics/npcstats.hpp" +#include "esmstore.hpp" #include "class.hpp" void MWWorld::InventoryStore::copySlots (const InventoryStore& store) @@ -231,7 +230,7 @@ const MWMechanics::MagicEffects& MWWorld::InventoryStore::getMagicEffects() if (!enchantmentId.empty()) { const ESM::Enchantment& enchantment = - *MWBase::Environment::get().getWorld()->getStore().enchants.find (enchantmentId); + *MWBase::Environment::get().getWorld()->getStore().get().find (enchantmentId); if (enchantment.mData.mType==ESM::Enchantment::ConstantEffect) mMagicEffects.add (enchantment.mEffects); diff --git a/apps/openmw/mwworld/localscripts.cpp b/apps/openmw/mwworld/localscripts.cpp index d0d698feb..a821ad486 100644 --- a/apps/openmw/mwworld/localscripts.cpp +++ b/apps/openmw/mwworld/localscripts.cpp @@ -1,8 +1,6 @@ - #include "localscripts.hpp" -#include - +#include "esmstore.hpp" #include "cellstore.hpp" namespace @@ -12,18 +10,18 @@ namespace MWWorld::CellRefList& cellRefList, MWWorld::Ptr::CellStore *cell) { for (typename MWWorld::CellRefList::List::iterator iter ( - cellRefList.list.begin()); - iter!=cellRefList.list.end(); ++iter) + cellRefList.mList.begin()); + iter!=cellRefList.mList.end(); ++iter) { - if (!iter->base->mScript.empty() && iter->mData.getCount()) + if (!iter->mBase->mScript.empty() && iter->mData.getCount()) { - localScripts.add (iter->base->mScript, MWWorld::Ptr (&*iter, cell)); + localScripts.add (iter->mBase->mScript, MWWorld::Ptr (&*iter, cell)); } } } } -MWWorld::LocalScripts::LocalScripts (const ESMS::ESMStore& store) : mStore (store) {} +MWWorld::LocalScripts::LocalScripts (const MWWorld::ESMStore& store) : mStore (store) {} void MWWorld::LocalScripts::setIgnore (const Ptr& ptr) { @@ -63,7 +61,7 @@ std::pair MWWorld::LocalScripts::getNext() void MWWorld::LocalScripts::add (const std::string& scriptName, const Ptr& ptr) { - if (const ESM::Script *script = mStore.scripts.find (scriptName)) + if (const ESM::Script *script = mStore.get().find (scriptName)) { ptr.getRefData().setLocals (*script); @@ -73,23 +71,23 @@ void MWWorld::LocalScripts::add (const std::string& scriptName, const Ptr& ptr) void MWWorld::LocalScripts::addCell (Ptr::CellStore *cell) { - listCellScripts (*this, cell->activators, cell); - listCellScripts (*this, cell->potions, cell); - listCellScripts (*this, cell->appas, cell); - listCellScripts (*this, cell->armors, cell); - listCellScripts (*this, cell->books, cell); - listCellScripts (*this, cell->clothes, cell); - listCellScripts (*this, cell->containers, cell); - listCellScripts (*this, cell->creatures, cell); - listCellScripts (*this, cell->doors, cell); - listCellScripts (*this, cell->ingreds, cell); - listCellScripts (*this, cell->lights, cell); - listCellScripts (*this, cell->lockpicks, cell); - listCellScripts (*this, cell->miscItems, cell); - listCellScripts (*this, cell->npcs, cell); - listCellScripts (*this, cell->probes, cell); - listCellScripts (*this, cell->repairs, cell); - listCellScripts (*this, cell->weapons, cell); + listCellScripts (*this, cell->mActivators, cell); + listCellScripts (*this, cell->mPotions, cell); + listCellScripts (*this, cell->mAppas, cell); + listCellScripts (*this, cell->mArmors, cell); + listCellScripts (*this, cell->mBooks, cell); + listCellScripts (*this, cell->mClothes, cell); + listCellScripts (*this, cell->mContainers, cell); + listCellScripts (*this, cell->mCreatures, cell); + listCellScripts (*this, cell->mDoors, cell); + listCellScripts (*this, cell->mIngreds, cell); + listCellScripts (*this, cell->mLights, cell); + listCellScripts (*this, cell->mLockpicks, cell); + listCellScripts (*this, cell->mMiscItems, cell); + listCellScripts (*this, cell->mNpcs, cell); + listCellScripts (*this, cell->mProbes, cell); + listCellScripts (*this, cell->mRepairs, cell); + listCellScripts (*this, cell->mWeapons, cell); } void MWWorld::LocalScripts::clear() diff --git a/apps/openmw/mwworld/localscripts.hpp b/apps/openmw/mwworld/localscripts.hpp index 78f65e356..028dcdeda 100644 --- a/apps/openmw/mwworld/localscripts.hpp +++ b/apps/openmw/mwworld/localscripts.hpp @@ -6,13 +6,9 @@ #include "ptr.hpp" -namespace ESMS -{ - struct ESMStore; -} - namespace MWWorld { + struct ESMStore; class CellStore; /// \brief List of active local scripts @@ -21,11 +17,11 @@ namespace MWWorld std::list > mScripts; std::list >::iterator mIter; MWWorld::Ptr mIgnore; - const ESMS::ESMStore& mStore; + const MWWorld::ESMStore& mStore; public: - LocalScripts (const ESMS::ESMStore& store); + LocalScripts (const MWWorld::ESMStore& store); void setIgnore (const Ptr& ptr); ///< Mark a single reference for ignoring during iteration over local scripts (will revoke diff --git a/apps/openmw/mwworld/manualref.hpp b/apps/openmw/mwworld/manualref.hpp index 6570761ab..91b8cf8cd 100644 --- a/apps/openmw/mwworld/manualref.hpp +++ b/apps/openmw/mwworld/manualref.hpp @@ -3,8 +3,7 @@ #include -#include - +#include "esmstore.hpp" #include "ptr.hpp" #include "cellstore.hpp" @@ -20,29 +19,12 @@ namespace MWWorld ManualRef& operator= (const ManualRef&); template - bool create (const ESMS::RecListT& list, const std::string& name) + bool create (const MWWorld::Store& list, const std::string& name) { if (const T *instance = list.search (name)) { LiveCellRef ref; - ref.base = instance; - - mRef = ref; - mPtr = Ptr (&boost::any_cast&> (mRef), 0); - - return true; - } - - return false; - } - - template - bool create (const ESMS::RecListWithIDT& list, const std::string& name) - { - if (const T *instance = list.search (name)) - { - LiveCellRef ref; - ref.base = instance; + ref.mBase = instance; mRef = ref; mPtr = Ptr (&boost::any_cast&> (mRef), 0); @@ -55,29 +37,29 @@ namespace MWWorld public: - ManualRef (const ESMS::ESMStore& store, const std::string& name) + ManualRef (const MWWorld::ESMStore& store, const std::string& name) { // create - if (!create (store.activators, name) && - !create (store.potions, name) && - !create (store.appas, name) && - !create (store.armors, name) && - !create (store.books, name) && - !create (store.clothes, name) && - !create (store.containers, name) && - !create (store.creatures, name) && - !create (store.doors, name) && - !create (store.ingreds, name) && - !create (store.creatureLists, name) && - !create (store.itemLists, name) && - !create (store.lights, name) && - !create (store.lockpicks, name) && - !create (store.miscItems, name) && - !create (store.npcs, name) && - !create (store.probes, name) && - !create (store.repairs, name) && - !create (store.statics, name) && - !create (store.weapons, name)) + if (!create (store.get(), name) && + !create (store.get(), name) && + !create (store.get(), name) && + !create (store.get(), name) && + !create (store.get(), name) && + !create (store.get(), name) && + !create (store.get(), name) && + !create (store.get(), name) && + !create (store.get(), name) && + !create (store.get(), name) && + !create (store.get(), name) && + !create (store.get(), name) && + !create (store.get(), name) && + !create (store.get(), name) && + !create (store.get(), name) && + !create (store.get(), name) && + !create (store.get(), name) && + !create (store.get(), name) && + !create (store.get(), name) && + !create (store.get(), name)) throw std::logic_error ("failed to create manual cell ref for " + name); // initialise diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 3be85c7f3..5359c4eb2 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -12,6 +12,7 @@ #include //#include "../mwbase/world.hpp" // FIXME +#include "../mwbase/environment.hpp" #include "ptr.hpp" #include "class.hpp" @@ -249,31 +250,36 @@ namespace MWWorld mEngine->removeHeightField(x, y); } - void PhysicsSystem::addObject (const std::string& handle, const std::string& mesh, - const Ogre::Quaternion& rotation, float scale, const Ogre::Vector3& position) + void PhysicsSystem::addObject (const Ptr& ptr) { - handleToMesh[handle] = mesh; - OEngine::Physic::RigidBody* body = mEngine->createAndAdjustRigidBody(mesh,handle,scale, position, rotation); + std::string mesh = MWWorld::Class::get(ptr).getModel(ptr); + Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); + handleToMesh[node->getName()] = mesh; + OEngine::Physic::RigidBody* body = mEngine->createAndAdjustRigidBody(mesh, node->getName(), node->getScale().x, node->getPosition(), node->getOrientation()); mEngine->addRigidBody(body); } - void PhysicsSystem::addActor (const std::string& handle, const std::string& mesh, - const Ogre::Vector3& position, float scale, const Ogre::Quaternion& rotation) + void PhysicsSystem::addActor (const Ptr& ptr) { + std::string mesh = MWWorld::Class::get(ptr).getModel(ptr); + Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); //TODO:optimize this. Searching the std::map isn't very efficient i think. - mEngine->addCharacter(handle, mesh, position, scale, rotation); + mEngine->addCharacter(node->getName(), mesh, node->getPosition(), node->getScale().x, node->getOrientation()); } void PhysicsSystem::removeObject (const std::string& handle) { //TODO:check if actor??? + mEngine->removeCharacter(handle); mEngine->removeRigidBody(handle); mEngine->deleteRigidBody(handle); } - void PhysicsSystem::moveObject (const std::string& handle, Ogre::SceneNode* node) + void PhysicsSystem::moveObject (const Ptr& ptr) { + Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); + std::string handle = node->getName(); Ogre::Vector3 position = node->getPosition(); if (OEngine::Physic::RigidBody* body = mEngine->getRigidBody(handle)) { @@ -307,8 +313,10 @@ namespace MWWorld } } - void PhysicsSystem::rotateObject (const std::string& handle, Ogre::SceneNode* node) + void PhysicsSystem::rotateObject (const Ptr& ptr) { + Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); + std::string handle = node->getName(); Ogre::Quaternion rotation = node->getOrientation(); if (OEngine::Physic::PhysicActor* act = mEngine->getCharacter(handle)) { @@ -324,23 +332,18 @@ namespace MWWorld } } - void PhysicsSystem::scaleObject (const std::string& handle, Ogre::SceneNode* node) + void PhysicsSystem::scaleObject (const Ptr& ptr) { + Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); + std::string handle = node->getName(); if(handleToMesh.find(handle) != handleToMesh.end()) { removeObject(handle); - - float scale = node->getScale().x; - Ogre::Quaternion quat = node->getOrientation(); - Ogre::Vector3 vec = node->getPosition(); - addObject(handle, handleToMesh[handle], quat, scale, vec); + addObject(ptr); } if (OEngine::Physic::PhysicActor* act = mEngine->getCharacter(handle)) - { - float scale = node->getScale().x; - act->setScale(scale); - } + act->setScale(node->getScale().x); } bool PhysicsSystem::toggleCollisionMode() @@ -371,23 +374,6 @@ namespace MWWorld throw std::logic_error ("can't find player"); } - void PhysicsSystem::insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string model){ - - Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); - - addObject( - node->getName(), - model, - node->getOrientation(), - node->getScale().x, - node->getPosition()); - } - - void PhysicsSystem::insertActorPhysics(const MWWorld::Ptr& ptr, const std::string model){ - Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); - addActor (node->getName(), model, node->getPosition(), node->getScale().x, node->getOrientation()); - } - bool PhysicsSystem::getObjectAABB(const MWWorld::Ptr &ptr, Ogre::Vector3 &min, Ogre::Vector3 &max) { std::string model = MWWorld::Class::get(ptr).getModel(ptr); diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index 1427060f6..8bd73fd6c 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -20,11 +20,9 @@ namespace MWWorld std::vector< std::pair > doPhysicsFixed (const std::vector >& actors); ///< do physics with fixed timestep - Usage: first call doPhysics with frame dt, then call doPhysicsFixed as often as time steps have passed - void addObject (const std::string& handle, const std::string& mesh, - const Ogre::Quaternion& rotation, float scale, const Ogre::Vector3& position); + void addObject (const MWWorld::Ptr& ptr); - void addActor (const std::string& handle, const std::string& mesh, - const Ogre::Vector3& position, float scale, const Ogre::Quaternion& rotation); + void addActor (const MWWorld::Ptr& ptr); void addHeightField (float* heights, int x, int y, float yoffset, @@ -32,13 +30,14 @@ namespace MWWorld void removeHeightField (int x, int y); + // have to keep this as handle for now as unloadcell only knows scenenode names void removeObject (const std::string& handle); - void moveObject (const std::string& handle, Ogre::SceneNode* node); + void moveObject (const MWWorld::Ptr& ptr); - void rotateObject (const std::string& handle, Ogre::SceneNode* node); + void rotateObject (const MWWorld::Ptr& ptr); - void scaleObject (const std::string& handle, Ogre::SceneNode* node); + void scaleObject (const MWWorld::Ptr& ptr); bool toggleCollisionMode(); @@ -60,10 +59,6 @@ namespace MWWorld std::pair castRay(float mouseX, float mouseY); ///< cast ray from the mouse, return true if it hit something and the first result (in OGRE coordinates) - void insertObjectPhysics(const MWWorld::Ptr& ptr, std::string model); - - void insertActorPhysics(const MWWorld::Ptr&, std::string model); - OEngine::Physic::PhysicEngine* getEngine(); void setCurrentWater(bool hasWater, int waterHeight); diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index e1eb02c32..3414ba448 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -1,7 +1,6 @@ #include "player.hpp" -#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -9,37 +8,21 @@ #include "../mwmechanics/movement.hpp" #include "../mwmechanics/npcstats.hpp" +#include "esmstore.hpp" #include "class.hpp" namespace MWWorld { - Player::Player (const ESM::NPC *player, const MWBase::World& world) : - mCellStore (0), mClass (0), - mAutoMove (false), mForwardBackward (0) + Player::Player (const ESM::NPC *player, const MWBase::World& world) + : mCellStore(0), + mAutoMove(false), + mForwardBackward (0) { - mPlayer.base = player; - mPlayer.ref.mRefID = "player"; - mName = player->mName; - mMale = !(player->mFlags & ESM::NPC::Female); - mRace = player->mRace; + mPlayer.mBase = player; + mPlayer.mRef.mRefID = "player"; float* playerPos = mPlayer.mData.getPosition().pos; playerPos[0] = playerPos[1] = playerPos[2] = 0; - - /// \todo Do not make a copy of classes defined in esm/p records. - mClass = new ESM::Class (*world.getStore().classes.find (player->mClass)); - } - - Player::~Player() - { - delete mClass; - } - - void Player::setClass (const ESM::Class& class_) - { - ESM::Class *new_class = new ESM::Class (class_); - delete mClass; - mClass = new_class; } void Player::setDrawState (MWMechanics::DrawState_ state) @@ -102,5 +85,4 @@ namespace MWWorld MWWorld::Ptr ptr = getPlayer(); return MWWorld::Class::get(ptr).getNpcStats(ptr).getDrawState(); } - } diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index 68df2ec6d..1c1ef76cf 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -1,8 +1,6 @@ #ifndef GAME_MWWORLD_PLAYER_H #define GAME_MWWORLD_PLAYER_H -#include "OgreCamera.h" - #include "../mwworld/cellstore.hpp" #include "../mwworld/refdata.hpp" #include "../mwworld/ptr.hpp" @@ -21,21 +19,17 @@ namespace MWWorld /// \brief NPC object representing the player and additional player data class Player { - LiveCellRef mPlayer; - MWWorld::CellStore *mCellStore; - std::string mName; - bool mMale; - std::string mRace; - std::string mBirthsign; - ESM::Class *mClass; - bool mAutoMove; - int mForwardBackward; + LiveCellRef mPlayer; + MWWorld::CellStore *mCellStore; + std::string mSign; + + bool mAutoMove; + int mForwardBackward; + public: Player(const ESM::NPC *player, const MWBase::World& world); - ~Player(); - void setCell (MWWorld::CellStore *cellStore) { mCellStore = cellStore; @@ -47,55 +41,16 @@ namespace MWWorld return ptr; } - void setName (const std::string& name) - { - mName = name; + void setBirthSign(const std::string &sign) { + mSign = sign; } - void setGender (bool male) - { - mMale = male; + const std::string &getBirthSign() const { + return mSign; } - void setRace (const std::string& race) - { - mRace = race; - } - - void setBirthsign (const std::string& birthsign) - { - mBirthsign = birthsign; - } - - void setClass (const ESM::Class& class_); - void setDrawState (MWMechanics::DrawState_ state); - std::string getName() const - { - return mName; - } - - bool isMale() const - { - return mMale; - } - - std::string getRace() const - { - return mRace; - } - - std::string getBirthsign() const - { - return mBirthsign; - } - - const ESM::Class& getClass() const - { - return *mClass; - } - bool getAutoMove() const { return mAutoMove; diff --git a/apps/openmw/mwworld/ptr.hpp b/apps/openmw/mwworld/ptr.hpp index f74fdd3ef..594ddef2d 100644 --- a/apps/openmw/mwworld/ptr.hpp +++ b/apps/openmw/mwworld/ptr.hpp @@ -50,7 +50,7 @@ namespace MWWorld : mContainerStore (0) { mPtr = liveCellRef; - mCellRef = &liveCellRef->ref; + mCellRef = &liveCellRef->mRef; mRefData = &liveCellRef->mData; mCell = cell; mTypeName = typeid (T).name(); diff --git a/apps/openmw/mwworld/recordcmp.hpp b/apps/openmw/mwworld/recordcmp.hpp new file mode 100644 index 000000000..7de4f5565 --- /dev/null +++ b/apps/openmw/mwworld/recordcmp.hpp @@ -0,0 +1,34 @@ +#ifndef OPENMW_MWWORLD_RECORDCMP_H +#define OPENMW_MWWORLD_RECORDCMP_H + +#include + +#include + +namespace MWWorld +{ + struct RecordCmp + { + template + bool operator()(const T &x, const T& y) const { + return x.mId < y.mId; + } + }; + + template <> + inline bool RecordCmp::operator()(const ESM::Dialogue &x, const ESM::Dialogue &y) const { + return Misc::StringUtils::ciLess(x.mId, y.mId); + } + + template <> + inline bool RecordCmp::operator()(const ESM::Cell &x, const ESM::Cell &y) const { + return Misc::StringUtils::ciLess(x.mName, y.mName); + } + + template <> + inline bool RecordCmp::operator()(const ESM::Pathgrid &x, const ESM::Pathgrid &y) const { + return Misc::StringUtils::ciLess(x.mCell, y.mCell); + } + +} // end namespace +#endif diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 517025fb2..6b9abf508 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -1,6 +1,5 @@ #include "scene.hpp" -#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" /// FIXME @@ -10,6 +9,7 @@ #include "player.hpp" #include "localscripts.hpp" +#include "esmstore.hpp" #include "cellfunctors.hpp" @@ -20,15 +20,15 @@ namespace void insertCellRefList(MWRender::RenderingManager& rendering, T& cellRefList, MWWorld::CellStore &cell, MWWorld::PhysicsSystem& physics) { - if (!cellRefList.list.empty()) + if (!cellRefList.mList.empty()) { const MWWorld::Class& class_ = - MWWorld::Class::get (MWWorld::Ptr (&*cellRefList.list.begin(), &cell)); + MWWorld::Class::get (MWWorld::Ptr (&*cellRefList.mList.begin(), &cell)); - int numRefs = cellRefList.list.size(); + int numRefs = cellRefList.mList.size(); int current = 0; - for (typename T::List::iterator it = cellRefList.list.begin(); - it != cellRefList.list.end(); it++) + for (typename T::List::iterator it = cellRefList.mList.begin(); + it != cellRefList.mList.end(); it++) { MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Loading cells", 1, current, numRefs); ++current; @@ -41,6 +41,8 @@ namespace { rendering.addObject(ptr); class_.insertObject(ptr, physics); + MWBase::Environment::get().getWorld()->rotateObject(ptr, 0, 0, 0, true); + MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().mScale); } catch (const std::exception& e) { @@ -62,8 +64,8 @@ namespace namespace MWWorld { - void Scene::update (float duration){ - mRendering.update (duration); + void Scene::update (float duration, bool paused){ + mRendering.update (duration, paused); } void Scene::unloadCell (CellStoreCollection::iterator iter) @@ -80,11 +82,15 @@ namespace MWWorld mPhysics->removeObject (node->getName()); } - if (!((*iter)->cell->mData.mFlags & ESM::Cell::Interior)) + if ((*iter)->mCell->isExterior()) { - ESM::Land* land = MWBase::Environment::get().getWorld()->getStore().lands.search((*iter)->cell->mData.mX,(*iter)->cell->mData.mY); + ESM::Land* land = + MWBase::Environment::get().getWorld()->getStore().get().search( + (*iter)->mCell->getGridX(), + (*iter)->mCell->getGridY() + ); if (land) - mPhysics->removeHeightField( (*iter)->cell->mData.mX, (*iter)->cell->mData.mY ); + mPhysics->removeHeightField( (*iter)->mCell->getGridX(), (*iter)->mCell->getGridY() ); } } @@ -111,13 +117,23 @@ namespace MWWorld float verts = ESM::Land::LAND_SIZE; float worldsize = ESM::Land::REAL_SIZE; - if (!(cell->cell->mData.mFlags & ESM::Cell::Interior)) + if (cell->mCell->isExterior()) { - ESM::Land* land = MWBase::Environment::get().getWorld()->getStore().lands.search(cell->cell->mData.mX,cell->cell->mData.mY); - if (land) - mPhysics->addHeightField (land->mLandData->mHeights, - cell->cell->mData.mX, cell->cell->mData.mY, - 0, ( worldsize/(verts-1) ), verts); + ESM::Land* land = + MWBase::Environment::get().getWorld()->getStore().get().search( + cell->mCell->getGridX(), + cell->mCell->getGridY() + ); + if (land) { + mPhysics->addHeightField ( + land->mLandData->mHeights, + cell->mCell->getGridX(), + cell->mCell->getGridY(), + 0, + worldsize / (verts-1), + verts) + ; + } } mRendering.configureAmbient(*cell); @@ -128,8 +144,8 @@ namespace MWWorld void Scene::playerCellChange(MWWorld::CellStore *cell, const ESM::Position& pos, bool adjustPlayerPos) { - bool hasWater = cell->cell->mData.mFlags & cell->cell->HasWater; - mPhysics->setCurrentWater(hasWater, cell->cell->mWater); + bool hasWater = cell->mCell->mData.mFlags & ESM::Cell::HasWater; + mPhysics->setCurrentWater(hasWater, cell->mCell->mWater); MWBase::World *world = MWBase::Environment::get().getWorld(); world->getPlayer().setCell(cell); @@ -167,10 +183,10 @@ namespace MWWorld int numUnload = 0; while (active!=mActiveCells.end()) { - if (!((*active)->cell->mData.mFlags & ESM::Cell::Interior)) + if ((*active)->mCell->isExterior()) { - if (std::abs (X-(*active)->cell->mData.mX)<=1 && - std::abs (Y-(*active)->cell->mData.mY)<=1) + if (std::abs (X-(*active)->mCell->getGridX())<=1 && + std::abs (Y-(*active)->mCell->getGridY())<=1) { // keep cells within the new 3x3 grid ++active; @@ -185,10 +201,10 @@ namespace MWWorld active = mActiveCells.begin(); while (active!=mActiveCells.end()) { - if (!((*active)->cell->mData.mFlags & ESM::Cell::Interior)) + if ((*active)->mCell->isExterior()) { - if (std::abs (X-(*active)->cell->mData.mX)<=1 && - std::abs (Y-(*active)->cell->mData.mY)<=1) + if (std::abs (X-(*active)->mCell->getGridX())<=1 && + std::abs (Y-(*active)->mCell->getGridY())<=1) { // keep cells within the new 3x3 grid ++active; @@ -210,10 +226,10 @@ namespace MWWorld while (iter!=mActiveCells.end()) { - assert (!((*iter)->cell->mData.mFlags & ESM::Cell::Interior)); + assert ((*iter)->mCell->isExterior()); - if (x==(*iter)->cell->mData.mX && - y==(*iter)->cell->mData.mY) + if (x==(*iter)->mCell->getGridX() && + y==(*iter)->mCell->getGridY()) break; ++iter; @@ -232,10 +248,10 @@ namespace MWWorld while (iter!=mActiveCells.end()) { - assert (!((*iter)->cell->mData.mFlags & ESM::Cell::Interior)); + assert ((*iter)->mCell->isExterior()); - if (x==(*iter)->cell->mData.mX && - y==(*iter)->cell->mData.mY) + if (x==(*iter)->mCell->getGridX() && + y==(*iter)->mCell->getGridY()) break; ++iter; @@ -256,10 +272,10 @@ namespace MWWorld while (iter!=mActiveCells.end()) { - assert (!((*iter)->cell->mData.mFlags & ESM::Cell::Interior)); + assert ((*iter)->mCell->isExterior()); - if (X==(*iter)->cell->mData.mX && - Y==(*iter)->cell->mData.mY) + if (X==(*iter)->mCell->getGridX() && + Y==(*iter)->mCell->getGridY()) break; ++iter; @@ -304,9 +320,24 @@ namespace MWWorld void Scene::changeToInteriorCell (const std::string& cellName, const ESM::Position& position) { - std::cout << "Changing to interior\n"; - CellStore *cell = MWBase::Environment::get().getWorld()->getInterior(cellName); + bool loadcell = (mCurrentCell == NULL); + if(!loadcell) + loadcell = *mCurrentCell != *cell; + + if(!loadcell) + { + MWBase::World *world = MWBase::Environment::get().getWorld(); + world->moveObject(world->getPlayer().getPlayer(), position.pos[0], position.pos[1], position.pos[2]); + + float x = Ogre::Radian(position.rot[0]).valueDegrees(); + float y = Ogre::Radian(position.rot[1]).valueDegrees(); + float z = Ogre::Radian(position.rot[2]).valueDegrees(); + world->rotateObject(world->getPlayer().getPlayer(), x, y, z); + return; + } + + std::cout << "Changing to interior\n"; // remove active CellStoreCollection::iterator active = mActiveCells.begin(); @@ -331,19 +362,19 @@ namespace MWWorld } // Load cell. - std::cout << "cellName:" << cellName << std::endl; - + std::cout << "cellName: " << cell->mCell->mName << std::endl; MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Loading cells", 0, 0, 1); loadCell (cell); - // adjust player mCurrentCell = cell; - playerCellChange (cell, position); // adjust fog mRendering.switchToInterior(); - mRendering.configureFog(*cell); + mRendering.configureFog(*mCurrentCell); + + // adjust player + playerCellChange (mCurrentCell, position); // Sky system MWBase::Environment::get().getWorld()->adjustSky(); @@ -376,32 +407,34 @@ namespace MWWorld void Scene::insertCell (Ptr::CellStore &cell) { // Loop through all references in the cell - insertCellRefList(mRendering, cell.activators, cell, *mPhysics); - insertCellRefList(mRendering, cell.potions, cell, *mPhysics); - insertCellRefList(mRendering, cell.appas, cell, *mPhysics); - insertCellRefList(mRendering, cell.armors, cell, *mPhysics); - insertCellRefList(mRendering, cell.books, cell, *mPhysics); - insertCellRefList(mRendering, cell.clothes, cell, *mPhysics); - insertCellRefList(mRendering, cell.containers, cell, *mPhysics); - insertCellRefList(mRendering, cell.creatures, cell, *mPhysics); - insertCellRefList(mRendering, cell.doors, cell, *mPhysics); - insertCellRefList(mRendering, cell.ingreds, cell, *mPhysics); - insertCellRefList(mRendering, cell.creatureLists, cell, *mPhysics); - insertCellRefList(mRendering, cell.itemLists, cell, *mPhysics); - insertCellRefList(mRendering, cell.lights, cell, *mPhysics); - insertCellRefList(mRendering, cell.lockpicks, cell, *mPhysics); - insertCellRefList(mRendering, cell.miscItems, cell, *mPhysics); - insertCellRefList(mRendering, cell.npcs, cell, *mPhysics); - insertCellRefList(mRendering, cell.probes, cell, *mPhysics); - insertCellRefList(mRendering, cell.repairs, cell, *mPhysics); - insertCellRefList(mRendering, cell.statics, cell, *mPhysics); - insertCellRefList(mRendering, cell.weapons, cell, *mPhysics); + insertCellRefList(mRendering, cell.mActivators, cell, *mPhysics); + insertCellRefList(mRendering, cell.mPotions, cell, *mPhysics); + insertCellRefList(mRendering, cell.mAppas, cell, *mPhysics); + insertCellRefList(mRendering, cell.mArmors, cell, *mPhysics); + insertCellRefList(mRendering, cell.mBooks, cell, *mPhysics); + insertCellRefList(mRendering, cell.mClothes, cell, *mPhysics); + insertCellRefList(mRendering, cell.mContainers, cell, *mPhysics); + insertCellRefList(mRendering, cell.mCreatures, cell, *mPhysics); + insertCellRefList(mRendering, cell.mDoors, cell, *mPhysics); + insertCellRefList(mRendering, cell.mIngreds, cell, *mPhysics); + insertCellRefList(mRendering, cell.mCreatureLists, cell, *mPhysics); + insertCellRefList(mRendering, cell.mItemLists, cell, *mPhysics); + insertCellRefList(mRendering, cell.mLights, cell, *mPhysics); + insertCellRefList(mRendering, cell.mLockpicks, cell, *mPhysics); + insertCellRefList(mRendering, cell.mMiscItems, cell, *mPhysics); + insertCellRefList(mRendering, cell.mNpcs, cell, *mPhysics); + insertCellRefList(mRendering, cell.mProbes, cell, *mPhysics); + insertCellRefList(mRendering, cell.mRepairs, cell, *mPhysics); + insertCellRefList(mRendering, cell.mStatics, cell, *mPhysics); + insertCellRefList(mRendering, cell.mWeapons, cell, *mPhysics); } void Scene::addObjectToScene (const Ptr& ptr) { mRendering.addObject(ptr); MWWorld::Class::get(ptr).insertObject(ptr, *mPhysics); + MWBase::Environment::get().getWorld()->rotateObject(ptr, 0, 0, 0, true); + MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().mScale); } void Scene::removeObjectFromScene (const Ptr& ptr) diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index 59e13dafe..ad6ad1559 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -88,7 +88,7 @@ namespace MWWorld void insertCell (Ptr::CellStore &cell); - void update (float duration); + void update (float duration, bool paused); void addObjectToScene (const Ptr& ptr); ///< Add an object that already exists in the world model to the scene. diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp new file mode 100644 index 000000000..431cd3cf9 --- /dev/null +++ b/apps/openmw/mwworld/store.hpp @@ -0,0 +1,889 @@ +#ifndef OPENMW_MWWORLD_STORE_H +#define OPENMW_MWWORLD_STORE_H + +#include +#include +#include +#include + +#include "recordcmp.hpp" + +namespace MWWorld +{ + struct StoreBase + { + virtual ~StoreBase() {} + + virtual void setUp() {} + virtual void listIdentifier(std::vector &list) const {} + + virtual int getSize() const = 0; + virtual void load(ESM::ESMReader &esm, const std::string &id) = 0; + }; + + template + class SharedIterator + { + typedef typename std::vector::const_iterator Iter; + + Iter mIter; + + public: + SharedIterator() {} + + SharedIterator(const SharedIterator &orig) + : mIter(orig.mIter) + {} + + SharedIterator(const Iter &iter) + : mIter(iter) + {} + + SharedIterator &operator++() { + ++mIter; + return *this; + } + + SharedIterator operator++(int) { + SharedIterator iter = *this; + mIter++; + + return iter; + } + + SharedIterator &operator--() { + --mIter; + return *this; + } + + SharedIterator operator--(int) { + SharedIterator iter = *this; + mIter--; + + return iter; + } + + bool operator==(const SharedIterator &x) const { + return mIter == x.mIter; + } + + bool operator!=(const SharedIterator &x) const { + return !(*this == x); + } + + const T &operator*() const { + return **mIter; + } + + const T *operator->() const { + return &(**mIter); + } + }; + + class ESMStore; + + template + class Store : public StoreBase + { + std::vector mStatic; + std::vector mShared; + std::map mDynamic; + + typedef std::map Dynamic; + + friend class ESMStore; + + public: + Store() + {} + + Store(const Store &orig) + : mStatic(orig.mData) + {} + + typedef SharedIterator iterator; + + const T *search(const std::string &id) const { + T item; + item.mId = Misc::StringUtils::lowerCase(id); + + typename std::vector::const_iterator it = + std::lower_bound(mStatic.begin(), mStatic.end(), item, RecordCmp()); + + if (it != mStatic.end() && Misc::StringUtils::ciEqual(it->mId, id)) { + return &(*it); + } + + typename Dynamic::const_iterator dit = mDynamic.find(item.mId); + if (dit != mDynamic.end()) { + return &dit->second; + } + + return 0; + } + + const T *find(const std::string &id) const { + const T *ptr = search(id); + if (ptr == 0) { + std::ostringstream msg; + msg << "Object '" << id << "' not found (const)"; + throw std::runtime_error(msg.str()); + } + return ptr; + } + + void load(ESM::ESMReader &esm, const std::string &id) { + mStatic.push_back(T()); + mStatic.back().mId = Misc::StringUtils::lowerCase(id); + mStatic.back().load(esm); + } + + void setUp() { + std::sort(mStatic.begin(), mStatic.end(), RecordCmp()); + + mShared.reserve(mStatic.size()); + typename std::vector::iterator it = mStatic.begin(); + for (; it != mStatic.end(); ++it) { + mShared.push_back(&(*it)); + } + } + + iterator begin() const { + return mShared.begin(); + } + + iterator end() const { + return mShared.end(); + } + + int getSize() const { + return mShared.size(); + } + + void listIdentifier(std::vector &list) const { + list.reserve(list.size() + getSize()); + typename std::vector::const_iterator it = mShared.begin(); + for (; it != mShared.end(); ++it) { + list.push_back((*it)->mId); + } + } + + T *insert(const T &item) { + std::string id = Misc::StringUtils::lowerCase(item.mId); + std::pair result = + mDynamic.insert(std::pair(id, item)); + T *ptr = &result.first->second; + if (result.second) { + mShared.push_back(ptr); + } else { + *ptr = item; + } + return ptr; + } + + bool erase(const std::string &id) { + std::string key = Misc::StringUtils::lowerCase(id); + typename Dynamic::iterator it = mDynamic.find(key); + if (it == mDynamic.end()) { + return false; + } + mDynamic.erase(it); + + // have to reinit the whole shared part + mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); + for (it = mDynamic.begin(); it != mDynamic.end(); ++it) { + mShared.push_back(&it->second); + } + return true; + } + + bool erase(const T &item) { + return erase(item.mId); + } + }; + + template <> + inline void Store::load(ESM::ESMReader &esm, const std::string &id) { + mStatic.push_back(ESM::Dialogue()); + mStatic.back().mId = id; + mStatic.back().load(esm); + } + + template <> + inline void Store::load(ESM::ESMReader &esm, const std::string &id) { + mStatic.push_back(ESM::Script()); + mStatic.back().load(esm); + Misc::StringUtils::toLower(mStatic.back().mId); + } + + template <> + class Store : public StoreBase + { + std::vector mStatic; + + public: + Store() { + mStatic.reserve(128); + } + + typedef std::vector::const_iterator iterator; + + const ESM::LandTexture *search(size_t index) const { + if (index < mStatic.size()) { + return &mStatic.at(index); + } + return 0; + } + + const ESM::LandTexture *find(size_t index) const { + const ESM::LandTexture *ptr = search(index); + if (ptr == 0) { + std::ostringstream msg; + msg << "Land texture with index " << index << " not found"; + throw std::runtime_error(msg.str()); + } + return ptr; + } + + int getSize() const { + return mStatic.size(); + } + + void load(ESM::ESMReader &esm, const std::string &id) { + ESM::LandTexture ltex; + ltex.load(esm); + + if (ltex.mIndex >= (int) mStatic.size()) { + mStatic.resize(ltex.mIndex + 1); + } + mStatic[ltex.mIndex] = ltex; + mStatic[ltex.mIndex].mId = id; + } + + iterator begin() const { + return mStatic.begin(); + } + + iterator end() const { + return mStatic.end(); + } + }; + + template <> + class Store : public StoreBase + { + std::vector mStatic; + + struct Compare + { + bool operator()(const ESM::Land *x, const ESM::Land *y) { + if (x->mX == y->mX) { + return x->mY < y->mY; + } + return x->mX < y->mX; + } + }; + + public: + typedef SharedIterator iterator; + + virtual ~Store() + { + for (std::vector::const_iterator it = + mStatic.begin(); it != mStatic.end(); ++it) + { + delete *it; + } + + } + + int getSize() const { + return mStatic.size(); + } + + iterator begin() const { + return iterator(mStatic.begin()); + } + + iterator end() const { + return iterator(mStatic.end()); + } + + ESM::Land *search(int x, int y) const { + ESM::Land land; + land.mX = x, land.mY = y; + + std::vector::const_iterator it = + std::lower_bound(mStatic.begin(), mStatic.end(), &land, Compare()); + + if (it != mStatic.end() && (*it)->mX == x && (*it)->mY == y) { + return const_cast(*it); + } + return 0; + } + + ESM::Land *find(int x, int y) const{ + ESM::Land *ptr = search(x, y); + if (ptr == 0) { + std::ostringstream msg; + msg << "Land at (" << x << ", " << y << ") not found"; + throw std::runtime_error(msg.str()); + } + return ptr; + } + + void load(ESM::ESMReader &esm, const std::string &id) { + ESM::Land *ptr = new ESM::Land(); + ptr->load(esm); + + mStatic.push_back(ptr); + } + + void setUp() { + std::sort(mStatic.begin(), mStatic.end(), Compare()); + } + }; + + template <> + class Store : public StoreBase + { + struct ExtCmp + { + bool operator()(const ESM::Cell &x, const ESM::Cell &y) { + if (x.mData.mX == y.mData.mX) { + return x.mData.mY < y.mData.mY; + } + return x.mData.mX < y.mData.mX; + } + }; + + std::vector mInt; + std::vector mExt; + + std::vector mSharedInt; + std::vector mSharedExt; + + typedef std::map DynamicInt; + typedef std::map, ESM::Cell> DynamicExt; + + DynamicInt mDynamicInt; + DynamicExt mDynamicExt; + + + const ESM::Cell *search(const ESM::Cell &cell) const { + if (cell.isExterior()) { + return search(cell.getGridX(), cell.getGridY()); + } + return search(cell.mName); + } + + public: + typedef SharedIterator iterator; + + Store() + {} + + const ESM::Cell *search(const std::string &id) const { + ESM::Cell cell; + cell.mName = Misc::StringUtils::lowerCase(id); + + std::vector::const_iterator it = + std::lower_bound(mInt.begin(), mInt.end(), cell, RecordCmp()); + + if (it != mInt.end() && Misc::StringUtils::ciEqual(it->mName, id)) { + return &(*it); + } + + DynamicInt::const_iterator dit = mDynamicInt.find(cell.mName); + if (dit != mDynamicInt.end()) { + return &dit->second; + } + + return 0; + } + + const ESM::Cell *search(int x, int y) const { + ESM::Cell cell; + cell.mData.mX = x, cell.mData.mY = y; + + std::vector::const_iterator it = + std::lower_bound(mExt.begin(), mExt.end(), cell, ExtCmp()); + + if (it != mExt.end() && it->mData.mX == x && it->mData.mY == y) { + return &(*it); + } + + std::pair key(x, y); + DynamicExt::const_iterator dit = mDynamicExt.find(key); + if (dit != mDynamicExt.end()) { + return &dit->second; + } + + return 0; + } + + const ESM::Cell *find(const std::string &id) const { + const ESM::Cell *ptr = search(id); + if (ptr == 0) { + std::ostringstream msg; + msg << "Interior cell '" << id << "' not found"; + throw std::runtime_error(msg.str()); + } + return ptr; + } + + const ESM::Cell *find(int x, int y) const { + const ESM::Cell *ptr = search(x, y); + if (ptr == 0) { + std::ostringstream msg; + msg << "Exterior at (" << x << ", " << y << ") not found"; + throw std::runtime_error(msg.str()); + } + return ptr; + } + + void setUp() { + typedef std::vector::iterator Iterator; + + std::sort(mInt.begin(), mInt.end(), RecordCmp()); + mSharedInt.reserve(mInt.size()); + for (Iterator it = mInt.begin(); it != mInt.end(); ++it) { + mSharedInt.push_back(&(*it)); + } + + std::sort(mExt.begin(), mExt.end(), ExtCmp()); + mSharedExt.reserve(mExt.size()); + for (Iterator it = mExt.begin(); it != mExt.end(); ++it) { + mSharedExt.push_back(&(*it)); + } + } + + void load(ESM::ESMReader &esm, const std::string &id) { + ESM::Cell cell; + cell.mName = id; + cell.load(esm); + + if (cell.isExterior()) { + mExt.push_back(cell); + } else { + mInt.push_back(cell); + } + } + + iterator intBegin() const { + return iterator(mSharedInt.begin()); + } + + iterator intEnd() const { + return iterator(mSharedInt.end()); + } + + iterator extBegin() const { + return iterator(mSharedExt.begin()); + } + + iterator extEnd() const { + return iterator(mSharedExt.end()); + } + + /// \todo implement appropriate index + const ESM::Cell *searchExtByName(const std::string &id) const { + std::vector::const_iterator it = mSharedExt.begin(); + for (; it != mSharedExt.end(); ++it) { + if (Misc::StringUtils::ciEqual((*it)->mName, id)) { + return *it; + } + } + return 0; + } + + /// \todo implement appropriate index + const ESM::Cell *searchExtByRegion(const std::string &id) const { + std::vector::const_iterator it = mSharedExt.begin(); + for (; it != mSharedExt.end(); ++it) { + if (Misc::StringUtils::ciEqual((*it)->mRegion, id)) { + return *it; + } + } + return 0; + } + + int getSize() const { + return mSharedInt.size() + mSharedExt.size(); + } + + void listIdentifier(std::vector &list) const { + list.reserve(list.size() + mSharedInt.size()); + + std::vector::const_iterator it = mSharedInt.begin(); + for (; it != mSharedInt.end(); ++it) { + list.push_back((*it)->mName); + } + } + + ESM::Cell *insert(const ESM::Cell &cell) { + if (search(cell) != 0) { + std::ostringstream msg; + msg << "Failed to create "; + msg << ((cell.isExterior()) ? "exterior" : "interior"); + msg << " cell"; + + throw std::runtime_error(msg.str()); + } + ESM::Cell *ptr; + if (cell.isExterior()) { + std::pair key(cell.getGridX(), cell.getGridY()); + + // duplicate insertions are avoided by search(ESM::Cell &) + std::pair result = + mDynamicExt.insert(std::make_pair(key, cell)); + + ptr = &result.first->second; + mSharedExt.push_back(ptr); + } else { + std::string key = Misc::StringUtils::lowerCase(cell.mName); + + // duplicate insertions are avoided by search(ESM::Cell &) + std::pair result = + mDynamicInt.insert(std::make_pair(key, cell)); + + ptr = &result.first->second; + mSharedInt.push_back(ptr); + } + return ptr; + } + + bool erase(const ESM::Cell &cell) { + if (cell.isExterior()) { + return erase(cell.getGridX(), cell.getGridY()); + } + return erase(cell.mName); + } + + bool erase(const std::string &id) { + std::string key = Misc::StringUtils::lowerCase(id); + DynamicInt::iterator it = mDynamicInt.find(key); + + if (it == mDynamicInt.end()) { + return false; + } + mDynamicInt.erase(it); + mSharedInt.erase( + mSharedInt.begin() + mSharedInt.size(), + mSharedInt.end() + ); + + for (it = mDynamicInt.begin(); it != mDynamicInt.end(); ++it) { + mSharedInt.push_back(&it->second); + } + + return true; + } + + bool erase(int x, int y) { + std::pair key(x, y); + DynamicExt::iterator it = mDynamicExt.find(key); + + if (it == mDynamicExt.end()) { + return false; + } + mDynamicExt.erase(it); + mSharedExt.erase( + mSharedExt.begin() + mSharedExt.size(), + mSharedExt.end() + ); + + for (it = mDynamicExt.begin(); it != mDynamicExt.end(); ++it) { + mSharedExt.push_back(&it->second); + } + + return true; + } + }; + + template <> + class Store : public StoreBase + { + public: + typedef std::vector::const_iterator iterator; + + private: + std::vector mStatic; + + std::vector::iterator mIntBegin, mIntEnd, mExtBegin, mExtEnd; + + struct IntExtOrdering + { + bool operator()(const ESM::Pathgrid &x, const ESM::Pathgrid &y) const { + // interior pathgrids precedes exterior ones (x < y) + if ((x.mData.mX == 0 && x.mData.mY == 0) && + (y.mData.mX != 0 || y.mData.mY != 0)) + { + return true; + } + return false; + } + }; + + struct ExtCompare + { + bool operator()(const ESM::Pathgrid &x, const ESM::Pathgrid &y) const { + if (x.mData.mX == y.mData.mX) { + return x.mData.mY < y.mData.mY; + } + return x.mData.mX < y.mData.mX; + } + }; + + public: + + void load(ESM::ESMReader &esm, const std::string &id) { + mStatic.push_back(ESM::Pathgrid()); + mStatic.back().load(esm); + } + + int getSize() const { + return mStatic.size(); + } + + void setUp() { + IntExtOrdering cmp; + std::sort(mStatic.begin(), mStatic.end(), cmp); + + ESM::Pathgrid pg; + pg.mData.mX = pg.mData.mY = 1; + mExtBegin = + std::lower_bound(mStatic.begin(), mStatic.end(), pg, cmp); + mExtEnd = mStatic.end(); + + mIntBegin = mStatic.begin(); + mIntEnd = mExtBegin; + + std::sort(mIntBegin, mIntEnd, RecordCmp()); + std::sort(mExtBegin, mExtEnd, ExtCompare()); + } + + const ESM::Pathgrid *search(int x, int y) const { + ESM::Pathgrid pg; + pg.mData.mX = x; + pg.mData.mY = y; + + iterator it = + std::lower_bound(mExtBegin, mExtEnd, pg, ExtCompare()); + if (it != mExtEnd && it->mData.mX == x && it->mData.mY == y) { + return &(*it); + } + return 0; + } + + const ESM::Pathgrid *find(int x, int y) const { + const ESM::Pathgrid *ptr = search(x, y); + if (ptr == 0) { + std::ostringstream msg; + msg << "Pathgrid at (" << x << ", " << y << ") not found"; + throw std::runtime_error(msg.str()); + } + return ptr; + } + + const ESM::Pathgrid *search(const std::string &name) const { + ESM::Pathgrid pg; + pg.mCell = name; + + iterator it = std::lower_bound(mIntBegin, mIntEnd, pg, RecordCmp()); + if (it != mIntEnd && Misc::StringUtils::ciEqual(it->mCell, name)) { + return &(*it); + } + return 0; + } + + const ESM::Pathgrid *find(const std::string &name) const { + const ESM::Pathgrid *ptr = search(name); + if (ptr == 0) { + std::ostringstream msg; + msg << "Pathgrid in cell '" << name << "' not found"; + throw std::runtime_error(msg.str()); + } + return ptr; + } + + const ESM::Pathgrid *search(const ESM::Cell &cell) const { + if (cell.mData.mFlags & ESM::Cell::Interior) { + return search(cell.mName); + } + return search(cell.mData.mX, cell.mData.mY); + } + + const ESM::Pathgrid *find(const ESM::Cell &cell) const { + if (cell.mData.mFlags & ESM::Cell::Interior) { + return find(cell.mName); + } + return find(cell.mData.mX, cell.mData.mY); + } + + iterator begin() const { + return mStatic.begin(); + } + + iterator end() const { + return mStatic.end(); + } + + iterator interiorPathsBegin() const { + return mIntBegin; + } + + iterator interiorPathsEnd() const { + return mIntEnd; + } + + iterator exteriorPathsBegin() const { + return mExtBegin; + } + + iterator exteriorPathsEnd() const { + return mExtEnd; + } + }; + + template + class IndexedStore + { + struct Compare + { + bool operator()(const T &x, const T &y) const { + return x.mIndex < y.mIndex; + } + }; + protected: + std::vector mStatic; + + public: + typedef typename std::vector::const_iterator iterator; + + IndexedStore() {} + + IndexedStore(unsigned int size) { + mStatic.reserve(size); + } + + iterator begin() const { + return mStatic.begin(); + } + + iterator end() const { + return mStatic.end(); + } + + /// \todo refine loading order + void load(ESM::ESMReader &esm) { + mStatic.push_back(T()); + mStatic.back().load(esm); + } + + int getSize() const { + return mStatic.size(); + } + + void setUp() { + std::sort(mStatic.begin(), mStatic.end(), Compare()); + } + + const T *search(int index) const { + T item; + item.mIndex = index; + + iterator it = + std::lower_bound(mStatic.begin(), mStatic.end(), item, Compare()); + if (it != mStatic.end() && it->mIndex == index) { + return &(*it); + } + return 0; + } + + const T *find(int index) const { + const T *ptr = search(index); + if (ptr == 0) { + std::ostringstream msg; + msg << "Object with index " << index << " not found"; + throw std::runtime_error(msg.str()); + } + return ptr; + } + }; + + template <> + struct Store : public IndexedStore + { + Store() {} + Store(unsigned int size) + : IndexedStore(size) + {} + }; + + template <> + struct Store : public IndexedStore + { + Store() {} + Store(unsigned int size) + : IndexedStore(size) + {} + }; + + template <> + class Store : public IndexedStore + { + std::vector mStatic; + + public: + typedef std::vector::const_iterator iterator; + + Store() { + mStatic.reserve(ESM::Attribute::Length); + } + + const ESM::Attribute *search(size_t index) const { + if (index >= mStatic.size()) { + return 0; + } + return &mStatic.at(index); + } + + const ESM::Attribute *find(size_t index) const { + const ESM::Attribute *ptr = search(index); + if (ptr == 0) { + std::ostringstream msg; + msg << "Attribute with index " << index << " not found"; + throw std::runtime_error(msg.str()); + } + return ptr; + } + + void setUp() { + for (int i = 0; i < ESM::Attribute::Length; ++i) { + mStatic.push_back( + ESM::Attribute( + ESM::Attribute::sAttributeIds[i], + ESM::Attribute::sGmstAttributeIds[i], + ESM::Attribute::sGmstAttributeDescIds[i] + ) + ); + } + } + + int getSize() const { + return mStatic.size(); + } + + iterator begin() const { + return mStatic.begin(); + } + + iterator end() const { + return mStatic.end(); + } + }; + +} //end namespace + +#endif diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 391b34a84..009b325c0 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -5,8 +5,6 @@ #include -#include - #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/soundmanager.hpp" @@ -14,6 +12,7 @@ #include "../mwrender/renderingmanager.hpp" #include "player.hpp" +#include "esmstore.hpp" using namespace Ogre; using namespace MWWorld; @@ -497,7 +496,7 @@ void WeatherManager::update(float duration) if (exterior) { - std::string regionstr = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell()->cell->mRegion; + std::string regionstr = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell()->mCell->mRegion; boost::algorithm::to_lower(regionstr); if (mWeatherUpdateTime <= 0 || regionstr != mCurrentRegion) @@ -512,7 +511,8 @@ void WeatherManager::update(float duration) else { // get weather probabilities for the current region - const ESM::Region *region = MWBase::Environment::get().getWorld()->getStore().regions.search (regionstr); + const ESM::Region *region = + MWBase::Environment::get().getWorld()->getStore().get().search (regionstr); if (region != 0) { diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index fe8aeb90b..5e7a19caa 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -11,6 +11,8 @@ #include "../mwrender/sky.hpp" #include "../mwrender/player.hpp" +#include "../mwclass/door.hpp" + #include "player.hpp" #include "manualref.hpp" #include "cellfunctors.hpp" @@ -19,34 +21,37 @@ using namespace Ogre; namespace { +/* // NOTE this code is never instantiated (proper copy in localscripts.cpp), + // so this commented out to not produce syntactic errors + template - void listCellScripts (const ESMS::ESMStore& store, + void listCellScripts (const MWWorld::ESMStore& store, MWWorld::CellRefList& cellRefList, MWWorld::LocalScripts& localScripts, MWWorld::Ptr::CellStore *cell) { for (typename MWWorld::CellRefList::List::iterator iter ( - cellRefList.list.begin()); - iter!=cellRefList.list.end(); ++iter) + cellRefList.mList.begin()); + iter!=cellRefList.mList.end(); ++iter) { - if (!iter->base->script.empty() && iter->mData.getCount()) + if (!iter->mBase->mScript.empty() && iter->mData.getCount()) { - if (const ESM::Script *script = store.scripts.find (iter->base->script)) + if (const ESM::Script *script = store.get().find (iter->mBase->mScript)) { iter->mData.setLocals (*script); - localScripts.add (iter->base->script, MWWorld::Ptr (&*iter, cell)); + localScripts.add (iter->mBase->mScript, MWWorld::Ptr (&*iter, cell)); } } } } - +*/ template MWWorld::LiveCellRef *searchViaHandle (const std::string& handle, MWWorld::CellRefList& refList) { typedef typename MWWorld::CellRefList::List::iterator iterator; - for (iterator iter (refList.list.begin()); iter!=refList.list.end(); ++iter) + for (iterator iter (refList.mList.begin()); iter!=refList.mList.end(); ++iter) { if(iter->mData.getCount() > 0 && iter->mData.getBaseNode()){ if (iter->mData.getHandle()==handle) @@ -64,44 +69,44 @@ namespace MWWorld Ptr World::getPtrViaHandle (const std::string& handle, Ptr::CellStore& cell) { if (MWWorld::LiveCellRef *ref = - searchViaHandle (handle, cell.activators)) + searchViaHandle (handle, cell.mActivators)) return Ptr (ref, &cell); - if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.potions)) + if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.mPotions)) return Ptr (ref, &cell); - if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.appas)) + if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.mAppas)) return Ptr (ref, &cell); - if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.armors)) + if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.mArmors)) return Ptr (ref, &cell); - if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.books)) + if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.mBooks)) return Ptr (ref, &cell); - if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.clothes)) + if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.mClothes)) return Ptr (ref, &cell); if (MWWorld::LiveCellRef *ref = - searchViaHandle (handle, cell.containers)) + searchViaHandle (handle, cell.mContainers)) return Ptr (ref, &cell); if (MWWorld::LiveCellRef *ref = - searchViaHandle (handle, cell.creatures)) + searchViaHandle (handle, cell.mCreatures)) return Ptr (ref, &cell); - if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.doors)) + if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.mDoors)) return Ptr (ref, &cell); if (MWWorld::LiveCellRef *ref = - searchViaHandle (handle, cell.ingreds)) + searchViaHandle (handle, cell.mIngreds)) return Ptr (ref, &cell); - if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.lights)) + if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.mLights)) return Ptr (ref, &cell); - if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.lockpicks)) + if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.mLockpicks)) return Ptr (ref, &cell); - if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.miscItems)) + if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.mMiscItems)) return Ptr (ref, &cell); - if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.npcs)) + if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.mNpcs)) return Ptr (ref, &cell); - if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.probes)) + if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.mProbes)) return Ptr (ref, &cell); - if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.repairs)) + if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.mRepairs)) return Ptr (ref, &cell); - if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.statics)) + if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.mStatics)) return Ptr (ref, &cell); - if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.weapons)) + if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.mWeapons)) return Ptr (ref, &cell); return Ptr(); } @@ -165,9 +170,9 @@ namespace MWWorld World::World (OEngine::Render::OgreRenderer& renderer, const Files::Collections& fileCollections, const std::string& master, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, bool newGame, - const std::string& encoding, std::map fallbackMap) + const ToUTF8::FromType& encoding, std::map fallbackMap) : mPlayer (0), mLocalScripts (mStore), mGlobalVariables (0), - mSky (true), mNextDynamicRecord (0), mCells (mStore, mEsm), + mSky (true), mCells (mStore, mEsm), mNumFacing(0) { mPhysics = new PhysicsSystem(renderer); @@ -186,12 +191,10 @@ namespace MWWorld mEsm.open (masterPath.string()); mStore.load (mEsm); - mPlayer = new MWWorld::Player (mStore.npcs.find ("player"), *this); + mPlayer = new MWWorld::Player (mStore.get().find ("player"), *this); mRendering->attachCameraTo(mPlayer->getPlayer()); - std::string playerCollisionFile = "meshes\\base_anim.nif"; //This is used to make a collision shape for our player - //We will need to support the 1st person file too in the future - mPhysics->addActor (mPlayer->getPlayer().getRefData().getHandle(), playerCollisionFile, Ogre::Vector3 (0, 0, 0), 1, Ogre::Quaternion::ZERO); + mPhysics->addActor(mPlayer->getPlayer()); // global variables mGlobalVariables = new Globals (mStore); @@ -202,6 +205,8 @@ namespace MWWorld mGlobalVariables->setInt ("chargenstate", 1); } + mGlobalVariables->setInt ("pcrace", 3); + mWorldScene = new Scene(*mRendering, mPhysics); setFallbackValues(fallbackMap); @@ -224,21 +229,28 @@ namespace MWWorld const ESM::Cell *World::getExterior (const std::string& cellName) const { // first try named cells - if (const ESM::Cell *cell = mStore.cells.searchExtByName (cellName)) + const ESM::Cell *cell = mStore.get().searchExtByName (cellName); + if (cell != 0) { return cell; + } // didn't work -> now check for regions +<<<<<<< HEAD std::string cellName2 = Misc::toLower (cellName); for (ESMS::RecListT::MapType::const_iterator iter (mStore.regions.list.begin()); iter!=mStore.regions.list.end(); ++iter) { if (Misc::toLower (iter->second.mName)==cellName2) +======= + const MWWorld::Store ®ions = mStore.get(); + MWWorld::Store::iterator it = regions.begin(); + for (; it != regions.end(); ++it) + { + if (Misc::StringUtils::ciEqual(cellName, it->mName)) +>>>>>>> 92623921add0d6e16a34973dcf6f2ee1f52dbbe7 { - if (const ESM::Cell *cell = mStore.cells.searchExtByRegion (iter->first)) - return cell; - - break; + return mStore.get().searchExtByRegion(it->mId); } } @@ -260,7 +272,7 @@ namespace MWWorld return *mPlayer; } - const ESMS::ESMStore& World::getStore() const + const MWWorld::ESMStore& World::getStore() const { return mStore; } @@ -295,6 +307,49 @@ namespace MWWorld return mGlobalVariables->getType (name); } + std::vector World::getGlobals () const + { + return mGlobalVariables->getGlobals(); + } + + std::string World::getCurrentCellName () const + { + std::string name; + + Ptr::CellStore *cell = mWorldScene->getCurrentCell(); + if (cell->mCell->isExterior()) + { + if (cell->mCell->mName != "") + { + name = cell->mCell->mName; + } + else + { + const ESM::Region* region = + MWBase::Environment::get().getWorld()->getStore().get().search(cell->mCell->mRegion); + if (region) + name = region->mName; + else + { + const ESM::GameSetting *setting = + MWBase::Environment::get().getWorld()->getStore().get().search("sDefaultCellname"); + + if (setting && setting->mType == ESM::VT_String) + name = setting->getString(); + else + name = "Wilderness"; + } + + } + } + else + { + name = cell->mCell->mName; + } + + return name; + } + Ptr World::getPtr (const std::string& name, bool activeOnly) { // the player is always in an active cell. @@ -407,15 +462,15 @@ namespace MWWorld void World::setDay (int day) { - if (day<0) - day = 0; + if (day<1) + day = 1; int month = mGlobalVariables->getInt ("month"); while (true) { int days = getDaysPerMonth (month); - if (dayskySetDate (day, month); mWeatherManager->setDate (day, month); - - } void World::setMonth (int month) @@ -451,8 +504,8 @@ namespace MWWorld int days = getDaysPerMonth (month); - if (mGlobalVariables->getInt ("day")>=days) - mGlobalVariables->setInt ("day", days-1); + if (mGlobalVariables->getInt ("day")>days) + mGlobalVariables->setInt ("day", days); mGlobalVariables->setInt ("month", month); @@ -536,7 +589,7 @@ namespace MWWorld std::pair result = mPhysics->getFacedHandle (*this); if (result.first.empty() || - result.second>getStore().gameSettings.find ("iMaxActivateDist")->getInt()) + result.second>getStore().get().find ("iMaxActivateDist")->getInt()) return ""; return result.first; @@ -572,6 +625,7 @@ namespace MWWorld CellStore *currCell = ptr.getCell(); bool isPlayer = ptr == mPlayer->getPlayer(); bool haveToMove = mWorldScene->isCellActive(*currCell) || isPlayer; +<<<<<<< HEAD if (*currCell != newCell) { if (isPlayer) { if (!newCell.isExterior()) { @@ -579,32 +633,51 @@ namespace MWWorld } else { int cellX = newCell.cell->mData.mX; int cellY = newCell.cell->mData.mY; +======= + + if (*currCell != newCell) + { + if (isPlayer) + if (!newCell.isExterior()) + changeToInteriorCell(toLower(newCell.mCell->mName), pos); + else + { + int cellX = newCell.mCell->getGridX(); + int cellY = newCell.mCell->getGridY(); +>>>>>>> 92623921add0d6e16a34973dcf6f2ee1f52dbbe7 mWorldScene->changeCell(cellX, cellY, pos, false); } - } else { - if (!mWorldScene->isCellActive(*currCell)) { + else { + if (!mWorldScene->isCellActive(*currCell)) copyObjectToCell(ptr, newCell, pos); - } else if (!mWorldScene->isCellActive(newCell)) { + else if (!mWorldScene->isCellActive(newCell)) + { MWWorld::Class::get(ptr).copyToCell(ptr, newCell); mWorldScene->removeObjectFromScene(ptr); mLocalScripts.remove(ptr); haveToMove = false; - } else { + } + else + { MWWorld::Ptr copy = MWWorld::Class::get(ptr).copyToCell(ptr, newCell); mRendering->moveObjectToCell(copy, vec, currCell); - if (MWWorld::Class::get(ptr).isActor()) { + if (MWWorld::Class::get(ptr).isActor()) + { MWBase::MechanicsManager *mechMgr = MWBase::Environment::get().getMechanicsManager(); mechMgr->removeActor(ptr); mechMgr->addActor(copy); - } else { + } + else + { std::string script = MWWorld::Class::get(ptr).getScript(ptr); - if (!script.empty()) { + if (!script.empty()) + { mLocalScripts.remove(ptr); mLocalScripts.add(script, copy); } @@ -613,9 +686,10 @@ namespace MWWorld ptr.getRefData().setCount(0); } } - if (haveToMove) { + if (haveToMove) + { mRendering->moveObject(ptr, vec); - mPhysics->moveObject (ptr.getRefData().getHandle(), ptr.getRefData().getBaseNode()); + mPhysics->moveObject (ptr); } } @@ -636,18 +710,17 @@ namespace MWWorld void World::moveObject (const Ptr& ptr, float x, float y, float z) { moveObjectImp(ptr, x, y, z); - - } void World::scaleObject (const Ptr& ptr, float scale) { MWWorld::Class::get(ptr).adjustScale(ptr,scale); - ptr.getCellRef().mScale = scale; - //scale = scale/ptr.getRefData().getBaseNode()->getScale().x; - ptr.getRefData().getBaseNode()->setScale(scale,scale,scale); - mPhysics->scaleObject( ptr.getRefData().getHandle(), ptr.getRefData().getBaseNode()); + + if(ptr.getRefData().getBaseNode() == 0) + return; + mRendering->scaleObject(ptr, Vector3(scale,scale,scale)); + mPhysics->scaleObject(ptr); } void World::rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust) @@ -656,20 +729,17 @@ namespace MWWorld rot.x = Ogre::Degree(x).valueRadians(); rot.y = Ogre::Degree(y).valueRadians(); rot.z = Ogre::Degree(z).valueRadians(); - - if (mRendering->rotateObject(ptr, rot, adjust)) { - float *objRot = ptr.getRefData().getPosition().rot; - objRot[0] = rot.x, objRot[1] = rot.y, objRot[2] = rot.z; + float *objRot = ptr.getRefData().getPosition().rot; + if(ptr.getRefData().getBaseNode() == 0 || !mRendering->rotateObject(ptr, rot, adjust)) + { + objRot[0] = (adjust ? objRot[0] + rot.x : rot.x), objRot[1] = (adjust ? objRot[1] + rot.y : rot.y), objRot[2] = (adjust ? objRot[2] + rot.z : rot.z); + return; + } - if (ptr.getRefData().getBaseNode() != 0) { - mPhysics->rotateObject( - ptr.getRefData().getHandle(), - ptr.getRefData().getBaseNode() - ); - } - } - + // do this after rendering rotated the object so it gets changed by Class->adjustRotation + objRot[0] = rot.x, objRot[1] = rot.y, objRot[2] = rot.z; + mPhysics->rotateObject(ptr); } void World::safePlaceObject(const MWWorld::Ptr& ptr,MWWorld::CellStore &Cell,ESM::Position pos) @@ -765,76 +835,59 @@ namespace MWWorld return mRendering->toggleRenderMode (mode); } - std::pair World::createRecord (const ESM::Potion& record) + const ESM::Potion *World::createRecord (const ESM::Potion& record) { - /// \todo Rewrite the ESMStore so that a dynamic 2nd ESMStore can be attached to it. - /// This function should then insert the record into the 2nd store (the code for this - /// should also be moved to the ESMStore class). It might be a good idea to review - /// the STL-container usage of the ESMStore before the rewrite. - - std::ostringstream stream; - stream << "$dynamic" << mNextDynamicRecord++; - - ESM::Potion record2 (record); - record2.mId = stream.str(); - - const ESM::Potion *created = - &mStore.potions.list.insert (std::make_pair (stream.str(), record2)).first->second; - - mStore.all.insert (std::make_pair (stream.str(), ESM::REC_ALCH)); - - return std::make_pair (stream.str(), created); + return mStore.insert(record); } - std::pair World::createRecord (const ESM::Class& record) + const ESM::Class *World::createRecord (const ESM::Class& record) { - /// \todo See function above. - std::ostringstream stream; - stream << "$dynamic" << mNextDynamicRecord++; - - const ESM::Class *created = - &mStore.classes.list.insert (std::make_pair (stream.str(), record)).first->second; - - mStore.all.insert (std::make_pair (stream.str(), ESM::REC_CLAS)); - - return std::make_pair (stream.str(), created); + return mStore.insert(record); } - std::pair World::createRecord (const ESM::Spell& record) + const ESM::Spell *World::createRecord (const ESM::Spell& record) { - /// \todo See function above. - std::ostringstream stream; - stream << "$dynamic" << mNextDynamicRecord++; - - const ESM::Spell *created = - &mStore.spells.list.insert (std::make_pair (stream.str(), record)).first->second; - - mStore.all.insert (std::make_pair (stream.str(), ESM::REC_SPEL)); - - return std::make_pair (stream.str(), created); + return mStore.insert(record); } const ESM::Cell *World::createRecord (const ESM::Cell& record) { - if (record.mData.mFlags & ESM::Cell::Interior) - { - if (mStore.cells.searchInt (record.mName)) - throw std::runtime_error ("failed creating interior cell"); + return mStore.insert(record); + } - ESM::Cell *cell = new ESM::Cell (record); - mStore.cells.intCells.insert (std::make_pair (record.mName, cell)); - return cell; - } - else - { - if (mStore.cells.searchExt (record.mData.mX, record.mData.mY)) - throw std::runtime_error ("failed creating exterior cell"); + const ESM::NPC *World::createRecord(const ESM::NPC &record) + { + bool update = false; - ESM::Cell *cell = new ESM::Cell (record); - mStore.cells.extCells.insert ( - std::make_pair (std::make_pair (record.mData.mX, record.mData.mY), cell)); - return cell; + if (Misc::StringUtils::ciEqual(record.mId, "player")) + { + static const char *sRaces[] = + { + "Argonian", "Breton", "Dark Elf", "High Elf", "Imperial", "Khajiit", "Nord", "Orc", "Redguard", + "Woodelf", 0 + }; + + int i=0; + + for (; sRaces[i]; ++i) + if (Misc::StringUtils::ciEqual (sRaces[i], record.mRace)) + break; + + mGlobalVariables->setInt ("pcrace", sRaces[i] ? i+1 : 0); + + const ESM::NPC *player = + mPlayer->getPlayer().get()->mBase; + + update = record.isMale() != player->isMale() || + !Misc::StringUtils::ciEqual(record.mRace, player->mRace) || + !Misc::StringUtils::ciEqual(record.mHead, player->mHead) || + !Misc::StringUtils::ciEqual(record.mHair, player->mHair); } + const ESM::NPC *ret = mStore.insert(record); + if (update) { + mRendering->renderPlayer(mPlayer->getPlayer()); + } + return ret; } void World::playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode, @@ -848,12 +901,12 @@ namespace MWWorld mRendering->skipAnimation (ptr); } - void World::update (float duration) + void World::update (float duration, bool paused) { /// \todo split this function up into subfunctions - mWorldScene->update (duration); - + mWorldScene->update (duration, paused); + float pitch, yaw; Ogre::Vector3 eyepos; mRendering->getPlayerData(eyepos, pitch, yaw); @@ -1023,10 +1076,7 @@ namespace MWWorld Ptr::CellStore *currentCell = mWorldScene->getCurrentCell(); if (currentCell) { - if (!(currentCell->cell->mData.mFlags & ESM::Cell::Interior)) - return true; - else - return false; + return currentCell->mCell->isExterior(); } return false; } @@ -1036,7 +1086,7 @@ namespace MWWorld Ptr::CellStore *currentCell = mWorldScene->getCurrentCell(); if (currentCell) { - if (!(currentCell->cell->mData.mFlags & ESM::Cell::QuasiEx)) + if (!(currentCell->mCell->mData.mFlags & ESM::Cell::QuasiEx)) return false; else return true; @@ -1061,7 +1111,7 @@ namespace MWWorld Ogre::Vector2 World::getNorthVector (CellStore* cell) { - MWWorld::CellRefList& statics = cell->statics; + MWWorld::CellRefList& statics = cell->mStatics; MWWorld::LiveCellRef* ref = statics.find("northmarker"); if (!ref) return Vector2(0, 1); @@ -1075,38 +1125,16 @@ namespace MWWorld { std::vector result; - MWWorld::CellRefList& doors = cell->doors; - std::list< MWWorld::LiveCellRef >& refList = doors.list; + MWWorld::CellRefList& doors = cell->mDoors; + std::list< MWWorld::LiveCellRef >& refList = doors.mList; for (std::list< MWWorld::LiveCellRef >::iterator it = refList.begin(); it != refList.end(); ++it) { MWWorld::LiveCellRef& ref = *it; - if (ref.ref.mTeleport) + if (ref.mRef.mTeleport) { World::DoorMarker newMarker; - - std::string dest; - if (ref.ref.mDestCell != "") - { - // door leads to an interior, use interior name - dest = ref.ref.mDestCell; - } - else - { - // door leads to exterior, use cell name (if any), otherwise translated region name - int x,y; - positionToIndex (ref.ref.mDoorDest.pos[0], ref.ref.mDoorDest.pos[1], x, y); - const ESM::Cell* cell = mStore.cells.findExt(x,y); - if (cell->mName != "") - dest = cell->mName; - else - { - const ESM::Region* region = mStore.regions.search(cell->mRegion); - dest = region->mName; - } - } - - newMarker.name = dest; + newMarker.name = MWClass::Door::getDestination(ref); ESM::Position pos = ref.mData.getPosition (); @@ -1246,7 +1274,7 @@ namespace MWWorld /// \fixme should rely on object height pos.z += 30; - return isUnderwater(*object.getCell()->cell, pos); + return isUnderwater(*object.getCell()->mCell, pos); } bool @@ -1282,10 +1310,10 @@ namespace MWWorld mPhysics->castRay(playerPos, Ogre::Vector3(0,0,-1), 50); bool isOnGround = (hit.first ? (hit.second.distance (playerPos) < 25) : false); - if (!isOnGround || isUnderwater (*currentCell->cell, playerPos)) + if (!isOnGround || isUnderwater (*currentCell->mCell, playerPos)) return 2; - if (currentCell->cell->mData.mFlags & ESM::Cell::NoSleep) + if (currentCell->mCell->mData.mFlags & ESM::Cell::NoSleep) return 1; return 0; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 527a608a6..71ae9597f 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -1,12 +1,11 @@ #ifndef GAME_MWWORLD_WORLDIMP_H #define GAME_MWWORLD_WORLDIMP_H -#include - #include "../mwrender/debugging.hpp" #include "ptr.hpp" #include "scene.hpp" +#include "esmstore.hpp" #include "physicssystem.hpp" #include "cells.hpp" #include "localscripts.hpp" @@ -56,12 +55,11 @@ namespace MWWorld MWWorld::Scene *mWorldScene; MWWorld::Player *mPlayer; ESM::ESMReader mEsm; - ESMS::ESMStore mStore; + MWWorld::ESMStore mStore; LocalScripts mLocalScripts; MWWorld::Globals *mGlobalVariables; MWWorld::PhysicsSystem *mPhysics; bool mSky; - int mNextDynamicRecord; Cells mCells; @@ -97,7 +95,7 @@ namespace MWWorld World (OEngine::Render::OgreRenderer& renderer, const Files::Collections& fileCollections, const std::string& master, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, bool newGame, - const std::string& encoding, std::map fallbackMap); + const ToUTF8::FromType& encoding, std::map fallbackMap); virtual ~World(); @@ -124,7 +122,7 @@ namespace MWWorld virtual Player& getPlayer(); - virtual const ESMS::ESMStore& getStore() const; + virtual const MWWorld::ESMStore& getStore() const; virtual ESM::ESMReader& getEsmReader(); @@ -155,6 +153,10 @@ namespace MWWorld virtual char getGlobalVariableType (const std::string& name) const; ///< Return ' ', if there is no global variable with this name. + + virtual std::vector getGlobals () const; + + virtual std::string getCurrentCellName () const; virtual Ptr getPtr (const std::string& name, bool activeOnly); ///< Return a pointer to a liveCellRef with the given name. @@ -230,7 +232,7 @@ namespace MWWorld virtual void rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust = false); virtual void safePlaceObject(const MWWorld::Ptr& ptr,MWWorld::CellStore &Cell,ESM::Position pos); - ///< place an object in a "safe" location (ie not in the void, etc). Makes a copy of the Ptr. + ///< place an object in a "safe" location (ie not in the void, etc). Makes a copy of the Ptr. virtual void indexToPosition (int cellX, int cellY, float &x, float &y, bool centre = false) const; @@ -252,21 +254,26 @@ namespace MWWorld ///< Toggle a render mode. ///< \return Resulting mode - virtual std::pair createRecord (const ESM::Potion& record); + virtual const ESM::Potion *createRecord (const ESM::Potion& record); ///< Create a new recrod (of type potion) in the ESM store. - /// \return ID, pointer to created record + /// \return pointer to created record - virtual std::pair createRecord (const ESM::Spell& record); + virtual const ESM::Spell *createRecord (const ESM::Spell& record); ///< Create a new recrod (of type spell) in the ESM store. - /// \return ID, pointer to created record + /// \return pointer to created record - virtual std::pair createRecord (const ESM::Class& record); + virtual const ESM::Class *createRecord (const ESM::Class& record); ///< Create a new recrod (of type class) in the ESM store. - /// \return ID, pointer to created record + /// \return pointer to created record virtual const ESM::Cell *createRecord (const ESM::Cell& record); ///< Create a new recrod (of type cell) in the ESM store. - /// \return ID, pointer to created record + /// \return pointer to created record + + virtual const ESM::NPC *createRecord(const ESM::NPC &record); + ///< Create a new recrod (of type npc) in the ESM store. + /// \return pointer to created record + virtual void playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number = 1); @@ -280,7 +287,7 @@ namespace MWWorld ///< Skip the animation for the given MW-reference for one frame. Calls to this function for /// references that are currently not in the rendered scene should be ignored. - virtual void update (float duration); + virtual void update (float duration, bool paused); virtual bool placeObject (const Ptr& object, float cursorX, float cursorY); ///< place an object into the gameworld at the specified cursor position @@ -320,7 +327,7 @@ namespace MWWorld } virtual void renderPlayer(); - + virtual void setupExternalRendering (MWRender::ExternalRendering& rendering); virtual int canRest(); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index c714693c3..f3d5f4aee 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -34,10 +34,6 @@ add_component_dir (file_finder file_finder filename_less search ) -add_component_dir (esm_store - reclists store - ) - add_component_dir (esm attr defs esmcommon esmreader esmwriter loadacti loadalch loadappa loadarmo loadbody loadbook loadbsgn loadcell loadclas loadclot loadcont loadcrea loadcrec loaddial loaddoor loadench loadfact loadglob loadgmst @@ -63,7 +59,11 @@ add_component_dir (compiler add_component_dir (interpreter context controlopcodes genericopcodes installopcodes interpreter localopcodes mathopcodes - miscopcodes opcodes runtime scriptopcodes spatialopcodes types + miscopcodes opcodes runtime scriptopcodes spatialopcodes types defines + ) + +add_component_dir (translation + translation ) include_directories(${BULLET_INCLUDE_DIRS}) diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index 2915a1ce7..580e006df 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -347,21 +347,9 @@ void ESMReader::fail(const std::string &msg) throw std::runtime_error(ss.str()); } -void ESMReader::setEncoding(const std::string& encoding) +void ESMReader::setEncoding(const ToUTF8::FromType& encoding) { - if (encoding == "win1250") - { - mEncoding = ToUTF8::WINDOWS_1250; - } - else if (encoding == "win1251") - { - mEncoding = ToUTF8::WINDOWS_1251; - } - else - { - // Default Latin encoding - mEncoding = ToUTF8::WINDOWS_1252; - } + mEncoding = encoding; } } diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index 6a74c53e8..1d0f6f580 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -234,7 +234,7 @@ public: void fail(const std::string &msg); /// Sets font encoding for ESM strings - void setEncoding(const std::string& encoding); + void setEncoding(const ToUTF8::FromType& encoding); private: Ogre::DataStreamPtr mEsm; diff --git a/components/esm/loadacti.hpp b/components/esm/loadacti.hpp index 86c2f44c4..8cb335feb 100644 --- a/components/esm/loadacti.hpp +++ b/components/esm/loadacti.hpp @@ -11,7 +11,7 @@ class ESMWriter; struct Activator { - std::string mName, mScript, mModel; + std::string mId, mName, mScript, mModel; void load(ESMReader &esm); void save(ESMWriter &esm); diff --git a/components/esm/loadappa.hpp b/components/esm/loadappa.hpp index 101c39f41..486a559f8 100644 --- a/components/esm/loadappa.hpp +++ b/components/esm/loadappa.hpp @@ -32,7 +32,7 @@ struct Apparatus }; AADTstruct mData; - std::string mModel, mIcon, mScript, mName; + std::string mId, mModel, mIcon, mScript, mName; void load(ESMReader &esm); void save(ESMWriter &esm); diff --git a/components/esm/loadarmo.hpp b/components/esm/loadarmo.hpp index 57c9ccf12..a94ae6735 100644 --- a/components/esm/loadarmo.hpp +++ b/components/esm/loadarmo.hpp @@ -84,7 +84,7 @@ struct Armor AODTstruct mData; PartReferenceList mParts; - std::string mName, mModel, mIcon, mScript, mEnchant; + std::string mId, mName, mModel, mIcon, mScript, mEnchant; void load(ESMReader &esm); void save(ESMWriter &esm); diff --git a/components/esm/loadbody.hpp b/components/esm/loadbody.hpp index 8a05d9924..c91bb40bf 100644 --- a/components/esm/loadbody.hpp +++ b/components/esm/loadbody.hpp @@ -52,7 +52,7 @@ struct BodyPart }; BYDTstruct mData; - std::string mModel, mName; + std::string mId, mModel, mName; void load(ESMReader &esm); void save(ESMWriter &esm); diff --git a/components/esm/loadbsgn.hpp b/components/esm/loadbsgn.hpp index ac4050878..b0bc28be4 100644 --- a/components/esm/loadbsgn.hpp +++ b/components/esm/loadbsgn.hpp @@ -13,7 +13,7 @@ class ESMWriter; struct BirthSign { - std::string mName, mDescription, mTexture; + std::string mId, mName, mDescription, mTexture; // List of powers and abilities that come with this birth sign. SpellList mPowers; diff --git a/components/esm/loadclas.hpp b/components/esm/loadclas.hpp index 0311002b8..264e342e6 100644 --- a/components/esm/loadclas.hpp +++ b/components/esm/loadclas.hpp @@ -60,7 +60,7 @@ struct Class int mCalc; }; // 60 bytes - std::string mName, mDescription; + std::string mId, mName, mDescription; CLDTstruct mData; void load(ESMReader &esm); diff --git a/components/esm/loadclot.hpp b/components/esm/loadclot.hpp index df64c87d3..623983ccf 100644 --- a/components/esm/loadclot.hpp +++ b/components/esm/loadclot.hpp @@ -42,7 +42,7 @@ struct Clothing PartReferenceList mParts; - std::string mName, mModel, mIcon, mEnchant, mScript; + std::string mId, mName, mModel, mIcon, mEnchant, mScript; void load(ESMReader &esm); void save(ESMWriter &esm); diff --git a/components/esm/loadcont.hpp b/components/esm/loadcont.hpp index eb1f64d6f..b66ca086d 100644 --- a/components/esm/loadcont.hpp +++ b/components/esm/loadcont.hpp @@ -39,7 +39,7 @@ struct Container Unknown = 8 }; - std::string mName, mModel, mScript; + std::string mId, mName, mModel, mScript; float mWeight; // Not sure, might be max total weight allowed? int mFlags; diff --git a/components/esm/loadcrec.hpp b/components/esm/loadcrec.hpp index a95656f63..6904df15a 100644 --- a/components/esm/loadcrec.hpp +++ b/components/esm/loadcrec.hpp @@ -1,6 +1,8 @@ #ifndef OPENMW_ESM_CREC_H #define OPENMW_ESM_CREC_H +#include + // TODO create implementation files and remove this one #include "esmreader.hpp" @@ -15,6 +17,8 @@ class ESMWriter; /// Changes a creature struct LoadCREC { + std::string mId; + void load(ESMReader &esm) { esm.skipRecord(); @@ -28,6 +32,8 @@ struct LoadCREC /// Changes an item list / container struct LoadCNTC { + std::string mId; + void load(ESMReader &esm) { esm.skipRecord(); diff --git a/components/esm/loaddoor.hpp b/components/esm/loaddoor.hpp index 5c0af52e4..e992a592f 100644 --- a/components/esm/loaddoor.hpp +++ b/components/esm/loaddoor.hpp @@ -11,7 +11,7 @@ class ESMWriter; struct Door { - std::string mName, mModel, mScript, mOpenSound, mCloseSound; + std::string mId, mName, mModel, mScript, mOpenSound, mCloseSound; void load(ESMReader &esm); void save(ESMWriter &esm); diff --git a/components/esm/loadench.hpp b/components/esm/loadench.hpp index d89549322..999f93ad9 100644 --- a/components/esm/loadench.hpp +++ b/components/esm/loadench.hpp @@ -1,6 +1,8 @@ #ifndef OPENMW_ESM_ENCH_H #define OPENMW_ESM_ENCH_H +#include + #include "effectlist.hpp" namespace ESM @@ -32,6 +34,7 @@ struct Enchantment // calculate }; + std::string mId; ENDTstruct mData; EffectList mEffects; diff --git a/components/esm/loadglob.cpp b/components/esm/loadglob.cpp index 39c07fb31..ceaa86948 100644 --- a/components/esm/loadglob.cpp +++ b/components/esm/loadglob.cpp @@ -44,4 +44,14 @@ void Global::save(ESMWriter &esm) esm.writeHNT("FLTV", mValue); } + void Global::blank() + { + mValue = 0; + mType = VT_Float; + } + + bool operator== (const Global& left, const Global& right) + { + return left.mId==right.mId && left.mValue==right.mValue && left.mType==right.mType; + } } diff --git a/components/esm/loadglob.hpp b/components/esm/loadglob.hpp index b85af74bc..6111648a6 100644 --- a/components/esm/loadglob.hpp +++ b/components/esm/loadglob.hpp @@ -1,6 +1,8 @@ #ifndef OPENMW_ESM_GLOB_H #define OPENMW_ESM_GLOB_H +#include + #include "defs.hpp" namespace ESM @@ -15,11 +17,18 @@ class ESMWriter; struct Global { - unsigned mValue; + std::string mId; + float mValue; VarType mType; void load(ESMReader &esm); void save(ESMWriter &esm); + + void blank(); + ///< Set record to default state (does not touch the ID). }; + +bool operator== (const Global& left, const Global& right); + } #endif diff --git a/components/esm/loadgmst.cpp b/components/esm/loadgmst.cpp index dcc500125..a73095a66 100644 --- a/components/esm/loadgmst.cpp +++ b/components/esm/loadgmst.cpp @@ -8,136 +8,10 @@ namespace ESM { -/// \todo Review GMST "fixing". Probably remove completely or at least make it optional. Its definitely not -/// working properly in its current state and I doubt it can be fixed without breaking other stuff. - -// Some handy macros -#define cI(s,x) { if(mId == (s)) return (mI == (x)); } -#define cF(s,x) { if(mId == (s)) return (mF == (x)); } -#define cS(s,x) { if(mId == (s)) return (mStr == (x)); } - -bool GameSetting::isDirtyTribunal() -{ - /* - Here, mId contains the game setting name, and we check the - setting for certain values. If it matches, this is a "mDirty" - entry. The correct entry (as defined in Tribunal and Bloodmoon - esms) are given in the comments. Many of the values are correct, - and are marked as 'same'. We still ignore them though, as they - are still in the wrong file and might override custom values - from other mods. - */ - - // Strings - cS("sProfitValue", "Profit Value"); // 'Profit:' - cS("sEditNote", "Edit Note"); // same - cS("sDeleteNote", "Delete Note?"); // same - cS("sMaxSale", "Max Sale"); // 'Seller Max' - cS("sMagicFabricantID", "Fabricant"); // 'Fabricant_summon' - cS("sTeleportDisabled", - "Teleportation magic does not work here.");// same - cS("sLevitateDisabled", - "Levitation magic does not work here."); // same - cS("sCompanionShare", "Companion Share"); // 'Share' - cS("sCompanionWarningButtonOne", - "Let the mercenary quit."); // same - cS("sCompanionWarningButtonTwo", - "Return to Companion Share display."); // same - cS("sCompanionWarningMessage", - "Your mercenary is poorer now than when he contracted with you. Your mercenary will quit if you do not give him gold or goods to bring his Profit Value to a positive value."); - // 'Your mercenary is poorer now than when he contracted with - // you. Your mercenary will quit if you do not give him gold - // or goods to bring his Profit to a positive value.' - // [The difference here is "Profit Value" -> "Profit"] - - // Strings that matches the mId - cS("sEffectSummonFabricant", mId);// 'Summon Fabricant' - return false; -} - -// Bloodmoon variant -bool GameSetting::isDirtyBloodmoon() -{ - // Strings - cS("sWerewolfPopup", "Werewolf"); // same - cS("sWerewolfRestMessage", - "You cannot rest in werewolf form."); // same - cS("sWerewolfRefusal", - "You cannot do this as a werewolf."); // same - cS("sWerewolfAlarmMessage", - "You have been detected changing from a werewolf state."); - // 'You have been detected as a known werewolf.' - - // Strings that matches the mId - cS("sMagicCreature01ID", mId); // 'BM_wolf_grey_summon' - cS("sMagicCreature02ID", mId); // 'BM_bear_black_summon' - cS("sMagicCreature03ID", mId); // 'BM_wolf_bone_summon' - cS("sMagicCreature04ID", mId); // same - cS("sMagicCreature05ID", mId); // same - cS("sEffectSummonCreature01", mId); // 'Calf Wolf' - cS("sEffectSummonCreature02", mId); // 'Calf Bear' - cS("sEffectSummonCreature03", mId); // 'Summon Bonewolf' - cS("sEffectSummonCreature04", mId); // same - cS("sEffectSummonCreature05", mId); // same - - // Integers - cI("iWereWolfBounty", 10000); // 1000 - cI("iWereWolfFightMod", 100); // same - cI("iWereWolfFleeMod", 100); // same - cI("iWereWolfLevelToAttack", 20); // same - - // Floats - cF("fFleeDistance", 3000); // same - cF("fCombatDistanceWerewolfMod", 0.3); // same - cF("fWereWolfFatigue", 400); // same - cF("fWereWolfEnchant", 1); // 0 - cF("fWereWolfArmorer", 1); // 0 - cF("fWereWolfBlock", 1); // 0 - cF("fWereWolfSneak", 1); // 95 - cF("fWereWolfDestruction", 1); // 0 - cF("fWereWolfEndurance", 150); // same - cF("fWereWolfConjuration", 1); // 0 - cF("fWereWolfRestoration", 1); // 0 - cF("fWereWolfAthletics", 150); // 50 - cF("fWereWolfLuck", 1); // 25 - cF("fWereWolfSilverWeaponDamageMult", 1.5); // 2 - cF("fWereWolfMediumArmor", 1); // 0 - cF("fWereWolfShortBlade", 1); // 0 - cF("fWereWolfAcrobatics", 150); // 80 - cF("fWereWolfSpeechcraft", 1); // 0 - cF("fWereWolfAlteration", 1); // 0 - cF("fWereWolfIllusion", 1); // 0 - cF("fWereWolfLongBlade", 1); // 0 - cF("fWereWolfMarksman", 1); // 0 - cF("fWereWolfHandtoHand", 100); // same - cF("fWereWolfIntellegence", 1); // 0 - cF("fWereWolfAlchemy", 1); // 0 - cF("fWereWolfUnarmored", 100); // same - cF("fWereWolfAxe", 1); // 0 - cF("fWereWolfRunMult", 1.5); // 1.3 - cF("fWereWolfMagicka", 100); // same - cF("fWereWolfAgility", 150); // same - cF("fWereWolfBluntWeapon", 1); // 0 - cF("fWereWolfSecurity", 1); // 0 - cF("fWereWolfPersonality", 1); // 0 - cF("fWereWolfMerchantile", 1); // 0 - cF("fWereWolfHeavyArmor", 1); // 0 - cF("fWereWolfSpear", 1); // 0 - cF("fWereWolfStrength", 150); // same - cF("fWereWolfHealth", 2); // same - cF("fWereWolfMysticism", 1); // 0 - cF("fWereWolfLightArmor", 1); // 0 - cF("fWereWolfWillPower", 1); // 0 - cF("fWereWolfSpeed", 150); // 90 - return false; -} - void GameSetting::load(ESMReader &esm) { assert(mId != ""); - mDirty = false; - // We are apparently allowed to be empty if (!esm.hasMoreSubs()) { @@ -165,17 +39,8 @@ void GameSetting::load(ESMReader &esm) } else esm.fail("Unwanted subrecord type"); - - int spf = esm.getSpecial(); - - // Check if this is one of the mDirty values mentioned above. If it - // is, we set the mDirty flag. This will ONLY work if you've set - // the 'id' string correctly before calling load(). - - if ((spf != SF_Tribunal && isDirtyTribunal()) || (spf != SF_Bloodmoon - && isDirtyBloodmoon())) - mDirty = true; } + void GameSetting::save(ESMWriter &esm) { switch(mType) diff --git a/components/esm/loadgmst.hpp b/components/esm/loadgmst.hpp index a3471598c..ab9a9551e 100644 --- a/components/esm/loadgmst.hpp +++ b/components/esm/loadgmst.hpp @@ -25,66 +25,6 @@ struct GameSetting float mF; VarType mType; - // Set to true if this is a 'dirty' entry which should be ignored - bool mDirty; - - /* - These functions check if this game setting is one of the "dirty" - GMST records found in many mods. These are due to a serious bug in - the official TES3 editor. It only occurs in the newer editor - versions that came with Tribunal and Bloodmoon, and only if a - modder tries to make a mod without loading the corresponding - expansion master file. For example, if you have Tribunal installed - and try to make a mod without loading Tribunal.esm, the editor - will insert these GMST records as a replacement for the entries it - cannot find in the ESMs. - - The values of these "dirty" records differ in general from their - values as defined in Tribunal.esm and Bloodmoon.esm, and are - always set to the same "default" values. Most of these values are - nonsensical, ie. changing the "Seller Max" string to "Max Sale", - or change the stats of werewolves to useless values like 1. Some - of them break certain spell effects. - - It is most likely that these values are just leftover values from - an early stage of development that are inserted as default values - by the editor code. They are supposed to be overridden when the - correct esm file is loaded. When it isn't loaded however, you get - stuck with the initial value, and this gets written to every mod - by the editor, for some reason. - - Bethesda themselves have fallen for this bug. If you install both - Tribunal and Bloodmoon, the updated Tribunal.esm will contain the - dirty GMST settings from Bloodmoon, and Bloodmoon.esm will contain - some of the dirty settings from Tribunal. In other words, this bug - affects the game EVEN IF YOU DO NOT USE ANY MODS! - - The guys at Bethesda are well aware of this bug (and many others), - as the mod community and fan base complained about them for a long - time. But unfortunately it was never fixed. - - There are several tools available to help modders remove these - records from their files, but not all modders use them, and they - really shouldn't have to. In this file we choose instead to reject - all the corrupt values at load time. - - These functions checks if the current game setting is one of the - "dirty" ones as described above. TODO: I have not checked this - against other sources yet, do that later. Currently recognizes 22 - values for tribunal and 50 for bloodmoon. Legitimate GMSTs in mods - (setting values other than the default "dirty" ones) are not - affected and will work correctly. - */ - - /* - Checks for dirty tribunal values. These will be ignored if found - in any file except when they are found in "Tribunal.esm". - */ - bool isDirtyTribunal(); - - // Bloodmoon variant - bool isDirtyBloodmoon(); - void load(ESMReader &esm); int getInt() const; diff --git a/components/esm/loadinfo.hpp b/components/esm/loadinfo.hpp index f04fe862e..f1decb9c6 100644 --- a/components/esm/loadinfo.hpp +++ b/components/esm/loadinfo.hpp @@ -32,10 +32,10 @@ struct DialInfo { int mUnknown1; int mDisposition; - char mRank; // Rank of NPC - char mGender; // See Gender enum - char mPCrank; // Player rank - char mUnknown2; + signed char mRank; // Rank of NPC + signed char mGender; // See Gender enum + signed char mPCrank; // Player rank + signed char mUnknown2; }; // 12 bytes DATAstruct mData; diff --git a/components/esm/loadlevlist.hpp b/components/esm/loadlevlist.hpp index 72b4af92f..b7db5db36 100644 --- a/components/esm/loadlevlist.hpp +++ b/components/esm/loadlevlist.hpp @@ -33,6 +33,7 @@ struct LeveledListBase // list.) int mFlags; unsigned char mChanceNone; // Chance that none are selected (0-255?) + std::string mId; // Record name used to read references. Must be set before load() is // called. diff --git a/components/esm/loadligh.hpp b/components/esm/loadligh.hpp index c425af6b3..b3d703cc2 100644 --- a/components/esm/loadligh.hpp +++ b/components/esm/loadligh.hpp @@ -41,7 +41,7 @@ struct Light LHDTstruct mData; - std::string mSound, mScript, mModel, mIcon, mName; + std::string mSound, mScript, mModel, mIcon, mName, mId; void load(ESMReader &esm); void save(ESMWriter &esm); diff --git a/components/esm/loadlocks.hpp b/components/esm/loadlocks.hpp index 72d375cbb..8e88c548e 100644 --- a/components/esm/loadlocks.hpp +++ b/components/esm/loadlocks.hpp @@ -36,7 +36,7 @@ struct Tool Data mData; Type mType; - std::string mName, mModel, mIcon, mScript; + std::string mId, mName, mModel, mIcon, mScript; void load(ESMReader &esm); void save(ESMWriter &esm); diff --git a/components/esm/loadmgef.cpp b/components/esm/loadmgef.cpp index d0230e3b6..4aef97838 100644 --- a/components/esm/loadmgef.cpp +++ b/components/esm/loadmgef.cpp @@ -1,5 +1,7 @@ #include "loadmgef.hpp" +#include + #include #include "esmreader.hpp" diff --git a/components/esm/loadmisc.hpp b/components/esm/loadmisc.hpp index 1a34e6504..26d25139c 100644 --- a/components/esm/loadmisc.hpp +++ b/components/esm/loadmisc.hpp @@ -26,7 +26,7 @@ struct Miscellaneous }; MCDTstruct mData; - std::string mName, mModel, mIcon, mScript; + std::string mId, mName, mModel, mIcon, mScript; void load(ESMReader &esm); void save(ESMWriter &esm); diff --git a/components/esm/loadnpc.hpp b/components/esm/loadnpc.hpp index ee9ef6b0b..46be29961 100644 --- a/components/esm/loadnpc.hpp +++ b/components/esm/loadnpc.hpp @@ -117,6 +117,17 @@ struct NPC // Implementation moved to load_impl.cpp void load(ESMReader &esm); void save(ESMWriter &esm); + + bool isMale() const { + return (mFlags & Female) == 0; + } + + void setIsMale(bool value) { + mFlags |= Female; + if (value) { + mFlags ^= Female; + } + } }; } #endif diff --git a/components/esm/loadnpcc.hpp b/components/esm/loadnpcc.hpp index 3da14655f..79d92397f 100644 --- a/components/esm/loadnpcc.hpp +++ b/components/esm/loadnpcc.hpp @@ -1,6 +1,8 @@ #ifndef OPENMW_ESM_NPCC_H #define OPENMW_ESM_NPCC_H +#include + // TODO: create implementation files to remove this #include "esmreader.hpp" @@ -76,6 +78,8 @@ class ESMWriter; struct LoadNPCC { + std::string mId; + void load(ESMReader &esm) { esm.skipRecord(); diff --git a/components/esm/loadrace.hpp b/components/esm/loadrace.hpp index 42b2c91a7..91a424c10 100644 --- a/components/esm/loadrace.hpp +++ b/components/esm/loadrace.hpp @@ -64,7 +64,7 @@ struct Race RADTstruct mData; - std::string mName, mDescription; + std::string mId, mName, mDescription; SpellList mPowers; void load(ESMReader &esm); diff --git a/components/esm/loadregn.hpp b/components/esm/loadregn.hpp index fd0863b5b..0496ef5af 100644 --- a/components/esm/loadregn.hpp +++ b/components/esm/loadregn.hpp @@ -42,7 +42,7 @@ struct Region // sleepList refers to a eveled list of creatures you can meet if // you sleep outside in this region. - std::string mName, mSleepList; + std::string mId, mName, mSleepList; std::vector mSoundList; diff --git a/components/esm/loadscpt.cpp b/components/esm/loadscpt.cpp index dc28166d4..d9b6497d9 100644 --- a/components/esm/loadscpt.cpp +++ b/components/esm/loadscpt.cpp @@ -6,9 +6,18 @@ namespace ESM { +struct SCHD +{ + NAME32 mName; + Script::SCHDstruct mData; +}; + void Script::load(ESMReader &esm) { - esm.getHNT(mData, "SCHD", 52); + SCHD data; + esm.getHNT(data, "SCHD", 52); + mData = data.mData; + mId = data.mName.toString(); // List of local variables if (esm.isNextSub("SCVR")) @@ -48,7 +57,13 @@ void Script::save(ESMWriter &esm) for (std::vector::iterator it = mVarNames.begin(); it != mVarNames.end(); ++it) varNameString.append(*it); - esm.writeHNT("SCHD", mData, 52); + SCHD data; + memset(&data, 0, sizeof(data)); + + data.mData = mData; + memcpy(data.mName.name, mId.c_str(), mId.size()); + + esm.writeHNT("SCHD", data, 52); if (!mVarNames.empty()) { diff --git a/components/esm/loadscpt.hpp b/components/esm/loadscpt.hpp index db8f85057..10a6d24b1 100644 --- a/components/esm/loadscpt.hpp +++ b/components/esm/loadscpt.hpp @@ -42,13 +42,13 @@ public: approach though. */ - NAME32 mName; - // These describe the sizes we need to allocate for the script // data. int mNumShorts, mNumLongs, mNumFloats, mScriptDataSize, mStringTableSize; }; // 52 bytes + std::string mId; + SCHDstruct mData; std::vector mVarNames; // Variable names diff --git a/components/esm/loadsndg.hpp b/components/esm/loadsndg.hpp index dadfbd239..a6226c154 100644 --- a/components/esm/loadsndg.hpp +++ b/components/esm/loadsndg.hpp @@ -30,7 +30,7 @@ struct SoundGenerator // Type int mType; - std::string mCreature, mSound; + std::string mId, mCreature, mSound; void load(ESMReader &esm); void save(ESMWriter &esm); diff --git a/components/esm/loadsoun.hpp b/components/esm/loadsoun.hpp index 5443c6cb9..8f59f690a 100644 --- a/components/esm/loadsoun.hpp +++ b/components/esm/loadsoun.hpp @@ -17,7 +17,7 @@ struct SOUNstruct struct Sound { SOUNstruct mData; - std::string mSound; + std::string mId, mSound; void load(ESMReader &esm); void save(ESMWriter &esm); diff --git a/components/esm/loadspel.hpp b/components/esm/loadspel.hpp index 5ad184126..0d5e0be52 100644 --- a/components/esm/loadspel.hpp +++ b/components/esm/loadspel.hpp @@ -38,7 +38,7 @@ struct Spell }; SPDTstruct mData; - std::string mName; + std::string mId, mName; EffectList mEffects; void load(ESMReader &esm); diff --git a/components/esm/loadsscr.hpp b/components/esm/loadsscr.hpp index d180bfcff..713fe96b5 100644 --- a/components/esm/loadsscr.hpp +++ b/components/esm/loadsscr.hpp @@ -20,7 +20,7 @@ class ESMWriter; struct StartScript { std::string mData; - std::string mScript; + std::string mId, mScript; // Load a record and add it to the list void load(ESMReader &esm); diff --git a/components/esm/loadstat.hpp b/components/esm/loadstat.hpp index ba35fa718..790a71147 100644 --- a/components/esm/loadstat.hpp +++ b/components/esm/loadstat.hpp @@ -22,7 +22,7 @@ class ESMWriter; struct Static { - std::string mModel; + std::string mId, mModel; void load(ESMReader &esm); void save(ESMWriter &esm); diff --git a/components/esm/loadweap.hpp b/components/esm/loadweap.hpp index 341a2c86e..e482d3b10 100644 --- a/components/esm/loadweap.hpp +++ b/components/esm/loadweap.hpp @@ -56,7 +56,7 @@ struct Weapon WPDTstruct mData; - std::string mName, mModel, mIcon, mEnchant, mScript; + std::string mId, mName, mModel, mIcon, mEnchant, mScript; void load(ESMReader &esm); void save(ESMWriter &esm); diff --git a/components/esm_store/store.cpp b/components/esm_store/store.cpp deleted file mode 100644 index d1fe9b10b..000000000 --- a/components/esm_store/store.cpp +++ /dev/null @@ -1,115 +0,0 @@ -#include -#include -#include "store.hpp" - -using namespace std; -using namespace ESM; -using namespace ESMS; - -/* -static string toStr(int i) -{ - char name[5]; - *((int*)name) = i; - name[4] = 0; - return std::string(name); -} -*/ - -void ESMStore::load(ESMReader &esm) -{ - set missing; - - ESM::Dialogue *dialogue = 0; - - // Loop through all records - while(esm.hasMoreRecs()) - { - NAME n = esm.getRecName(); - esm.getRecHeader(); - - // Look up the record type. - RecListList::iterator it = recLists.find(n.val); - - if(it == recLists.end()) - { - if (n.val==ESM::REC_INFO) - { - if (dialogue) - { - ESM::DialInfo info; - info.load (esm); - - dialogue->mInfo.push_back (info); - } - else - { - std::cerr << "error: info record without dialog" << std::endl; - esm.skipRecord(); - } - } - else if (n.val==ESM::REC_MGEF) - { - magicEffects.load (esm); - } - else if (n.val==ESM::REC_SKIL) - { - skills.load (esm); - } - else - { - // Not found (this would be an error later) - esm.skipRecord(); - missing.insert(n.toString()); - } - } - else - { - // Load it - std::string id = esm.getHNOString("NAME"); - it->second->load(esm, id); - - if (n.val==ESM::REC_DIAL) - { - RecListCaseT& recList = static_cast& > (*it->second); - - ESM::Dialogue* d = recList.search (id); - - assert (d != NULL); - - dialogue = d; - } - else - dialogue = 0; - - // Insert the reference into the global lookup - if(!id.empty() && - (n.val==REC_ACTI || n.val==REC_ALCH || n.val==REC_APPA || n.val==REC_ARMO || - n.val==REC_BOOK || n.val==REC_CLOT || n.val==REC_CONT || n.val==REC_CREA || - n.val==REC_DOOR || n.val==REC_INGR || n.val==REC_LEVC || n.val==REC_LEVI || - n.val==REC_LIGH || n.val==REC_LOCK || n.val==REC_MISC || n.val==REC_NPC_ || - n.val==REC_PROB || n.val==REC_REPA || n.val==REC_STAT || n.val==REC_WEAP) - ) - all[id] = n.val; - } - } - - for (int i = 0; i < Attribute::Length; ++i) - { - Attribute::AttributeID id = Attribute::sAttributeIds[i]; - attributes.list.insert(std::make_pair(id, Attribute(id, Attribute::sGmstAttributeIds[i], Attribute::sGmstAttributeDescIds[i]))); - } - - /* This information isn't needed on screen. But keep the code around - for debugging purposes later. - - cout << "\n" << recLists.size() << " record types:\n"; - for(RecListList::iterator it = recLists.begin(); it != recLists.end(); it++) - cout << " " << toStr(it->first) << ": " << it->second->getSize() << endl; - cout << "\nNot implemented yet: "; - for(set::iterator it = missing.begin(); - it != missing.end(); it++ ) - cout << *it << " "; - cout << endl; - */ -} diff --git a/components/esm_store/store.hpp b/components/esm_store/store.hpp deleted file mode 100644 index 7329386d4..000000000 --- a/components/esm_store/store.hpp +++ /dev/null @@ -1,146 +0,0 @@ -#ifndef _GAME_ESM_STORE_H -#define _GAME_ESM_STORE_H - -/* - The ESM storage module. - - This is separate from the ESM loader module, located in esm/. It is - also unaware of the cell loading and storage module. - - The advantage of this, as with all other modularizations, is that - you can replace the storage method later without touching the - loading code. Cutting down dependencies also help on the general - maintainability. - */ - -#include "components/esm/records.hpp" -#include "reclists.hpp" - -namespace ESMS -{ - using namespace ESM; - - struct ESMStore - { - /* Lists all the list types. Mostly used for quick lookup on - loading. The key is the record name (4 chars) parsed as a 32 - bit int. See esm/records.hpp for the complete list. - */ - RecListList recLists; - - // Each individual list - RecListT activators; - RecListWithIDT potions; - RecListT appas; - RecListT armors; - RecListT bodyParts; - RecListWithIDT books; - RecListT birthSigns; - RecListT classes; - RecListT clothes; - RecListT contChange; - RecListT containers; - RecListWithIDT creatures; - RecListT creaChange; - RecListCaseT dialogs; - RecListT doors; - RecListT enchants; - RecListT factions; - RecListT globals; - RecListWithIDT ingreds; - RecListT creatureLists; - RecListT itemLists; - RecListT lights; - RecListT lockpicks; - RecListT miscItems; - RecListWithIDT npcs; - RecListT npcChange; - RecListT probes; - RecListT races; - RecListT regions; - RecListT repairs; - RecListT soundGens; - RecListT sounds; - RecListT spells; - RecListT startScripts; - RecListT statics; - RecListT weapons; - - // Lists that need special rules - CellList cells; - RecIDListT gameSettings; - LandList lands; - LTexList landTexts; - ScriptListT