diff --git a/CMakeLists.txt b/CMakeLists.txt index c3def1381..f31603460 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -408,7 +408,7 @@ IF(NOT WIN32 AND NOT APPLE) # Install binaries INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw" DESTINATION "${BINDIR}" ) IF(BUILD_LAUNCHER) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/omwlauncher" DESTINATION "${BINDIR}" ) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-launcher" DESTINATION "${BINDIR}" ) ENDIF(BUILD_LAUNCHER) IF(BUILD_BSATOOL) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/bsatool" DESTINATION "${BINDIR}" ) @@ -417,7 +417,7 @@ IF(NOT WIN32 AND NOT APPLE) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/esmtool" DESTINATION "${BINDIR}" ) ENDIF(BUILD_ESMTOOL) IF(BUILD_MWINIIMPORTER) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/mwiniimport" DESTINATION "${BINDIR}" ) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-iniimporter" DESTINATION "${BINDIR}" ) ENDIF(BUILD_MWINIIMPORTER) IF(BUILD_ESSIMPORTER) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-essimporter" DESTINATION "${BINDIR}" ) @@ -476,10 +476,10 @@ if(WIN32) DESTINATION ".") IF(BUILD_LAUNCHER) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/omwlauncher.exe" DESTINATION ".") + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-launcher.exe" DESTINATION ".") ENDIF(BUILD_LAUNCHER) IF(BUILD_MWINIIMPORTER) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/mwiniimport.exe" DESTINATION ".") + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-iniimporter.exe" DESTINATION ".") ENDIF(BUILD_MWINIIMPORTER) IF(BUILD_ESSIMPORTER) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-essimporter.exe" DESTINATION ".") @@ -506,7 +506,7 @@ if(WIN32) SET(CPACK_PACKAGE_VERSION_PATCH ${OPENMW_VERSION_RELEASE}) SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW") IF(BUILD_LAUNCHER) - SET(CPACK_PACKAGE_EXECUTABLES "${CPACK_PACKAGE_EXECUTABLES};omwlauncher;OpenMW Launcher") + SET(CPACK_PACKAGE_EXECUTABLES "${CPACK_PACKAGE_EXECUTABLES};openmw-launcher;OpenMW Launcher") ENDIF(BUILD_LAUNCHER) IF(BUILD_OPENCS) SET(CPACK_PACKAGE_EXECUTABLES "${CPACK_PACKAGE_EXECUTABLES};opencs;OpenMW Construction Set") @@ -525,7 +525,7 @@ if(WIN32) SET(CPACK_NSIS_DISPLAY_NAME "OpenMW ${OPENMW_VERSION}") SET(CPACK_NSIS_HELP_LINK "http:\\\\\\\\www.openmw.org") SET(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\\\\\www.openmw.org") - SET(CPACK_NSIS_INSTALLED_ICON_NAME "omwlauncher.exe") + SET(CPACK_NSIS_INSTALLED_ICON_NAME "openmw-launcher.exe") SET(CPACK_NSIS_MUI_ICON "${OpenMW_SOURCE_DIR}/files/windows/openmw.ico") SET(CPACK_NSIS_MUI_UNIICON "${OpenMW_SOURCE_DIR}/files/windows/openmw.ico") SET(CPACK_PACKAGE_ICON "${OpenMW_SOURCE_DIR}\\\\files\\\\openmw.bmp") @@ -699,7 +699,7 @@ if (WIN32) set_target_properties(oics PROPERTIES COMPILE_FLAGS "${OICS_WARNINGS} ${MT_BUILD}") set_target_properties(components PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") if (BUILD_LAUNCHER) - set_target_properties(omwlauncher PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") + set_target_properties(openmw-launcher PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") endif (BUILD_LAUNCHER) set_target_properties(openmw PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") if (BUILD_BSATOOL) @@ -717,7 +717,7 @@ if (WIN32) set_target_properties(opencs PROPERTIES COMPILE_FLAGS ${OPENCS_WARNINGS}) endif (BUILD_OPENCS) if (BUILD_MWINIIMPORTER) - set_target_properties(mwiniimport PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") + set_target_properties(openmw-iniimporter PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") endif (BUILD_MWINIIMPORTER) endif(MSVC) diff --git a/apps/essimporter/CMakeLists.txt b/apps/essimporter/CMakeLists.txt index 76fc9aa94..72ef364ee 100644 --- a/apps/essimporter/CMakeLists.txt +++ b/apps/essimporter/CMakeLists.txt @@ -25,6 +25,7 @@ set(ESSIMPORTER_FILES convertcntc.cpp convertscri.cpp convertscpt.cpp + convertplayer.cpp ) add_executable(openmw-essimporter diff --git a/apps/essimporter/convertacdt.cpp b/apps/essimporter/convertacdt.cpp index 496eab9e9..718403a8c 100644 --- a/apps/essimporter/convertacdt.cpp +++ b/apps/essimporter/convertacdt.cpp @@ -29,6 +29,12 @@ namespace ESSImport } cStats.mGoldPool = acdt.mGoldPool; cStats.mTalkedTo = acdt.mFlags & TalkedToPlayer; + cStats.mAttacked = acdt.mFlags & Attacked; + } + + void convertACSC (const ACSC& acsc, ESM::CreatureStats& cStats) + { + cStats.mDead = acsc.mFlags & Dead; } void convertNpcData (const ActorData& actorData, ESM::NpcStats& npcStats) diff --git a/apps/essimporter/convertacdt.hpp b/apps/essimporter/convertacdt.hpp index a98ba36dd..bc9a7bd00 100644 --- a/apps/essimporter/convertacdt.hpp +++ b/apps/essimporter/convertacdt.hpp @@ -15,6 +15,7 @@ namespace ESSImport void convertACDT (const ACDT& acdt, ESM::CreatureStats& cStats); + void convertACSC (const ACSC& acsc, ESM::CreatureStats& cStats); void convertNpcData (const ActorData& actorData, ESM::NpcStats& npcStats); } diff --git a/apps/essimporter/converter.cpp b/apps/essimporter/converter.cpp index 4d21d2b7a..91d290f33 100644 --- a/apps/essimporter/converter.cpp +++ b/apps/essimporter/converter.cpp @@ -274,6 +274,8 @@ namespace ESSImport const CellRef& cellref = *refIt; ESM::CellRef out (cellref); + // TODO: use mContext->mCreatures/mNpcs + if (!isIndexedRefId(cellref.mIndexedRefId)) { // non-indexed RefNum, i.e. no CREC/NPCC/CNTC record associated with it @@ -309,9 +311,12 @@ namespace ESSImport objstate.blank(); objstate.mRef = out; objstate.mRef.mRefID = idLower; - // probably need more micromanagement here so we don't overwrite values + // TODO: need more micromanagement here so we don't overwrite values // from the ESM with default values - convertACDT(cellref.mACDT, objstate.mCreatureStats); + if (cellref.mHasACDT) + convertACDT(cellref.mACDT, objstate.mCreatureStats); + if (cellref.mHasACSC) + convertACSC(cellref.mACSC, objstate.mCreatureStats); convertNpcData(cellref, objstate.mNpcStats); convertNPCC(npccIt->second, objstate); convertCellRef(cellref, objstate); @@ -343,9 +348,12 @@ namespace ESSImport objstate.blank(); objstate.mRef = out; objstate.mRef.mRefID = idLower; - convertACDT(cellref.mACDT, objstate.mCreatureStats); - // probably need more micromanagement here so we don't overwrite values + // TODO: need more micromanagement here so we don't overwrite values // from the ESM with default values + if (cellref.mHasACDT) + convertACDT(cellref.mACDT, objstate.mCreatureStats); + if (cellref.mHasACSC) + convertACSC(cellref.mACSC, objstate.mCreatureStats); convertCREC(crecIt->second, objstate); convertCellRef(cellref, objstate); esm.writeHNT ("OBJE", ESM::REC_CREA); diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index c80ccb951..775995605 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -35,6 +35,7 @@ #include "convertacdt.hpp" #include "convertnpcc.hpp" #include "convertscpt.hpp" +#include "convertplayer.hpp" namespace ESSImport { @@ -104,10 +105,10 @@ public: npc.load(esm); if (id != "player") { - // TODO: - // this should handle changes to the NPC struct, but since there is no index here + // Handles changes to the NPC struct, but since there is no index here // it will apply to ALL instances of the class. seems to be the reason for the // "feature" in MW where changing AI settings of one guard will change it for all guards of that refID. + mContext->mNpcs[Misc::StringUtils::lowerCase(id)] = npc; } else { @@ -139,6 +140,7 @@ public: ESM::Creature creature; std::string id = esm.getHNString("NAME"); creature.load(esm); + mContext->mCreatures[Misc::StringUtils::lowerCase(id)] = creature; } }; @@ -259,32 +261,23 @@ private: class ConvertPCDT : public Converter { public: + ConvertPCDT() : mFirstPersonCam(true) {} + virtual void read(ESM::ESMReader &esm) { PCDT pcdt; pcdt.load(esm); - mContext->mPlayer.mBirthsign = pcdt.mBirthsign; - mContext->mPlayer.mObject.mNpcStats.mBounty = pcdt.mBounty; - for (std::vector::const_iterator it = pcdt.mFactions.begin(); it != pcdt.mFactions.end(); ++it) - { - ESM::NpcStats::Faction faction; - faction.mExpelled = (it->mFlags & 0x2) != 0; - faction.mRank = it->mRank; - faction.mReputation = it->mReputation; - mContext->mPlayer.mObject.mNpcStats.mFactions[Misc::StringUtils::lowerCase(it->mFactionName.toString())] = faction; - } - for (int i=0; i<8; ++i) - mContext->mPlayer.mObject.mNpcStats.mSkillIncrease[i] = pcdt.mPNAM.mSkillIncreases[i]; - mContext->mPlayer.mObject.mNpcStats.mLevelProgress = pcdt.mPNAM.mLevelProgress; - - for (std::vector::const_iterator it = pcdt.mKnownDialogueTopics.begin(); - it != pcdt.mKnownDialogueTopics.end(); ++it) - { - mContext->mDialogueState.mKnownTopics.push_back(Misc::StringUtils::lowerCase(*it)); - } - + convertPCDT(pcdt, mContext->mPlayer, mContext->mDialogueState.mKnownTopics, mFirstPersonCam); } + virtual void write(ESM::ESMWriter &esm) + { + esm.startRecord(ESM::REC_CAM_); + esm.writeHNT("FIRS", mFirstPersonCam); + esm.endRecord(ESM::REC_CAM_); + } +private: + bool mFirstPersonCam; }; class ConvertCNTC : public Converter @@ -416,7 +409,7 @@ private: /// Seen responses for a dialogue topic? /// Each DIAL record is followed by a number of INFO records, I believe, just like in ESMs -/// Dialogue conversion problems (probably have to adjust OpenMW format) - +/// Dialogue conversion problems: /// - Journal is stored in one continuous HTML markup rather than each entry separately with associated info ID. /// - Seen dialogue responses only store the INFO id, rather than the fulltext. /// - Quest stages only store the INFO id, rather than the journal entry fulltext. diff --git a/apps/essimporter/convertplayer.cpp b/apps/essimporter/convertplayer.cpp new file mode 100644 index 000000000..ef22660f5 --- /dev/null +++ b/apps/essimporter/convertplayer.cpp @@ -0,0 +1,39 @@ +#include "convertplayer.hpp" + +namespace ESSImport +{ + + void convertPCDT(const PCDT& pcdt, ESM::Player& out, std::vector& outDialogueTopics, bool& firstPersonCam) + { + out.mBirthsign = pcdt.mBirthsign; + out.mObject.mNpcStats.mBounty = pcdt.mBounty; + for (std::vector::const_iterator it = pcdt.mFactions.begin(); it != pcdt.mFactions.end(); ++it) + { + ESM::NpcStats::Faction faction; + faction.mExpelled = (it->mFlags & 0x2) != 0; + faction.mRank = it->mRank; + faction.mReputation = it->mReputation; + out.mObject.mNpcStats.mFactions[Misc::StringUtils::lowerCase(it->mFactionName.toString())] = faction; + } + for (int i=0; i<8; ++i) + out.mObject.mNpcStats.mSkillIncrease[i] = pcdt.mPNAM.mSkillIncreases[i]; + out.mObject.mNpcStats.mLevelProgress = pcdt.mPNAM.mLevelProgress; + + if (pcdt.mPNAM.mDrawState & PCDT::DrawState_Weapon) + out.mObject.mCreatureStats.mDrawState = 1; + if (pcdt.mPNAM.mDrawState & PCDT::DrawState_Spell) + out.mObject.mCreatureStats.mDrawState = 2; + + // TODO: convert PNAM.mSkillProgress, needs to be converted to uniform scale + // (or change openmw to accept non-uniform skill progress) + + firstPersonCam = (pcdt.mPNAM.mCameraState == PCDT::CameraState_FirstPerson); + + for (std::vector::const_iterator it = pcdt.mKnownDialogueTopics.begin(); + it != pcdt.mKnownDialogueTopics.end(); ++it) + { + outDialogueTopics.push_back(Misc::StringUtils::lowerCase(*it)); + } + } + +} diff --git a/apps/essimporter/convertplayer.hpp b/apps/essimporter/convertplayer.hpp new file mode 100644 index 000000000..f6731eed7 --- /dev/null +++ b/apps/essimporter/convertplayer.hpp @@ -0,0 +1,15 @@ +#ifndef OPENMW_ESSIMPORT_CONVERTPLAYER_H +#define OPENMW_ESSIMPORT_CONVERTPLAYER_H + +#include "importplayer.hpp" + +#include + +namespace ESSImport +{ + + void convertPCDT(const PCDT& pcdt, ESM::Player& out, std::vector& outDialogueTopics, bool& firstPersonCam); + +} + +#endif diff --git a/apps/essimporter/importacdt.cpp b/apps/essimporter/importacdt.cpp index 9a062484b..9d881515d 100644 --- a/apps/essimporter/importacdt.cpp +++ b/apps/essimporter/importacdt.cpp @@ -20,12 +20,22 @@ namespace ESSImport ESM::CellRef::loadData(esm); - // FIXME: not all actors have this, add flag - esm.getHNOT(mACDT, "ACDT"); + mHasACDT = false; + if (esm.isNextSub("ACDT")) + { + mHasACDT = true; + esm.getHT(mACDT); + } - ACSC acsc; - esm.getHNOT(acsc, "ACSC"); - esm.getHNOT(acsc, "ACSL"); + mHasACSC = false; + if (esm.isNextSub("ACSC")) + { + mHasACSC = true; + esm.getHT(mACSC); + } + + if (esm.isNextSub("ACSL")) + esm.skipHSubSize(112); if (esm.isNextSub("CSTN")) esm.skipHSub(); // "PlayerSaveGame", link to some object? diff --git a/apps/essimporter/importacdt.hpp b/apps/essimporter/importacdt.hpp index 53783a364..1e0317049 100644 --- a/apps/essimporter/importacdt.hpp +++ b/apps/essimporter/importacdt.hpp @@ -17,7 +17,13 @@ namespace ESSImport enum ACDTFlags { - TalkedToPlayer = 0x4 + TalkedToPlayer = 0x4, + Attacked = 0x100, + Unknown = 0x200 + }; + enum ACSCFlags + { + Dead = 0x2 }; /// Actor data, shared by (at least) REFR and CellRef @@ -28,23 +34,33 @@ namespace ESSImport // Note, not stored at *all*: // - Level changes are lost on reload, except for the player (there it's in the NPC record). unsigned char mUnknown[12]; - unsigned char mFlags; // ACDTFlags - unsigned char mUnknown1[3]; + unsigned int mFlags; float mBreathMeter; // Seconds left before drowning unsigned char mUnknown2[20]; float mDynamic[3][2]; unsigned char mUnknown3[16]; float mAttributes[8][2]; - unsigned char mUnknown4[112]; + float mMagicEffects[27]; // Effect attributes: https://wiki.openmw.org/index.php?title=Research:Magic#Effect_attributes + unsigned char mUnknown4[4]; unsigned int mGoldPool; unsigned char mUnknown5[4]; }; + struct ACSC + { + unsigned char mUnknown1[17]; + unsigned char mFlags; // ACSCFlags + unsigned char mUnknown2[94]; + }; #pragma pack(pop) struct ActorData : public ESM::CellRef { + bool mHasACDT; ACDT mACDT; + bool mHasACSC; + ACSC mACSC; + int mSkills[27][2]; // creature combat stats, base and modified @@ -60,12 +76,6 @@ namespace ESSImport void load(ESM::ESMReader& esm); }; - /// Unknown, shared by (at least) REFR and CellRef - struct ACSC - { - unsigned char unknown[112]; - }; - } #endif diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 8f6563dee..d5ed43b8a 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -21,6 +21,8 @@ #include #include +#include + #include "importercontext.hpp" #include "converter.hpp" @@ -44,9 +46,10 @@ namespace namespace ESSImport { - Importer::Importer(const std::string &essfile, const std::string &outfile) + Importer::Importer(const std::string &essfile, const std::string &outfile, const std::string &encoding) : mEssFile(essfile) , mOutFile(outfile) + , mEncoding(encoding) { } @@ -167,14 +170,30 @@ namespace ESSImport std::cout << "Data 1:" << std::endl; for (unsigned int k=0; k= sub2.mData.size() || sub2.mData[k] != sub.mData[k]) + different = true; + + if (different) + std::cout << "\033[033m"; std::cout << std::hex << std::setw(2) << std::setfill('0') << (int)sub.mData[k] << " "; + if (different) + std::cout << "\033[0m"; } std::cout << std::endl; std::cout << "Data 2:" << std::endl; for (unsigned int k=0; k= sub.mData.size() || sub.mData[k] != sub2.mData[k]) + different = true; + + if (different) + std::cout << "\033[033m"; std::cout << std::hex << std::setw(2) << std::setfill('0') << (int)sub2.mData[k] << " "; + if (different) + std::cout << "\033[0m"; } std::cout << std::endl; } @@ -188,10 +207,10 @@ namespace ESSImport Ogre::LogManager logman; Ogre::Root root; - // TODO: set up encoding on ESMReader based on openmw.cfg / --encoding switch - + ToUTF8::Utf8Encoder encoder(ToUTF8::calculateEncoding(mEncoding)); ESM::ESMReader esm; esm.open(mEssFile); + esm.setEncoder(&encoder); Context context; diff --git a/apps/essimporter/importer.hpp b/apps/essimporter/importer.hpp index eb199b6df..ccacd7972 100644 --- a/apps/essimporter/importer.hpp +++ b/apps/essimporter/importer.hpp @@ -9,7 +9,7 @@ namespace ESSImport class Importer { public: - Importer(const std::string& essfile, const std::string& outfile); + Importer(const std::string& essfile, const std::string& outfile, const std::string& encoding); void run(); @@ -18,6 +18,7 @@ namespace ESSImport private: std::string mEssFile; std::string mOutFile; + std::string mEncoding; }; } diff --git a/apps/essimporter/importercontext.hpp b/apps/essimporter/importercontext.hpp index a466770d0..3b010cb8f 100644 --- a/apps/essimporter/importercontext.hpp +++ b/apps/essimporter/importercontext.hpp @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include "importnpcc.hpp" #include "importcrec.hpp" @@ -15,6 +17,7 @@ + namespace ESSImport { @@ -42,6 +45,9 @@ namespace ESSImport std::map, NPCC> mNpcChanges; std::map, CNTC> mContainerChanges; + std::map mCreatures; + std::map mNpcs; + Context() { mPlayer.mAutoMove = 0; diff --git a/apps/essimporter/importplayer.hpp b/apps/essimporter/importplayer.hpp index 64ceddfd7..bc6b94be2 100644 --- a/apps/essimporter/importplayer.hpp +++ b/apps/essimporter/importplayer.hpp @@ -38,6 +38,17 @@ struct PCDT std::vector mKnownDialogueTopics; + enum DrawState_ + { + DrawState_Weapon = 0x80, + DrawState_Spell = 0x100 + }; + enum CameraState + { + CameraState_FirstPerson = 0x8, + CameraState_ThirdPerson = 0xa + }; + #pragma pack(push) #pragma pack(1) struct FNAM @@ -49,11 +60,13 @@ struct PCDT unsigned char mUnknown2[3]; ESM::NAME32 mFactionName; }; + struct PNAM { - unsigned char mUnknown1[4]; - unsigned char mLevelProgress; - unsigned char mUnknown2[111]; + short mDrawState; // DrawState + short mCameraState; // CameraState + unsigned int mLevelProgress; + float mSkillProgress[27]; // skill progress, non-uniform scaled unsigned char mSkillIncreases[8]; // number of skill increases for each attribute unsigned char mUnknown3[88]; }; diff --git a/apps/essimporter/main.cpp b/apps/essimporter/main.cpp index d467e053e..a4ad114ec 100644 --- a/apps/essimporter/main.cpp +++ b/apps/essimporter/main.cpp @@ -5,6 +5,8 @@ #include #include +#include + #include "importer.hpp" namespace bpo = boost::program_options; @@ -23,31 +25,36 @@ int main(int argc, char** argv) ("mwsave,m", bpo::value(), "morrowind .ess save file") ("output,o", bpo::value(), "output file (.omwsave)") ("compare,c", "compare two .ess files") + ("encoding", boost::program_options::value()->default_value("win1252"), "encoding of the save file") ; p_desc.add("mwsave", 1).add("output", 1); - bpo::variables_map vm; + bpo::variables_map variables; bpo::parsed_options parsed = bpo::command_line_parser(argc, argv) .options(desc) .positional(p_desc) .run(); - bpo::store(parsed, vm); + bpo::store(parsed, variables); - if(vm.count("help") || !vm.count("mwsave") || !vm.count("output")) { + if(variables.count("help") || !variables.count("mwsave") || !variables.count("output")) { std::cout << desc; return 0; } - bpo::notify(vm); + bpo::notify(variables); - std::string essFile = vm["mwsave"].as(); - std::string outputFile = vm["output"].as(); + Files::ConfigurationManager cfgManager(true); + cfgManager.readConfiguration(variables, desc); - ESSImport::Importer importer(essFile, outputFile); + std::string essFile = variables["mwsave"].as(); + std::string outputFile = variables["output"].as(); + std::string encoding = variables["encoding"].as(); - if (vm.count("compare")) + ESSImport::Importer importer(essFile, outputFile, encoding); + + if (variables.count("compare")) importer.compare(); else { diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index ba330f70c..0de79f8f6 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -78,7 +78,7 @@ if(NOT WIN32) endif(NOT WIN32) # Main executable -add_executable(omwlauncher +add_executable(openmw-launcher ${GUI_TYPE} ${LAUNCHER} ${LAUNCHER_HEADER} @@ -87,7 +87,7 @@ add_executable(omwlauncher ${UI_HDRS} ) -target_link_libraries(omwlauncher +target_link_libraries(openmw-launcher ${Boost_LIBRARIES} ${OGRE_LIBRARIES} ${OGRE_STATIC_PLUGINS} @@ -99,6 +99,6 @@ target_link_libraries(omwlauncher if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) - target_link_libraries(omwlauncher gcov) + target_link_libraries(openmw-launcher gcov) endif() diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 00c549969..b93d55c17 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -27,25 +27,6 @@ using namespace Process; Launcher::MainDialog::MainDialog(QWidget *parent) : mGameSettings(mCfgMgr), QMainWindow (parent) { - // Install the stylesheet font - QFile file; - QFontDatabase fontDatabase; - - const QStringList fonts = fontDatabase.families(); - - // Check if the font is installed - if (!fonts.contains("EB Garamond")) { - - QString font = QString::fromUtf8(mCfgMgr.getGlobalDataPath().string().c_str()) + QString("resources/mygui/EBGaramond-Regular.ttf"); - file.setFileName(font); - - if (!file.exists()) { - font = QString::fromUtf8(mCfgMgr.getLocalPath().string().c_str()) + QString("resources/mygui/EBGaramond-Regular.ttf"); - } - - fontDatabase.addApplicationFont(font); - } - setupUi(this); mGameInvoker = new ProcessInvoker(); diff --git a/apps/launcher/settingspage.cpp b/apps/launcher/settingspage.cpp index ace8f4310..71ab8f7f3 100644 --- a/apps/launcher/settingspage.cpp +++ b/apps/launcher/settingspage.cpp @@ -140,7 +140,7 @@ void Launcher::SettingsPage::on_importerButton_clicked() qDebug() << "arguments " << arguments; - if (!mImporterInvoker->startProcess(QLatin1String("mwiniimport"), arguments, false)) + if (!mImporterInvoker->startProcess(QLatin1String("openmw-iniimporter"), arguments, false)) return; } diff --git a/apps/mwiniimporter/CMakeLists.txt b/apps/mwiniimporter/CMakeLists.txt index deab88ce2..790d47dc4 100644 --- a/apps/mwiniimporter/CMakeLists.txt +++ b/apps/mwiniimporter/CMakeLists.txt @@ -9,16 +9,16 @@ set(MWINIIMPORT_HEADER source_group(launcher FILES ${MWINIIMPORT} ${MWINIIMPORT_HEADER}) -add_executable(mwiniimport +add_executable(openmw-iniimporter ${MWINIIMPORT} ) -target_link_libraries(mwiniimport +target_link_libraries(openmw-iniimporter ${Boost_LIBRARIES} components ) if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) - target_link_libraries(mwiniimport gcov) + target_link_libraries(openmw-iniimporter gcov) endif() diff --git a/apps/mwiniimporter/main.cpp b/apps/mwiniimporter/main.cpp index 316737c1d..f108678f3 100644 --- a/apps/mwiniimporter/main.cpp +++ b/apps/mwiniimporter/main.cpp @@ -59,7 +59,7 @@ int wmain(int argc, wchar_t *wargv[]) { try { - bpo::options_description desc("Syntax: mwiniimporter inifile configfile\nAllowed options"); + bpo::options_description desc("Syntax: openmw-iniimporter inifile configfile\nAllowed options"); bpo::positional_options_description p_desc; desc.add_options() ("help,h", "produce help message") diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 74d434f63..b96b90989 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -190,29 +190,23 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat bpo::store(valid_opts, variables); bpo::notify(variables); - bool run = true; - if (variables.count ("help")) { std::cout << desc << std::endl; - run = false; + return false; } + std::cout << "OpenMW version " << OPENMW_VERSION; + std::string rev = OPENMW_VERSION_COMMITHASH; + std::string tag = OPENMW_VERSION_TAGHASH; + if (!rev.empty() && !tag.empty()) + { + rev = rev.substr(0, 10); + std::cout << " (revision " << rev << ")"; + } + std::cout << std::endl; + if (variables.count ("version")) - { - std::cout << "OpenMW version " << OPENMW_VERSION << std::endl; - - std::string rev = OPENMW_VERSION_COMMITHASH; - std::string tag = OPENMW_VERSION_TAGHASH; - if (!rev.empty() && !tag.empty()) - { - rev = rev.substr(0, 10); - std::cout << "Revision " << rev << std::endl; - } - run = false; - } - - if (!run) return false; cfgMgr.readConfiguration(variables, desc); diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 02cbc69e9..69027d734 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -35,6 +35,7 @@ namespace ESM struct Class; class ESMReader; class ESMWriter; + struct CellId; } namespace MWWorld diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index ccda90832..9d8fc90a1 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -6,6 +6,8 @@ #include +#include + #include "../mwworld/globals.hpp" #include "../mwworld/ptr.hpp" @@ -33,7 +35,6 @@ namespace ESM struct Potion; struct Spell; struct NPC; - struct CellId; struct Armor; struct Weapon; struct Clothing; @@ -92,6 +93,7 @@ namespace MWBase { std::string name; float x, y; // world position + ESM::CellId dest; }; World() {} diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 2e53fe802..df3f9c0d3 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -228,18 +228,7 @@ namespace MWClass weapon = *weaponslot; } - // Reduce fatigue - // somewhat of a guess, but using the weapon weight makes sense - const float fFatigueAttackBase = gmst.find("fFatigueAttackBase")->getFloat(); - const float fFatigueAttackMult = gmst.find("fFatigueAttackMult")->getFloat(); - const float fWeaponFatigueMult = gmst.find("fWeaponFatigueMult")->getFloat(); - MWMechanics::DynamicStat fatigue = stats.getFatigue(); - const float normalizedEncumbrance = getNormalizedEncumbrance(ptr); - float fatigueLoss = fFatigueAttackBase + normalizedEncumbrance * fFatigueAttackMult; - if (!weapon.isEmpty()) - fatigueLoss += weapon.getClass().getWeight(weapon) * stats.getAttackStrength() * fWeaponFatigueMult; - fatigue.setCurrent(fatigue.getCurrent() - fatigueLoss); - stats.setFatigue(fatigue); + MWMechanics::applyFatigueLoss(ptr, weapon); // TODO: where is the distance defined? float dist = 200.f; diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 84c6c66fd..10b9b437d 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -93,9 +93,6 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - if (ptr.getCellRef().getTeleport() && !ptr.getCellRef().getDestCell().empty()) // TODO doors that lead to exteriors - return ptr.getCellRef().getDestCell(); - return ref->mBase->mName; } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index d01a9ec7f..c55f81d91 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -486,18 +486,7 @@ namespace MWClass if(!weapon.isEmpty() && weapon.getTypeName() != typeid(ESM::Weapon).name()) weapon = MWWorld::Ptr(); - // Reduce fatigue - // somewhat of a guess, but using the weapon weight makes sense - const float fFatigueAttackBase = store.find("fFatigueAttackBase")->getFloat(); - const float fFatigueAttackMult = store.find("fFatigueAttackMult")->getFloat(); - const float fWeaponFatigueMult = store.find("fWeaponFatigueMult")->getFloat(); - MWMechanics::DynamicStat fatigue = getCreatureStats(ptr).getFatigue(); - const float normalizedEncumbrance = getNormalizedEncumbrance(ptr); - float fatigueLoss = fFatigueAttackBase + normalizedEncumbrance * fFatigueAttackMult; - if (!weapon.isEmpty()) - fatigueLoss += weapon.getClass().getWeight(weapon) * getNpcStats(ptr).getAttackStrength() * fWeaponFatigueMult; - fatigue.setCurrent(fatigue.getCurrent() - fatigueLoss); - getCreatureStats(ptr).setFatigue(fatigue); + MWMechanics::applyFatigueLoss(ptr, weapon); const float fCombatDistance = store.find("fCombatDistance")->getFloat(); float dist = fCombatDistance * (!weapon.isEmpty() ? diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 122c8eeae..d1a44fd0e 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -189,9 +189,8 @@ namespace MWClass { return std::string("Item Weapon Longblade Up"); } - // Shortblade and thrown weapons - // thrown weapons may not be entirely correct - if (type == 0 || type == 11) + // Shortblade + if (type == 0) { return std::string("Item Weapon Shortblade Up"); } @@ -200,8 +199,8 @@ namespace MWClass { return std::string("Item Weapon Spear Up"); } - // Blunts and Axes - if (type == 3 || type == 4 || type == 5 || type == 7 || type == 8) + // Blunts, Axes and Thrown weapons + if (type == 3 || type == 4 || type == 5 || type == 7 || type == 8 || type == 11) { return std::string("Item Weapon Blunt Up"); } @@ -235,9 +234,8 @@ namespace MWClass { return std::string("Item Weapon Longblade Down"); } - // Shortblade and thrown weapons - // thrown weapons may not be entirely correct - if (type == 0 || type == 11) + // Shortblade + if (type == 0) { return std::string("Item Weapon Shortblade Down"); } @@ -246,8 +244,8 @@ namespace MWClass { return std::string("Item Weapon Spear Down"); } - // Blunts and Axes - if (type == 3 || type == 4 || type == 5 || type == 7 || type == 8) + // Blunts, Axes and Thrown weapons + if (type == 3 || type == 4 || type == 5 || type == 7 || type == 8 || type == 11) { return std::string("Item Weapon Blunt Down"); } diff --git a/apps/openmw/mwgui/companionitemmodel.cpp b/apps/openmw/mwgui/companionitemmodel.cpp index b8be9dcb8..983ef5017 100644 --- a/apps/openmw/mwgui/companionitemmodel.cpp +++ b/apps/openmw/mwgui/companionitemmodel.cpp @@ -3,6 +3,22 @@ #include "../mwmechanics/npcstats.hpp" #include "../mwworld/class.hpp" +namespace +{ + + void modifyProfit(const MWWorld::Ptr& actor, int diff) + { + std::string script = actor.getClass().getScript(actor); + if (!script.empty()) + { + int profit = actor.getRefData().getLocals().getIntVar(script, "minimumprofit"); + profit += diff; + actor.getRefData().getLocals().setVarByInt(script, "minimumprofit", profit); + } + } + +} + namespace MWGui { CompanionItemModel::CompanionItemModel(const MWWorld::Ptr &actor) @@ -12,23 +28,25 @@ namespace MWGui MWWorld::Ptr CompanionItemModel::copyItem (const ItemStack& item, size_t count, bool setNewOwner=false) { - if (mActor.getClass().isNpc()) - { - MWMechanics::NpcStats& stats = mActor.getClass().getNpcStats(mActor); - stats.modifyProfit(item.mBase.getClass().getValue(item.mBase) * count); - } + if (hasProfit(mActor)) + modifyProfit(mActor, item.mBase.getClass().getValue(item.mBase) * count); return InventoryItemModel::copyItem(item, count, setNewOwner); } void CompanionItemModel::removeItem (const ItemStack& item, size_t count) { - if (mActor.getClass().isNpc()) - { - MWMechanics::NpcStats& stats = mActor.getClass().getNpcStats(mActor); - stats.modifyProfit(-item.mBase.getClass().getValue(item.mBase) * count); - } + if (hasProfit(mActor)) + modifyProfit(mActor, -item.mBase.getClass().getValue(item.mBase) * count); InventoryItemModel::removeItem(item, count); } + + bool CompanionItemModel::hasProfit(const MWWorld::Ptr &actor) + { + std::string script = actor.getClass().getScript(actor); + if (script.empty()) + return false; + return actor.getRefData().getLocals().hasVar(script, "minimumprofit"); + } } diff --git a/apps/openmw/mwgui/companionitemmodel.hpp b/apps/openmw/mwgui/companionitemmodel.hpp index 172fa9508..4c77ee12f 100644 --- a/apps/openmw/mwgui/companionitemmodel.hpp +++ b/apps/openmw/mwgui/companionitemmodel.hpp @@ -15,6 +15,8 @@ namespace MWGui virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner); virtual void removeItem (const ItemStack& item, size_t count); + + bool hasProfit(const MWWorld::Ptr& actor); }; } diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index 53b14691b..8f709ec8d 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -17,6 +17,21 @@ #include "draganddrop.hpp" #include "countdialog.hpp" +namespace +{ + + int getProfit(const MWWorld::Ptr& actor) + { + std::string script = actor.getClass().getScript(actor); + if (!script.empty()) + { + return actor.getRefData().getLocals().getIntVar(script, "minimumprofit"); + } + return 0; + } + +} + namespace MWGui { @@ -116,13 +131,12 @@ void CompanionWindow::updateEncumbranceBar() float encumbrance = mPtr.getClass().getEncumbrance(mPtr); mEncumbranceBar->setValue(encumbrance, capacity); - if (mPtr.getTypeName() != typeid(ESM::NPC).name()) - mProfitLabel->setCaption(""); - else + if (mModel && mModel->hasProfit(mPtr)) { - MWMechanics::NpcStats& stats = mPtr.getClass().getNpcStats(mPtr); - mProfitLabel->setCaptionWithReplacing("#{sProfitValue} " + MyGUI::utility::toString(stats.getProfit())); + mProfitLabel->setCaptionWithReplacing("#{sProfitValue} " + MyGUI::utility::toString(getProfit(mPtr))); } + else + mProfitLabel->setCaption(""); } void CompanionWindow::onCloseButtonClicked(MyGUI::Widget* _sender) @@ -132,7 +146,7 @@ void CompanionWindow::onCloseButtonClicked(MyGUI::Widget* _sender) void CompanionWindow::exit() { - if (mPtr.getTypeName() == typeid(ESM::NPC).name() && mPtr.getClass().getNpcStats(mPtr).getProfit() < 0) + if (mModel && mModel->hasProfit(mPtr) && getProfit(mPtr) < 0) { std::vector buttons; buttons.push_back("#{sCompanionWarningButtonOne}"); @@ -148,9 +162,6 @@ void CompanionWindow::onMessageBoxButtonClicked(int button) { if (button == 0) { - mPtr.getRefData().getLocals().setVarByInt(mPtr.getClass().getScript(mPtr), - "minimumprofit", mPtr.getClass().getNpcStats(mPtr).getProfit()); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Companion); // Important for Calvus' contract script to work properly MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index b4312dc40..13a5c559c 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -182,6 +182,10 @@ namespace MWGui HUD::~HUD() { + mMainWidget->eventMouseLostFocus.clear(); + mMainWidget->eventMouseMove.clear(); + mMainWidget->eventMouseButtonClick.clear(); + delete mSpellIcons; } diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 00d60f23b..61712a470 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -12,6 +12,8 @@ #include #include +#include + #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" @@ -22,10 +24,9 @@ #include "../mwrender/globalmap.hpp" -#include - #include "widgets.hpp" #include "confirmationdialog.hpp" +#include "tooltips.hpp" namespace { @@ -226,7 +227,7 @@ namespace MWGui redraw(); } - MyGUI::IntPoint LocalMapBase::getMarkerPosition(float worldX, float worldY, MarkerPosition& markerPos) + MyGUI::IntPoint LocalMapBase::getMarkerPosition(float worldX, float worldY, MarkerUserData& markerPos) { MyGUI::IntPoint widgetPos; // normalized cell coordinates @@ -295,7 +296,7 @@ namespace MWGui continue; } - MarkerPosition markerPos; + MarkerUserData markerPos; MyGUI::IntPoint widgetPos = getMarkerPosition(marker.mWorldX, marker.mWorldY, markerPos); MyGUI::IntCoord widgetCoord(widgetPos.left - 4, @@ -380,8 +381,17 @@ namespace MWGui { MWBase::World::DoorMarker marker = *it; - MarkerPosition markerPos; - MyGUI::IntPoint widgetPos = getMarkerPosition(marker.x, marker.y, markerPos); + std::vector destNotes; + for (std::vector::const_iterator it = mCustomMarkers.begin(); it != mCustomMarkers.end(); ++it) + { + if (it->mCell == marker.dest) + destNotes.push_back(it->mNote); + } + + MarkerUserData data; + data.notes = destNotes; + data.caption = marker.name; + MyGUI::IntPoint widgetPos = getMarkerPosition(marker.x, marker.y, data); MyGUI::IntCoord widgetCoord(widgetPos.left - 4, widgetPos.top - 4, 8, 8); @@ -392,12 +402,10 @@ namespace MWGui markerWidget->setHoverColour(MyGUI::Colour::parse(MyGUI::LanguageManager::getInstance().replaceTags("#{fontcolour=normal_over}"))); markerWidget->setDepth(Local_MarkerLayer); markerWidget->setNeedMouseFocus(true); - markerWidget->setUserString("ToolTipType", "Layout"); - markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); - markerWidget->setUserString("Caption_TextOneLine", marker.name); // Used by tooltips to not show the tooltip if marker is hidden by fog of war - markerWidget->setUserString("IsMarker", "true"); - markerWidget->setUserData(markerPos); + markerWidget->setUserString("ToolTipType", "MapMarker"); + + markerWidget->setUserData(data); doorMarkerCreated(markerWidget); mDoorMarkerWidgets.push_back(markerWidget); @@ -480,7 +488,7 @@ namespace MWGui for (std::vector::iterator it = markers.begin(); it != markers.end(); ++it) { const ESM::Position& worldPos = it->getRefData().getPosition(); - MarkerPosition markerPos; + MarkerUserData markerPos; MyGUI::IntPoint widgetPos = getMarkerPosition(worldPos.pos[0], worldPos.pos[1], markerPos); MyGUI::IntCoord widgetCoord(widgetPos.left - 4, widgetPos.top - 4, @@ -490,9 +498,8 @@ namespace MWGui widgetCoord, MyGUI::Align::Default); markerWidget->setDepth(Local_MarkerAboveFogLayer); markerWidget->setImageTexture(markerTexture); - markerWidget->setUserString("IsMarker", "true"); - markerWidget->setUserData(markerPos); markerWidget->setColour(markerColour); + markerWidget->setNeedMouseFocus(false); mMagicMarkerWidgets.push_back(markerWidget); } } @@ -526,7 +533,7 @@ namespace MWGui if (markedCell && markedCell->isExterior() == !mInterior && (!mInterior || Misc::StringUtils::ciEqual(markedCell->getCell()->mName, mPrefix))) { - MarkerPosition markerPos; + MarkerUserData markerPos; MyGUI::IntPoint widgetPos = getMarkerPosition(markedPosition.pos[0], markedPosition.pos[1], markerPos); MyGUI::IntCoord widgetCoord(widgetPos.left - 4, widgetPos.top - 4, @@ -535,8 +542,7 @@ namespace MWGui widgetCoord, MyGUI::Align::Default); markerWidget->setDepth(Local_MarkerAboveFogLayer); markerWidget->setImageTexture("textures\\menu_map_smark.dds"); - markerWidget->setUserString("IsMarker", "true"); - markerWidget->setUserData(markerPos); + markerWidget->setNeedMouseFocus(false); mMagicMarkerWidgets.push_back(markerWidget); } diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 7b6c1f205..a80b3e4c5 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -65,13 +65,15 @@ namespace MWGui bool toggleFogOfWar(); - struct MarkerPosition + struct MarkerUserData { bool interior; int cellX; int cellY; float nX; float nY; + std::vector notes; + std::string caption; }; protected: @@ -100,7 +102,7 @@ namespace MWGui void applyFogOfWar(); - MyGUI::IntPoint getMarkerPosition (float worldX, float worldY, MarkerPosition& markerPos); + MyGUI::IntPoint getMarkerPosition (float worldX, float worldY, MarkerUserData& markerPos); virtual void notifyPlayerUpdate() {} virtual void notifyMapChanged() {} diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 303b8819f..2849688c2 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -163,15 +163,19 @@ namespace MWGui // 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") + if (type == "MapMarker") { - LocalMapBase::MarkerPosition pos = *focus->getUserData(); + LocalMapBase::MarkerUserData data = *focus->getUserData(); - if (!MWBase::Environment::get().getWorld ()->isPositionExplored (pos.nX, pos.nY, pos.cellX, pos.cellY, pos.interior)) + if (!MWBase::Environment::get().getWorld ()->isPositionExplored (data.nX, data.nY, data.cellX, data.cellY, data.interior)) return; - } - if (type == "ItemPtr") + ToolTipInfo info; + info.text = data.caption; + info.notes = data.notes; + tooltipSize = createToolTip(info); + } + else if (type == "ItemPtr") { mFocusObject = *focus->getUserData(); tooltipSize = getToolTipViaPtr(false); @@ -403,16 +407,33 @@ namespace MWGui MyGUI::IntSize totalSize = MyGUI::IntSize( std::min(std::max(textSize.width,captionSize.width + ((image != "") ? imageCaptionHPadding : 0)),maximumWidth), ((text != "") ? textSize.height + imageCaptionVPadding : 0) + captionHeight ); + for (std::vector::const_iterator it = info.notes.begin(); it != info.notes.end(); ++it) + { + MyGUI::ImageBox* icon = mDynamicToolTipBox->createWidget("MarkerButton", + MyGUI::IntCoord(padding.left, totalSize.height+padding.top, 8, 8), MyGUI::Align::Default); + icon->setColour(MyGUI::Colour(1.0,0.3,0.3)); + MyGUI::EditBox* edit = mDynamicToolTipBox->createWidget("SandText", + MyGUI::IntCoord(padding.left+8+4, totalSize.height+padding.top, 300-padding.left-8-4, 300-totalSize.height), + MyGUI::Align::Default); + edit->setEditMultiLine(true); + edit->setEditWordWrap(true); + edit->setCaption(*it); + edit->setSize(edit->getWidth(), edit->getTextSize().height); + icon->setPosition(icon->getLeft(),(edit->getTop()+edit->getBottom())/2-icon->getHeight()/2); + totalSize.height += std::max(edit->getHeight(), icon->getHeight()); + totalSize.width = std::max(totalSize.width, edit->getWidth()+8+4); + } + if (!info.effects.empty()) { MyGUI::Widget* effectArea = mDynamicToolTipBox->createWidget("", MyGUI::IntCoord(padding.left, totalSize.height, 300-padding.left, 300-totalSize.height), - MyGUI::Align::Stretch, "ToolTipEffectArea"); + MyGUI::Align::Stretch); MyGUI::IntCoord coord(0, 6, totalSize.width, 24); Widgets::MWEffectListPtr effectsWidget = effectArea->createWidget - ("MW_StatName", coord, MyGUI::Align::Default, "ToolTipEffectsWidget"); + ("MW_StatName", coord, MyGUI::Align::Default); effectsWidget->setEffectList(info.effects); std::vector effectItems; @@ -426,12 +447,12 @@ namespace MWGui assert(enchant); MyGUI::Widget* enchantArea = mDynamicToolTipBox->createWidget("", MyGUI::IntCoord(padding.left, totalSize.height, 300-padding.left, 300-totalSize.height), - MyGUI::Align::Stretch, "ToolTipEnchantArea"); + MyGUI::Align::Stretch); MyGUI::IntCoord coord(0, 6, totalSize.width, 24); Widgets::MWEffectListPtr enchantWidget = enchantArea->createWidget - ("MW_StatName", coord, MyGUI::Align::Default, "ToolTipEnchantWidget"); + ("MW_StatName", coord, MyGUI::Align::Default); enchantWidget->setEffectList(Widgets::MWEffectList::effectListFromESM(&enchant->mEffects)); std::vector enchantEffectItems; @@ -470,7 +491,7 @@ namespace MWGui chargeCoord = MyGUI::IntCoord((totalSize.width - chargeAndTextWidth)/2 + chargeTextWidth, coord.top+6, chargeWidth, 18); } Widgets::MWDynamicStatPtr chargeWidget = enchantArea->createWidget - ("MW_ChargeBar", chargeCoord, MyGUI::Align::Default, "ToolTipEnchantCharge"); + ("MW_ChargeBar", chargeCoord, MyGUI::Align::Default); chargeWidget->setValue(charge, maxCharge); totalSize.height += 24; } @@ -505,7 +526,7 @@ namespace MWGui { MyGUI::ImageBox* imageWidget = mDynamicToolTipBox->createWidget("ImageBox", MyGUI::IntCoord((totalSize.width - captionSize.width - imageCaptionHPadding)/2, 0, imageSize, imageSize), - MyGUI::Align::Left | MyGUI::Align::Top, "ToolTipImage"); + MyGUI::Align::Left | MyGUI::Align::Top); imageWidget->setImageTexture(realImage); imageWidget->setPosition (imageWidget->getPosition() + padding); } diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index 21b5527cc..4bd4d88aa 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -38,6 +38,9 @@ namespace MWGui // effects (for potions, ingredients) Widgets::SpellEffectList effects; + // local map notes + std::vector notes; + bool isPotion; // potions do not show target in the tooltip bool wordWrap; }; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index cf4679287..975ee6c29 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -352,6 +352,12 @@ namespace MWGui WindowManager::~WindowManager() { + MyGUI::LanguageManager::getInstance().eventRequestTag.clear(); + MyGUI::PointerManager::getInstance().eventChangeMousePointer.clear(); + MyGUI::InputManager::getInstance().eventChangeKeyFocus.clear(); + MyGUI::ClipboardManager::getInstance().eventClipboardChanged.clear(); + MyGUI::ClipboardManager::getInstance().eventClipboardRequested.clear(); + delete mConsole; delete mMessageBoxManager; delete mHud; @@ -385,7 +391,6 @@ namespace MWGui delete mMerchantRepair; delete mRepair; delete mSoulgemDialog; - delete mCursorManager; delete mRecharge; delete mCompanionWindow; delete mHitFader; @@ -394,6 +399,8 @@ namespace MWGui delete mBlindnessFader; delete mDebugWindow; + delete mCursorManager; + cleanupGarbage(); delete mGuiManager; diff --git a/apps/openmw/mwgui/windowpinnablebase.cpp b/apps/openmw/mwgui/windowpinnablebase.cpp index 7307ece2d..a6984b5a4 100644 --- a/apps/openmw/mwgui/windowpinnablebase.cpp +++ b/apps/openmw/mwgui/windowpinnablebase.cpp @@ -12,7 +12,7 @@ namespace MWGui ExposedWindow* window = mMainWidget->castType(); mPinButton = window->getSkinWidget ("Button"); - mPinButton->eventMouseButtonClick += MyGUI::newDelegate(this, &WindowPinnableBase::onPinButtonClicked); + mPinButton->eventMouseButtonPressed += MyGUI::newDelegate(this, &WindowPinnableBase::onPinButtonPressed); MyGUI::Button* button = NULL; MyGUI::VectorWidgetPtr widgets = window->getSkinWidgetsByName("Action"); @@ -26,8 +26,11 @@ namespace MWGui button->eventMouseButtonDoubleClick += MyGUI::newDelegate(this, &WindowPinnableBase::onDoubleClick); } - void WindowPinnableBase::onPinButtonClicked(MyGUI::Widget* _sender) + void WindowPinnableBase::onPinButtonPressed(MyGUI::Widget* _sender, int left, int top, MyGUI::MouseButton id) { + if (id != MyGUI::MouseButton::Left) + return; + mPinned = !mPinned; if (mPinned) @@ -46,7 +49,7 @@ namespace MWGui void WindowPinnableBase::setPinned(bool pinned) { if (pinned != mPinned) - onPinButtonClicked(mPinButton); + onPinButtonPressed(mPinButton, 0, 0, MyGUI::MouseButton::Left); } void WindowPinnableBase::setPinButtonVisible(bool visible) diff --git a/apps/openmw/mwgui/windowpinnablebase.hpp b/apps/openmw/mwgui/windowpinnablebase.hpp index 8b7bbefaf..c085bebf2 100644 --- a/apps/openmw/mwgui/windowpinnablebase.hpp +++ b/apps/openmw/mwgui/windowpinnablebase.hpp @@ -16,7 +16,7 @@ namespace MWGui void setPinButtonVisible(bool visible); private: - void onPinButtonClicked(MyGUI::Widget* _sender); + void onPinButtonPressed(MyGUI::Widget* _sender, int left, int top, MyGUI::MouseButton id); void onDoubleClick(MyGUI::Widget* _sender); protected: diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 8d438c703..91b375714 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1126,7 +1126,7 @@ bool CharacterController::updateWeaponState() attackStrength = std::min(1.f, 0.1f + std::rand() / float(RAND_MAX)); } - if(mAttackType != "shoot") + if(mWeaponType != WeapType_Crossbow && mWeaponType != WeapType_BowAndArrow) { MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index 1d243ef45..e22e9ec24 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -371,6 +371,23 @@ namespace MWMechanics sndMgr->playSound3D(victim, "Hand To Hand Hit", 1.0f, 1.0f); } + void applyFatigueLoss(const MWWorld::Ptr &attacker, const MWWorld::Ptr &weapon) + { + // somewhat of a guess, but using the weapon weight makes sense + const MWWorld::Store& store = MWBase::Environment::get().getWorld()->getStore().get(); + const float fFatigueAttackBase = store.find("fFatigueAttackBase")->getFloat(); + const float fFatigueAttackMult = store.find("fFatigueAttackMult")->getFloat(); + const float fWeaponFatigueMult = store.find("fWeaponFatigueMult")->getFloat(); + CreatureStats& stats = attacker.getClass().getCreatureStats(attacker); + MWMechanics::DynamicStat fatigue = stats.getFatigue(); + const float normalizedEncumbrance = attacker.getClass().getNormalizedEncumbrance(attacker); + float fatigueLoss = fFatigueAttackBase + normalizedEncumbrance * fFatigueAttackMult; + if (!weapon.isEmpty()) + fatigueLoss += weapon.getClass().getWeight(weapon) * stats.getAttackStrength() * fWeaponFatigueMult; + fatigue.setCurrent(fatigue.getCurrent() - fatigueLoss); + stats.setFatigue(fatigue); + } + bool isEnvironmentCompatible(const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim) { const MWWorld::Class& attackerClass = attacker.getClass(); diff --git a/apps/openmw/mwmechanics/combat.hpp b/apps/openmw/mwmechanics/combat.hpp index 41dd2d1a4..a48dcf72a 100644 --- a/apps/openmw/mwmechanics/combat.hpp +++ b/apps/openmw/mwmechanics/combat.hpp @@ -34,6 +34,9 @@ void adjustWeaponDamage (float& damage, const MWWorld::Ptr& weapon); void getHandToHandDamage (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, float& damage, bool& healthdmg); +/// Apply the fatigue loss incurred by attacking with the given weapon (weapon may be empty = hand-to-hand) +void applyFatigueLoss(const MWWorld::Ptr& attacker, const MWWorld::Ptr& weapon); + /// Can attacker operate in victim's environment? /// e.g. If attacker is a fish, is victim in water? Or, if attacker can't swim, is victim on land? bool isEnvironmentCompatible(const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim); diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index c61cc9697..ac35fc2ea 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -495,7 +495,10 @@ namespace MWMechanics state.mDead = mDead; state.mDied = mDied; state.mMurdered = mMurdered; - state.mFriendlyHits = mFriendlyHits; + // The vanilla engine does not store friendly hits in the save file. Since there's no other mechanism + // that ever resets the friendly hits (at least not to my knowledge) this should be regarded a feature + // rather than a bug. + //state.mFriendlyHits = mFriendlyHits; state.mTalkedTo = mTalkedTo; state.mAlarmed = mAlarmed; state.mAttacked = mAttacked; @@ -544,7 +547,6 @@ namespace MWMechanics mDead = state.mDead; mDied = state.mDied; mMurdered = state.mMurdered; - mFriendlyHits = state.mFriendlyHits; mTalkedTo = state.mTalkedTo; mAlarmed = state.mAlarmed; mAttacked = state.mAttacked; diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index c3a4d2312..c517b4df8 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -31,7 +31,6 @@ MWMechanics::NpcStats::NpcStats() , mReputation(0) , mCrimeId(-1) , mWerewolfKills (0) -, mProfit(0) , mTimeToStartDrowning(20.0) { mSkillIncreases.resize (ESM::Attribute::Length, 0); @@ -448,16 +447,6 @@ void MWMechanics::NpcStats::addWerewolfKill() ++mWerewolfKills; } -int MWMechanics::NpcStats::getProfit() const -{ - return mProfit; -} - -void MWMechanics::NpcStats::modifyProfit(int diff) -{ - mProfit += diff; -} - float MWMechanics::NpcStats::getTimeToStartDrowning() const { return mTimeToStartDrowning; @@ -501,7 +490,6 @@ void MWMechanics::NpcStats::writeState (ESM::NpcStats& state) const state.mReputation = mReputation; state.mWerewolfKills = mWerewolfKills; - state.mProfit = mProfit; state.mLevelProgress = mLevelProgress; for (int i=0; imControllers.size();i++) diff --git a/apps/openmw/mwrender/refraction.cpp b/apps/openmw/mwrender/refraction.cpp index 164380866..6cc49089a 100644 --- a/apps/openmw/mwrender/refraction.cpp +++ b/apps/openmw/mwrender/refraction.cpp @@ -33,7 +33,7 @@ namespace MWRender Ogre::Viewport* vp = mRenderTarget->addViewport(mCamera); vp->setOverlaysEnabled(false); vp->setShadowsEnabled(false); - vp->setVisibilityMask(RV_Actors + RV_Misc + RV_Statics + RV_StaticsSmall + RV_Terrain + RV_Sky + RV_FirstPerson); + vp->setVisibilityMask(RV_Refraction); vp->setMaterialScheme("water_refraction"); vp->setBackgroundColour (Ogre::ColourValue(0.090195, 0.115685, 0.12745)); mRenderTarget->setAutoUpdated(true); diff --git a/apps/openmw/mwrender/renderconst.hpp b/apps/openmw/mwrender/renderconst.hpp index 44599ebee..4ac21ad51 100644 --- a/apps/openmw/mwrender/renderconst.hpp +++ b/apps/openmw/mwrender/renderconst.hpp @@ -30,39 +30,44 @@ enum RenderQueueGroups enum VisibilityFlags { // Terrain - RV_Terrain = 1, + RV_Terrain = (1<<0), // Statics (e.g. trees, houses) - RV_Statics = 2, + RV_Statics = (1<<1), // Small statics - RV_StaticsSmall = 4, + RV_StaticsSmall = (1<<2), // Water - RV_Water = 8, + RV_Water = (1<<3), // Actors (npcs, creatures) - RV_Actors = 16, + RV_Actors = (1<<4), // Misc objects (containers, dynamic objects) - RV_Misc = 32, + RV_Misc = (1<<5), - RV_Sky = 64, + // VFX, don't appear on map and don't cast shadows + RV_Effects = (1<<6), + + RV_Sky = (1<<7), // not visible in reflection - RV_NoReflection = 128, + RV_NoReflection = (1<<8), - RV_OcclusionQuery = 256, + RV_OcclusionQuery = (1<<9), - RV_Debug = 512, + RV_Debug = (1<<10), // overlays, we only want these on the main render target - RV_Overlay = 1024, + RV_Overlay = (1<<11), // First person meshes do not cast shadows - RV_FirstPerson = 2048, + RV_FirstPerson = (1<<12), - RV_Map = RV_Terrain + RV_Statics + RV_StaticsSmall + RV_Misc + RV_Water + RV_Map = RV_Terrain + RV_Statics + RV_StaticsSmall + RV_Misc + RV_Water, + + RV_Refraction = RV_Actors + RV_Misc + RV_Statics + RV_StaticsSmall + RV_Terrain + RV_Effects + RV_Sky + RV_FirstPerson }; } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 149080d93..3ffd787c7 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -409,6 +409,7 @@ void RenderingManager::update (float duration, bool paused) mSkyManager->setGlare(mOcclusionQuery->getSunVisibility()); + mWater->changeCell(player.getCell()->getCell()); mWater->updateUnderwater(world->isUnderwater(player.getCell(), cam)); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 0b9dc091e..454ed8820 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -187,6 +187,8 @@ Moon::Moon( const String& textureName, { setVisibility(1.0); + mMaterial->setProperty("alphatexture", sh::makeProperty(new sh::StringValue(textureName + "_alpha"))); + mPhase = Moon::Phase_Full; } @@ -215,9 +217,15 @@ void Moon::setPhase(const Moon::Phase& phase) textureName += ".dds"; if (mType == Moon::Type_Secunda) + { sh::Factory::getInstance ().setTextureAlias ("secunda_texture", textureName); + sh::Factory::getInstance ().setTextureAlias ("secunda_texture_alpha", "textures\\tx_mooncircle_full_s.dds"); + } else + { sh::Factory::getInstance ().setTextureAlias ("masser_texture", textureName); + sh::Factory::getInstance ().setTextureAlias ("masser_texture_alpha", "textures\\tx_mooncircle_full_m.dds"); + } mPhase = phase; } diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index fd790b363..44e184269 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -210,10 +210,10 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend) : mWaterPlane = Plane(Vector3::UNIT_Z, 0); - int waterScale = 300; + int waterScale = 30; MeshManager::getSingleton().createPlane("water", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, mWaterPlane, - CELL_SIZE*5*waterScale, CELL_SIZE*5*waterScale, 10, 10, true, 1, 3*waterScale,3*waterScale, Vector3::UNIT_Y); + CELL_SIZE*5*waterScale, CELL_SIZE*5*waterScale, 40, 40, true, 1, 3*waterScale,3*waterScale, Vector3::UNIT_Y); mWater = mSceneMgr->createEntity("water"); mWater->setVisibilityFlags(RV_Water); @@ -305,11 +305,7 @@ Water::~Water() void Water::changeCell(const ESM::Cell* cell) { - mTop = cell->mWater; - - setHeight(mTop); - - if(!(cell->mData.mFlags & cell->Interior)) + if(cell->isExterior()) mWaterNode->setPosition(getSceneNodeCoordinates(cell->mData.mX, cell->mData.mY)); } @@ -424,6 +420,7 @@ void Water::applyVisibilityMask() mVisibilityFlags = RV_Terrain * Settings::Manager::getBool("reflect terrain", "Water") + (RV_Statics + RV_StaticsSmall + RV_Misc) * Settings::Manager::getBool("reflect statics", "Water") + RV_Actors * Settings::Manager::getBool("reflect actors", "Water") + + RV_Effects + RV_Sky; if (mReflection) diff --git a/apps/openmw/mwrender/weaponanimation.cpp b/apps/openmw/mwrender/weaponanimation.cpp index 8af4d637a..d16afe3ce 100644 --- a/apps/openmw/mwrender/weaponanimation.cpp +++ b/apps/openmw/mwrender/weaponanimation.cpp @@ -7,12 +7,14 @@ #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" +#include "../mwbase/soundmanager.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/combat.hpp" #include "animation.hpp" @@ -44,9 +46,22 @@ void WeaponAnimation::attachArrow(MWWorld::Ptr actor) { MWWorld::InventoryStore& inv = actor.getClass().getInventoryStore(actor); MWWorld::ContainerStoreIterator weaponSlot = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); - if (weaponSlot != inv.end() && weaponSlot->get()->mBase->mData.mType == ESM::Weapon::MarksmanThrown) + if (weaponSlot == inv.end()) + return; + if (weaponSlot->getTypeName() != typeid(ESM::Weapon).name()) + return; + int weaponType = weaponSlot->get()->mBase->mData.mType; + if (weaponType == ESM::Weapon::MarksmanThrown) + { + std::string soundid = weaponSlot->getClass().getUpSoundId(*weaponSlot); + if(!soundid.empty()) + { + MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); + sndMgr->playSound3D(actor, soundid, 1.0f, 1.0f); + } showWeapon(true); - else + } + else if (weaponType == ESM::Weapon::MarksmanBow || weaponType == ESM::Weapon::MarksmanCrossbow) { NifOgre::ObjectScenePtr weapon = getWeapon(); if (!weapon.get()) @@ -72,6 +87,8 @@ void WeaponAnimation::releaseArrow(MWWorld::Ptr actor) MWWorld::ContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); if (weapon == inv.end()) return; + if (weapon->getTypeName() != typeid(ESM::Weapon).name()) + return; // The orientation of the launched projectile. Always the same as the actor orientation, even if the ArrowBone's orientation dictates otherwise. Ogre::Quaternion orient = Ogre::Quaternion(Ogre::Radian(actor.getRefData().getPosition().rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * @@ -80,19 +97,7 @@ void WeaponAnimation::releaseArrow(MWWorld::Ptr actor) const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); - // Reduce fatigue - // somewhat of a guess, but using the weapon weight makes sense - const float fFatigueAttackBase = gmst.find("fFatigueAttackBase")->getFloat(); - const float fFatigueAttackMult = gmst.find("fFatigueAttackMult")->getFloat(); - const float fWeaponFatigueMult = gmst.find("fWeaponFatigueMult")->getFloat(); - MWMechanics::CreatureStats& attackerStats = actor.getClass().getCreatureStats(actor); - MWMechanics::DynamicStat fatigue = attackerStats.getFatigue(); - const float normalizedEncumbrance = actor.getClass().getNormalizedEncumbrance(actor); - float fatigueLoss = fFatigueAttackBase + normalizedEncumbrance * fFatigueAttackMult; - if (!weapon->isEmpty()) - fatigueLoss += weapon->getClass().getWeight(*weapon) * attackerStats.getAttackStrength() * fWeaponFatigueMult; - fatigue.setCurrent(fatigue.getCurrent() - fatigueLoss); - attackerStats.setFatigue(fatigue); + MWMechanics::applyFatigueLoss(actor, *weapon); if (weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanThrown) { diff --git a/apps/openmw/mwrender/weaponanimation.hpp b/apps/openmw/mwrender/weaponanimation.hpp index cbe910c71..e1ccd9465 100644 --- a/apps/openmw/mwrender/weaponanimation.hpp +++ b/apps/openmw/mwrender/weaponanimation.hpp @@ -35,8 +35,11 @@ namespace MWRender WeaponAnimation() : mPitchFactor(0) {} virtual ~WeaponAnimation() {} - virtual void attachArrow(MWWorld::Ptr actor); - virtual void releaseArrow(MWWorld::Ptr actor); + /// @note If no weapon (or an invalid weapon) is equipped, this function is a no-op. + void attachArrow(MWWorld::Ptr actor); + + /// @note If no weapon (or an invalid weapon) is equipped, this function is a no-op. + void releaseArrow(MWWorld::Ptr actor); protected: NifOgre::ObjectScenePtr mAmmunition; diff --git a/apps/openmw/mwscript/locals.cpp b/apps/openmw/mwscript/locals.cpp index fe3e49827..9dbf07fba 100644 --- a/apps/openmw/mwscript/locals.cpp +++ b/apps/openmw/mwscript/locals.cpp @@ -32,6 +32,21 @@ namespace MWScript return (mShorts.empty() && mLongs.empty() && mFloats.empty()); } + bool Locals::hasVar(const std::string &script, const std::string &var) + { + try + { + const Compiler::Locals& locals = + MWBase::Environment::get().getScriptManager()->getLocals(script); + int index = locals.getIndex(var); + return (index != -1); + } + catch (const Compiler::SourceException&) + { + return false; + } + } + int Locals::getIntVar(const std::string &script, const std::string &var) { const Compiler::Locals& locals = MWBase::Environment::get().getScriptManager()->getLocals(script); diff --git a/apps/openmw/mwscript/locals.hpp b/apps/openmw/mwscript/locals.hpp index 9fa4214ac..bd95835ac 100644 --- a/apps/openmw/mwscript/locals.hpp +++ b/apps/openmw/mwscript/locals.hpp @@ -24,11 +24,15 @@ namespace MWScript bool isEmpty() const; void configure (const ESM::Script& script); + /// @note var needs to be in lowercase bool setVarByInt(const std::string& script, const std::string& var, int val); - int getIntVar (const std::string& script, const std::string& var); - ///< if var does not exist, returns 0 + + bool hasVar(const std::string& script, const std::string& var); + + /// if var does not exist, returns 0 /// @note var needs to be in lowercase + int getIntVar (const std::string& script, const std::string& var); void write (ESM::Locals& locals, const std::string& script) const; diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 7568f604d..3bbde2003 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -518,42 +518,41 @@ namespace MWScript if (count<0) throw std::runtime_error ("count must be non-negative"); - // no-op - if (count == 0) - return; - - ESM::Position ipos = actor.getRefData().getPosition(); - Ogre::Vector3 pos(ipos.pos[0],ipos.pos[1],ipos.pos[2]); - Ogre::Quaternion rot(Ogre::Radian(-ipos.rot[2]), Ogre::Vector3::UNIT_Z); - if(direction == 0) pos = pos + distance*rot.yAxis(); - else if(direction == 1) pos = pos - distance*rot.yAxis(); - else if(direction == 2) pos = pos - distance*rot.xAxis(); - else if(direction == 3) pos = pos + distance*rot.xAxis(); - else throw std::runtime_error ("direction must be 0,1,2 or 3"); - - ipos.pos[0] = pos.x; - ipos.pos[1] = pos.y; - ipos.pos[2] = pos.z; - - if (actor.getClass().isActor()) + for (int i=0; igetStore(), itemID, count); - ref.getPtr().getCellRef().setPosition(ipos); + ESM::Position ipos = actor.getRefData().getPosition(); + Ogre::Vector3 pos(ipos.pos[0],ipos.pos[1],ipos.pos[2]); + Ogre::Quaternion rot(Ogre::Radian(-ipos.rot[2]), Ogre::Vector3::UNIT_Z); + if(direction == 0) pos = pos + distance*rot.yAxis(); + else if(direction == 1) pos = pos - distance*rot.yAxis(); + else if(direction == 2) pos = pos - distance*rot.xAxis(); + else if(direction == 3) pos = pos + distance*rot.xAxis(); + else throw std::runtime_error ("direction must be 0,1,2 or 3"); - MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,ipos); + ipos.pos[0] = pos.x; + ipos.pos[1] = pos.y; + ipos.pos[2] = pos.z; + + if (actor.getClass().isActor()) + { + // TODO: should this depend on the 'direction' parameter? + ipos.rot[0] = 0; + ipos.rot[1] = 0; + ipos.rot[2] = 0; + } + else + { + ipos.rot[0] = actor.getRefData().getPosition().rot[0]; + ipos.rot[1] = actor.getRefData().getPosition().rot[1]; + ipos.rot[2] = actor.getRefData().getPosition().rot[2]; + } + // create item + MWWorld::CellStore* store = actor.getCell(); + MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), itemID, 1); + ref.getPtr().getCellRef().setPosition(ipos); + + MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,ipos); + } } }; diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index 2eddc98d3..bc467acff 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -25,14 +25,28 @@ void FFmpeg_Decoder::fail(const std::string &msg) int FFmpeg_Decoder::readPacket(void *user_data, uint8_t *buf, int buf_size) { - Ogre::DataStreamPtr stream = static_cast(user_data)->mDataStream; - return stream->read(buf, buf_size); + try + { + Ogre::DataStreamPtr stream = static_cast(user_data)->mDataStream; + return stream->read(buf, buf_size); + } + catch (std::exception& e) + { + return 0; + } } int FFmpeg_Decoder::writePacket(void *user_data, uint8_t *buf, int buf_size) { - Ogre::DataStreamPtr stream = static_cast(user_data)->mDataStream; - return stream->write(buf, buf_size); + try + { + Ogre::DataStreamPtr stream = static_cast(user_data)->mDataStream; + return stream->write(buf, buf_size); + } + catch (std::exception& e) + { + return 0; + } } int64_t FFmpeg_Decoder::seek(void *user_data, int64_t offset, int whence) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 0090ca010..bea99029a 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -303,26 +303,15 @@ namespace MWWorld Ogre::Vector3 halfExtents = physicActor->getHalfExtents(); position.z += halfExtents.z; - waterlevel -= halfExtents.z * 0.5; - /* - * A 3/4 submerged example - * - * +---+ - * | | - * | | <- (original waterlevel) - * | | - * | | <- position <- waterlevel - * | | - * | | - * | | - * +---+ <- (original position) - */ + static const float fSwimHeightScale = MWBase::Environment::get().getWorld()->getStore().get() + .find("fSwimHeightScale")->getFloat(); + float swimlevel = waterlevel + halfExtents.z - (halfExtents.z * 2 * fSwimHeightScale); OEngine::Physic::ActorTracer tracer; Ogre::Vector3 inertia = physicActor->getInertialForce(); Ogre::Vector3 velocity; - if(position.z < waterlevel || isFlying) + if(position.z < swimlevel || isFlying) { velocity = (Ogre::Quaternion(Ogre::Radian(refpos.rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z)* Ogre::Quaternion(Ogre::Radian(refpos.rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X)) * movement; @@ -364,12 +353,10 @@ namespace MWWorld Ogre::Vector3 nextpos = newPosition + velocity * remainingTime; // If not able to fly, don't allow to swim up into the air - // TODO: this if condition may not work for large creatures or situations - // where the creature gets above the waterline for some reason - if(newPosition.z < waterlevel && // started 3/4 under water + if(newPosition.z < swimlevel && !isFlying && // can't fly - nextpos.z > waterlevel && // but about to go above water - newPosition.z <= waterlevel) + nextpos.z > swimlevel && // but about to go above water + newPosition.z <= swimlevel) { const Ogre::Vector3 down(0,0,-1); Ogre::Real movelen = velocity.normalise(); @@ -423,7 +410,7 @@ namespace MWWorld { // don't let pure water creatures move out of water after stepMove if (ptr.getClass().isPureWaterCreature(ptr) - && newPosition.z > (waterlevel - halfExtents.z * 0.5)) + && newPosition.z + halfExtents.z > waterlevel) newPosition = oldPosition; } else @@ -444,13 +431,13 @@ namespace MWWorld // Do not allow sliding upward if there is gravity. Stepping will have taken // care of that. - if(!(newPosition.z < waterlevel || isFlying)) + if(!(newPosition.z < swimlevel || isFlying)) velocity.z = std::min(velocity.z, 0.0f); } } bool isOnGround = false; - if (!(inertia.z > 0.f) && !(newPosition.z < waterlevel)) + if (!(inertia.z > 0.f) && !(newPosition.z < swimlevel)) { Ogre::Vector3 from = newPosition; Ogre::Vector3 to = newPosition - (physicActor->getOnGround() ? @@ -494,7 +481,7 @@ namespace MWWorld } } - if(isOnGround || newPosition.z < waterlevel || isFlying) + if(isOnGround || newPosition.z < swimlevel || isFlying) physicActor->setInertialForce(Ogre::Vector3(0.0f)); else { diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 41fbfea9f..7af51fd28 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -44,7 +44,7 @@ namespace MWWorld state.mObject->mControllers[i].setSource(Ogre::SharedPtr (new MWRender::EffectAnimationTime())); } - MWRender::Animation::setRenderProperties(state.mObject, MWRender::RV_Misc, + MWRender::Animation::setRenderProperties(state.mObject, MWRender::RV_Effects, MWRender::RQG_Main, MWRender::RQG_Alpha, 0.f, false, NULL); } diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index b6ad5c104..72d475f16 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -544,9 +544,16 @@ namespace MWWorld void Scene::addObjectToScene (const Ptr& ptr) { - addObject(ptr, *mPhysics, mRendering); - MWBase::Environment::get().getWorld()->rotateObject(ptr, 0, 0, 0, true); - MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().getScale()); + try + { + addObject(ptr, *mPhysics, mRendering); + MWBase::Environment::get().getWorld()->rotateObject(ptr, 0, 0, 0, true); + MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().getScale()); + } + catch (std::exception& e) + { + std::cerr << "error during rendering: " << e.what() << std::endl; + } } void Scene::removeObjectFromScene (const Ptr& ptr) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 929ff62a2..a155a3760 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -360,6 +360,8 @@ namespace MWWorld std::pair inserted = mStatic.insert(std::make_pair(scpt.mId, scpt)); if (inserted.second) mShared.push_back(&inserted.first->second); + else + inserted.first->second = scpt; } template <> @@ -371,6 +373,8 @@ namespace MWWorld std::pair inserted = mStatic.insert(std::make_pair(s.mId, s)); if (inserted.second) mShared.push_back(&inserted.first->second); + else + inserted.first->second = s; } template <> diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 8cdd7037b..1036d8ce6 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -187,6 +187,8 @@ namespace MWWorld mStore.setUp(); mStore.movePlayerRecord(); + mSwimHeightScale = mStore.get().find("fSwimHeightScale")->getFloat(); + mGlobalVariables.fill (mStore); mWorldScene = new Scene(*mRendering, mPhysics); @@ -1735,6 +1737,23 @@ namespace MWWorld World::DoorMarker newMarker; newMarker.name = MWClass::Door::getDestination(ref); + ESM::CellId cellid; + if (!ref.mRef.getDestCell().empty()) + { + cellid.mWorldspace = ref.mRef.getDestCell(); + cellid.mPaged = false; + } + else + { + cellid.mPaged = true; + MWBase::Environment::get().getWorld()->positionToIndex( + ref.mRef.getDoorDest().pos[0], + ref.mRef.getDoorDest().pos[1], + cellid.mIndex.mX, + cellid.mIndex.mY); + } + newMarker.dest = cellid; + ESM::Position pos = ref.mData.getPosition (); newMarker.x = pos.pos[0]; @@ -1935,8 +1954,7 @@ namespace MWWorld mRendering->getTriangleBatchCount(triangles, batches); } - bool - World::isFlying(const MWWorld::Ptr &ptr) const + bool World::isFlying(const MWWorld::Ptr &ptr) const { const MWMechanics::CreatureStats &stats = ptr.getClass().getCreatureStats(ptr); bool isParalyzed = (stats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0); @@ -1961,8 +1979,7 @@ namespace MWWorld return false; } - bool - World::isSlowFalling(const MWWorld::Ptr &ptr) const + bool World::isSlowFalling(const MWWorld::Ptr &ptr) const { if(!ptr.getClass().isActor()) return false; @@ -1976,27 +1993,21 @@ namespace MWWorld bool World::isSubmerged(const MWWorld::Ptr &object) const { - const float neckDeep = 1.85f; - return isUnderwater(object, neckDeep); + return isUnderwater(object, 1.0/mSwimHeightScale); } - bool - World::isSwimming(const MWWorld::Ptr &object) const + bool World::isSwimming(const MWWorld::Ptr &object) const { - /// \todo add check ifActor() - only actors can swim - /// \fixme 3/4ths submerged? - return isUnderwater(object, 1.5f); + return isUnderwater(object, mSwimHeightScale); } - bool - World::isWading(const MWWorld::Ptr &object) const + bool World::isWading(const MWWorld::Ptr &object) const { - const float kneeDeep = 0.5f; + const float kneeDeep = 0.25f; return isUnderwater(object, kneeDeep); } - bool - World::isUnderwater(const MWWorld::Ptr &object, const float heightRatio) const + bool World::isUnderwater(const MWWorld::Ptr &object, const float heightRatio) const { const float *fpos = object.getRefData().getPosition().pos; Ogre::Vector3 pos(fpos[0], fpos[1], fpos[2]); @@ -2004,14 +2015,13 @@ namespace MWWorld const OEngine::Physic::PhysicActor *actor = mPhysEngine->getCharacter(object.getRefData().getHandle()); if (actor) { - pos.z += heightRatio*actor->getHalfExtents().z; + pos.z += heightRatio*2*actor->getHalfExtents().z; } return isUnderwater(object.getCell(), pos); } - bool - World::isUnderwater(const MWWorld::CellStore* cell, const Ogre::Vector3 &pos) const + bool World::isUnderwater(const MWWorld::CellStore* cell, const Ogre::Vector3 &pos) const { if (!(cell->getCell()->mData.mFlags & ESM::Cell::HasWater)) { return false; @@ -2606,7 +2616,7 @@ namespace MWWorld // Check mana MWMechanics::DynamicStat magicka = stats.getMagicka(); - if (magicka.getCurrent() < spell->mData.mCost) + if (magicka.getCurrent() < spell->mData.mCost && !(isPlayer && getGodModeState())) { message = "#{sMagicInsufficientSP}"; fail = true; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 18fb354bc..1d103c6a9 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -139,6 +139,7 @@ namespace MWWorld void loadContentFiles(const Files::Collections& fileCollections, const std::vector& content, ContentLoader& contentLoader); + float mSwimHeightScale; bool isUnderwater(const MWWorld::Ptr &object, const float heightRatio) const; ///< helper function for implementing isSwimming(), isSubmerged(), isWading() diff --git a/apps/wizard/mainwizard.cpp b/apps/wizard/mainwizard.cpp index 9a8ec2056..a1370b125 100644 --- a/apps/wizard/mainwizard.cpp +++ b/apps/wizard/mainwizard.cpp @@ -281,7 +281,7 @@ void Wizard::MainWizard::runSettingsImporter() arguments.append(QLatin1String("--cfg")); arguments.append(userPath + QLatin1String("openmw.cfg")); - if (!mImporterInvoker->startProcess(QLatin1String("mwiniimport"), arguments, false)) + if (!mImporterInvoker->startProcess(QLatin1String("openmw-iniimporter"), arguments, false)) return qApp->quit(); } diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index dfc3052ee..0dd2987b5 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -153,7 +153,7 @@ void ESM::CellRef::blank() mLockLevel = 0; mKey.clear(); mTrap.clear(); - mReferenceBlocked = 0; + mReferenceBlocked = -1; mTeleport = false; for (int i=0; i<3; ++i) diff --git a/components/esm/creaturestats.cpp b/components/esm/creaturestats.cpp index cac5cc0a6..75c1c28bc 100644 --- a/components/esm/creaturestats.cpp +++ b/components/esm/creaturestats.cpp @@ -24,8 +24,8 @@ void ESM::CreatureStats::load (ESMReader &esm) mMurdered = false; esm.getHNOT (mMurdered, "MURD"); - mFriendlyHits = 0; - esm.getHNOT (mFriendlyHits, "FRHT"); + if (esm.isNextSub("FRHT")) + esm.skipHSub(); // Friendly hits, no longer used mTalkedTo = false; esm.getHNOT (mTalkedTo, "TALK"); @@ -140,9 +140,6 @@ void ESM::CreatureStats::save (ESMWriter &esm) const if (mMurdered) esm.writeHNT ("MURD", mMurdered); - if (mFriendlyHits) - esm.writeHNT ("FRHT", mFriendlyHits); - if (mTalkedTo) esm.writeHNT ("TALK", mTalkedTo); @@ -235,7 +232,6 @@ void ESM::CreatureStats::blank() mDead = false; mDied = false; mMurdered = false; - mFriendlyHits = 0; mTalkedTo = false; mAlarmed = false; mAttacked = false; diff --git a/components/esm/creaturestats.hpp b/components/esm/creaturestats.hpp index 91ee98333..2a03136d0 100644 --- a/components/esm/creaturestats.hpp +++ b/components/esm/creaturestats.hpp @@ -42,7 +42,6 @@ namespace ESM bool mDead; bool mDied; bool mMurdered; - int mFriendlyHits; bool mTalkedTo; bool mAlarmed; bool mAttacked; diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index 3c43d067f..bbe475ff7 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -123,7 +123,7 @@ std::string ESMReader::getHString() // Skip the following zero byte mCtx.leftRec--; char c; - mEsm->read(&c, 1); + getExact(&c, 1); return ""; } @@ -186,7 +186,7 @@ void ESMReader::getSubName() } // reading the subrecord data anyway. - mEsm->read(mCtx.subName.name, 4); + getExact(mCtx.subName.name, 4); mCtx.leftRec -= 4; } @@ -194,7 +194,7 @@ bool ESMReader::isEmptyOrGetName() { if (mCtx.leftRec) { - mEsm->read(mCtx.subName.name, 4); + getExact(mCtx.subName.name, 4); mCtx.leftRec -= 4; return false; } @@ -294,9 +294,16 @@ void ESMReader::getRecHeader(uint32_t &flags) void ESMReader::getExact(void*x, int size) { - int t = mEsm->read(x, size); - if (t != size) - fail("Read error"); + try + { + int t = mEsm->read(x, size); + if (t != size) + fail("Read error"); + } + catch (std::exception& e) + { + fail(std::string("Read error: ") + e.what()); + } } std::string ESMReader::getString(int size) diff --git a/components/esm/npcstats.cpp b/components/esm/npcstats.cpp index e305ddab0..cc1d6b3dd 100644 --- a/components/esm/npcstats.cpp +++ b/components/esm/npcstats.cpp @@ -57,12 +57,13 @@ void ESM::NpcStats::load (ESMReader &esm) mWerewolfKills = 0; esm.getHNOT (mWerewolfKills, "WKIL"); - mProfit = 0; - esm.getHNOT (mProfit, "PROF"); + // No longer used + if (esm.isNextSub("PROF")) + esm.skipHSub(); // int profit // No longer used. Now part of CreatureStats. - float attackStrength = 0; - esm.getHNOT (attackStrength, "ASTR"); + if (esm.isNextSub("ASTR")) + esm.skipHSub(); // attackStrength mLevelProgress = 0; esm.getHNOT (mLevelProgress, "LPRO"); @@ -132,9 +133,6 @@ void ESM::NpcStats::save (ESMWriter &esm) const if (mWerewolfKills) esm.writeHNT ("WKIL", mWerewolfKills); - if (mProfit) - esm.writeHNT ("PROF", mProfit); - if (mLevelProgress) esm.writeHNT ("LPRO", mLevelProgress); @@ -158,7 +156,6 @@ void ESM::NpcStats::blank() mBounty = 0; mReputation = 0; mWerewolfKills = 0; - mProfit = 0; mLevelProgress = 0; for (int i=0; i<8; ++i) mSkillIncrease[i] = 0; diff --git a/components/esm/npcstats.hpp b/components/esm/npcstats.hpp index 1eb1a3d1a..0138ab209 100644 --- a/components/esm/npcstats.hpp +++ b/components/esm/npcstats.hpp @@ -40,7 +40,6 @@ namespace ESM int mBounty; int mReputation; int mWerewolfKills; - int mProfit; int mLevelProgress; int mSkillIncrease[8]; std::vector mUsedIds; // lower case IDs diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp index 942f47d4e..e321b5814 100644 --- a/components/files/configurationmanager.cpp +++ b/components/files/configurationmanager.cpp @@ -27,8 +27,9 @@ const char* const localToken = "?local?"; const char* const userDataToken = "?userdata?"; const char* const globalToken = "?global?"; -ConfigurationManager::ConfigurationManager() +ConfigurationManager::ConfigurationManager(bool silent) : mFixedPath(applicationName) + , mSilent(silent) { setupTokensMapping(); @@ -129,7 +130,8 @@ void ConfigurationManager::loadConfig(const boost::filesystem::path& path, cfgFile /= std::string(openmwCfgFile); if (boost::filesystem::is_regular_file(cfgFile)) { - std::cout << "Loading config file: " << cfgFile.string() << "... "; + if (!mSilent) + std::cout << "Loading config file: " << cfgFile.string() << "... "; boost::filesystem::ifstream configFileStream(cfgFile); if (configFileStream.is_open()) @@ -137,11 +139,13 @@ void ConfigurationManager::loadConfig(const boost::filesystem::path& path, boost::program_options::store(boost::program_options::parse_config_file( configFileStream, description, true), variables); - std::cout << "done." << std::endl; + if (!mSilent) + std::cout << "done." << std::endl; } else { - std::cout << "failed." << std::endl; + if (!mSilent) + std::cout << "failed." << std::endl; } } } diff --git a/components/files/configurationmanager.hpp b/components/files/configurationmanager.hpp index 35144fe04..b0b7fea9a 100644 --- a/components/files/configurationmanager.hpp +++ b/components/files/configurationmanager.hpp @@ -25,7 +25,7 @@ namespace Files */ struct ConfigurationManager { - ConfigurationManager(); + ConfigurationManager(bool silent=false); /// @param silent Emit log messages to cout? virtual ~ConfigurationManager(); void readConfiguration(boost::program_options::variables_map& variables, @@ -69,6 +69,8 @@ struct ConfigurationManager boost::filesystem::path mLogPath; TokensMappingContainer mTokensMapping; + + bool mSilent; }; } /* namespace Cfg */ diff --git a/components/files/constrainedfiledatastream.cpp b/components/files/constrainedfiledatastream.cpp index 66f6fde97..d4d7c231a 100644 --- a/components/files/constrainedfiledatastream.cpp +++ b/components/files/constrainedfiledatastream.cpp @@ -11,162 +11,172 @@ namespace { class ConstrainedDataStream : public Ogre::DataStream { public: - static const size_t sBufferSize = 4096; // somewhat arbitrary though 64KB buffers didn't seem to improve performance any - static const size_t sBufferThreshold = 1024; // reads larger than this bypass buffering as cost of memcpy outweighs cost of system call + static const size_t sBufferSize = 4096; // somewhat arbitrary though 64KB buffers didn't seem to improve performance any + static const size_t sBufferThreshold = 1024; // reads larger than this bypass buffering as cost of memcpy outweighs cost of system call ConstrainedDataStream(const Ogre::String &fname, size_t start, size_t length) - { - mFile.open (fname.c_str ()); - mSize = length != 0xFFFFFFFF ? length : mFile.size () - start; + : Ogre::DataStream(fname) + { + mFile.open (fname.c_str ()); + mSize = length != 0xFFFFFFFF ? length : mFile.size () - start; - mPos = 0; - mOrigin = start; - mExtent = start + mSize; + mPos = 0; + mOrigin = start; + mExtent = start + mSize; - mBufferOrigin = 0; - mBufferExtent = 0; - } + mBufferOrigin = 0; + mBufferExtent = 0; + } - size_t read(void* buf, size_t count) - { - assert (mPos <= mSize); + size_t read(void* buf, size_t count) + { + try + { + assert (mPos <= mSize); - uint8_t * out = reinterpret_cast (buf); + uint8_t * out = reinterpret_cast (buf); - size_t posBeg = mOrigin + mPos; - size_t posEnd = posBeg + count; + size_t posBeg = mOrigin + mPos; + size_t posEnd = posBeg + count; - if (posEnd > mExtent) - posEnd = mExtent; + if (posEnd > mExtent) + posEnd = mExtent; - size_t posCur = posBeg; + size_t posCur = posBeg; - while (posCur != posEnd) - { - size_t readLeft = posEnd - posCur; + while (posCur != posEnd) + { + size_t readLeft = posEnd - posCur; - if (posCur < mBufferOrigin || posCur >= mBufferExtent) - { - if (readLeft >= sBufferThreshold || (posCur == mOrigin && posEnd == mExtent)) - { - assert (mFile.tell () == mBufferExtent); + if (posCur < mBufferOrigin || posCur >= mBufferExtent) + { + if (readLeft >= sBufferThreshold || (posCur == mOrigin && posEnd == mExtent)) + { + assert (mFile.tell () == mBufferExtent); - if (posCur != mBufferExtent) - mFile.seek (posCur); + if (posCur != mBufferExtent) + mFile.seek (posCur); - posCur += mFile.read (out, readLeft); + posCur += mFile.read (out, readLeft); - mBufferOrigin = mBufferExtent = posCur; + mBufferOrigin = mBufferExtent = posCur; - mPos = posCur - mOrigin; + mPos = posCur - mOrigin; - return posCur - posBeg; - } - else - { - size_t newBufferOrigin; + return posCur - posBeg; + } + else + { + size_t newBufferOrigin; - if ((posCur < mBufferOrigin) && (mBufferOrigin - posCur < sBufferSize)) - newBufferOrigin = std::max (mOrigin, mBufferOrigin > sBufferSize ? mBufferOrigin - sBufferSize : 0); - else - newBufferOrigin = posCur; + if ((posCur < mBufferOrigin) && (mBufferOrigin - posCur < sBufferSize)) + newBufferOrigin = std::max (mOrigin, mBufferOrigin > sBufferSize ? mBufferOrigin - sBufferSize : 0); + else + newBufferOrigin = posCur; - fill (newBufferOrigin); - } - } + fill (newBufferOrigin); + } + } - size_t xfer = std::min (readLeft, mBufferExtent - posCur); + size_t xfer = std::min (readLeft, mBufferExtent - posCur); - memcpy (out, mBuffer + (posCur - mBufferOrigin), xfer); + memcpy (out, mBuffer + (posCur - mBufferOrigin), xfer); - posCur += xfer; - out += xfer; - } + posCur += xfer; + out += xfer; + } - count = posEnd - posBeg; - mPos += count; - return count; - } + count = posEnd - posBeg; + mPos += count; + return count; + } + catch (std::exception& e) + { + std::stringstream error; + error << "Failed to read '" << mName << "': " << e.what(); + throw std::runtime_error(error.str()); + } + } void skip(long count) { - assert (mPos <= mSize); + assert (mPos <= mSize); if((count >= 0 && (size_t)count <= mSize-mPos) || (count < 0 && (size_t)-count <= mPos)) - mPos += count; + mPos += count; } void seek(size_t pos) { - assert (mPos <= mSize); + assert (mPos <= mSize); if (pos < mSize) - mPos = pos; + mPos = pos; } virtual size_t tell() const { - assert (mPos <= mSize); + assert (mPos <= mSize); - return mPos; - } + return mPos; + } virtual bool eof() const { - assert (mPos <= mSize); + assert (mPos <= mSize); - return mPos == mSize; - } + return mPos == mSize; + } virtual void close() { - mFile.close(); - } + mFile.close(); + } private: - void fill (size_t newOrigin) - { - assert (mFile.tell () == mBufferExtent); + void fill (size_t newOrigin) + { + assert (mFile.tell () == mBufferExtent); - size_t newExtent = newOrigin + sBufferSize; + size_t newExtent = newOrigin + sBufferSize; - if (newExtent > mExtent) - newExtent = mExtent; + if (newExtent > mExtent) + newExtent = mExtent; - size_t oldExtent = mBufferExtent; + size_t oldExtent = mBufferExtent; - if (newOrigin != oldExtent) - mFile.seek (newOrigin); + if (newOrigin != oldExtent) + mFile.seek (newOrigin); - mBufferOrigin = mBufferExtent = newOrigin; + mBufferOrigin = mBufferExtent = newOrigin; - size_t amountRequested = newExtent - newOrigin; + size_t amountRequested = newExtent - newOrigin; - size_t amountRead = mFile.read (mBuffer, amountRequested); + size_t amountRead = mFile.read (mBuffer, amountRequested); - if (amountRead != amountRequested) - throw std::runtime_error ("An unexpected condition occurred while reading from a file."); + if (amountRead != amountRequested) + throw std::runtime_error ("An unexpected condition occurred while reading from a file."); - mBufferExtent = newExtent; - } + mBufferExtent = newExtent; + } - LowLevelFile mFile; + LowLevelFile mFile; - size_t mOrigin; - size_t mExtent; - size_t mPos; + size_t mOrigin; + size_t mExtent; + size_t mPos; - uint8_t mBuffer [sBufferSize]; - size_t mBufferOrigin; - size_t mBufferExtent; + uint8_t mBuffer [sBufferSize]; + size_t mBufferOrigin; + size_t mBufferExtent; }; } // end of unnamed namespace Ogre::DataStreamPtr openConstrainedFileDataStream (char const * filename, size_t offset, size_t length) { - return Ogre::DataStreamPtr(new ConstrainedDataStream(filename, offset, length)); + return Ogre::DataStreamPtr(new ConstrainedDataStream(filename, offset, length)); } diff --git a/components/files/lowlevelfile.cpp b/components/files/lowlevelfile.cpp index 4cdeec043..8456c7a26 100644 --- a/components/files/lowlevelfile.cpp +++ b/components/files/lowlevelfile.cpp @@ -13,196 +13,196 @@ #if FILE_API == FILE_API_STDIO /* * - * Implementation of LowLevelFile methods using c stdio + * Implementation of LowLevelFile methods using c stdio * */ LowLevelFile::LowLevelFile () { - mHandle = NULL; + mHandle = NULL; } LowLevelFile::~LowLevelFile () { - if (mHandle != NULL) - fclose (mHandle); + if (mHandle != NULL) + fclose (mHandle); } void LowLevelFile::open (char const * filename) { - assert (mHandle == NULL); + assert (mHandle == NULL); - mHandle = fopen (filename, "rb"); + mHandle = fopen (filename, "rb"); - if (mHandle == NULL) - { - std::ostringstream os; - os << "Failed to open '" << filename << "' for reading."; - throw std::runtime_error (os.str ()); - } + if (mHandle == NULL) + { + std::ostringstream os; + os << "Failed to open '" << filename << "' for reading."; + throw std::runtime_error (os.str ()); + } } void LowLevelFile::close () { - assert (mHandle != NULL); + assert (mHandle != NULL); - fclose (mHandle); + fclose (mHandle); - mHandle = NULL; + mHandle = NULL; } size_t LowLevelFile::size () { - assert (mHandle != NULL); + assert (mHandle != NULL); - long oldPosition = ftell (mHandle); + long oldPosition = ftell (mHandle); - if (oldPosition == -1) - throw std::runtime_error ("A query operation on a file failed."); + if (oldPosition == -1) + throw std::runtime_error ("A query operation on a file failed."); - if (fseek (mHandle, 0, SEEK_END) != 0) - throw std::runtime_error ("A query operation on a file failed."); + if (fseek (mHandle, 0, SEEK_END) != 0) + throw std::runtime_error ("A query operation on a file failed."); - long Size = ftell (mHandle); + long Size = ftell (mHandle); - if (Size == -1) - throw std::runtime_error ("A query operation on a file failed."); + if (Size == -1) + throw std::runtime_error ("A query operation on a file failed."); - if (fseek (mHandle, oldPosition, SEEK_SET) != 0) - throw std::runtime_error ("A query operation on a file failed."); + if (fseek (mHandle, oldPosition, SEEK_SET) != 0) + throw std::runtime_error ("A query operation on a file failed."); - return size_t (Size); + return size_t (Size); } void LowLevelFile::seek (size_t Position) { - assert (mHandle != NULL); + assert (mHandle != NULL); - if (fseek (mHandle, Position, SEEK_SET) != 0) - throw std::runtime_error ("A seek operation on a file failed."); + if (fseek (mHandle, Position, SEEK_SET) != 0) + throw std::runtime_error ("A seek operation on a file failed."); } size_t LowLevelFile::tell () { - assert (mHandle != NULL); + assert (mHandle != NULL); - long Position = ftell (mHandle); + long Position = ftell (mHandle); - if (Position == -1) - throw std::runtime_error ("A query operation on a file failed."); + if (Position == -1) + throw std::runtime_error ("A query operation on a file failed."); - return size_t (Position); + return size_t (Position); } size_t LowLevelFile::read (void * data, size_t size) { - assert (mHandle != NULL); + assert (mHandle != NULL); - int amount = fread (data, 1, size, mHandle); + int amount = fread (data, 1, size, mHandle); - if (amount == 0 && ferror (mHandle)) - throw std::runtime_error ("A read operation on a file failed."); + if (amount == 0 && ferror (mHandle)) + throw std::runtime_error ("A read operation on a file failed."); - return amount; + return amount; } #elif FILE_API == FILE_API_POSIX /* * - * Implementation of LowLevelFile methods using posix IO calls + * Implementation of LowLevelFile methods using posix IO calls * */ LowLevelFile::LowLevelFile () { - mHandle = -1; + mHandle = -1; } LowLevelFile::~LowLevelFile () { - if (mHandle != -1) - ::close (mHandle); + if (mHandle != -1) + ::close (mHandle); } void LowLevelFile::open (char const * filename) { - assert (mHandle == -1); + assert (mHandle == -1); #ifdef O_BINARY - static const int openFlags = O_RDONLY | O_BINARY; + static const int openFlags = O_RDONLY | O_BINARY; #else - static const int openFlags = O_RDONLY; + static const int openFlags = O_RDONLY; #endif - mHandle = ::open (filename, openFlags, 0); + mHandle = ::open (filename, openFlags, 0); - if (mHandle == -1) - { - std::ostringstream os; - os << "Failed to open '" << filename << "' for reading."; - throw std::runtime_error (os.str ()); - } + if (mHandle == -1) + { + std::ostringstream os; + os << "Failed to open '" << filename << "' for reading."; + throw std::runtime_error (os.str ()); + } } void LowLevelFile::close () { - assert (mHandle != -1); + assert (mHandle != -1); - ::close (mHandle); + ::close (mHandle); - mHandle = -1; + mHandle = -1; } size_t LowLevelFile::size () { - assert (mHandle != -1); + assert (mHandle != -1); - size_t oldPosition = ::lseek (mHandle, 0, SEEK_CUR); + size_t oldPosition = ::lseek (mHandle, 0, SEEK_CUR); - if (oldPosition == size_t (-1)) - throw std::runtime_error ("A query operation on a file failed."); + if (oldPosition == size_t (-1)) + throw std::runtime_error ("A query operation on a file failed."); - size_t Size = ::lseek (mHandle, 0, SEEK_END); + size_t Size = ::lseek (mHandle, 0, SEEK_END); - if (Size == size_t (-1)) - throw std::runtime_error ("A query operation on a file failed."); + if (Size == size_t (-1)) + throw std::runtime_error ("A query operation on a file failed."); - if (lseek (mHandle, oldPosition, SEEK_SET) == -1) - throw std::runtime_error ("A query operation on a file failed."); + if (lseek (mHandle, oldPosition, SEEK_SET) == -1) + throw std::runtime_error ("A query operation on a file failed."); - return Size; + return Size; } void LowLevelFile::seek (size_t Position) { - assert (mHandle != -1); + assert (mHandle != -1); - if (::lseek (mHandle, Position, SEEK_SET) == -1) - throw std::runtime_error ("A seek operation on a file failed."); + if (::lseek (mHandle, Position, SEEK_SET) == -1) + throw std::runtime_error ("A seek operation on a file failed."); } size_t LowLevelFile::tell () { - assert (mHandle != -1); + assert (mHandle != -1); - size_t Position = ::lseek (mHandle, 0, SEEK_CUR); + size_t Position = ::lseek (mHandle, 0, SEEK_CUR); - if (Position == size_t (-1)) - throw std::runtime_error ("A query operation on a file failed."); + if (Position == size_t (-1)) + throw std::runtime_error ("A query operation on a file failed."); - return Position; + return Position; } size_t LowLevelFile::read (void * data, size_t size) { - assert (mHandle != -1); + assert (mHandle != -1); - int amount = ::read (mHandle, data, size); + int amount = ::read (mHandle, data, size); - if (amount == -1) - throw std::runtime_error ("A read operation on a file failed."); + if (amount == -1) + throw std::runtime_error ("A read operation on a file failed."); - return amount; + return amount; } #elif FILE_API == FILE_API_WIN32 @@ -210,93 +210,93 @@ size_t LowLevelFile::read (void * data, size_t size) #include /* * - * Implementation of LowLevelFile methods using Win32 API calls + * Implementation of LowLevelFile methods using Win32 API calls * */ LowLevelFile::LowLevelFile () { - mHandle = INVALID_HANDLE_VALUE; + mHandle = INVALID_HANDLE_VALUE; } LowLevelFile::~LowLevelFile () { - if (mHandle != INVALID_HANDLE_VALUE) - CloseHandle (mHandle); + if (mHandle != INVALID_HANDLE_VALUE) + CloseHandle (mHandle); } void LowLevelFile::open (char const * filename) { - assert (mHandle == INVALID_HANDLE_VALUE); + assert (mHandle == INVALID_HANDLE_VALUE); - std::wstring wname = boost::locale::conv::utf_to_utf(filename); - HANDLE handle = CreateFileW (wname.c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); + std::wstring wname = boost::locale::conv::utf_to_utf(filename); + HANDLE handle = CreateFileW (wname.c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); - if (handle == INVALID_HANDLE_VALUE) - { - std::ostringstream os; - os << "Failed to open '" << filename << "' for reading."; - throw std::runtime_error (os.str ()); - } + if (handle == INVALID_HANDLE_VALUE) + { + std::ostringstream os; + os << "Failed to open '" << filename << "' for reading."; + throw std::runtime_error (os.str ()); + } - mHandle = handle; + mHandle = handle; } void LowLevelFile::close () { - assert (mHandle != INVALID_HANDLE_VALUE); + assert (mHandle != INVALID_HANDLE_VALUE); - CloseHandle (mHandle); + CloseHandle (mHandle); - mHandle = INVALID_HANDLE_VALUE; + mHandle = INVALID_HANDLE_VALUE; } size_t LowLevelFile::size () { - assert (mHandle != INVALID_HANDLE_VALUE); + assert (mHandle != INVALID_HANDLE_VALUE); - BY_HANDLE_FILE_INFORMATION info; + BY_HANDLE_FILE_INFORMATION info; - if (!GetFileInformationByHandle (mHandle, &info)) - throw std::runtime_error ("A query operation on a file failed."); + if (!GetFileInformationByHandle (mHandle, &info)) + throw std::runtime_error ("A query operation on a file failed."); - if (info.nFileSizeHigh != 0) - throw std::runtime_error ("Files greater that 4GB are not supported."); + if (info.nFileSizeHigh != 0) + throw std::runtime_error ("Files greater that 4GB are not supported."); - return info.nFileSizeLow; + return info.nFileSizeLow; } void LowLevelFile::seek (size_t Position) { - assert (mHandle != INVALID_HANDLE_VALUE); + assert (mHandle != INVALID_HANDLE_VALUE); - if (SetFilePointer (mHandle, Position, NULL, SEEK_SET) == INVALID_SET_FILE_POINTER) - if (GetLastError () != NO_ERROR) - throw std::runtime_error ("A seek operation on a file failed."); + if (SetFilePointer (mHandle, Position, NULL, SEEK_SET) == INVALID_SET_FILE_POINTER) + if (GetLastError () != NO_ERROR) + throw std::runtime_error ("A seek operation on a file failed."); } size_t LowLevelFile::tell () { - assert (mHandle != INVALID_HANDLE_VALUE); + assert (mHandle != INVALID_HANDLE_VALUE); - DWORD value = SetFilePointer (mHandle, 0, NULL, SEEK_CUR); + DWORD value = SetFilePointer (mHandle, 0, NULL, SEEK_CUR); - if (value == INVALID_SET_FILE_POINTER && GetLastError () != NO_ERROR) - throw std::runtime_error ("A query operation on a file failed."); + if (value == INVALID_SET_FILE_POINTER && GetLastError () != NO_ERROR) + throw std::runtime_error ("A query operation on a file failed."); - return value; + return value; } size_t LowLevelFile::read (void * data, size_t size) { - assert (mHandle != INVALID_HANDLE_VALUE); + assert (mHandle != INVALID_HANDLE_VALUE); - DWORD read; + DWORD read; - if (!ReadFile (mHandle, data, size, &read, NULL)) - throw std::runtime_error ("A read operation on a file failed."); + if (!ReadFile (mHandle, data, size, &read, NULL)) + throw std::runtime_error ("A read operation on a file failed."); - return read; + return read; } #endif diff --git a/components/files/lowlevelfile.hpp b/components/files/lowlevelfile.hpp index f49c466a5..d94238ad6 100644 --- a/components/files/lowlevelfile.hpp +++ b/components/files/lowlevelfile.hpp @@ -5,16 +5,16 @@ #include -#define FILE_API_STDIO 0 -#define FILE_API_POSIX 1 -#define FILE_API_WIN32 2 +#define FILE_API_STDIO 0 +#define FILE_API_POSIX 1 +#define FILE_API_WIN32 2 #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX -#define FILE_API FILE_API_POSIX +#define FILE_API FILE_API_POSIX #elif OGRE_PLATFORM == OGRE_PLATFORM_WIN32 -#define FILE_API FILE_API_WIN32 +#define FILE_API FILE_API_WIN32 #else -#define FILE_API FILE_API_STDIO +#define FILE_API FILE_API_STDIO #endif #if FILE_API == FILE_API_STDIO @@ -30,26 +30,26 @@ class LowLevelFile { public: - LowLevelFile (); - ~LowLevelFile (); + LowLevelFile (); + ~LowLevelFile (); - void open (char const * filename); - void close (); + void open (char const * filename); + void close (); - size_t size (); + size_t size (); - void seek (size_t Position); - size_t tell (); + void seek (size_t Position); + size_t tell (); - size_t read (void * data, size_t size); + size_t read (void * data, size_t size); private: #if FILE_API == FILE_API_STDIO - FILE* mHandle; + FILE* mHandle; #elif FILE_API == FILE_API_POSIX - int mHandle; + int mHandle; #elif FILE_API == FILE_API_WIN32 - HANDLE mHandle; + HANDLE mHandle; #endif }; diff --git a/components/nif/nifstream.hpp b/components/nif/nifstream.hpp index cc14971fd..6c5e83eeb 100644 --- a/components/nif/nifstream.hpp +++ b/components/nif/nifstream.hpp @@ -37,31 +37,7 @@ public: NIFStream (NIFFile * file, Ogre::DataStreamPtr inp): file (file), inp (inp) {} - /************************************************* - Parser functions - ****************************************************/ - - template - struct GetHandler - { - typedef T (NIFStream::*fn_t)(); - - static const fn_t sValue; // this is specialized per supported type in the .cpp file - - static T read (NIFStream* nif) - { - return (nif->*sValue) (); - } - }; - - template - void read (NIFStream* nif, T & Value) - { - Value = GetHandler ::read (nif); - } - void skip(size_t size) { inp->skip(size); } - void read (void * data, size_t size) { inp->read (data, size); } char getChar() { return read_byte(); } short getShort() { return read_le16(); } diff --git a/extern/ogre-ffmpeg-videoplayer/videostate.cpp b/extern/ogre-ffmpeg-videoplayer/videostate.cpp index 9dac0bacd..0894499b2 100644 --- a/extern/ogre-ffmpeg-videoplayer/videostate.cpp +++ b/extern/ogre-ffmpeg-videoplayer/videostate.cpp @@ -175,13 +175,27 @@ void PacketQueue::clear() int VideoState::OgreResource_Read(void *user_data, uint8_t *buf, int buf_size) { Ogre::DataStreamPtr stream = static_cast(user_data)->stream; - return stream->read(buf, buf_size); + try + { + return stream->read(buf, buf_size); + } + catch (std::exception& e) + { + return 0; + } } int VideoState::OgreResource_Write(void *user_data, uint8_t *buf, int buf_size) { Ogre::DataStreamPtr stream = static_cast(user_data)->stream; - return stream->write(buf, buf_size); + try + { + return stream->write(buf, buf_size); + } + catch (std::exception& e) + { + return 0; + } } int64_t VideoState::OgreResource_Seek(void *user_data, int64_t offset, int whence) diff --git a/files/materials/moon.shader b/files/materials/moon.shader index eb7243d3f..0e1a4ffc8 100644 --- a/files/materials/moon.shader +++ b/files/materials/moon.shader @@ -38,16 +38,14 @@ shUniform(float4x4, projection) @shAutoConstant(projection, projection_matrix) SH_START_PROGRAM { - - float4 tex = shSample(diffuseMap, UV); - - shOutputColour(0) = float4(materialEmissive.xyz, 1) * tex; - - shOutputColour(0).a = shSample(alphaMap, UV).a * materialDiffuse.a; - - shOutputColour(0).rgb += (1.0-tex.a) * shOutputColour(0).a * atmosphereColour.rgb; //fill dark side of moon with atmosphereColour - shOutputColour(0).rgb += (1.0-materialDiffuse.a) * atmosphereColour.rgb; //fade bump + float4 phaseTex = shSample(diffuseMap, UV); + float4 fullCircleTex = shSample(alphaMap, UV); + shOutputColour(0).a = max(phaseTex.a, fullCircleTex.a) * materialDiffuse.a; + + shOutputColour(0).xyz = fullCircleTex.xyz * atmosphereColour.xyz; + shOutputColour(0).xyz = shLerp(shOutputColour(0).xyz, phaseTex.xyz, phaseTex.a); + shOutputColour(0).xyz *= materialEmissive.xyz; } #endif diff --git a/files/materials/sky.mat b/files/materials/sky.mat index ccf2a8053..c2e8ddeb0 100644 --- a/files/materials/sky.mat +++ b/files/materials/sky.mat @@ -50,7 +50,7 @@ material openmw_moon texture_unit alphaMap { - direct_texture textures\tx_secunda_full.dds + texture_alias $alphatexture } } } diff --git a/files/materials/water.shader b/files/materials/water.shader index a6f49e0a1..4dec57276 100644 --- a/files/materials/water.shader +++ b/files/materials/water.shader @@ -71,8 +71,6 @@ SH_BEGIN_PROGRAM shUniform(float4x4, wvp) @shAutoConstant(wvp, worldviewproj_matrix) - shVertexInput(float2, uv0) - shOutput(float2, UV) shOutput(float3, screenCoordsPassthrough) shOutput(float4, position) @@ -98,7 +96,6 @@ SH_START_PROGRAM { shOutputPosition = shMatrixMult(wvp, shInputPosition); - UV = uv0; #if !SH_GLSL @@ -187,7 +184,6 @@ } SH_BEGIN_PROGRAM - shInput(float2, UV) shInput(float3, screenCoordsPassthrough) shInput(float4, position) shInput(float, depthPassthrough) @@ -206,9 +202,10 @@ shSampler2D(depthMap) shSampler2D(normalMap) + shUniform(float4x4, wMat) @shAutoConstant(wMat, world_matrix) + #if RIPPLES shSampler2D(rippleNormalMap) - shUniform(float4x4, wMat) @shAutoConstant(wMat, world_matrix) #endif shUniform(float3, windDir_windSpeed) @shSharedParameter(windDir_windSpeed) @@ -251,6 +248,10 @@ SH_START_PROGRAM { + float3 worldPos = shMatrixMult (wMat, position).xyz; + float2 UV = worldPos.xy / (8192.0*5.0) * 3.0; + UV.y *= -1.0; + #if SHADOWS float shadow = depthShadowPCF (shadowMap0, lightSpacePos0, invShadowmapSize0); #endif diff --git a/files/mygui/openmw_resources.xml b/files/mygui/openmw_resources.xml index 7d7ba07b6..423281a62 100644 --- a/files/mygui/openmw_resources.xml +++ b/files/mygui/openmw_resources.xml @@ -137,4 +137,19 @@ + + + + + + + + + + + + + + diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index ebbc77bef..2854401c8 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -804,7 +804,7 @@ - +