diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 1ce6250b3..000000000 --- a/.gitmodules +++ /dev/null @@ -1,6 +0,0 @@ -[submodule "libs/mangle"] - path = libs/mangle - url = git://github.com/zinnschlag/mangle.git -[submodule "libs/openengine"] - path = libs/openengine - url = git://github.com/zinnschlag/OpenEngine diff --git a/CMakeLists.txt b/CMakeLists.txt index 7564fab90..8ba9a5f0b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,7 +18,7 @@ include (OpenMWMacros) # Version set (OPENMW_VERSION_MAJOR 0) -set (OPENMW_VERSION_MINOR 12) +set (OPENMW_VERSION_MINOR 13) set (OPENMW_VERSION_RELEASE 0) set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}") @@ -27,6 +27,8 @@ set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VE configure_file ("${OpenMW_SOURCE_DIR}/Docs/mainpage.hpp.cmake" "${OpenMW_SOURCE_DIR}/Docs/mainpage.hpp") +option(OGRE_STATIC "Link static build of Ogre and Ogre Plugins into the binaries" FALSE) + # Sound source selection option(USE_AUDIERE "use Audiere for sound" OFF) option(USE_FFMPEG "use ffmpeg for sound" OFF) @@ -116,6 +118,10 @@ set(OENGINE_BULLET ${LIBDIR}/openengine/bullet/physic.hpp ${LIBDIR}/openengine/bullet/BulletShapeLoader.cpp ${LIBDIR}/openengine/bullet/BulletShapeLoader.h + ${LIBDIR}/openengine/bullet/pmove.h + ${LIBDIR}/openengine/bullet/pmove.cpp + ${LIBDIR}/openengine/bullet/trace.h + ${LIBDIR}/openengine/bullet/trace.cpp ) # Sound setup @@ -189,8 +195,16 @@ find_package(Boost REQUIRED COMPONENTS system filesystem program_options thread) find_package(OIS REQUIRED) find_package(OpenAL REQUIRED) find_package(Bullet REQUIRED) +IF(OGRE_STATIC) +find_package(Cg REQUIRED) +IF(WIN32) +set(OGRE_PLUGIN_INCLUDE_DIRS ${OGRE_Plugin_CgProgramManager_INCLUDE_DIRS} ${OGRE_Plugin_OctreeSceneManager_INCLUDE_DIRS} ${OGRE_Plugin_ParticleFX_INCLUDE_DIRS} ${OGRE_RenderSystem_Direct3D9_INCLUDE_DIRS} ${OGRE_RenderSystem_GL_INCLUDE_DIRS}) +ELSE(WIN32) +set(OGRE_PLUGIN_INCLUDE_DIRS ${OGRE_Plugin_CgProgramManager_INCLUDE_DIRS} ${OGRE_Plugin_OctreeSceneManager_INCLUDE_DIRS} ${OGRE_Plugin_ParticleFX_INCLUDE_DIRS} ${OGRE_RenderSystem_GL_INCLUDE_DIRS}) +ENDIF(WIN32) +ENDIF(OGRE_STATIC) include_directories("." - ${OGRE_INCLUDE_DIR} ${OGRE_INCLUDE_DIR}/Ogre ${OGRE_INCLUDE_DIR}/OGRE + ${OGRE_INCLUDE_DIR} ${OGRE_INCLUDE_DIR}/Ogre ${OGRE_INCLUDE_DIR}/OGRE ${OGRE_PLUGIN_INCLUDE_DIRS} ${OIS_INCLUDE_DIRS} ${Boost_INCLUDE_DIR} ${PLATFORM_INCLUDE_DIR} ${CMAKE_HOME_DIRECTORY}/extern/mygui_3.0.1/MyGUIEngine/include @@ -255,6 +269,13 @@ if (APPLE) "${APP_BUNDLE_DIR}/Contents/Resources/OpenMW.icns" COPYONLY) # prepare plugins + if (${CMAKE_BUILD_TYPE} MATCHES "Release" OR + ${CMAKE_BUILD_TYPE} MATCHES "RelWithDebugInfo") + set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_REL}) + else() + set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_DBG}) + endif() + foreach(plugin ${USED_OGRE_PLUGINS}) configure_file("${OGRE_PLUGIN_DIR}/${plugin}.dylib" "${APP_BUNDLE_DIR}/Contents/Plugins/${plugin}.dylib" @@ -265,8 +286,7 @@ endif (APPLE) # Compiler settings if (CMAKE_COMPILER_IS_GNUCC) - #add_definitions (-Wall -Werror) - add_definitions (-Wall) + add_definitions (-Wall -Wextra -Wno-unused-parameter -Wno-unused-but-set-parameter -Wno-reorder) endif (CMAKE_COMPILER_IS_GNUCC) if(DPKG_PROGRAM) @@ -405,6 +425,47 @@ if (WIN32) set_target_properties(openmw PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:CONSOLE") set_target_properties(openmw PROPERTIES COMPILE_DEFINITIONS_RELEASE "_CONSOLE") set_target_properties(openmw PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:CONSOLE") + + # Play a bit with the warning levels + + set(WARNINGS "/Wall") # Since windows can only disable specific warnings, not enable them + + set(WARNINGS_DISABLE + # Warnings that aren't enabled normally and don't need to be enabled + # They're unneeded and sometimes completely retarded warnings that /Wall enables + # Not going to bother commenting them as they tend to warn on every standard library files + 4061 4263 4264 4266 4350 4514 4548 4571 4610 4619 4623 4625 4626 4628 4640 4668 4710 4711 4820 4826 4917 4946 + + # Warnings that are thrown on standard libraries and not OpenMW + 4347 # Non-template function with same name and parameter count as template function + 4365 # Variable signed/unsigned mismatch + 4510 4512 # Unable to generate copy constructor/assignment operator as it's not public in the base + 4706 # Assignment in conditional expression + 4738 # Storing 32-bit float result in memory, possible loss of performance + 4986 # Undocumented warning that occurs in the crtdbg.h file + 4996 # Function was declared deprecated + + # OpenMW specific warnings + 4099 # Type mismatch, declared class or struct is defined with other type + 4100 # Unreferenced formal parameter (-Wunused-parameter) + 4127 # Conditional expression is constant + 4242 # Storing value in a variable of a smaller type, possible loss of data + 4244 # Storing value of one type in variable of another (size_t in int, for example) + 4305 # Truncating value (double to float, for example) + 4309 # Variable overflow, trying to store 128 in a signed char for example + 4355 # Using 'this' in member initialization list + 4701 # Potentially uninitialized local variable used + ) + + foreach(d ${WARNINGS_DISABLE}) + set(WARNINGS "${WARNINGS} /wd${d}") + endforeach(d) + + set_target_properties(components PROPERTIES COMPILE_FLAGS ${WARNINGS}) + if (BUILD_LAUNCHER) + set_target_properties(omwlauncher PROPERTIES COMPILE_FLAGS ${WARNINGS}) + endif (BUILD_LAUNCHER) + set_target_properties(openmw PROPERTIES COMPILE_FLAGS ${WARNINGS}) endif(MSVC) # Same for MinGW diff --git a/README_Mac.md b/README_Mac.md index 39382e0c9..dc3918368 100644 --- a/README_Mac.md +++ b/README_Mac.md @@ -1,80 +1,79 @@ -NOTE: This README is for ardekantur's Mac branch of OpenMW. A README -for the main branch has yet to be written. If you want to submit one, -please send me a message! +#Getting OpenMW Working on OS X -OpenMW -====== +## Initial setup +First of all, clone OpenMW repo. -From the [official website][]: + $ git clone github.com/zinnschlag/openmw -> OpenMW is an attempt to reimplement the popular role playing game - Morrowind. It aims to be a fully playable, open source - implementation of the game. You must own Morrowind to use OpenMW. +Or use your github url if you forked. +About dependencies: I prefer not to install them globally (i. e. in /usr/local/), so I'm installing them in directory in my home directory. If OpenMW sources is in $HOME/path/openmw, I'm using $HOME/path/libs/root as prefix for boost and other libs. -About This Project ------------------- +It's useful to create env var for lib install prefix: + + $ export OMW_LIB_PREFIX=$HOME/path/libs/root` -This specific repository is a branch of OpenMW intended to keep pace -with development of the project in order to provide a Mac build for -interested parties to contribute. This is not an official, sanctioned -branch of the OpenMW project. I will only be able to answer specific -questions about getting this project running on Mac OS X, **no other -platform**. I will not even be able to guarantee my changes maintain -backwards compatibility against builds in other operating systems. You -have been warned. +Most of libs can be installed from [Homebrew][homebrew]. Only mpg123 needs to be installed from source (due to lack of universal compilation support). I think that some of libs can be installed from MacPorts or Fink too. +As OpenMW currently only supports i386 architecture on OS X, denendencies also should support it. Set some env vars in current terminal: -Getting OpenMW Working ----------------------- - -1. Clone this repository. -2. Note about libs: I prefer not to install them globally (i. e. in /usr/local/), so I installing them in directory in my home directory. If OpenMW sources is in $HOME/path/openmw, I'm using $HOME/path/libs/root as prefix for boost and other libs. - It's useful to create env var for lib install prefix: - $ export OMW_LIB_PREFIX=$HOME/path/libs/root - -3. First of all, set for current terminal some env vars: $ export CFLAGS="-arch i386" $ export CXXFLAGS="-arch i386" $ export LDFLAGS="-arch i386" - All libs will build with correct architecture. - If you close your terminal, you should set env vars again before pcoceeding to next steps! -4. Download [boost][] (tested with 1.45) and install it with the following command: +If you close your terminal, you should set env vars again before pcoceeding to next steps! + +## Boost +Download [boost][boost] and install it with the following command: $ cd /path/to/boost/source $ ./bootstrap.sh --prefix=$OMW_LIB_PREFIX $ ./bjam --build-dir=build --layout=versioned \ --toolset=darwin architecture=x86 address-model=32 \ --link-shared,static --prefix=$OMW_LIB_PREFIX install + + +Alternatively you can install boost with homebrew: + $ brew install boost --universal -5. Download [Ogre][] SDK (tested with 1.7.2), unpack it and move -`lib/Release/Ogre.framework` into `Library/Frameworks`. +I think MacPorts also should support universal build for boost. -6. Download [OIS][] and use the XCode project provided in - `ois/Mac/XCode-2.2`. Be sure to set your build architecture to - `i386` and your SDK platform to either 10.5 or 10.6. Once it - builds, move `ois/Mac/XCode-2.2/build/Debug/OIS.framework` to - `/Library/Frameworks`. +## Ogre +Download [Ogre][] SDK (tested with 1.7.3), unpack it somewhere and move +`lib/Release/Ogre.framework` into `/Library/Frameworks`. + +## OIS +Download patched [OIS][] and use the XCode project provided. Be sure to set your build architecture to + `i386`. Once it built, locate built OIS.framework with Xcode and move it to `/Library/Frameworks`. + +## mpg123 +Download [MPG 123][mpg123] and build it: -7. Download [mpg123][] and build it: $ cd /path/to/mpg123/source $ ./configure --prefix=$OMW_LIB_PREFIX --disable-debug \ --disable-dependency-tracking \ --with-optimization=4 \ - --with-audio=coreaudio \ - --with-default-audio=coreaudio \ + --with-audio=dummy \ + --with-default-audio=dummy \ --with-cpu=sse_alone \ $ make install -8. Download [libsndfile][] and build it: +## libsndfile +Download [libsndfile][] and build it: + $ cd /path/to/libsndfile/source $ ./configure --prefix=$OMW_LIB_PREFIX \ --disable-dependency-tracking $ make install -9. Download [Bullet][] and build it: +or install with homebrew: + + $ brew install libsndfile --universal + +## Bullet +Download [Bullet][] and build it: + $ cd /path/to/bullet/source $ mkdir build $ cd build @@ -87,12 +86,25 @@ Getting OpenMW Working -G"Unix Makefiles" ../ $ make install -10. Generate the Makefile for OpenMW as follows and build OpenMW: +or install with homebrew: + + $ brew install bullet --HEAD --universal + +I prefer head because 2.79 has some issue which causes OpenMW to lag. Also you can edit formula and install 2.77, which is stable and haven't mentioned issue. + +## Qt +Install [Qt][qt]. Qt SDK distributed by Nokia is not an option because it's 64 bit only, and OpenMW currently doesn't build for 64 bit on OS X. I'm installing it from Homebrew: + + $ brew install qt --universal + +## Run CMake +Generate the Makefile for OpenMW as follows and build OpenMW: + $ mkdir /path/to/openmw/build/dir $ cd /path/to/open/build/dir $ cmake \ -D CMAKE_OSX_ARCHITECTURES=i386 \ - -D OGRESDK=/path/to/ogre/sdk \ + -D OGRE_SDK=/path/to/ogre/sdk \ -D BOOST_INCLUDEDIR=$OMW_LIB_PREFIX/include/boost-1_45 \ -D BOOST_LIBRARYDIR=$OMW_LIB_PREFIX/lib \ -D SNDFILE_INCLUDE_DIR=$OMW_LIB_PREFIX/include \ @@ -106,27 +118,43 @@ Getting OpenMW Working -D BULLET_INCLUDE_DIR=$OMW_LIB_PREFIX/include/bullet/ \ -G "Unix Makefiles" /path/to/openmw/source/dir $ make - You can use -G"Xcode" if you prefer Xcode, or -G"Eclipse CDT4 - Unix Makefiles" - if you prefer Eclipse. You also can specify -D CMAKE_BUILD_TYPE=Debug for debug - build. + +You can use `-G"Xcode"` if you prefer Xcode, or -G"Eclipse CDT4 - Unix Makefiles" +if you prefer Eclipse. You also can specify `-D CMAKE_BUILD_TYPE=Debug` for debug +build. As for CMake 2.8.7 and Xcode 4.3, Xcode generator is broken. Sadly Eclipse CDT also cannot import generated project at least on my machine. -11. Copy your Morrowind `Data Files` directory into the OpenMW build dir - with the name `data` or create symlink: - $ ln -s /path/to/morrowind/data/files /path/to/openmw/build/dir/data +If all libs installed via homebrew (excluding mpg123), then command would be even simplier: + + $ cmake \ + -D CMAKE_OSX_ARCHITECTURES="i386" \ + -D OGRE_SDK=/path/to/ogre/sdk \ + -D MPG123_LIBRARY=$OMW_LIB_PREFIX/lib/libmpg123.a \ + -D MPG123_INCLUDE_DIR=$OMW_LIB_PREFIX/include \ + -G "Unix Makefiles" /path/to/openmw/source/dir + $ make + +Note for users with recent Xcode versions: you must explicitly specify what set of compilers do you use! If not, gcc will be used for C and Clang for C++. Just add this two -D's to command: `-D CMAKE_C_COMPILER=/usr/bin/clang` and `-D CMAKE_CXX_COMPILER=/usr/bin/clang` + +Note for Xcode 4.3 users: you should specify full path to used SDK, because current CMake (2.8.7) couldn't find SDKs inside Xcode app bundle: + + -D CMAKE_OSX_SYSROOT="/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk" + +# Run +From your build directory run: -12. From your build directory run: $ OpenMW.app/Contents/MacOS/openmw - or: +or: + $ open OpenMW.app - Enjoy! - - +Enjoy! +[homebrew]: https://github.com/mxcl/homebrew [boost]: http://www.boost.org [Ogre]: http://www.ogre3d.org [Bullet]: http://bulletphysics.org -[OIS]: http://wgois.sf.net +[OIS]: https://github.com/corristo/ois-fork [mpg123]: http://www.mpg123.de [libsndfile]: http://www.mega-nerd.com/libsndfile [official website]: http://openmw.com [Will Thimbleby's Ogre Framework]: http://www.thimbleby.net/ogre/ +[qt]: http://qt.nokia.com/ \ No newline at end of file diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index f0e5eba94..fd736e011 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -41,10 +41,11 @@ source_group(launcher FILES ${LAUNCHER} ${LAUNCHER_HEADER} ${LAUNCHER_HEADER_MOC find_package(Qt4 REQUIRED) set(QT_USE_QTGUI 1) -if (NOT APPLE) # this dependency can be completely removed, but now it only tested on OS X - find_package(PNG REQUIRED) - include_directories(${PNG_INCLUDE_DIR}) -endif() +# Set some platform specific settings +if(WIN32) + set(GUI_TYPE WIN32) + set(QT_USE_QTMAIN TRUE) +endif(WIN32) QT4_ADD_RESOURCES(RCC_SRCS resources.qrc) QT4_WRAP_CPP(MOC_SRCS ${LAUNCHER_HEADER_MOC}) @@ -52,7 +53,17 @@ QT4_WRAP_CPP(MOC_SRCS ${LAUNCHER_HEADER_MOC}) include(${QT_USE_FILE}) # Main executable +IF(OGRE_STATIC) +IF(WIN32) +ADD_DEFINITIONS(-DENABLE_PLUGIN_Direct3D9 -DENABLE_PLUGIN_GL) +set(OGRE_STATIC_PLUGINS ${OGRE_RenderSystem_Direct3D9_LIBRARIES} ${OGRE_RenderSystem_GL_LIBRARIES}) +ELSE(WIN32) +ADD_DEFINITIONS(-DENABLE_PLUGIN_GL) +set(OGRE_STATIC_PLUGINS ${OGRE_RenderSystem_GL_LIBRARIES}) +ENDIF(WIN32) +ENDIF(OGRE_STATIC) add_executable(omwlauncher + ${GUI_TYPE} ${LAUNCHER} ${RCC_SRCS} ${MOC_SRCS} @@ -61,8 +72,8 @@ add_executable(omwlauncher target_link_libraries(omwlauncher ${Boost_LIBRARIES} ${OGRE_LIBRARIES} + ${OGRE_STATIC_PLUGINS} ${QT_LIBRARIES} - ${PNG_LIBRARY} components ) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index c95446808..054cbf141 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -9,6 +9,23 @@ #include "pluginsmodel.hpp" #include "pluginsview.hpp" +#include +/** + * Workaround for problems with whitespaces in paths in older versions of Boost library + */ +#if (BOOST_VERSION <= 104600) +namespace boost +{ + + template<> + inline boost::filesystem::path lexical_cast(const std::string& arg) + { + return boost::filesystem::path(arg); + } + +} /* namespace boost */ +#endif /* (BOOST_VERSION <= 104600) */ + using namespace ESM; using namespace std; diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index b7d397f06..95b38d53e 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -186,7 +186,11 @@ void GraphicsPage::setupOgre() try { + #if defined(ENABLE_PLUGIN_GL) || defined(ENABLE_PLUGIN_Direct3D9) + mOgre = new Ogre::Root("", file.fileName().toStdString(), "./launcherOgre.log"); + #else mOgre = new Ogre::Root(pluginCfg.toStdString(), file.fileName().toStdString(), "./launcherOgre.log"); + #endif } catch(Ogre::Exception &ex) { @@ -207,6 +211,15 @@ void GraphicsPage::setupOgre() return; } + #ifdef ENABLE_PLUGIN_GL + mGLPlugin = new Ogre::GLPlugin(); + mOgre->installPlugin(mGLPlugin); + #endif + #ifdef ENABLE_PLUGIN_Direct3D9 + mD3D9Plugin = new Ogre::D3D9Plugin(); + mOgre->installPlugin(mD3D9Plugin); + #endif + // Get the available renderers and put them in the combobox const Ogre::RenderSystemList &renderers = mOgre->getAvailableRenderers(); diff --git a/apps/launcher/graphicspage.hpp b/apps/launcher/graphicspage.hpp index bdfd4f038..6a91a0628 100644 --- a/apps/launcher/graphicspage.hpp +++ b/apps/launcher/graphicspage.hpp @@ -8,6 +8,14 @@ #include #include +// Static plugin headers +#ifdef ENABLE_PLUGIN_GL +# include "OgreGLPlugin.h" +#endif +#ifdef ENABLE_PLUGIN_Direct3D9 +# include "OgreD3D9Plugin.h" +#endif + class QComboBox; class QCheckBox; class QStackedWidget; @@ -32,6 +40,12 @@ private: Ogre::RenderSystem *mSelectedRenderSystem; Ogre::RenderSystem *mOpenGLRenderSystem; Ogre::RenderSystem *mDirect3DRenderSystem; + #ifdef ENABLE_PLUGIN_GL + Ogre::GLPlugin* mGLPlugin; + #endif + #ifdef ENABLE_PLUGIN_Direct3D9 + Ogre::D3D9Plugin* mD3D9Plugin; + #endif QComboBox *mRendererComboBox; diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 39cd99cf6..6d33298df 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -44,7 +44,7 @@ add_openmw_dir (mwsound add_openmw_dir (mwworld refdata world physicssystem scene environment globals class action nullaction actionteleport containerstore actiontalk actiontake manualref player cellfunctors - cells localscripts customdata weather + cells localscripts customdata weather inventorystore ) add_openmw_dir (mwclass @@ -57,6 +57,15 @@ add_openmw_dir (mwmechanics ) # Main executable +IF(OGRE_STATIC) +IF(WIN32) +ADD_DEFINITIONS(-DENABLE_PLUGIN_CgProgramManager -DENABLE_PLUGIN_OctreeSceneManager -DENABLE_PLUGIN_ParticleFX -DENABLE_PLUGIN_-DENABLE_PLUGIN_Direct3D9 -DENABLE_PLUGIN_GL) +set(OGRE_STATIC_PLUGINS ${OGRE_Plugin_CgProgramManager_LIBRARIES} ${OGRE_Plugin_OctreeSceneManager_LIBRARIES} ${OGRE_Plugin_ParticleFX_LIBRARIES} ${OGRE_RenderSystem_Direct3D9_LIBRARIES} ${OGRE_RenderSystem_GL_LIBRARIES}) +ELSE(WIN32) +ADD_DEFINITIONS(-DENABLE_PLUGIN_CgProgramManager -DENABLE_PLUGIN_OctreeSceneManager -DENABLE_PLUGIN_ParticleFX -DENABLE_PLUGIN_GL) +set(OGRE_STATIC_PLUGINS ${OGRE_Plugin_CgProgramManager_LIBRARIES} ${Cg_LIBRARIES} ${OGRE_Plugin_OctreeSceneManager_LIBRARIES} ${OGRE_Plugin_ParticleFX_LIBRARIES} ${OGRE_RenderSystem_GL_LIBRARIES}) +ENDIF(WIN32) +ENDIF(OGRE_STATIC) add_executable(openmw ${OPENMW_LIBS} ${OPENMW_LIBS_HEADER} ${COMPONENT_FILES} @@ -72,6 +81,7 @@ add_definitions(${SOUND_DEFINE}) target_link_libraries(openmw ${OGRE_LIBRARIES} + ${OGRE_STATIC_PLUGINS} ${OIS_LIBRARIES} ${Boost_LIBRARIES} ${OPENAL_LIBRARY} diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 0e2189307..89068ce53 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -60,7 +60,7 @@ void OMW::Engine::executeLocalScripts() MWScript::InterpreterContext interpreterContext (mEnvironment, &script.second.getRefData().getLocals(), script.second); - mScriptManager->run (script.first, interpreterContext); + mEnvironment.mScriptManager->run (script.first, interpreterContext); if (mEnvironment.mWorld->hasCellChanged()) break; @@ -182,7 +182,6 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) , mCompileAll (false) , mReportFocus (false) , mFocusTDiff (0) - , mScriptManager (0) , mScriptContext (0) , mFSStrict (false) , mCfgMgr(configurationManager) @@ -199,7 +198,7 @@ OMW::Engine::~Engine() delete mEnvironment.mMechanicsManager; delete mEnvironment.mDialogueManager; delete mEnvironment.mJournal; - delete mScriptManager; + delete mEnvironment.mScriptManager; delete mScriptContext; delete mOgre; } @@ -348,18 +347,18 @@ void OMW::Engine::go() mEnvironment); mScriptContext->setExtensions (&mExtensions); - mScriptManager = new MWScript::ScriptManager (mEnvironment.mWorld->getStore(), mVerboseScripts, - *mScriptContext); + mEnvironment.mScriptManager = new MWScript::ScriptManager (mEnvironment.mWorld->getStore(), + mVerboseScripts, *mScriptContext); mEnvironment.mGlobalScripts = new MWScript::GlobalScripts (mEnvironment.mWorld->getStore(), - *mScriptManager); + *mEnvironment.mScriptManager); // Create game mechanics system mEnvironment.mMechanicsManager = new MWMechanics::MechanicsManager (mEnvironment); // Create dialog system mEnvironment.mJournal = new MWDialogue::Journal (mEnvironment); - mEnvironment.mDialogueManager = new MWDialogue::DialogueManager (mEnvironment); + mEnvironment.mDialogueManager = new MWDialogue::DialogueManager (mEnvironment,mExtensions); // load cell ESM::Position pos; @@ -393,7 +392,7 @@ void OMW::Engine::go() // scripts if (mCompileAll) { - std::pair result = mScriptManager->compileAll(); + std::pair result = mEnvironment.mScriptManager->compileAll(); if (result.first) std::cout @@ -411,6 +410,9 @@ void OMW::Engine::go() void OMW::Engine::activate() { + if (mEnvironment.mWindowManager->getMode()!=MWGui::GM_Game) + return; + std::string handle = mEnvironment.mWorld->getFacedHandle(); if (handle.empty()) @@ -435,7 +437,7 @@ void OMW::Engine::activate() if (!script.empty()) { mEnvironment.mWorld->getLocalScripts().setIgnore (ptr); - mScriptManager->run (script, interpreterContext); + mEnvironment.mScriptManager->run (script, interpreterContext); } if (!interpreterContext.hasActivationBeenHandled()) diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 5c5cdc018..690430784 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -78,10 +78,9 @@ namespace OMW std::string mFocusName; MWWorld::Environment mEnvironment; - MWScript::ScriptManager *mScriptManager; Compiler::Extensions mExtensions; Compiler::Context *mScriptContext; - + Files::Collections mFileCollections; bool mFSStrict; diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index da7ff8696..e95fb572f 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -7,9 +7,12 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" +#include "../mwworld/environment.hpp" #include "../mwrender/objects.hpp" +#include "../mwsound/soundmanager.hpp" + namespace MWClass { void Apparatus::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const @@ -53,6 +56,8 @@ namespace MWClass boost::shared_ptr Apparatus::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const { + environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, false, true); + return boost::shared_ptr ( new MWWorld::ActionTake (ptr)); } @@ -71,4 +76,14 @@ namespace MWClass registerClass (typeid (ESM::Apparatus).name(), instance); } + + std::string Apparatus::getUpSoundId (const MWWorld::Ptr& ptr) const + { + return std::string("Item Apparatus Up"); + } + + std::string Apparatus::getDownSoundId (const MWWorld::Ptr& ptr) const + { + return std::string("Item Apparatus Down"); + } } diff --git a/apps/openmw/mwclass/apparatus.hpp b/apps/openmw/mwclass/apparatus.hpp index 86223cf60..c0849e1fe 100644 --- a/apps/openmw/mwclass/apparatus.hpp +++ b/apps/openmw/mwclass/apparatus.hpp @@ -26,6 +26,12 @@ namespace MWClass ///< Return name of the script attached to ptr static void registerSelf(); + + virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const; + ///< Return the pick up sound Id + + virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; + ///< Return the put down sound Id }; } diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 3cdf63119..e1c2734f0 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -2,14 +2,22 @@ #include "armor.hpp" #include +#include +#include #include #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" +#include "../mwworld/inventorystore.hpp" +#include "../mwworld/environment.hpp" +#include "../mwworld/world.hpp" + #include "../mwrender/objects.hpp" +#include "../mwsound/soundmanager.hpp" + namespace MWClass { void Armor::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const @@ -52,6 +60,8 @@ namespace MWClass boost::shared_ptr Armor::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const { + environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true); + return boost::shared_ptr ( new MWWorld::ActionTake (ptr)); } @@ -77,10 +87,105 @@ namespace MWClass return ref->base->script; } + std::pair, bool> Armor::getEquipmentSlots (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + std::vector slots; + + const int size = 11; + + static const int sMapping[size][2] = + { + { ESM::Armor::Helmet, MWWorld::InventoryStore::Slot_Helmet }, + { ESM::Armor::Cuirass, MWWorld::InventoryStore::Slot_Cuirass }, + { ESM::Armor::LPauldron, MWWorld::InventoryStore::Slot_LeftPauldron }, + { ESM::Armor::RPauldron, MWWorld::InventoryStore::Slot_RightPauldron }, + { ESM::Armor::Greaves, MWWorld::InventoryStore::Slot_Greaves }, + { ESM::Armor::Boots, MWWorld::InventoryStore::Slot_Boots }, + { ESM::Armor::LGauntlet, MWWorld::InventoryStore::Slot_LeftGauntlet }, + { ESM::Armor::RGauntlet, MWWorld::InventoryStore::Slot_RightGauntlet }, + { ESM::Armor::Shield, MWWorld::InventoryStore::Slot_CarriedLeft }, + { ESM::Armor::LBracer, MWWorld::InventoryStore::Slot_LeftGauntlet }, + { ESM::Armor::RBracer, MWWorld::InventoryStore::Slot_RightGauntlet } + }; + + for (int i=0; ibase->data.type) + { + slots.push_back (int (sMapping[i][1])); + break; + } + + return std::make_pair (slots, false); + } + + int Armor::getEquipmentSkill (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + std::string typeGmst; + + switch (ref->base->data.type) + { + case ESM::Armor::Helmet: typeGmst = "iHelmWeight"; break; + case ESM::Armor::Cuirass: typeGmst = "iCuirassWeight"; break; + case ESM::Armor::LPauldron: + case ESM::Armor::RPauldron: typeGmst = "iPauldronWeight"; break; + case ESM::Armor::Greaves: typeGmst = "iGreavesWeight"; break; + case ESM::Armor::Boots: typeGmst = "iBootsWeight"; break; + case ESM::Armor::LGauntlet: + case ESM::Armor::RGauntlet: typeGmst = "iGauntletWeight"; break; +/// \todo how to determine if shield light, medium or heavy? +// case ESM::Armor::Shield: + case ESM::Armor::LBracer: + case ESM::Armor::RBracer: typeGmst = "iGauntletWeight"; break; + } + + if (typeGmst.empty()) + return -1; + + float iWeight = environment.mWorld->getStore().gameSettings.find (typeGmst)->i; + + if (iWeight * environment.mWorld->getStore().gameSettings.find ("fLightMaxMod")->f>= + ref->base->data.weight) + return ESM::Skill::LightArmor; + + if (iWeight * environment.mWorld->getStore().gameSettings.find ("fMedMaxMod")->f>= + ref->base->data.weight) + return ESM::Skill::MediumArmor; + + return ESM::Skill::HeavyArmor; + } + void Armor::registerSelf() { boost::shared_ptr instance (new Armor); registerClass (typeid (ESM::Armor).name(), instance); } + + std::string Armor::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + { + int es = getEquipmentSkill(ptr, environment); + if (es == ESM::Skill::LightArmor) + return std::string("Item Armor Light Up"); + else if (es == ESM::Skill::MediumArmor) + return std::string("Item Armor Medium Up"); + else + return std::string("Item Armor Heavy Up"); + } + + std::string Armor::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + { + int es = getEquipmentSkill(ptr, environment); + if (es == ESM::Skill::LightArmor) + return std::string("Item Armor Light Down"); + else if (es == ESM::Skill::MediumArmor) + return std::string("Item Armor Medium Down"); + else + return std::string("Item Armor Heavy Down"); + } } diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 060bc364e..2b66ff828 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -31,7 +31,22 @@ namespace MWClass virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr + virtual std::pair, bool> getEquipmentSlots (const MWWorld::Ptr& ptr) const; + ///< \return first: Return IDs of the slot this object can be equipped in; second: can object + /// stay stacked when equipped? + + virtual int getEquipmentSkill (const MWWorld::Ptr& ptr, + const MWWorld::Environment& environment) const; + /// Return the index of the skill this item corresponds to when equiopped or -1, if there is + /// no such skill. + static void registerSelf(); + + virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + ///< Return the pick up sound Id + + virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + ///< Return the put down sound Id }; } diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 576e521ee..0a81ebafb 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -7,9 +7,12 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" +#include "../mwworld/environment.hpp" #include "../mwrender/objects.hpp" +#include "../mwsound/soundmanager.hpp" + namespace MWClass { void Book::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const @@ -55,6 +58,8 @@ namespace MWClass { // TODO implement reading + environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true); + return boost::shared_ptr ( new MWWorld::ActionTake (ptr)); } @@ -73,4 +78,14 @@ namespace MWClass registerClass (typeid (ESM::Book).name(), instance); } + + std::string Book::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + { + return std::string("Item Book Up"); + } + + std::string Book::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + { + return std::string("Item Book Down"); + } } diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index 12dc27bb2..ccbbfb4b2 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -26,6 +26,12 @@ namespace MWClass ///< Return name of the script attached to ptr static void registerSelf(); + + virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + ///< Return the pick up sound Id + + virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + ///< Return the put down sound Id }; } diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 88c43d82c..4fe19ada4 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -7,9 +7,13 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" +#include "../mwworld/environment.hpp" +#include "../mwworld/inventorystore.hpp" #include "../mwrender/objects.hpp" +#include "../mwsound/soundmanager.hpp" + namespace MWClass { void Clothing::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const @@ -53,6 +57,8 @@ namespace MWClass boost::shared_ptr Clothing::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const { + environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true); + return boost::shared_ptr ( new MWWorld::ActionTake (ptr)); } @@ -65,10 +71,86 @@ namespace MWClass return ref->base->script; } + std::pair, bool> Clothing::getEquipmentSlots (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + std::vector slots; + + if (ref->base->data.type==ESM::Clothing::Ring) + { + slots.push_back (int (MWWorld::InventoryStore::Slot_LeftRing)); + slots.push_back (int (MWWorld::InventoryStore::Slot_RightRing)); + } + else + { + const int size = 9; + + static const int sMapping[size][2] = + { + { ESM::Clothing::Shirt, MWWorld::InventoryStore::Slot_Cuirass }, + { ESM::Clothing::Belt, MWWorld::InventoryStore::Slot_Belt }, + { ESM::Clothing::Robe, MWWorld::InventoryStore::Slot_Robe }, + { ESM::Clothing::Pants, MWWorld::InventoryStore::Slot_Pants }, + { ESM::Clothing::Shoes, MWWorld::InventoryStore::Slot_Boots }, + { ESM::Clothing::LGlove, MWWorld::InventoryStore::Slot_LeftGauntlet }, + { ESM::Clothing::RGlove, MWWorld::InventoryStore::Slot_RightGauntlet }, + { ESM::Clothing::Skirt, MWWorld::InventoryStore::Slot_Skirt }, + { ESM::Clothing::Amulet, MWWorld::InventoryStore::Slot_Amulet } + }; + + for (int i=0; ibase->data.type) + { + slots.push_back (int (sMapping[i][1])); + break; + } + } + + return std::make_pair (slots, false); + } + + int Clothing::getEquipmentSkill (const MWWorld::Ptr& ptr, + const MWWorld::Environment& environment) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + if (ref->base->data.type==ESM::Clothing::Shoes) + return ESM::Skill::Unarmored; + + return -1; + } + void Clothing::registerSelf() { boost::shared_ptr instance (new Clothing); registerClass (typeid (ESM::Clothing).name(), instance); } + + std::string Clothing::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + if (ref->base->data.type == 8) + { + return std::string("Item Ring Up"); + } + return std::string("Item Clothes Up"); + } + + std::string Clothing::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + if (ref->base->data.type == 8) + { + return std::string("Item Ring Down"); + } + return std::string("Item Clothes Down"); + } } diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 606aba9e0..171b06246 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -25,7 +25,22 @@ namespace MWClass virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr + virtual std::pair, bool> getEquipmentSlots (const MWWorld::Ptr& ptr) const; + ///< \return first: Return IDs of the slot this object can be equipped in; second: can object + /// stay stacked when equipped? + + virtual int getEquipmentSkill (const MWWorld::Ptr& ptr, + const MWWorld::Environment& environment) const; + /// Return the index of the skill this item corresponds to when equiopped or -1, if there is + /// no such skill. + static void registerSelf(); + + virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + ///< Return the pick up sound Id + + virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + ///< Return the put down sound Id }; } diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index c58606996..c58a25c03 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -85,7 +85,7 @@ namespace MWClass { // TODO check for key std::cout << "Locked container" << std::endl; - environment.mSoundManager->playSound(lockedSound, 1.0, 1.0); + environment.mSoundManager->playSound3D (ptr, lockedSound, 1.0, 1.0, false); return boost::shared_ptr (new MWWorld::NullAction); } else @@ -100,7 +100,7 @@ namespace MWClass { // Trap activation goes here std::cout << "Activated trap: " << ptr.getCellRef().trap << std::endl; - environment.mSoundManager->playSound(trapActivationSound, 1.0, 1.0); + environment.mSoundManager->playSound3D (ptr, trapActivationSound, 1.0, 1.0, false); ptr.getCellRef().trap = ""; return boost::shared_ptr (new MWWorld::NullAction); } diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index bd7af9597..5654dff69 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -73,7 +73,7 @@ namespace MWClass // TODO check for key // TODO report failure to player (message, sound?). Look up behaviour of original MW. std::cout << "Locked!" << std::endl; - environment.mSoundManager->playSound(lockedSound, 1.0, 1.0); + environment.mSoundManager->playSound3D (ptr, lockedSound, 1.0, 1.0, false); return boost::shared_ptr (new MWWorld::NullAction); } @@ -81,7 +81,7 @@ namespace MWClass { // Trap activation std::cout << "Activated trap: " << ptr.getCellRef().trap << std::endl; - environment.mSoundManager->playSound(trapActivationSound, 1.0, 1.0); + environment.mSoundManager->playSound3D(ptr, trapActivationSound, 1.0, 1.0, false); ptr.getCellRef().trap = ""; return boost::shared_ptr (new MWWorld::NullAction); } @@ -92,6 +92,7 @@ namespace MWClass if (environment.mWorld->getPlayer().getPlayer()==actor) { // the player is using the door + // The reason this is not 3D is that it would get interrupted when you teleport environment.mSoundManager->playSound(openSound, 1.0, 1.0); return boost::shared_ptr ( new MWWorld::ActionTeleportPlayer (ref->ref.destCell, ref->ref.doorDest)); @@ -109,7 +110,7 @@ namespace MWClass // TODO return action for rotating the door // This is a little pointless, but helps with testing - environment.mSoundManager->playSound(openSound, 1.0, 1.0); + environment.mSoundManager->playSound3D (ptr, openSound, 1.0, 1.0, false); return boost::shared_ptr (new MWWorld::NullAction); } } diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index d00e4592d..1a7edf632 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -7,9 +7,12 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" +#include "../mwworld/environment.hpp" #include "../mwrender/objects.hpp" +#include "../mwsound/soundmanager.hpp" + namespace MWClass { void Ingredient::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const @@ -51,6 +54,8 @@ namespace MWClass boost::shared_ptr Ingredient::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const { + environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true); + return boost::shared_ptr ( new MWWorld::ActionTake (ptr)); } @@ -69,4 +74,14 @@ namespace MWClass registerClass (typeid (ESM::Ingredient).name(), instance); } + + std::string Ingredient::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + { + return std::string("Item Ingredient Up"); + } + + std::string Ingredient::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + { + return std::string("Item Ingredient Down"); + } } diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index 92d2c4eef..9463dcf8d 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -26,6 +26,12 @@ namespace MWClass ///< Return name of the script attached to ptr static void registerSelf(); + + virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + ///< Return the pick up sound Id + + virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + ///< Return the put down sound Id }; } diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index f9ec1c956..e2e63a89b 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -9,6 +9,7 @@ #include "../mwworld/actiontake.hpp" #include "../mwworld/nullaction.hpp" #include "../mwworld/environment.hpp" +#include "../mwworld/inventorystore.hpp" #include "../mwsound/soundmanager.hpp" @@ -82,6 +83,8 @@ namespace MWClass if (!(ref->base->data.flags & ESM::Light::Carry)) return boost::shared_ptr (new MWWorld::NullAction); + environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true); + return boost::shared_ptr ( new MWWorld::ActionTake (ptr)); } @@ -94,10 +97,33 @@ namespace MWClass return ref->base->script; } + std::pair, bool> Light::getEquipmentSlots (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + std::vector slots; + + if (ref->base->data.flags & ESM::Light::Carry) + slots.push_back (int (MWWorld::InventoryStore::Slot_CarriedLeft)); + + return std::make_pair (slots, false); + } + void Light::registerSelf() { boost::shared_ptr instance (new Light); registerClass (typeid (ESM::Light).name(), instance); } + + std::string Light::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + { + return std::string("Item Misc Up"); + } + + std::string Light::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + { + return std::string("Item Misc Down"); + } } diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index c9940d0a5..46a4d60ba 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -30,7 +30,17 @@ namespace MWClass virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr + virtual std::pair, bool> getEquipmentSlots (const MWWorld::Ptr& ptr) const; + ///< \return first: Return IDs of the slot this object can be equipped in; second: can object + /// stay stacked when equipped? + static void registerSelf(); + + virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + ///< Return the pick up sound Id + + virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + ///< Return the put down sound Id }; } diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 98c05a1b3..3dda2f4af 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -7,9 +7,13 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" +#include "../mwworld/environment.hpp" +#include "../mwworld/inventorystore.hpp" #include "../mwrender/objects.hpp" +#include "../mwsound/soundmanager.hpp" + namespace MWClass { void Lockpick::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const @@ -54,6 +58,8 @@ namespace MWClass boost::shared_ptr Lockpick::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const { + environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true); + return boost::shared_ptr ( new MWWorld::ActionTake (ptr)); } @@ -66,10 +72,29 @@ namespace MWClass return ref->base->script; } + std::pair, bool> Lockpick::getEquipmentSlots (const MWWorld::Ptr& ptr) const + { + std::vector slots; + + slots.push_back (int (MWWorld::InventoryStore::Slot_CarriedRight)); + + return std::make_pair (slots, false); + } + void Lockpick::registerSelf() { boost::shared_ptr instance (new Lockpick); registerClass (typeid (ESM::Tool).name(), instance); } + + std::string Lockpick::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + { + return std::string("Item Lockpick Up"); + } + + std::string Lockpick::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + { + return std::string("Item Lockpick Down"); + } } diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index 9cbfa0d23..0c9189c54 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -25,7 +25,17 @@ namespace MWClass virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr + virtual std::pair, bool> getEquipmentSlots (const MWWorld::Ptr& ptr) const; + ///< \return first: Return IDs of the slot this object can be equipped in; second: can object + /// stay stacked when equipped? + static void registerSelf(); + + virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + ///< Return the pick up sound Id + + virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + ///< Return the put down sound Id }; } diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 8dde84be9..864fc1e38 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -7,9 +7,12 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" +#include "../mwworld/environment.hpp" #include "../mwrender/objects.hpp" +#include "../mwsound/soundmanager.hpp" + namespace MWClass { void Miscellaneous::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const @@ -53,6 +56,8 @@ namespace MWClass boost::shared_ptr Miscellaneous::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const { + environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true); + return boost::shared_ptr ( new MWWorld::ActionTake (ptr)); } @@ -71,4 +76,28 @@ namespace MWClass registerClass (typeid (ESM::Miscellaneous).name(), instance); } + + std::string Miscellaneous::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + if (ref->base->name =="Gold") + { + return std::string("Item Gold Up"); + } + return std::string("Item Misc Up"); + } + + std::string Miscellaneous::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + if (ref->base->name =="Gold") + { + return std::string("Item Gold Down"); + } + return std::string("Item Misc Down"); + } } diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index de01a64f4..b07964f99 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -26,6 +26,12 @@ namespace MWClass ///< Return name of the script attached to ptr static void registerSelf(); + + virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + ///< Return the pick up sound Id + + virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + ///< Return the put down sound Id }; } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index cc7daa83e..83a94d27d 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -16,7 +16,7 @@ #include "../mwworld/actiontalk.hpp" #include "../mwworld/environment.hpp" #include "../mwworld/world.hpp" -#include "../mwworld/containerstore.hpp" +#include "../mwworld/inventorystore.hpp" #include "../mwworld/customdata.hpp" namespace @@ -29,7 +29,7 @@ namespace MWMechanics::NpcStats mNpcStats; MWMechanics::CreatureStats mCreatureStats; MWMechanics::Movement mMovement; - MWWorld::ContainerStore mContainerStore; + MWWorld::InventoryStore mInventoryStore; virtual MWWorld::CustomData *clone() const; }; @@ -161,7 +161,15 @@ namespace MWClass { ensureCustomData (ptr); - return dynamic_cast (*ptr.getRefData().getCustomData()).mContainerStore; + return dynamic_cast (*ptr.getRefData().getCustomData()).mInventoryStore; + } + + MWWorld::InventoryStore& Npc::getInventoryStore (const MWWorld::Ptr& ptr) + const + { + ensureCustomData (ptr); + + return dynamic_cast (*ptr.getRefData().getCustomData()).mInventoryStore; } std::string Npc::getScript (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index bef417332..f210eda5f 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -38,6 +38,9 @@ namespace MWClass virtual MWWorld::ContainerStore& getContainerStore (const MWWorld::Ptr& ptr) const; ///< Return container store + virtual MWWorld::InventoryStore& getInventoryStore (const MWWorld::Ptr& ptr) const; + ///< Return inventory store + virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; ///< Generate action for activation diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index c57c18fd1..4ab374590 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -7,9 +7,12 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" +#include "../mwworld/environment.hpp" #include "../mwrender/objects.hpp" +#include "../mwsound/soundmanager.hpp" + namespace MWClass { void Potion::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const @@ -53,6 +56,8 @@ namespace MWClass boost::shared_ptr Potion::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const { + environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true); + return boost::shared_ptr ( new MWWorld::ActionTake (ptr)); } @@ -71,4 +76,14 @@ namespace MWClass registerClass (typeid (ESM::Potion).name(), instance); } + + std::string Potion::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + { + return std::string("Item Potion Up"); + } + + std::string Potion::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + { + return std::string("Item Potion Down"); + } } diff --git a/apps/openmw/mwclass/potion.hpp b/apps/openmw/mwclass/potion.hpp index fd78bba53..be9e713fb 100644 --- a/apps/openmw/mwclass/potion.hpp +++ b/apps/openmw/mwclass/potion.hpp @@ -26,6 +26,12 @@ namespace MWClass ///< Return name of the script attached to ptr static void registerSelf(); + + virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + ///< Return the pick up sound Id + + virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + ///< Return the put down sound Id }; } diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index de024e430..4b4d79a73 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -7,9 +7,13 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" +#include "../mwworld/environment.hpp" +#include "../mwworld/inventorystore.hpp" #include "../mwrender/objects.hpp" +#include "../mwsound/soundmanager.hpp" + namespace MWClass { void Probe::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const @@ -53,6 +57,8 @@ namespace MWClass boost::shared_ptr Probe::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const { + environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true); + return boost::shared_ptr ( new MWWorld::ActionTake (ptr)); } @@ -65,10 +71,29 @@ namespace MWClass return ref->base->script; } + std::pair, bool> Probe::getEquipmentSlots (const MWWorld::Ptr& ptr) const + { + std::vector slots; + + slots.push_back (int (MWWorld::InventoryStore::Slot_CarriedRight)); + + return std::make_pair (slots, false); + } + void Probe::registerSelf() { boost::shared_ptr instance (new Probe); registerClass (typeid (ESM::Probe).name(), instance); } + + std::string Probe::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + { + return std::string("Item Probe Up"); + } + + std::string Probe::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + { + return std::string("Item Probe Down"); + } } diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index 3f2bfed5b..1507d65aa 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -25,7 +25,17 @@ namespace MWClass virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr + virtual std::pair, bool> getEquipmentSlots (const MWWorld::Ptr& ptr) const; + ///< \return first: Return IDs of the slot this object can be equipped in; second: can object + /// stay stacked when equipped? + static void registerSelf(); + + virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + ///< Return the pick up sound Id + + virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + ///< Return the put down sound Id }; } diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index f831b6b50..758bf4079 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -7,9 +7,12 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" +#include "../mwworld/environment.hpp" #include "../mwrender/objects.hpp" +#include "../mwsound/soundmanager.hpp" + namespace MWClass { void Repair::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const @@ -53,6 +56,8 @@ namespace MWClass boost::shared_ptr Repair::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const { + environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true); + return boost::shared_ptr ( new MWWorld::ActionTake (ptr)); } @@ -71,4 +76,14 @@ namespace MWClass registerClass (typeid (ESM::Repair).name(), instance); } + + std::string Repair::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + { + return std::string("Item Repair Up"); + } + + std::string Repair::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + { + return std::string("Item Repair Down"); + } } diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index a5864ab35..17b606f4c 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -26,6 +26,12 @@ namespace MWClass ///< Return name of the script attached to ptr static void registerSelf(); + + virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + ///< Return the pick up sound Id + + virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + ///< Return the put down sound Id }; } diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 90fd3e33b..20db0cf38 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -7,9 +7,13 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" +#include "../mwworld/environment.hpp" +#include "../mwworld/inventorystore.hpp" #include "../mwrender/objects.hpp" +#include "../mwsound/soundmanager.hpp" + namespace MWClass { void Weapon::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const @@ -53,6 +57,8 @@ namespace MWClass boost::shared_ptr Weapon::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const { + environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true); + return boost::shared_ptr ( new MWWorld::ActionTake (ptr)); } @@ -78,10 +84,157 @@ namespace MWClass return ref->base->script; } + std::pair, bool> Weapon::getEquipmentSlots (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + std::vector slots; + bool stack = false; + + if (ref->base->data.type==ESM::Weapon::Arrow || ref->base->data.type==ESM::Weapon::Bolt) + { + slots.push_back (int (MWWorld::InventoryStore::Slot_Ammunition)); + stack = true; + } + else if (ref->base->data.type==ESM::Weapon::MarksmanThrown) + { + slots.push_back (int (MWWorld::InventoryStore::Slot_CarriedRight)); + stack = true; + } + else + slots.push_back (int (MWWorld::InventoryStore::Slot_CarriedRight)); + + return std::make_pair (slots, stack); + } + + int Weapon::getEquipmentSkill (const MWWorld::Ptr& ptr, + const MWWorld::Environment& environment) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + const int size = 12; + + static const int sMapping[size][2] = + { + { ESM::Weapon::ShortBladeOneHand, ESM::Skill::ShortBlade }, + { ESM::Weapon::LongBladeOneHand, ESM::Skill::LongBlade }, + { ESM::Weapon::LongBladeTwoHand, ESM::Skill::LongBlade }, + { ESM::Weapon::BluntOneHand, ESM::Skill::BluntWeapon }, + { ESM::Weapon::BluntTwoClose, ESM::Skill::BluntWeapon }, + { ESM::Weapon::BluntTwoWide, ESM::Skill::BluntWeapon }, + { ESM::Weapon::SpearTwoWide, ESM::Skill::Spear }, + { ESM::Weapon::AxeOneHand, ESM::Skill::Axe }, + { ESM::Weapon::AxeTwoHand, ESM::Skill::Axe }, + { ESM::Weapon::MarksmanBow, ESM::Skill::Marksman }, + { ESM::Weapon::MarksmanCrossbow, ESM::Skill::Marksman }, + { ESM::Weapon::MarksmanThrown, ESM::Skill::Marksman } + }; + + for (int i=0; ibase->data.type) + return sMapping[i][1]; + + return -1; + } + void Weapon::registerSelf() { boost::shared_ptr instance (new Weapon); registerClass (typeid (ESM::Weapon).name(), instance); } + + std::string Weapon::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + int type = ref->base->data.type; + // Ammo + if (type == 12 || type == 13) + { + return std::string("Item Ammo Up"); + } + // Bow + if (type == 9) + { + return std::string("Item Weapon Bow Up"); + } + // Crossbow + if (type == 10) + { + return std::string("Item Weapon Crossbow Up"); + } + // Longblades, One hand and Two + if (type == 1 || type == 2) + { + return std::string("Item Weapon Longblade Up"); + } + // Shortblade and thrown weapons + // thrown weapons may not be entirely correct + if (type == 0 || type == 11) + { + return std::string("Item Weapon Shortblade Up"); + } + // Spear + if (type == 6) + { + return std::string("Item Weapon Spear Up"); + } + // Blunts and Axes + if (type == 3 || type == 4 || type == 5 || type == 7 || type == 8) + { + return std::string("Item Weapon Blunt Up"); + } + + return std::string("Item Misc Up"); + } + + std::string Weapon::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + int type = ref->base->data.type; + // Ammo + if (type == 12 || type == 13) + { + return std::string("Item Ammo Down"); + } + // Bow + if (type == 9) + { + return std::string("Item Weapon Bow Down"); + } + // Crossbow + if (type == 10) + { + return std::string("Item Weapon Crossbow Down"); + } + // Longblades, One hand and Two + if (type == 1 || type == 2) + { + return std::string("Item Weapon Longblade Down"); + } + // Shortblade and thrown weapons + // thrown weapons may not be entirely correct + if (type == 0 || type == 11) + { + return std::string("Item Weapon Shortblade Down"); + } + // Spear + if (type == 6) + { + return std::string("Item Weapon Spear Down"); + } + // Blunts and Axes + if (type == 3 || type == 4 || type == 5 || type == 7 || type == 8) + { + return std::string("Item Weapon Blunt Down"); + } + + return std::string("Item Misc Down"); + } } diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index b056249b9..f863c0bfe 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -31,7 +31,22 @@ namespace MWClass virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr + virtual std::pair, bool> getEquipmentSlots (const MWWorld::Ptr& ptr) const; + ///< \return first: Return IDs of the slot this object can be equipped in; second: can object + /// stay stacked when equipped? + + virtual int getEquipmentSkill (const MWWorld::Ptr& ptr, + const MWWorld::Environment& environment) const; + /// Return the index of the skill this item corresponds to when equiopped or -1, if there is + /// no such skill. + static void registerSelf(); + + virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + ///< Return the pick up sound Id + + virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + ///< Return the put down sound Id }; } diff --git a/apps/openmw/mwdialogue/dialoguemanager.cpp b/apps/openmw/mwdialogue/dialoguemanager.cpp index f78160cd7..dd57dfda0 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.cpp +++ b/apps/openmw/mwdialogue/dialoguemanager.cpp @@ -9,16 +9,36 @@ #include + #include "../mwworld/class.hpp" #include "../mwworld/environment.hpp" #include "../mwworld/world.hpp" #include "../mwworld/refdata.hpp" #include "../mwworld/player.hpp" +#include "../mwworld/containerstore.hpp" #include "../mwinput/inputmanager.hpp" +#include "../mwgui/dialogue.hpp" +#include "../mwgui/window_manager.hpp" + +#include "journal.hpp" #include +#include "../mwscript/extensions.hpp" +#include "../mwscript/scriptmanager.hpp" + +#include +#include +#include +#include +#include +#include + +#include "../mwscript/compilercontext.hpp" +#include "../mwscript/interpretercontext.hpp" +#include + namespace { std::string toLower (const std::string& name) @@ -31,17 +51,18 @@ namespace return lowerCase; } + template bool selectCompare (char comp, T1 value1, T2 value2) { switch (comp) { - case '0': return value1==value2; - case '1': return value1!=value2; - case '2': return value1>value2; - case '3': return value1>=value2; - case '4': return value1value2; + case '3': return value1>=value2; + case '4': return value1::const_iterator iter (info.selects.begin()); + iter != info.selects.end(); ++iter) + { + ESM::DialInfo::SelectStruct select = *iter; + char type = select.selectRule[1]; + if(type == '1') + { + isFunction = true; + char comp = select.selectRule[4]; + std::string name = select.selectRule.substr (5); + std::string function = select.selectRule.substr(2,2); + + int ifunction; + std::istringstream iss(function); + iss >> ifunction; + switch(ifunction) + { + case 39://PC Expelled + if(!selectCompare(comp,0,select.i)) return false; + break; + + case 40://PC Common Disease + if(!selectCompare(comp,0,select.i)) return false; + break; + + case 41://PC Blight Disease + if(!selectCompare(comp,0,select.i)) return false; + break; + + case 43://PC Crime level + if(!selectCompare(comp,0,select.i)) return false; + break; + + case 46://Same faction + if(!selectCompare(comp,0,select.i)) return false; + break; + + case 48://Detected + if(!selectCompare(comp,1,select.i)) return false; + break; + + case 49://Alarmed + if(!selectCompare(comp,0,select.i)) return false; + break; + + case 50://choice + isAChoice = true; + if(choice) + { + if(!selectCompare(comp,mChoice,select.i)) return false; + } + break; + + case 60://PC Vampire + if(!selectCompare(comp,0,select.i)) return false; + break; + + case 61://Level + if(!selectCompare(comp,1,select.i)) return false; + break; + + case 62://Attacked + if(!selectCompare(comp,0,select.i)) return false; + break; + + case 63://Talked to PC + if(!selectCompare(comp,0,select.i)) return false; + break; + + case 64://PC Health + if(!selectCompare(comp,50,select.i)) return false; + break; + + case 65://Creature target + if(!selectCompare(comp,0,select.i)) return false; + break; + + case 66://Friend hit + if(!selectCompare(comp,0,select.i)) return false; + break; + + case 67://Fight + if(!selectCompare(comp,0,select.i)) return false; + break; + + case 68://Hello???? + if(!selectCompare(comp,0,select.i)) return false; + break; + + case 69://Alarm + if(!selectCompare(comp,0,select.i)) return false; + break; + + case 70://Flee + if(!selectCompare(comp,0,select.i)) return false; + break; + + case 71://Should Attack + if(!selectCompare(comp,0,select.i)) return false; + break; + + default: + break; + + } + } + } + + return true; + } + bool DialogueManager::isMatching (const MWWorld::Ptr& actor, const ESM::DialInfo::SelectStruct& select) const { @@ -124,58 +267,173 @@ namespace MWDialogue { char comp = select.selectRule[4]; std::string name = select.selectRule.substr (5); - - // TODO types 4, 5, 6, 7, 8, 9, A, B, C + std::string function = select.selectRule.substr(1,2); switch (type) { - case '1': // function + case '1': // function - return false; // TODO implement functions + return true; // TODO implement functions - case '2': // global + case '2': // global - if (select.type==ESM::VT_Short || select.type==ESM::VT_Int || - select.type==ESM::VT_Long) - { - if (!checkGlobal (comp, toLower (name), select.i, *mEnvironment.mWorld)) - return false; - } - else if (select.type==ESM::VT_Float) - { - if (!checkGlobal (comp, toLower (name), select.f, *mEnvironment.mWorld)) - return false; - } - else - throw std::runtime_error ( - "unsupported variable type in dialogue info select"); + if (select.type==ESM::VT_Short || select.type==ESM::VT_Int || + select.type==ESM::VT_Long) + { + if (!checkGlobal (comp, toLower (name), select.i, *mEnvironment.mWorld)) + return false; + } + else if (select.type==ESM::VT_Float) + { + if (!checkGlobal (comp, toLower (name), select.f, *mEnvironment.mWorld)) + return false; + } + else + throw std::runtime_error ( + "unsupported variable type in dialogue info select"); - return true; + return true; - case '3': // local + case '3': // local - if (select.type==ESM::VT_Short || select.type==ESM::VT_Int || - select.type==ESM::VT_Long) - { - if (!checkLocal (comp, toLower (name), select.i, actor, - mEnvironment.mWorld->getStore())) - return false; - } - else if (select.type==ESM::VT_Float) - { - if (!checkLocal (comp, toLower (name), select.f, actor, - mEnvironment.mWorld->getStore())) - return false; - } - else - throw std::runtime_error ( - "unsupported variable type in dialogue info select"); + if (select.type==ESM::VT_Short || select.type==ESM::VT_Int || + select.type==ESM::VT_Long) + { + if (!checkLocal (comp, toLower (name), select.i, actor, + mEnvironment.mWorld->getStore())) + return false; + } + else if (select.type==ESM::VT_Float) + { + if (!checkLocal (comp, toLower (name), select.f, actor, + mEnvironment.mWorld->getStore())) + return false; + } + else + throw std::runtime_error ( + "unsupported variable type in dialogue info select"); - return true; + return true; - default: + case '4'://journal + if(select.type==ESM::VT_Int) + { + if(!selectCompare(comp,mEnvironment.mJournal->getJournalIndex(toLower(name)),select.i)) return false; + } + else + throw std::runtime_error ( + "unsupported variable type in dialogue info select"); - std::cout << "unchecked select: " << type << " " << comp << " " << name << std::endl; + return true; + + case '5'://item + { + MWWorld::Ptr player = mEnvironment.mWorld->getPlayer().getPlayer(); + MWWorld::ContainerStore& store = MWWorld::Class::get (player).getContainerStore (player); + + int sum = 0; + + for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter) + if (iter->getCellRef().refID==name) + sum += iter->getRefData().getCount(); + if(!selectCompare(comp,sum,select.i)) return false; + } + + return true; + + + case '6'://dead + if(!selectCompare(comp,0,select.i)) return false; + + case '7':// not ID + if(select.type==ESM::VT_String ||select.type==ESM::VT_Int)//bug in morrowind here? it's not a short, it's a string + { + int isID = int(toLower(name)==toLower(MWWorld::Class::get (actor).getId (actor))); + if (selectCompare(comp,!isID,select.i)) return false; + } + else + throw std::runtime_error ( + "unsupported variable type in dialogue info select"); + + return true; + + case '8':// not faction + if(select.type==ESM::VT_Int) + { + ESMS::LiveCellRef* npc = actor.get(); + int isFaction = int(toLower(npc->base->faction) == toLower(name)); + if(selectCompare(comp,!isFaction,select.i)) + return false; + } + else + throw std::runtime_error ( + "unsupported variable type in dialogue info select"); + + return true; + + case '9':// not class + if(select.type==ESM::VT_Int) + { + ESMS::LiveCellRef* npc = actor.get(); + int isClass = int(toLower(npc->base->cls) == toLower(name)); + if(selectCompare(comp,!isClass,select.i)) + return false; + } + else + throw std::runtime_error ( + "unsupported variable type in dialogue info select"); + + return true; + + case 'A'://not Race + if(select.type==ESM::VT_Int) + { + ESMS::LiveCellRef* npc = actor.get(); + int isRace = int(toLower(npc->base->race) == toLower(name)); + if(selectCompare(comp,!isRace,select.i)) + return false; + } + else + throw std::runtime_error ( + "unsupported variable type in dialogue info select"); + + return true; + + case 'B'://not Cell + if(select.type==ESM::VT_Int) + { + int isCell = int(toLower(actor.getCell()->cell->name) == toLower(name)); + if(selectCompare(comp,!isCell,select.i)) + return false; + } + else + throw std::runtime_error ( + "unsupported variable type in dialogue info select"); + return true; + + case 'C'://not local + if (select.type==ESM::VT_Short || select.type==ESM::VT_Int || + select.type==ESM::VT_Long) + { + if (checkLocal (comp, toLower (name), select.i, actor, + mEnvironment.mWorld->getStore())) + return false; + } + else if (select.type==ESM::VT_Float) + { + if (checkLocal (comp, toLower (name), select.f, actor, + mEnvironment.mWorld->getStore())) + return false; + } + else + throw std::runtime_error ( + "unsupported variable type in dialogue info select"); + return true; + + + default: + + std::cout << "unchecked select: " << type << " " << comp << " " << name << std::endl; } } @@ -189,6 +447,10 @@ namespace MWDialogue if (toLower (info.actor)!=MWWorld::Class::get (actor).getId (actor)) return false; + //PC Faction + if(!info.pcFaction.empty()) return false; + + //NPC race if (!info.race.empty()) { ESMS::LiveCellRef *cellRef = actor.get(); @@ -200,6 +462,7 @@ namespace MWDialogue return false; } + //NPC class if (!info.clas.empty()) { ESMS::LiveCellRef *cellRef = actor.get(); @@ -211,6 +474,7 @@ namespace MWDialogue return false; } + //NPC faction if (!info.npcFaction.empty()) { ESMS::LiveCellRef *cellRef = actor.get(); @@ -220,10 +484,32 @@ namespace MWDialogue if (toLower (info.npcFaction)!=toLower (cellRef->base->faction)) return false; + + //check NPC rank + if(cellRef->base->npdt52.gold != -10) + { + if(cellRef->base->npdt52.rank < info.data.rank) return false; + } + else + { + if(cellRef->base->npdt12.rank < info.data.rank) return false; + } } // TODO check player faction + //check gender + ESMS::LiveCellRef* npc = actor.get(); + if(npc->base->flags&npc->base->Female) + { + if(static_cast (info.data.gender)==0) return false; + } + else + { + if(static_cast (info.data.gender)==1) return false; + } + + // check cell if (!info.cell.empty()) if (mEnvironment.mWorld->getPlayer().getPlayer().getCell()->cell->name != info.cell) @@ -236,50 +522,281 @@ namespace MWDialogue if (!isMatching (actor, *iter)) return false; - std::cout - << "unchecked entries:" << std::endl - << " player faction: " << info.pcFaction << std::endl - << " disposition: " << info.data.disposition << std::endl - << " NPC rank: " << static_cast (info.data.rank) << std::endl - << " gender: " << static_cast (info.data.gender) << std::endl - << " PC rank: " << static_cast (info.data.PCrank) << std::endl; - return true; } - DialogueManager::DialogueManager (MWWorld::Environment& environment) : mEnvironment (environment) {} + DialogueManager::DialogueManager (MWWorld::Environment& environment,const Compiler::Extensions& extensions) : + mEnvironment (environment),mCompilerContext (MWScript::CompilerContext::Type_Dialgoue, environment), + mErrorStream(std::cout.rdbuf()),mErrorHandler(mErrorStream) + { + mChoice = -1; + mIsInChoice = false; + mCompilerContext.setExtensions (&extensions); + } + + void DialogueManager::addTopic(std::string topic) + { + knownTopics[toLower(topic)] = true; + } + + void DialogueManager::parseText(std::string text) + { + std::list::iterator it; + for(it = actorKnownTopics.begin();it != actorKnownTopics.end();it++) + { + size_t pos = find_str_ci(text,*it,0); + if(pos !=std::string::npos) + { + if(pos==0) + { + knownTopics[*it] = true; + } + else if(text.substr(pos -1,1) == " ") + { + knownTopics[*it] = true; + } + } + } + updateTopics(); + } void DialogueManager::startDialogue (const MWWorld::Ptr& actor) { - std::cout << "talking with " << MWWorld::Class::get (actor).getName (actor) << std::endl; + mChoice = -1; + mIsInChoice = false; - const ESM::Dialogue *dialogue = mEnvironment.mWorld->getStore().dialogs.find ("hello"); + mActor = actor; - for (std::vector::const_iterator iter (dialogue->mInfo.begin()); - iter!=dialogue->mInfo.end(); ++iter) + mDialogueMap.clear(); + actorKnownTopics.clear(); + ESMS::RecListT::MapType dialogueList = mEnvironment.mWorld->getStore().dialogs.list; + for(ESMS::RecListT::MapType::iterator it = dialogueList.begin(); it!=dialogueList.end();it++) { - if (isMatching (actor, *iter)) + mDialogueMap[it->first] = it->second; + } + + //initialise the GUI + mEnvironment.mInputManager->setGuiMode(MWGui::GM_Dialogue); + MWGui::DialogueWindow* win = mEnvironment.mWindowManager->getDialogueWindow(); + win->startDialogue(MWWorld::Class::get (actor).getName (actor)); + + //setup the list of topics known by the actor. Topics who are also on the knownTopics list will be added to the GUI + updateTopics(); + + //greeting + bool greetingFound = false; + //ESMS::RecListT::MapType dialogueList = mEnvironment.mWorld->getStore().dialogs.list; + for(ESMS::RecListT::MapType::iterator it = dialogueList.begin(); it!=dialogueList.end();it++) + { + ESM::Dialogue ndialogue = it->second; + if(ndialogue.type == ESM::Dialogue::Greeting) { - // start dialogue - std::cout << "found matching info record" << std::endl; - - std::cout << "response: " << iter->response << std::endl; - - if (!iter->sound.empty()) + if (greetingFound) break; + for (std::vector::const_iterator iter (it->second.mInfo.begin()); + iter!=it->second.mInfo.end(); ++iter) { - // TODO play sound - } + if (isMatching (actor, *iter) && functionFilter(mActor,*iter,true)) + { + if (!iter->sound.empty()) + { + // TODO play sound + } - if (!iter->resultScript.empty()) - { - std::cout << "script: " << iter->resultScript << std::endl; - // TODO execute script + std::string text = iter->response; + parseText(text); + win->addText(iter->response); + executeScript(iter->resultScript); + greetingFound = true; + mLastTopic = it->first; + mLastDialogue = *iter; + break; + } } - - mEnvironment.mInputManager->setGuiMode(MWGui::GM_Dialogue); - break; } } } + bool DialogueManager::compile (const std::string& cmd,std::vector& code) + { + try + { + mErrorHandler.reset(); + + std::istringstream input (cmd + "\n"); + + Compiler::Scanner scanner (mErrorHandler, input, mCompilerContext.getExtensions()); + + Compiler::Locals locals; + + std::string actorScript = MWWorld::Class::get (mActor).getScript (mActor); + + if (!actorScript.empty()) + { + // grab local variables from actor's script, if available. + locals = mEnvironment.mScriptManager->getLocals (actorScript); + } + + Compiler::ScriptParser parser(mErrorHandler,mCompilerContext, locals, false); + + scanner.scan (parser); + if(mErrorHandler.isGood()) + { + parser.getCode(code); + return true; + } + return false; + } + catch (const Compiler::SourceException& error) + { + // error has already been reported via error handler + } + catch (const std::exception& error) + { + printError (std::string ("An exception has been thrown: ") + error.what()); + } + + return false; + } + + void DialogueManager::executeScript(std::string script) + { + std::vector code; + if(compile(script,code)) + { + try + { + MWScript::InterpreterContext interpreterContext(mEnvironment,&mActor.getRefData().getLocals(),mActor); + Interpreter::Interpreter interpreter; + MWScript::installOpcodes (interpreter); + interpreter.run (&code[0], code.size(), interpreterContext); + } + catch (const std::exception& error) + { + printError (std::string ("An exception has been thrown: ") + error.what()); + } + } + } + + void DialogueManager::updateTopics() + { + std::list keywordList; + + actorKnownTopics.clear(); + MWGui::DialogueWindow* win = mEnvironment.mWindowManager->getDialogueWindow(); + ESMS::RecListT::MapType dialogueList = mEnvironment.mWorld->getStore().dialogs.list; + for(ESMS::RecListT::MapType::iterator it = dialogueList.begin(); it!=dialogueList.end();it++) + { + ESM::Dialogue ndialogue = it->second; + if(ndialogue.type == ESM::Dialogue::Topic) + { + for (std::vector::const_iterator iter (it->second.mInfo.begin()); + iter!=it->second.mInfo.end(); ++iter) + { + if (isMatching (mActor, *iter) && functionFilter(mActor,*iter,false)) + { + actorKnownTopics.push_back(it->first); + //does the player know the topic? + if(knownTopics.find(toLower(it->first)) != knownTopics.end()) + { + keywordList.push_back(it->first); + break; + } + } + } + } + } + win->setKeywords(keywordList); + } + + void DialogueManager::keywordSelected(std::string keyword) + { + if(!mIsInChoice) + { + if(mDialogueMap.find(keyword) != mDialogueMap.end()) + { + ESM::Dialogue ndialogue = mDialogueMap[keyword]; + std::vector::const_iterator iter; + if(ndialogue.type == ESM::Dialogue::Topic) + { + for (iter = ndialogue.mInfo.begin(); + iter!=ndialogue.mInfo.end(); ++iter) + { + if (isMatching (mActor, *iter) && functionFilter(mActor,*iter,true)) + { + std::string text = iter->response; + std::string script = iter->resultScript; + + parseText(text); + + MWGui::DialogueWindow* win = mEnvironment.mWindowManager->getDialogueWindow(); + win->addTitle(keyword); + win->addText(iter->response); + + executeScript(script); + + mLastTopic = keyword; + mLastDialogue = *iter; + break; + } + } + } + } + } + updateTopics(); + } + + void DialogueManager::goodbyeSelected() + { + mEnvironment.mInputManager->setGuiMode(MWGui::GM_Game); + } + + void DialogueManager::questionAnswered(std::string answere) + { + if(mChoiceMap.find(answere) != mChoiceMap.end()) + { + mChoice = mChoiceMap[answere]; + + std::vector::const_iterator iter; + if(mDialogueMap.find(mLastTopic) != mDialogueMap.end()) + { + ESM::Dialogue ndialogue = mDialogueMap[mLastTopic]; + if(ndialogue.type == ESM::Dialogue::Topic) + { + for (std::vector::const_iterator iter = ndialogue.mInfo.begin(); + iter!=ndialogue.mInfo.end(); ++iter) + { + if (isMatching (mActor, *iter) && functionFilter(mActor,*iter,true)) + { + mChoiceMap.clear(); + mChoice = -1; + mIsInChoice = false; + MWGui::DialogueWindow* win = mEnvironment.mWindowManager->getDialogueWindow(); + std::string text = iter->response; + parseText(text); + win->addText(text); + executeScript(iter->resultScript); + mLastTopic = mLastTopic; + mLastDialogue = *iter; + break; + } + } + } + } + updateTopics(); + } + } + + void DialogueManager::printError(std::string error) + { + MWGui::DialogueWindow* win = mEnvironment.mWindowManager->getDialogueWindow(); + win->addText(error); + } + + void DialogueManager::askQuestion(std::string question, int choice) + { + MWGui::DialogueWindow* win = mEnvironment.mWindowManager->getDialogueWindow(); + win->askQuestion(question); + mChoiceMap[question] = choice; + mIsInChoice = true; + } } diff --git a/apps/openmw/mwdialogue/dialoguemanager.hpp b/apps/openmw/mwdialogue/dialoguemanager.hpp index 5b6b26240..260d8e339 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.hpp +++ b/apps/openmw/mwdialogue/dialoguemanager.hpp @@ -3,7 +3,13 @@ #include +#include +#include "../mwscript/compilercontext.hpp" +#include "../mwscript/interpretercontext.hpp" +#include + #include "../mwworld/ptr.hpp" +#include namespace MWWorld { @@ -20,12 +26,48 @@ namespace MWDialogue bool isMatching (const MWWorld::Ptr& actor, const ESM::DialInfo& info) const; + bool functionFilter(const MWWorld::Ptr& actor, const ESM::DialInfo& info,bool choice); + + void parseText(std::string text); + + void updateTopics(); + + std::map mDialogueMap; + std::map knownTopics;// Those are the topics the player knows. + std::list actorKnownTopics; + + MWScript::CompilerContext mCompilerContext; + std::ostream mErrorStream; + Compiler::StreamErrorHandler mErrorHandler; + + + bool compile (const std::string& cmd,std::vector& code); + void executeScript(std::string script); + MWWorld::Ptr mActor; + + void printError(std::string error); + + int mChoice; + std::map mChoiceMap; + std::string mLastTopic; + ESM::DialInfo mLastDialogue; + bool mIsInChoice; + public: - DialogueManager (MWWorld::Environment& environment); + DialogueManager (MWWorld::Environment& environment,const Compiler::Extensions& extensions); void startDialogue (const MWWorld::Ptr& actor); + void addTopic(std::string topic); + + void askQuestion(std::string question,int choice); + + //calbacks for the GUI + void keywordSelected(std::string keyword); + void goodbyeSelected(); + void questionAnswered(std::string answere); + }; } diff --git a/apps/openmw/mwdialogue/journal.cpp b/apps/openmw/mwdialogue/journal.cpp index 42cce5cf5..0715214eb 100644 --- a/apps/openmw/mwdialogue/journal.cpp +++ b/apps/openmw/mwdialogue/journal.cpp @@ -3,6 +3,9 @@ #include "../mwworld/environment.hpp" +#include "../mwgui/window_manager.hpp" +#include "../mwgui/messagebox.hpp" + namespace MWDialogue { Quest& Journal::getQuest (const std::string& id) @@ -34,6 +37,10 @@ namespace MWDialogue Quest& quest = getQuest (id); quest.addEntry (entry, *mEnvironment.mWorld); // we are doing slicing on purpose here + + std::vector empty; + std::string notification = "Your Journal has been updated."; + mEnvironment.mWindowManager->messageBox (notification, empty); } void Journal::setJournalIndex (const std::string& id, int index) @@ -60,7 +67,12 @@ namespace MWDialogue int Journal::getJournalIndex (const std::string& id) const { - return 0; + TQuestContainer::const_iterator iter = mQuests.find (id); + + if (iter==mQuests.end()) + return 0; + + return iter->second.getIndex(); } Journal::TEntryIter Journal::begin() const diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index 0e2e692d3..3fd6e7892 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -50,7 +50,7 @@ namespace MWGui return isGood(); } - catch (const Compiler::SourceException& error) + catch (const Compiler::SourceException&) { // error has already been reported via error handler } @@ -342,7 +342,7 @@ namespace MWGui if( ( matches.front().find(' ') != string::npos ) ) { if( !has_front_quote ) output.append(string("\"")); - return output.append(matches.front() + string("\" ")); + return output.append(matches.front() + string("\" ")); } else if( has_front_quote ) { return output.append(matches.front() + string("\" ")); @@ -361,7 +361,7 @@ namespace MWGui /* Append the longest match to the end of the output string*/ output.append(matches.front().substr( 0, i)); return output; - } + } } } diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index e48c142aa..cef47d074 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -3,6 +3,8 @@ #include "window_manager.hpp" #include "widgets.hpp" #include "components/esm_store/store.hpp" +#include "../mwworld/environment.hpp" +#include "../mwdialogue/dialoguemanager.hpp" #include #include @@ -14,32 +16,54 @@ using namespace MWGui; using namespace Widgets; -DialogueWindow::DialogueWindow(WindowManager& parWindowManager) - : WindowBase("openmw_dialogue_window_layout.xml", parWindowManager) +/** +*Copied from the internet. +*/ + +std::string lower_string(const std::string& str) +{ + std::string lowerCase; + + std::transform (str.begin(), str.end(), std::back_inserter (lowerCase), + (int(*)(int)) std::tolower); + + return lowerCase; +} + +std::string::size_type find_str_ci(const std::string& str, const std::string& substr,size_t pos) +{ + return lower_string(str).find(lower_string(substr),pos); +} + + +DialogueWindow::DialogueWindow(WindowManager& parWindowManager,MWWorld::Environment& environment) + : WindowBase("openmw_dialogue_window_layout.xml", parWindowManager), + mEnvironment(environment) { // Centre dialog center(); //WindowManager *wm = environment.mWindowManager; setText("NpcName", "Name of character"); - + //History view getWidget(history, "History"); history->setOverflowToTheLeft(true); history->getClient()->eventMouseButtonClick = MyGUI::newDelegate(this, &DialogueWindow::onHistoryClicked); - - //Topics list + history->setMaxTextLength(1000000); + //Topics list getWidget(topicsList, "TopicsList"); topicsList->setScrollVisible(true); - topicsList->eventListSelectAccept = MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic); + //topicsList->eventListSelectAccept = MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic); topicsList->eventListMouseItemActivate = MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic); - topicsList->eventListChangePosition = MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic); + //topicsList->eventListChangePosition = MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic); MyGUI::ButtonPtr byeButton; getWidget(byeButton, "ByeButton"); byeButton->eventMouseButtonClick = MyGUI::newDelegate(this, &DialogueWindow::onByeClicked); - updateOptions(); + getWidget(pDispositionBar, "Disposition"); + getWidget(pDispositionText,"DispositionText"); } void DialogueWindow::onHistoryClicked(MyGUI::Widget* _sender) @@ -51,70 +75,126 @@ void DialogueWindow::onHistoryClicked(MyGUI::Widget* _sender) const IntPoint& lastPressed = InputManager::getInstance().getLastLeftPressed(); size_t cursorPosition = t->getCursorPosition(lastPressed); - if(history->getColorAtPos(cursorPosition) != "#FFFFFF") + MyGUI::UString color = history->getColorAtPos(cursorPosition); + if(color != "#B29154") { UString key = history->getColorTextAt(cursorPosition); - std::cout << "Clicked on key: " << key << std::endl; - //eventTopicSelected(key); + if(color == "#686EBA") mEnvironment.mDialogueManager->keywordSelected(lower_string(key)); + + if(color == "#572D21") mEnvironment.mDialogueManager->questionAnswered(key); } } void DialogueWindow::open() { + topicsList->removeAllItems(); + pTopicsText.clear(); + history->eraseText(0,history->getTextLength()); updateOptions(); setVisible(true); } void DialogueWindow::onByeClicked(MyGUI::Widget* _sender) { - eventBye(); + mEnvironment.mDialogueManager->goodbyeSelected(); } void DialogueWindow::onSelectTopic(MyGUI::List* _sender, size_t _index) { if (_index == MyGUI::ITEM_NONE) return; - - //const std::string* theTopic = topicsList->getItemDataAt(_index); - //std::cout << "Selected: "<< theTopic << std::endl; - //eventTopicSelected(key); + std::string topic = _sender->getItemNameAt(_index); + mEnvironment.mDialogueManager->keywordSelected(lower_string(topic)); } +void DialogueWindow::startDialogue(std::string npcName) +{ + setText("NpcName", npcName); +} + +void DialogueWindow::setKeywords(std::list keyWords) +{ + topicsList->removeAllItems(); + for(std::list::iterator it = keyWords.begin(); it != keyWords.end(); it++) + { + topicsList->addItem(*it); + } +} + +void DialogueWindow::removeKeyword(std::string keyWord) +{ + if(topicsList->findItemIndexWith(keyWord) != MyGUI::ITEM_NONE) + { + topicsList->removeItemAt(topicsList->findItemIndexWith(keyWord)); + pTopicsText.erase(keyWord); + } +} + +void addColorInString(std::string& str, const std::string& keyword,std::string color1, std::string color2) +{ + size_t pos = 0; + while((pos = find_str_ci(str,keyword, pos)) != std::string::npos) + { + if(pos==0) + { + str.insert(pos,color1); + pos += color1.length(); + pos += keyword.length(); + str.insert(pos,color2); + pos+= color2.length(); + } + else + { + if(str.substr(pos -1,1) == " ") + { + str.insert(pos,color1); + pos += color1.length(); + pos += keyword.length(); + str.insert(pos,color2); + pos+= color2.length(); + } + else + { + pos += keyword.length(); + } + } + } +} + +std::string DialogueWindow::parseText(std::string text) +{ + for(unsigned int i = 0;igetItemCount();i++) + { + std::string keyWord = topicsList->getItemNameAt(i); + addColorInString(text,keyWord,"#686EBA","#B29154"); + } + return text; +} + +void DialogueWindow::addText(std::string text) +{ + history->addDialogText("#B29154"+parseText(text)+"#B29154"); +} + +void DialogueWindow::addTitle(std::string text) +{ + history->addDialogHeading(text); +} + +void DialogueWindow::askQuestion(std::string question) +{ + history->addDialogText("#572D21"+question+"#B29154"+" "); +} void DialogueWindow::updateOptions() { - //FIXME Add this properly - history->addDialogText("Through the translucent surface of the orb, you see shifting images of distant locations..."); - for(int z = 0; z < 10; z++) - { - history->addDialogHeading("Fort Frostmoth"); - history->addDialogText("The image in the orb flickers, and you see.... The cold courtyard of #FF0000Fort Frostmoth#FFFFFF, battered bu werewolf attack, but still standing, still projecting Imperial might even to this distant and cold corner of the world."); - } - //Clear the list of topics topicsList->removeAllItems(); - int i = 0; - topicsList->addItem("Ald'ruhn", i++); - topicsList->addItem("Balmora", i++); - topicsList->addItem("Sadrith Mora", i++); - topicsList->addItem("Vivec", i++); - topicsList->addItem("Ald Velothi", i++); - topicsList->addItem("Caldera", i++); - topicsList->addItem("Dagon Fel ", i++); - topicsList->addItem("Gnaar Mok", i++); - topicsList->addItem("Gnisis", i++); - topicsList->addItem("Hla Oad", i++); - topicsList->addItem("Khuul", i++); - topicsList->addItem("Maar Gan", i++); - topicsList->addItem("Molag Mar", i++); - topicsList->addItem("Pelagiad", i++); - topicsList->addItem("Seyda Neen", i++); - topicsList->addItem("Suran", i++); - topicsList->addItem("Tel Aruhn", i++); - topicsList->addItem("Tel Branora", i++); - topicsList->addItem("Tel Fyr", i++); - topicsList->addItem("Tel Mora", i++); - topicsList->addItem("Tel Vos", i++); - topicsList->addItem("Vos", i++); -} + pTopicsText.clear(); + history->eraseText(0,history->getTextLength()); + pDispositionBar->setProgressRange(100); + pDispositionBar->setProgressPosition(40); + pDispositionText->eraseText(0,pDispositionText->getTextLength()); + pDispositionText->addText("#B29154"+std::string("40/100")+"#B29154"); +} diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index ddb6f8a4c..7dfd7bb7f 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -9,6 +9,11 @@ namespace MWGui class WindowManager; } +namespace MWWorld +{ + class Environment; +} + /* This file contains the dialouge window Layout is defined by resources/mygui/openmw_dialogue_window_layout.xml. @@ -23,7 +28,7 @@ namespace MWGui class DialogueWindow: public WindowBase { public: - DialogueWindow(WindowManager& parWindowManager); + DialogueWindow(WindowManager& parWindowManager,MWWorld::Environment& environment); void open(); @@ -35,6 +40,14 @@ namespace MWGui */ EventHandle_Void eventBye; + void startDialogue(std::string npcName); + void stopDialogue(); + void setKeywords(std::list keyWord); + void removeKeyword(std::string keyWord); + void addText(std::string text); + void addTitle(std::string text); + void askQuestion(std::string question); + protected: void onSelectTopic(MyGUI::List* _sender, size_t _index); void onByeClicked(MyGUI::Widget* _sender); @@ -42,9 +55,18 @@ namespace MWGui private: void updateOptions(); + /** + *Helper function that add topic keyword in blue in a text. + */ + std::string parseText(std::string text); DialogeHistory* history; MyGUI::ListPtr topicsList; + MyGUI::ProgressPtr pDispositionBar; + MyGUI::EditPtr pDispositionText; + std::map pTopicsText;// this map links keyword and "real" text. + + MWWorld::Environment& mEnvironment; }; } #endif diff --git a/apps/openmw/mwgui/dialogue_history.cpp b/apps/openmw/mwgui/dialogue_history.cpp index aaa559d24..ceb904528 100644 --- a/apps/openmw/mwgui/dialogue_history.cpp +++ b/apps/openmw/mwgui/dialogue_history.cpp @@ -61,9 +61,9 @@ UString DialogeHistory::getColorTextAt(size_t _pos) void DialogeHistory::addDialogHeading(const UString& parText) { - UString head("\n#00FF00"); + UString head("\n#D8C09A"); head.append(parText); - head.append("#FFFFFF\n"); + head.append("#B29154\n"); addText(head); } diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 3f3c89f39..5c9ef1f9b 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -4,6 +4,8 @@ #include "../mwworld/environment.hpp" #include "../mwworld/world.hpp" +#include "../mwsound/soundmanager.hpp" + namespace { struct book @@ -115,6 +117,8 @@ MWGui::JournalWindow::JournalWindow (WindowManager& parWindowManager) void MWGui::JournalWindow::open() { mPageNumber = 0; + std::string journalOpenSound = "book open"; + mWindowManager.getEnvironment().mSoundManager->playSound (journalOpenSound, 1.0, 1.0); if(mWindowManager.getEnvironment().mJournal->begin()!=mWindowManager.getEnvironment().mJournal->end()) { book journal; @@ -176,6 +180,8 @@ void MWGui::JournalWindow::notifyNextPage(MyGUI::WidgetPtr _sender) { if(mPageNumber < int(leftPages.size())-1) { + std::string nextSound = "book page2"; + mWindowManager.getEnvironment().mSoundManager->playSound (nextSound, 1.0, 1.0); mPageNumber = mPageNumber + 1; displayLeftText(leftPages[mPageNumber]); displayRightText(rightPages[mPageNumber]); @@ -186,6 +192,8 @@ void MWGui::JournalWindow::notifyPrevPage(MyGUI::WidgetPtr _sender) { if(mPageNumber > 0) { + std::string prevSound = "book page"; + mWindowManager.getEnvironment().mSoundManager->playSound (prevSound, 1.0, 1.0); mPageNumber = mPageNumber - 1; displayLeftText(leftPages[mPageNumber]); displayRightText(rightPages[mPageNumber]); diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index aca9fbd9a..baf854814 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -51,6 +51,7 @@ WindowManager::WindowManager(MWWorld::Environment& environment, console = new Console(w,h, environment, extensions); mJournal = new JournalWindow(*this); mMessageBoxManager = new MessageBoxManager(this); + dialogueWindow = new DialogueWindow(*this,environment); // The HUD is always on hud->setVisible(true); @@ -149,6 +150,7 @@ void WindowManager::updateVisible() stats->setVisible(false); console->disable(); mJournal->setVisible(false); + dialogueWindow->setVisible(false); // Mouse is visible whenever we're not in game mode gui->setVisiblePointer(isGuiMode()); @@ -195,11 +197,6 @@ void WindowManager::updateVisible() if (mode == GM_Dialogue) { - if (!dialogueWindow) - { - dialogueWindow = new DialogueWindow(*this); - dialogueWindow->eventBye = MyGUI::newDelegate(this, &WindowManager::onDialogueWindowBye); - } dialogueWindow->open(); return; } @@ -349,6 +346,7 @@ void WindowManager::updateSkillArea() void WindowManager::removeDialog(OEngine::GUI::Layout*dialog) { + std::cout << "dialogue a la poubelle"; assert(dialog); if (!dialog) return; @@ -387,7 +385,8 @@ void WindowManager::onDialogueWindowBye() if (dialogueWindow) { //FIXME set some state and stuff? - removeDialog(dialogueWindow); + //removeDialog(dialogueWindow); + dialogueWindow->setVisible(false); } setGuiMode(GM_Game); } diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index 89ff4b9bb..0124c9239 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -124,6 +124,8 @@ namespace MWGui updateVisible(); } + MWGui::DialogueWindow* getDialogueWindow() {return dialogueWindow;} + MyGUI::Gui* getGui() const { return gui; } void wmUpdateFps(float fps, size_t triangleCount, size_t batchCount) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 9df987dc1..7b0d7015c 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -111,7 +111,6 @@ namespace MWRender{ Nif::NiTriShapeCopy& copy = *allshapesiter; std::vector* allvertices = ©.vertices; - std::vector* allnormals = ©.normals; @@ -182,7 +181,6 @@ namespace MWRender{ std::vector inds = iter->second; int verIndex = iter->first; Ogre::Vector3 currentVertex = (*allvertices)[verIndex]; - Ogre::Vector3 currentNormal = (*allnormals)[verIndex]; Nif::NiSkinData::BoneInfoCopy* boneinfocopy = &(allshapesiter->boneinfo[inds[0].boneinfocopyindex]); Ogre::Bone *bonePtr = 0; @@ -276,7 +274,7 @@ namespace MWRender{ rotmult = bonePtr->getOrientation(); scale = bonePtr->getScale().x; boneSequenceIter++; - + for(; boneSequenceIter != boneSequence.end(); boneSequenceIter++) { if(creaturemodel->getSkeleton()->hasBone(*boneSequenceIter)){ @@ -390,7 +388,7 @@ namespace MWRender{ void Animation::handleAnimationTransforms(){ - + Ogre::SkeletonInstance* skel = base->getSkeleton(); @@ -430,11 +428,11 @@ namespace MWRender{ const std::vector & quats = iter->getQuat(); const std::vector & ttime = iter->gettTime(); - + const std::vector & rtime = iter->getrTime(); int rindexJ = rindexI[slot]; - + timeIndex(time, rtime, rindexI[slot], rindexJ, x2); int tindexJ = tindexI[slot]; @@ -447,10 +445,10 @@ namespace MWRender{ Ogre::Quaternion r; bool bTrans = translist1.size() > 0; - + bool bQuats = quats.size() > 0; - + if(skel->hasBone(iter->getBonename())){ Ogre::Bone* bone = skel->getBone(iter->getBonename()); if(bTrans){ @@ -467,10 +465,10 @@ namespace MWRender{ - + } - + slot++; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index e08b86e8d..d1e8071f0 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -66,7 +66,7 @@ class Animation{ void stopScript(); - ~Animation(); + virtual ~Animation(); }; } diff --git a/apps/openmw/mwrender/creatureanimation.hpp b/apps/openmw/mwrender/creatureanimation.hpp index 179991442..2229eeec9 100644 --- a/apps/openmw/mwrender/creatureanimation.hpp +++ b/apps/openmw/mwrender/creatureanimation.hpp @@ -16,7 +16,7 @@ namespace MWRender{ class CreatureAnimation: public Animation{ public: - ~CreatureAnimation(); + virtual ~CreatureAnimation(); CreatureAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env, OEngine::Render::OgreRenderer& _rend); virtual void runAnimation(float timepassed); diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index e8ce735f7..e2071957c 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -20,7 +20,7 @@ class NpcAnimation: public Animation{ public: NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env, OEngine::Render::OgreRenderer& _rend); - ~NpcAnimation(); + virtual ~NpcAnimation(); Ogre::Entity* insertBoundedPart(const std::string &mesh, std::string bonename); void insertFreePart(const std::string &mesh, const std::string suffix, Ogre::SceneNode* insert); virtual void runAnimation(float timepassed); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 7b58a80d7..4f84d90a9 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -51,7 +51,7 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const cameraPitchNode->attachObject(mRendering.getCamera()); //mSkyManager = 0; - mSkyManager = new SkyManager(mMwRoot, mRendering.getCamera()); + mSkyManager = new SkyManager(mMwRoot, mRendering.getCamera(), &environment); mPlayer = new MWRender::Player (mRendering.getCamera(), playerNode); mSun = 0; @@ -210,9 +210,14 @@ void RenderingManager::configureFog(ESMS::CellStore &mCell) void RenderingManager::configureFog(const float density, const Ogre::ColourValue& colour) { /// \todo make the viewing distance and fog start/end configurable - float low = 3000 / density; - float high = 6200 / density; - + + // right now we load 3x3 cells, so the maximum viewing distance we + // can allow (to prevent objects suddenly popping up) equals: + // 8192 * 0.69 + // ^ cell size ^ minimum density value used (clear weather) + float low = 5652.48 / density / 2.f; + float high = 5652.48 / density; + mRendering.getScene()->setFog (FOG_LINEAR, colour, 0, low, high); mRendering.getCamera()->setFarClipDistance ( high ); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 1b324459a..a747b9be0 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -10,16 +10,12 @@ #include +#include "../mwworld/environment.hpp" +#include "../mwworld/world.hpp" + using namespace MWRender; using namespace Ogre; -// the speed at which the clouds are animated -#define CLOUD_SPEED 0.001 - -// this distance has to be set accordingly so that the -// celestial bodies are behind the clouds, but in front of the atmosphere -#define CELESTIAL_BODY_DISTANCE 1000.f - BillboardObject::BillboardObject( const String& textureName, const float initialSize, const Vector3& position, @@ -50,7 +46,7 @@ void BillboardObject::setVisibility(const float visibility) void BillboardObject::setPosition(const Vector3& pPosition) { Vector3 normalised = pPosition.normalisedCopy(); - Vector3 finalPosition = normalised * CELESTIAL_BODY_DISTANCE; + Vector3 finalPosition = normalised * 1000.f; mBBSet->setCommonDirection( -normalised ); @@ -59,7 +55,8 @@ void BillboardObject::setPosition(const Vector3& pPosition) Vector3 BillboardObject::getPosition() const { - return mNode->getPosition(); + Vector3 p = mNode->_getDerivedPosition() - mNode->getParentSceneNode()->_getDerivedPosition(); + return Vector3(p.x, -p.z, p.y); } void BillboardObject::setColour(const ColourValue& pColour) @@ -84,7 +81,7 @@ void BillboardObject::init(const String& textureName, { SceneManager* sceneMgr = rootNode->getCreator(); - Vector3 finalPosition = position.normalisedCopy() * CELESTIAL_BODY_DISTANCE; + Vector3 finalPosition = position.normalisedCopy() * 1000.f; static unsigned int bodyCount=0; @@ -161,14 +158,20 @@ Moon::Moon( const String& textureName, " in float2 uv : TEXCOORD0, \n" " out float4 oColor : COLOR, \n" " uniform sampler2D texture : TEXUNIT0, \n" + " uniform float4 skyColour, \n" " uniform float4 diffuse, \n" " uniform float4 emissive \n" ") \n" "{ \n" " float4 tex = tex2D(texture, uv); \n" - " oColor = float4(emissive.xyz,1) * tex2D(texture, uv) * float4(1,1,1,diffuse.a); \n" - " float bump = pow((1-diffuse.a),4); \n" - " oColor.rgb += float3(bump, bump, bump)*0.5; \n" + " oColor = float4(emissive.xyz,1) * tex; \n" + // use a circle for the alpha (compute UV distance to center) + // looks a bit bad because its not filtered on the edges, + // but it's cheaper than a seperate alpha texture. + " float sqrUVdist = pow(uv.x-0.5,2) + pow(uv.y-0.5, 2); \n" + " oColor.a = diffuse.a * (sqrUVdist >= 0.24 ? 0 : 1); \n" + " oColor.rgb += (1-tex.a) * oColor.a * skyColour.rgb; \n"//fill dark side of moon with skycolour + " oColor.rgb += (1-diffuse.a) * skyColour.rgb; \n"//fade bump "}"; fshader->setSource(outStream2.str()); fshader->load(); @@ -186,15 +189,19 @@ void Moon::setType(const Moon::Type& type) mType = type; } +void Moon::setSkyColour(const Ogre::ColourValue& colour) +{ + mMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstant("skyColour", colour); +} -/// \todo the moon phase rendering is not correct - the dark part of the moon does not occlude the stars void Moon::setPhase(const Moon::Phase& phase) { + // Colour texture Ogre::String textureName = "textures\\tx_"; - + if (mType == Moon::Type_Secunda) textureName += "secunda_"; else textureName += "masser_"; - + if (phase == Moon::Phase_New) textureName += "new"; else if (phase == Moon::Phase_WaxingCrescent) textureName += "one_wax"; else if (phase == Moon::Phase_WaxingHalf) textureName += "half_wax"; @@ -203,9 +210,9 @@ void Moon::setPhase(const Moon::Phase& phase) else if (phase == Moon::Phase_WaningHalf) textureName += "half_wan"; else if (phase == Moon::Phase_WaningGibbous) textureName += "three_wan"; else if (phase == Moon::Phase_Full) textureName += "full"; - + textureName += ".dds"; - + mMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(textureName); mPhase = phase; @@ -285,9 +292,10 @@ void SkyManager::ModVertexAlpha(Entity* ent, unsigned int meshType) ent->getMesh()->getSubMesh(0)->vertexData->vertexBufferBinding->getBuffer(ves_diffuse->getSource())->unlock(); } -SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera) : +SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera, MWWorld::Environment* env) : mGlareFade(0), mGlareEnabled(false) { + mEnvironment = env; mViewport = pCamera->getViewport(); mSceneMgr = pMwRoot->getCreator(); mRootNode = pCamera->getParentSceneNode()->createChildSceneNode(); @@ -301,7 +309,7 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera) : Pass* pass = material->getTechnique(0)->getPass(0); pass->setSceneBlending(SBT_TRANSPARENT_ALPHA); mThunderTextureUnit = pass->createTextureUnitState(); - mThunderTextureUnit->setColourOperationEx(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT, ColourValue(1.f, 1.f, 1.f)); // always black colour + mThunderTextureUnit->setColourOperationEx(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT, ColourValue(1.f, 1.f, 1.f)); mThunderTextureUnit->setAlphaOperation(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT, 0.5f); OverlayManager& ovm = OverlayManager::getSingleton(); mThunderOverlay = ovm.create( "ThunderOverlay" ); @@ -338,24 +346,11 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera) : mAtmosphereNight = mRootNode->createChildSceneNode(); mAtmosphereNight->attachObject(night1_ent); - for (unsigned int i=0; igetNumSubEntities(); ++i) - { - MaterialPtr mp = night1_ent->getSubEntity(i)->getMaterial(); - mp->getTechnique(0)->getPass(0)->setSelfIllumination(1.0, 1.0, 1.0); - mp->getTechnique(0)->getPass(0)->setAmbient(0.0, 0.0, 0.0); - mp->getTechnique(0)->getPass(0)->setDiffuse(0.0, 0.0, 0.0, 1.0); - mp->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false); - mp->getTechnique(0)->getPass(0)->setDepthCheckEnabled(false); - mp->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA); - - mStarsMaterials[i] = mp; - } - // Stars vertex shader - HighLevelGpuProgramPtr vshader3 = mgr.createProgram("Stars_VP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, + HighLevelGpuProgramPtr stars_vp = mgr.createProgram("Stars_VP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, "cg", GPT_VERTEX_PROGRAM); - vshader3->setParameter("profiles", "vs_2_x arbvp1"); - vshader3->setParameter("entry_point", "main_vp"); + stars_vp->setParameter("profiles", "vs_2_x arbvp1"); + stars_vp->setParameter("entry_point", "main_vp"); StringUtil::StrStreamType outStream4; outStream4 << "void main_vp( \n" @@ -371,10 +366,9 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera) : " oFade = (position.z > 50) ? 1.f : 0.f; \n" " oPosition = mul( worldViewProj, position ); \n" "}"; - vshader3->setSource(outStream4.str()); - vshader3->load(); - vshader3->getDefaultParameters()->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX); - night1_ent->getSubEntity(3)->getMaterial()->getTechnique(0)->getPass(0)->setVertexProgram(vshader3->getName()); + stars_vp->setSource(outStream4.str()); + stars_vp->load(); + stars_vp->getDefaultParameters()->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX); // Stars fragment shader HighLevelGpuProgramPtr stars_fp = mgr.createProgram("Stars_FP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, @@ -399,7 +393,20 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera) : stars_fp->load(); stars_fp->getDefaultParameters()->setNamedAutoConstant("emissive", GpuProgramParameters::ACT_SURFACE_EMISSIVE_COLOUR); stars_fp->getDefaultParameters()->setNamedAutoConstant("diffuse", GpuProgramParameters::ACT_SURFACE_DIFFUSE_COLOUR); - night1_ent->getSubEntity(3)->getMaterial()->getTechnique(0)->getPass(0)->setFragmentProgram(stars_fp->getName()); + + for (unsigned int i=0; igetNumSubEntities(); ++i) + { + MaterialPtr mp = night1_ent->getSubEntity(i)->getMaterial(); + mp->getTechnique(0)->getPass(0)->setSelfIllumination(1.0, 1.0, 1.0); + mp->getTechnique(0)->getPass(0)->setAmbient(0.0, 0.0, 0.0); + mp->getTechnique(0)->getPass(0)->setDiffuse(0.0, 0.0, 0.0, 1.0); + mp->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false); + mp->getTechnique(0)->getPass(0)->setDepthCheckEnabled(false); + mp->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA); + mp->getTechnique(0)->getPass(0)->setVertexProgram(stars_vp->getName()); + mp->getTechnique(0)->getPass(0)->setFragmentProgram(stars_fp->getName()); + mStarsMaterials[i] = mp; + } // Atmosphere (day) mesh = NifOgre::NIFLoader::load("meshes\\sky_atmosphere.nif"); @@ -494,7 +501,7 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera) : " uniform float4 emissive \n" ") \n" "{ \n" - " uv += float2(1,1) * time * speed * "<getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstantFromTime("time", 1); + mCloudMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstantFromTime("time", mEnvironment->mWorld->getTimeScaleFactor()/30.f); /// \todo improve this mMasser->setPhase( static_cast( (int) ((mDay % 32)/4.f)) ); @@ -583,6 +590,9 @@ void SkyManager::update(float duration) mSun->setVisible(mSunEnabled); mMasser->setVisible(mMasserEnabled); mSecunda->setVisible(mSecundaEnabled); + + // rotate the stars by 360 degrees every 4 days + mAtmosphereNight->roll(Degree(mEnvironment->mWorld->getTimeScaleFactor()*duration*360 / (3600*96.f))); } void SkyManager::enable() @@ -647,6 +657,8 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) if (mSkyColour != weather.mSkyColor) { mAtmosphereMaterial->getTechnique(0)->getPass(0)->setSelfIllumination(weather.mSkyColor); + mMasser->setSkyColour(weather.mSkyColor); + mSecunda->setSkyColour(weather.mSkyColor); mSkyColour = weather.mSkyColor; } @@ -677,6 +689,7 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) strength = 1.f; mSunGlare->setVisibility(weather.mGlareView * strength); + mSun->setVisibility(strength); mAtmosphereNight->setVisible(weather.mNight && mEnabled); } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 2678165e3..bf52afd8d 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -34,6 +34,8 @@ namespace MWRender Ogre::SceneNode* rootNode ); BillboardObject(); + + virtual ~BillboardObject() {} void setColour(const Ogre::ColourValue& pColour); void setPosition(const Ogre::Vector3& pPosition); @@ -69,6 +71,8 @@ namespace MWRender const Ogre::Vector3& position, Ogre::SceneNode* rootNode ); + + virtual ~Moon() {} enum Phase { @@ -90,6 +94,7 @@ namespace MWRender void setPhase(const Phase& phase); void setType(const Type& type); + void setSkyColour(const Ogre::ColourValue& colour); Phase getPhase() const; unsigned int getPhaseInt() const; @@ -102,7 +107,7 @@ namespace MWRender class SkyManager { public: - SkyManager(Ogre::SceneNode* pMwRoot, Ogre::Camera* pCamera); + SkyManager(Ogre::SceneNode* pMwRoot, Ogre::Camera* pCamera, MWWorld::Environment* env); ~SkyManager(); void update(float duration); @@ -159,10 +164,11 @@ namespace MWRender Ogre::Vector3 getRealSunPos(); private: + MWWorld::Environment* mEnvironment; float mHour; int mDay; int mMonth; - + BillboardObject* mSun; BillboardObject* mSunGlare; Moon* mMasser; diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index c2ff9ed8b..0cca028e2 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -8,6 +8,7 @@ #include #include "../mwdialogue/journal.hpp" +#include "../mwdialogue/dialoguemanager.hpp" #include "interpretercontext.hpp" @@ -72,15 +73,62 @@ namespace MWScript } }; + class OpAddTopic : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + + std::string topic = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + context.getEnvironment().mDialogueManager->addTopic(topic); + } + }; + + class OpChoice : public Interpreter::Opcode1 + { + public: + + virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) + { + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + MWDialogue::DialogueManager* dialogue = context.getEnvironment().mDialogueManager; + while(arg0>0) + { + std::string question = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + arg0 = arg0 -1; + Interpreter::Type_Integer choice = 1; + if(arg0>0) + { + choice = runtime[0].mInteger; + runtime.pop(); + arg0 = arg0 -1; + } + dialogue->askQuestion(question,choice); + } + } + }; + + const int opcodeJournal = 0x2000133; const int opcodeSetJournalIndex = 0x2000134; const int opcodeGetJournalIndex = 0x2000135; + const int opcodeAddTopic = 0x200013a; + const int opcodeChoice = 0x2000a; void registerExtensions (Compiler::Extensions& extensions) { extensions.registerInstruction ("journal", "cl", opcodeJournal); extensions.registerInstruction ("setjournalindex", "cl", opcodeSetJournalIndex); extensions.registerFunction ("getjournalindex", 'l', "c", opcodeGetJournalIndex); + extensions.registerInstruction ("addtopic", "S" , opcodeAddTopic); + extensions.registerInstruction ("choice", "/SlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSl", opcodeChoice); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -88,6 +136,8 @@ namespace MWScript interpreter.installSegment5 (opcodeJournal, new OpJournal); interpreter.installSegment5 (opcodeSetJournalIndex, new OpSetJournalIndex); interpreter.installSegment5 (opcodeGetJournalIndex, new OpGetJournalIndex); + interpreter.installSegment5 (opcodeAddTopic, new OpAddTopic); + interpreter.installSegment3 (opcodeChoice,new OpChoice); } } diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 09b0c0482..eab5bf846 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -23,7 +23,8 @@ op 0x20006: PlayAnim op 0x20007: PlayAnim, explicit reference op 0x20008: LoopAnim op 0x20009: LoopAnim, explicit reference -opcodes 0x2000a-0x3ffff unused +op 0x2000a: Choice +opcodes 0x2000b-0x3ffff unused Segment 4: (not implemented yet) @@ -115,6 +116,7 @@ op 0x2000136: GetPCCell op 0x2000137: GetButtonPressed op 0x2000138: SkipAnim op 0x2000139: SkipAnim, expplicit reference +op 0x200013a: AddTopic op 0x200013b: twf op 0x200013c: FadeIn op 0x200013d: FadeOut diff --git a/apps/openmw/mwscript/scriptmanager.cpp b/apps/openmw/mwscript/scriptmanager.cpp index 5fcfcc605..e93f2deec 100644 --- a/apps/openmw/mwscript/scriptmanager.cpp +++ b/apps/openmw/mwscript/scriptmanager.cpp @@ -63,7 +63,7 @@ namespace MWScript { std::vector code; mParser.getCode (code); - mScripts.insert (std::make_pair (name, code)); + mScripts.insert (std::make_pair (name, std::make_pair (code, mParser.getLocals()))); // TODO sanity check on generated locals @@ -77,8 +77,7 @@ namespace MWScript void ScriptManager::run (const std::string& name, Interpreter::Context& interpreterContext) { // compile script - std::map >::iterator iter = - mScripts.find (name); + ScriptCollection::iterator iter = mScripts.find (name); if (iter==mScripts.end()) { @@ -86,7 +85,7 @@ namespace MWScript { // failed -> ignore script from now on. std::vector empty; - mScripts.insert (std::make_pair (name, empty)); + mScripts.insert (std::make_pair (name, std::make_pair (empty, Compiler::Locals()))); return; } @@ -95,7 +94,7 @@ namespace MWScript } // execute script - if (!iter->second.empty()) + if (!iter->second.first.empty()) try { if (!mOpcodesInstalled) @@ -104,7 +103,7 @@ namespace MWScript mOpcodesInstalled = true; } - mInterpreter.run (&iter->second[0], iter->second.size(), interpreterContext); + mInterpreter.run (&iter->second.first[0], iter->second.first.size(), interpreterContext); } catch (const std::exception& e) { @@ -113,7 +112,7 @@ namespace MWScript if (mVerbose) std::cerr << "(" << e.what() << ")" << std::endl; - iter->second.clear(); // don't execute again. + iter->second.first.clear(); // don't execute again. } } @@ -132,4 +131,24 @@ namespace MWScript return std::make_pair (count, success); } + + Compiler::Locals& ScriptManager::getLocals (const std::string& name) + { + ScriptCollection::iterator iter = mScripts.find (name); + + if (iter==mScripts.end()) + { + if (!compile (name)) + { + // failed -> ignore script from now on. + std::vector empty; + mScripts.insert (std::make_pair (name, std::make_pair (empty, Compiler::Locals()))); + throw std::runtime_error ("failed to compile script " + name); + } + + iter = mScripts.find (name); + } + + return iter->second.second; + } } diff --git a/apps/openmw/mwscript/scriptmanager.hpp b/apps/openmw/mwscript/scriptmanager.hpp index 74511f456..35cbc0d1e 100644 --- a/apps/openmw/mwscript/scriptmanager.hpp +++ b/apps/openmw/mwscript/scriptmanager.hpp @@ -39,7 +39,11 @@ namespace MWScript Interpreter::Interpreter mInterpreter; bool mOpcodesInstalled; - std::map > mScripts; + typedef std::pair, Compiler::Locals> CompiledScript; + typedef std::map ScriptCollection; + + + ScriptCollection mScripts; public: @@ -56,6 +60,9 @@ namespace MWScript std::pair compileAll(); ///< Compile all scripts /// \return count, success + + Compiler::Locals& getLocals (const std::string& name); + ///< Return locals for script \a name. }; }; diff --git a/apps/openmw/mwsound/soundmanager.cpp b/apps/openmw/mwsound/soundmanager.cpp index 2440eda23..226796603 100644 --- a/apps/openmw/mwsound/soundmanager.cpp +++ b/apps/openmw/mwsound/soundmanager.cpp @@ -67,6 +67,7 @@ namespace MWSound , updater(mgr) , cameraTracker(mgr) , mCurrentPlaylist(NULL) + , mUsingSound(useSound) { if(useSound) { @@ -105,8 +106,11 @@ namespace MWSound SoundManager::~SoundManager() { - Ogre::Root::getSingleton().removeFrameListener(&updater); - cameraTracker.unfollowCamera(); + if(mUsingSound) + { + Ogre::Root::getSingleton().removeFrameListener(&updater); + cameraTracker.unfollowCamera(); + } } // Convert a soundId to file name, and modify the volume @@ -136,7 +140,7 @@ namespace MWSound max = std::max(min, max); } - return Files::FileListLocator(mSoundFiles, snd->sound, mFSStrict); + return Files::FileListLocator(mSoundFiles, snd->sound, mFSStrict, false); } // Add a sound to the list and play it @@ -145,7 +149,7 @@ namespace MWSound const std::string &id, float volume, float pitch, float min, float max, - bool loop) + bool loop, bool untracked) { try { @@ -157,7 +161,10 @@ namespace MWSound setPos(snd, ptr); snd->play(); - sounds[ptr][id] = WSoundPtr(snd); + if (!untracked) + { + sounds[ptr][id] = WSoundPtr(snd); + } } catch(...) { @@ -290,7 +297,7 @@ namespace MWSound void SoundManager::streamMusic(const std::string& filename) { - std::string filePath = mMusicLibrary.locate(filename, mFSStrict).string(); + std::string filePath = mMusicLibrary.locate(filename, mFSStrict, true).string(); if(!filePath.empty()) { streamMusicFull(filePath); @@ -351,6 +358,9 @@ namespace MWSound void SoundManager::playPlaylist(std::string playlist) { + if (!mUsingSound) + return; + if (playlist == "") { if(!isMusicPlaying()) @@ -372,8 +382,11 @@ namespace MWSound void SoundManager::say (MWWorld::Ptr ptr, const std::string& filename) { + if (!mUsingSound) + return; + // The range values are not tested - std::string filePath = Files::FileListLocator(mSoundFiles, filename, mFSStrict); + std::string filePath = Files::FileListLocator(mSoundFiles, filename, mFSStrict, true); if(!filePath.empty()) add(filePath, ptr, "_say_sound", 1, 1, 100, 20000, false); else @@ -397,6 +410,7 @@ namespace MWSound snd->setVolume(volume); snd->setRange(min,max); snd->setPitch(pitch); + snd->setRelative(true); snd->play(); if (loop) @@ -412,13 +426,13 @@ namespace MWSound } void SoundManager::playSound3D (MWWorld::Ptr ptr, const std::string& soundId, - float volume, float pitch, bool loop) + float volume, float pitch, bool loop, bool untracked) { // Look up the sound in the ESM data float min, max; const std::string &file = lookup(soundId, volume, min, max); if (file != "") - add(file, ptr, soundId, volume, pitch, min, max, loop); + add(file, ptr, soundId, volume, pitch, min, max, loop, untracked); } void SoundManager::stopSound3D (MWWorld::Ptr ptr, const std::string& soundId) diff --git a/apps/openmw/mwsound/soundmanager.hpp b/apps/openmw/mwsound/soundmanager.hpp index 03c19ce77..dcf64b90c 100644 --- a/apps/openmw/mwsound/soundmanager.hpp +++ b/apps/openmw/mwsound/soundmanager.hpp @@ -82,12 +82,14 @@ namespace MWSound IDMap mLoopedSounds; + bool mUsingSound; + std::string lookup(const std::string &soundId, float &volume, float &min, float &max); void add(const std::string &file, MWWorld::Ptr ptr, const std::string &id, float volume, float pitch, float min, float max, - bool loop); + bool loop, bool untracked=false); void clearAll(PtrMap::iterator& it); void remove(MWWorld::Ptr ptr, const std::string &id = ""); bool isPlaying(MWWorld::Ptr ptr, const std::string &id) const; @@ -136,7 +138,7 @@ namespace MWSound ///< Play a sound, independently of 3D-position void playSound3D (MWWorld::Ptr reference, const std::string& soundId, - float volume, float pitch, bool loop); + float volume, float pitch, bool loop, bool untracked=false); ///< Play a sound from an object void stopSound3D (MWWorld::Ptr reference, const std::string& soundId = ""); diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index 079c888aa..8c657a5c8 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -5,6 +5,8 @@ #include #include "world.hpp" +#include "class.hpp" +#include "containerstore.hpp" MWWorld::Ptr::CellStore *MWWorld::Cells::getCellStore (const ESM::Cell *cell) { @@ -35,6 +37,39 @@ MWWorld::Ptr::CellStore *MWWorld::Cells::getCellStore (const ESM::Cell *cell) } } +void MWWorld::Cells::fillContainers (Ptr::CellStore& cellStore) +{ + for (ESMS::CellRefList::List::iterator iter ( + cellStore.containers.list.begin()); + iter!=cellStore.containers.list.end(); ++iter) + { + Ptr container (&*iter, &cellStore); + + Class::get (container).getContainerStore (container).fill ( + iter->base->inventory, mStore); + } + + for (ESMS::CellRefList::List::iterator iter ( + cellStore.creatures.list.begin()); + iter!=cellStore.creatures.list.end(); ++iter) + { + Ptr container (&*iter, &cellStore); + + Class::get (container).getContainerStore (container).fill ( + iter->base->inventory, mStore); + } + + for (ESMS::CellRefList::List::iterator iter ( + cellStore.npcs.list.begin()); + iter!=cellStore.npcs.list.end(); ++iter) + { + Ptr container (&*iter, &cellStore); + + Class::get (container).getContainerStore (container).fill ( + iter->base->inventory, mStore); + } +} + MWWorld::Cells::Cells (const ESMS::ESMStore& store, ESM::ESMReader& reader, MWWorld::World& world) : mStore (store), mReader (reader), mWorld (world) {} @@ -43,6 +78,8 @@ MWWorld::Ptr::CellStore *MWWorld::Cells::getExterior (int x, int y) std::map, Ptr::CellStore>::iterator result = mExteriors.find (std::make_pair (x, y)); + bool fill = false; + if (result==mExteriors.end()) { const ESM::Cell *cell = mStore.cells.searchExt (x, y); @@ -63,11 +100,16 @@ MWWorld::Ptr::CellStore *MWWorld::Cells::getExterior (int x, int y) result = mExteriors.insert (std::make_pair ( std::make_pair (x, y), Ptr::CellStore (cell))).first; + + fill = true; } if (result->second.mState!=Ptr::CellStore::State_Loaded) result->second.load (mStore, mReader); + if (fill) + fillContainers (result->second); + return &result->second; } @@ -75,16 +117,23 @@ MWWorld::Ptr::CellStore *MWWorld::Cells::getInterior (const std::string& name) { std::map::iterator result = mInteriors.find (name); + bool fill = false; + if (result==mInteriors.end()) { const ESM::Cell *cell = mStore.cells.findInt (name); result = mInteriors.insert (std::make_pair (name, Ptr::CellStore (cell))).first; + + fill = true; } if (result->second.mState!=Ptr::CellStore::State_Loaded) result->second.load (mStore, mReader); + if (fill) + fillContainers (result->second); + return &result->second; } diff --git a/apps/openmw/mwworld/cells.hpp b/apps/openmw/mwworld/cells.hpp index 0ecbd02d3..42aa1050c 100644 --- a/apps/openmw/mwworld/cells.hpp +++ b/apps/openmw/mwworld/cells.hpp @@ -34,6 +34,8 @@ namespace MWWorld Ptr::CellStore *getCellStore (const ESM::Cell *cell); + void fillContainers (Ptr::CellStore& cellStore); + public: Cells (const ESMS::ESMStore& store, ESM::ESMReader& reader, MWWorld::World& world); diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 641da73e1..9d766909f 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -77,6 +77,11 @@ namespace MWWorld throw std::runtime_error ("class does not have a container store"); } + InventoryStore& Class::getInventoryStore (const Ptr& ptr) const + { + throw std::runtime_error ("class does not have an inventory store"); + } + void Class::lock (const Ptr& ptr, int lockLevel) const { throw std::runtime_error ("class does not support locking"); @@ -122,6 +127,16 @@ namespace MWWorld return Ogre::Vector3 (0, 0, 0); } + std::pair, bool> Class::getEquipmentSlots (const Ptr& ptr) const + { + return std::make_pair (std::vector(), false); + } + + int Class::getEquipmentSkill (const Ptr& ptr, const Environment& environment) const + { + return -1; + } + const Class& Class::get (const std::string& key) { std::map >::const_iterator iter = sClasses.find (key); @@ -141,4 +156,14 @@ namespace MWWorld { sClasses.insert (std::make_pair (key, instance)); } + + std::string Class::getUpSoundId (const Ptr& ptr, const MWWorld::Environment& environment) const + { + throw std::runtime_error ("class does not have an up sound"); + } + + std::string Class::getDownSoundId (const Ptr& ptr, const MWWorld::Environment& environment) const + { + throw std::runtime_error ("class does not have an down sound"); + } } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 9b6acb3ce..67320b3e0 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -3,6 +3,7 @@ #include #include +#include #include @@ -34,6 +35,7 @@ namespace MWWorld class Ptr; class Environment; class ContainerStore; + class InventoryStore; /// \brief Base class for referenceable esm records class Class @@ -108,6 +110,10 @@ namespace MWWorld ///< Return container store or throw an exception, if class does not have a /// container store (default implementation: throw an exceoption) + virtual InventoryStore& getInventoryStore (const Ptr& ptr) const; + ///< Return inventory store or throw an exception, if class does not have a + /// inventory store (default implementation: throw an exceoption) + virtual void lock (const Ptr& ptr, int lockLevel) const; ///< Lock object (default implementation: throw an exception) @@ -137,6 +143,18 @@ namespace MWWorld ///< Return desired movement vector (determined based on movement settings, /// stance and stats). + virtual std::pair, bool> getEquipmentSlots (const Ptr& ptr) const; + ///< \return first: Return IDs of the slot this object can be equipped in; second: can object + /// stay stacked when equipped? + /// + /// Default implementation: return (empty vector, false). + + virtual int getEquipmentSkill (const Ptr& ptr, const Environment& environment) + const; + /// Return the index of the skill this item corresponds to when equiopped or -1, if there is + /// no such skill. + /// (default implementation: return -1) + static const Class& get (const std::string& key); ///< If there is no class for this \a key, an exception is thrown. @@ -144,6 +162,14 @@ namespace MWWorld ///< If there is no class for this pointer, an exception is thrown. static void registerClass (const std::string& key, boost::shared_ptr instance); + + virtual std::string getUpSoundId (const Ptr& ptr, const MWWorld::Environment& environment) const; + ///< Return the up sound ID of \a ptr or throw an exception, if class does not support ID retrieval + /// (default implementation: throw an exception) + + virtual std::string getDownSoundId (const Ptr& ptr, const MWWorld::Environment& environment) const; + ///< Return the down sound ID of \a ptr or throw an exception, if class does not support ID retrieval + /// (default implementation: throw an exception) }; } diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 54908deec..c498cabce 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -5,6 +5,12 @@ #include #include +#include + +#include "manualref.hpp" + +MWWorld::ContainerStore::~ContainerStore() {} + MWWorld::ContainerStoreIterator MWWorld::ContainerStore::begin (int mask) { return ContainerStoreIterator (mask, this); @@ -17,7 +23,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::end() void MWWorld::ContainerStore::add (const Ptr& ptr) { - /// \todo implement item stocking + /// \todo implement item stacking switch (getType (ptr)) { @@ -36,6 +42,40 @@ void MWWorld::ContainerStore::add (const Ptr& ptr) } } +void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const ESMS::ESMStore& store) +{ + for (std::vector::const_iterator iter (items.list.begin()); iter!=items.list.end(); + ++iter) + { + ManualRef ref (store, iter->item.toString()); + + if (ref.getPtr().getTypeName()==typeid (ESM::ItemLevList).name()) + { + /// \todo implement leveled item lists + continue; + } + + ref.getPtr().getRefData().setCount (iter->count); + add (ref.getPtr()); + } +} + +void MWWorld::ContainerStore::clear() +{ + potions.list.clear(); + appas.list.clear(); + armors.list.clear(); + books.list.clear(); + clothes.list.clear(); + ingreds.list.clear(); + lights.list.clear(); + lockpicks.list.clear(); + miscItems.list.clear(); + probes.list.clear(); + repairs.list.clear(); + weapons.list.clear(); +} + int MWWorld::ContainerStore::getType (const Ptr& ptr) { if (ptr.isEmpty()) @@ -331,6 +371,11 @@ int MWWorld::ContainerStoreIterator::getType() const return mType; } +const MWWorld::ContainerStore *MWWorld::ContainerStoreIterator::getContainerStore() const +{ + return mContainer; +} + bool MWWorld::operator== (const ContainerStoreIterator& left, const ContainerStoreIterator& right) { return left.isEqual (right); diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 7263245f3..69e5ba446 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -1,11 +1,18 @@ #ifndef GAME_MWWORLD_CONTAINERSTORE_H #define GAME_MWWORLD_CONTAINERSTORE_H +#include + #include #include "refdata.hpp" #include "ptr.hpp" +namespace ESM +{ + struct InventoryList; +} + namespace MWWorld { class ContainerStoreIterator; @@ -48,6 +55,8 @@ namespace MWWorld public: + virtual ~ContainerStore(); + ContainerStoreIterator begin (int mask = Type_All); ContainerStoreIterator end(); @@ -60,6 +69,12 @@ namespace MWWorld /// \attention Do not add items to an existing stack by increasing the count instead of /// calling this function! + void fill (const ESM::InventoryList& items, const ESMS::ESMStore& store); + ///< Insert items into *this. + + void clear(); + ///< Empty container. + static int getType (const Ptr& ptr); ///< This function throws an exception, if ptr does not point to an object, that can be /// put into a container. @@ -71,6 +86,7 @@ namespace MWWorld /// /// \note The iterator will automatically skip over deleted objects. class ContainerStoreIterator + : public std::iterator { int mType; int mMask; @@ -126,6 +142,8 @@ namespace MWWorld int getType() const; + const ContainerStore *getContainerStore() const; + friend class ContainerStore; }; diff --git a/apps/openmw/mwworld/environment.hpp b/apps/openmw/mwworld/environment.hpp index a403ee165..3a83f886f 100644 --- a/apps/openmw/mwworld/environment.hpp +++ b/apps/openmw/mwworld/environment.hpp @@ -9,6 +9,7 @@ namespace MWSound namespace MWScript { class GlobalScripts; + class ScriptManager; } namespace MWGui @@ -41,7 +42,7 @@ namespace MWWorld { public: Environment() - : mWorld (0), mSoundManager (0), mGlobalScripts (0), mWindowManager (0), + : mWorld (0), mSoundManager (0), mGlobalScripts (0), mScriptManager (0), mWindowManager (0), mMechanicsManager (0), mDialogueManager (0), mJournal (0), mFrameDuration (0), mInputManager (0) {} @@ -49,6 +50,7 @@ namespace MWWorld World *mWorld; MWSound::SoundManager *mSoundManager; MWScript::GlobalScripts *mGlobalScripts; + MWScript::ScriptManager *mScriptManager; MWGui::WindowManager *mWindowManager; MWMechanics::MechanicsManager *mMechanicsManager; MWDialogue::DialogueManager *mDialogueManager; diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp new file mode 100644 index 000000000..264be7bb3 --- /dev/null +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -0,0 +1,86 @@ + +#include "inventorystore.hpp" + +#include +#include + +#include "class.hpp" + +void MWWorld::InventoryStore::copySlots (const InventoryStore& store) +{ + // some const-trickery, required because of a flaw in the handling of MW-references and the + // resulting workarounds + for (std::vector::const_iterator iter ( + const_cast (store).mSlots.begin()); + iter!=const_cast (store).mSlots.end(); ++iter) + { + std::size_t distance = std::distance (const_cast (store).begin(), *iter); + + ContainerStoreIterator slot = begin(); + + std::advance (slot, distance); + + mSlots.push_back (slot); + } +} + +MWWorld::InventoryStore::InventoryStore() +{ + for (int i=0; i=static_cast (mSlots.size())) + throw std::runtime_error ("slot number out of range"); + + if (iterator.getContainerStore()!=this) + throw std::runtime_error ("attempt to equip an item that is not in the inventory"); + + if (iterator!=end()) + { + std::pair, bool> slots = Class::get (*iterator).getEquipmentSlots (*iterator); + + if (std::find (slots.first.begin(), slots.first.end(), slot)==slots.first.end()) + throw std::runtime_error ("invalid slot"); + } + + /// \todo restack item previously in this slot (if required) + + /// \todo unstack item pointed to by iterator if required) + + mSlots[slot] = iterator; +} + +MWWorld::ContainerStoreIterator MWWorld::InventoryStore::getSlot (int slot) +{ + if (slot<0 || slot>=static_cast (mSlots.size())) + throw std::runtime_error ("slot number out of range"); + + if (mSlots[slot]==end()) + return end(); + + if (mSlots[slot]->getRefData().getCount()<1) + { + // object has been deleted + mSlots[slot] = end(); + return end(); + } + + return mSlots[slot]; +} diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp new file mode 100644 index 000000000..c41f9e8e3 --- /dev/null +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -0,0 +1,58 @@ +#ifndef GAME_MWWORLD_INVENTORYSTORE_H +#define GAME_MWWORLD_INVENTORYSTORE_H + +#include "containerstore.hpp" + +namespace MWWorld +{ + ///< \brief Variant of the ContainerStore for NPCs + class InventoryStore : public ContainerStore + { + public: + + static const int Slot_Helmet = 0; + static const int Slot_Cuirass = 1; + static const int Slot_Greaves = 2; + static const int Slot_LeftPauldron = 3; + static const int Slot_RightPauldron = 4; + static const int Slot_LeftGauntlet = 5; + static const int Slot_RightGauntlet = 6; + static const int Slot_Boots = 7; + static const int Slot_Shirt = 8; + static const int Slot_Pants = 9; + static const int Slot_Skirt = 10; + static const int Slot_Robe = 11; + static const int Slot_LeftRing = 12; + static const int Slot_RightRing = 13; + static const int Slot_Amulet = 14; + static const int Slot_Belt = 15; + static const int Slot_CarriedRight = 16; + static const int Slot_CarriedLeft = 17; + static const int Slot_Ammunition = 18; + + static const int Slots = 19; + + static const int Slot_NoSlot = -1; + + private: + + mutable std::vector mSlots; + + void copySlots (const InventoryStore& store); + + public: + + InventoryStore(); + + InventoryStore (const InventoryStore& store); + + InventoryStore& operator= (const InventoryStore& store); + + void equip (int slot, const ContainerStoreIterator& iterator); + ///< \note \a iteartor can be an end-iterator + + ContainerStoreIterator getSlot (int slot); + }; +} + +#endif diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 90afc4e78..2bd3825aa 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -26,6 +26,7 @@ const float WeatherGlobals::mSunsetTime = 18; const float WeatherGlobals::mSunriseDuration = 2; const float WeatherGlobals::mSunsetDuration = 2; const float WeatherGlobals::mWeatherUpdateTime = 20.f; + const float WeatherGlobals::mThunderFrequency = .4; const float WeatherGlobals::mThunderThreshold = 0.6; const float WeatherGlobals::mThunderSoundDelay = 0.25; @@ -328,6 +329,9 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, Environmen void WeatherManager::setWeather(const String& weather, bool instant) { + if (weather == mCurrentWeather && mNextWeather == "") + return; + if (instant || mFirstUpdate) { mNextWeather = ""; @@ -339,12 +343,12 @@ void WeatherManager::setWeather(const String& weather, bool instant) if (mNextWeather != "") { // transition more than 50% finished? - if (mRemainingTransitionTime/(mWeatherSettings[mCurrentWeather].mTransitionDelta*24.f*60) <= 0.5) + if (mRemainingTransitionTime/(mWeatherSettings[mCurrentWeather].mTransitionDelta*24.f*3600) <= 0.5) mCurrentWeather = mNextWeather; } - + mNextWeather = weather; - mRemainingTransitionTime = mWeatherSettings[mCurrentWeather].mTransitionDelta*24.f*60; + mRemainingTransitionTime = mWeatherSettings[mCurrentWeather].mTransitionDelta*24.f*3600; } } @@ -352,7 +356,7 @@ WeatherResult WeatherManager::getResult(const String& weather) { const Weather& current = mWeatherSettings[weather]; WeatherResult result; - + result.mCloudTexture = current.mCloudTexture; result.mCloudBlendFactor = 0; result.mCloudOpacity = current.mCloudsMaximumPercent; @@ -361,16 +365,13 @@ WeatherResult WeatherManager::getResult(const String& weather) result.mGlareView = current.mGlareView; result.mAmbientLoopSoundID = current.mAmbientLoopSoundID; result.mSunColor = current.mSunDiscSunsetColor; - - const float fade_duration = current.mTransitionDelta * 24.f; - - result.mNight = (mHour < 6.f+fade_duration || mHour > 20.f-fade_duration); - + + result.mNight = (mHour < 6 || mHour > 19); + result.mFogDepth = result.mNight ? current.mLandFogNightDepth : current.mLandFogDayDepth; - + // night - if (mHour <= (WeatherGlobals::mSunriseTime-WeatherGlobals::mSunriseDuration) - || mHour >= (WeatherGlobals::mSunsetTime+WeatherGlobals::mSunsetDuration)) + if (mHour <= 5.5f || mHour >= 21) { result.mFogColor = current.mFogNightColor; result.mAmbientColor = current.mAmbientNightColor; @@ -378,82 +379,68 @@ WeatherResult WeatherManager::getResult(const String& weather) result.mSkyColor = current.mSkyNightColor; result.mNightFade = 1.f; } - + // sunrise - else if (mHour >= (WeatherGlobals::mSunriseTime-WeatherGlobals::mSunriseDuration) && mHour <= WeatherGlobals::mSunriseTime) + else if (mHour >= 5.5f && mHour <= 9) { - if (mHour <= (WeatherGlobals::mSunriseTime-WeatherGlobals::mSunriseDuration+fade_duration)) + if (mHour <= 6) { // fade in - float advance = (WeatherGlobals::mSunriseTime-WeatherGlobals::mSunriseDuration+fade_duration)-mHour; - float factor = (advance / fade_duration); + float advance = 6-mHour; + float factor = advance / 0.5f; result.mFogColor = lerp(current.mFogSunriseColor, current.mFogNightColor); result.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientNightColor); result.mSunColor = lerp(current.mSunSunriseColor, current.mSunNightColor); result.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyNightColor); result.mNightFade = factor; } - else if (mHour >= (WeatherGlobals::mSunriseTime-fade_duration)) + else //if (mHour >= 6) { // fade out - float advance = mHour-(WeatherGlobals::mSunriseTime-fade_duration); - float factor = advance / fade_duration; + float advance = mHour-6; + float factor = advance / 3.f; result.mFogColor = lerp(current.mFogSunriseColor, current.mFogDayColor); result.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientDayColor); result.mSunColor = lerp(current.mSunSunriseColor, current.mSunDayColor); result.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyDayColor); } - else - { - result.mFogColor = current.mFogSunriseColor; - result.mAmbientColor = current.mAmbientSunriseColor; - result.mSunColor = current.mSunSunriseColor; - result.mSkyColor = current.mSkySunriseColor; - } } - + // day - else if (mHour >= (WeatherGlobals::mSunriseTime) && mHour <= (WeatherGlobals::mSunsetTime)) + else if (mHour >= 9 && mHour <= 17) { result.mFogColor = current.mFogDayColor; result.mAmbientColor = current.mAmbientDayColor; result.mSunColor = current.mSunDayColor; result.mSkyColor = current.mSkyDayColor; } - + // sunset - else if (mHour >= (WeatherGlobals::mSunsetTime) && mHour <= (WeatherGlobals::mSunsetTime+WeatherGlobals::mSunsetDuration)) + else if (mHour >= 17 && mHour <= 21) { - if (mHour <= (WeatherGlobals::mSunsetTime+fade_duration)) + if (mHour <= 19) { // fade in - float advance = (WeatherGlobals::mSunsetTime+fade_duration)-mHour; - float factor = (advance / fade_duration); + float advance = 19-mHour; + float factor = (advance / 2); result.mFogColor = lerp(current.mFogSunsetColor, current.mFogDayColor); result.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientDayColor); result.mSunColor = lerp(current.mSunSunsetColor, current.mSunDayColor); result.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyDayColor); } - else if (mHour >= (WeatherGlobals::mSunsetTime+WeatherGlobals::mSunsetDuration-fade_duration)) + else //if (mHour >= 19) { // fade out - float advance = mHour-(WeatherGlobals::mSunsetTime+WeatherGlobals::mSunsetDuration-fade_duration); - float factor = advance / fade_duration; + float advance = mHour-19; + float factor = advance / 2.f; result.mFogColor = lerp(current.mFogSunsetColor, current.mFogNightColor); result.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientNightColor); result.mSunColor = lerp(current.mSunSunsetColor, current.mSunNightColor); result.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyNightColor); result.mNightFade = factor; } - else - { - result.mFogColor = current.mFogSunsetColor; - result.mAmbientColor = current.mAmbientSunsetColor; - result.mSunColor = current.mSunSunsetColor; - result.mSkyColor = current.mSkySunsetColor; - } } - + return result; } @@ -462,41 +449,37 @@ WeatherResult WeatherManager::transition(float factor) const WeatherResult& current = getResult(mCurrentWeather); const WeatherResult& other = getResult(mNextWeather); WeatherResult result; - + result.mCloudTexture = current.mCloudTexture; result.mNextCloudTexture = other.mCloudTexture; result.mCloudBlendFactor = factor; - + result.mCloudOpacity = lerp(current.mCloudOpacity, other.mCloudOpacity); result.mFogColor = lerp(current.mFogColor, other.mFogColor); result.mSunColor = lerp(current.mSunColor, other.mSunColor); result.mSkyColor = lerp(current.mSkyColor, other.mSkyColor); - + result.mAmbientColor = lerp(current.mAmbientColor, other.mAmbientColor); result.mSunDiscColor = lerp(current.mSunDiscColor, other.mSunDiscColor); result.mFogDepth = lerp(current.mFogDepth, other.mFogDepth); result.mWindSpeed = lerp(current.mWindSpeed, other.mWindSpeed); - result.mCloudSpeed = lerp(current.mCloudSpeed, other.mCloudSpeed); + //result.mCloudSpeed = lerp(current.mCloudSpeed, other.mCloudSpeed); + result.mCloudSpeed = current.mCloudSpeed; result.mCloudOpacity = lerp(current.mCloudOpacity, other.mCloudOpacity); result.mGlareView = lerp(current.mGlareView, other.mGlareView); - + result.mNight = current.mNight; - - // sound change behaviour: - // if 'other' has a new sound, switch to it after 1/2 of the transition length - if (other.mAmbientLoopSoundID != "") - result.mAmbientLoopSoundID = factor>0.5 ? other.mAmbientLoopSoundID : current.mAmbientLoopSoundID; - // if 'current' has a sound and 'other' does not have a sound, turn off the sound immediately - else if (current.mAmbientLoopSoundID != "") - result.mAmbientLoopSoundID = ""; - + return result; } void WeatherManager::update(float duration) { - mWeatherUpdateTime -= duration; - if (mEnvironment->mWorld->isCellExterior() || mEnvironment->mWorld->isCellQuasiExterior()) + mWeatherUpdateTime -= duration * mEnvironment->mWorld->getTimeScaleFactor(); + + bool exterior = (mEnvironment->mWorld->isCellExterior() || mEnvironment->mWorld->isCellQuasiExterior()); + + if (exterior) { std::string regionstr = mEnvironment->mWorld->getPlayer().getPlayer().getCell()->cell->region; boost::algorithm::to_lower(regionstr); @@ -504,17 +487,17 @@ void WeatherManager::update(float duration) if (mWeatherUpdateTime <= 0 || regionstr != mCurrentRegion) { mCurrentRegion = regionstr; - mWeatherUpdateTime = WeatherGlobals::mWeatherUpdateTime*60.f; - + mWeatherUpdateTime = WeatherGlobals::mWeatherUpdateTime*3600; + std::string weather; - + if (mRegionOverrides.find(regionstr) != mRegionOverrides.end()) weather = mRegionOverrides[regionstr]; else { // get weather probabilities for the current region const ESM::Region *region = mEnvironment->mWorld->getStore().regions.find (regionstr); - + float clear = region->data.clear/255.f; float cloudy = region->data.cloudy/255.f; float foggy = region->data.foggy/255.f; @@ -525,13 +508,13 @@ void WeatherManager::update(float duration) float blight = region->data.blight/255.f; float snow = region->data.a/255.f; float blizzard = region->data.b/255.f; - + // re-scale to 100 percent const float total = clear+cloudy+foggy+overcast+rain+thunder+ash+blight+snow+blizzard; - + srand(time(NULL)); float random = ((rand()%100)/100.f) * total; - + if (random >= snow+blight+ash+thunder+rain+overcast+foggy+cloudy+clear) weather = "blizzard"; else if (random >= blight+ash+thunder+rain+overcast+foggy+cloudy+clear) @@ -553,56 +536,54 @@ void WeatherManager::update(float duration) else weather = "clear"; } - + setWeather(weather, false); - /* - std::cout << "roll result: " << random << std::endl; - - std::cout << regionstr << " weather probabilities: " << clear << " " << cloudy << " " << foggy << " " - << overcast << " " << rain << " " << thunder << " " << ash << " " << blight << " " << snow << " " - << blizzard << std::endl; - - std::cout << "New weather : " << weather << std::endl; - */ } - + WeatherResult result; - + if (mNextWeather != "") { - mRemainingTransitionTime -= duration; + mRemainingTransitionTime -= duration * mEnvironment->mWorld->getTimeScaleFactor(); if (mRemainingTransitionTime < 0) { mCurrentWeather = mNextWeather; mNextWeather = ""; } } - + if (mNextWeather != "") - result = transition(1-(mRemainingTransitionTime/(mWeatherSettings[mCurrentWeather].mTransitionDelta*24.f*60))); + result = transition(1-(mRemainingTransitionTime/(mWeatherSettings[mCurrentWeather].mTransitionDelta*24.f*3600))); else result = getResult(mCurrentWeather); - + mRendering->configureFog(result.mFogDepth, result.mFogColor); - + // disable sun during night - if (mHour >= WeatherGlobals::mSunsetTime+WeatherGlobals::mSunsetDuration - || mHour <= WeatherGlobals::mSunriseTime-WeatherGlobals::mSunriseDuration) + if (mHour >= 20 || mHour <= 6.f) mRendering->getSkyManager()->sunDisable(); else - { - // during day, calculate sun angle - float height = 1-std::abs(((mHour-13)/7.f)); - int facing = mHour > 13.f ? 1 : -1; - Vector3 final( - (1-height)*facing, - (1-height)*facing, - height); - mRendering->setSunDirection(final); - mRendering->getSkyManager()->sunEnable(); - } - + + // sun angle + float height; + + // rise at 6, set at 20 + if (mHour >= 6 && mHour <= 20) + height = 1-std::abs(((mHour-13)/7.f)); + else if (mHour > 20) + height = (mHour-20.f)/4.f; + else //if (mHour > 0 && mHour < 6) + height = 1-(mHour/6.f); + + int facing = (mHour > 13.f) ? 1 : -1; + + Vector3 final( + (1-height)*facing, + (1-height)*facing, + height); + mRendering->setSunDirection(final); + // moon calculations float night; if (mHour >= 14) @@ -611,9 +592,9 @@ void WeatherManager::update(float duration) night = mHour+10; else night = 0; - + night /= 20.f; - + if (night != 0) { float moonHeight = 1-std::abs((night-0.5)*2); @@ -622,17 +603,17 @@ void WeatherManager::update(float duration) (1-moonHeight)*facing, (1-moonHeight)*facing, moonHeight); - + Vector3 secunda( (1-moonHeight)*facing*0.8, (1-moonHeight)*facing*1.25, moonHeight); - + mRendering->getSkyManager()->setMasserDirection(masser); mRendering->getSkyManager()->setSecundaDirection(secunda); mRendering->getSkyManager()->masserEnable(); mRendering->getSkyManager()->secundaEnable(); - + float hour_fade; if (mHour >= 7.f && mHour <= 14.f) hour_fade = 1-(mHour-7)/3.f; @@ -640,28 +621,28 @@ void WeatherManager::update(float duration) hour_fade = mHour-14; else hour_fade = 1; - + float secunda_angle_fade; float masser_angle_fade; float angle = moonHeight*90.f; - + if (angle >= 30 && angle <= 50) secunda_angle_fade = (angle-30)/20.f; else if (angle <30) secunda_angle_fade = 0.f; else secunda_angle_fade = 1.f; - + if (angle >= 40 && angle <= 50) masser_angle_fade = (angle-40)/10.f; else if (angle <40) masser_angle_fade = 0.f; else masser_angle_fade = 1.f; - + masser_angle_fade *= hour_fade; secunda_angle_fade *= hour_fade; - + mRendering->getSkyManager()->setMasserFade(masser_angle_fade); mRendering->getSkyManager()->setSecundaFade(secunda_angle_fade); } @@ -670,8 +651,8 @@ void WeatherManager::update(float duration) mRendering->getSkyManager()->masserDisable(); mRendering->getSkyManager()->secundaDisable(); } - - if (mCurrentWeather == "thunderstorm" && mNextWeather == "") + + if (mCurrentWeather == "thunderstorm" && mNextWeather == "" && exterior) { if (mThunderFlash > 0) { @@ -689,7 +670,7 @@ void WeatherManager::update(float duration) mEnvironment->mSoundManager->playSound(soundname, 1.0, 1.0); mThunderSoundDelay = 1000; } - + mThunderFlash -= duration; if (mThunderFlash > 0) mRendering->getSkyManager()->setThunder( mThunderFlash / WeatherGlobals::mThunderThreshold ); @@ -708,20 +689,20 @@ void WeatherManager::update(float duration) if (mThunderChance >= mThunderChanceNeeded) { mThunderFlash = WeatherGlobals::mThunderThreshold; - + mRendering->getSkyManager()->setThunder( mThunderFlash / WeatherGlobals::mThunderThreshold ); - + mThunderSoundDelay = WeatherGlobals::mThunderSoundDelay; } } } else mRendering->getSkyManager()->setThunder(0.f); - + mRendering->setAmbientColour(result.mAmbientColor); mRendering->sunEnable(); mRendering->setSunColour(result.mSunColor); - + mRendering->getSkyManager()->setWeather(result); } else @@ -730,19 +711,46 @@ void WeatherManager::update(float duration) mRendering->skyDisable(); mRendering->getSkyManager()->setThunder(0.f); } + + // play sounds + std::string ambientSnd = (mNextWeather == "" ? mWeatherSettings[mCurrentWeather].mAmbientLoopSoundID : ""); + if (!exterior) ambientSnd = ""; + if (ambientSnd != "") + { + if (std::find(mSoundsPlaying.begin(), mSoundsPlaying.end(), ambientSnd) == mSoundsPlaying.end()) + { + mSoundsPlaying.push_back(ambientSnd); + mEnvironment->mSoundManager->playSound(ambientSnd, 1.0, 1.0, true); + } + } + + std::string rainSnd = (mNextWeather == "" ? mWeatherSettings[mCurrentWeather].mRainLoopSoundID : ""); + if (!exterior) rainSnd = ""; + if (rainSnd != "") + { + if (std::find(mSoundsPlaying.begin(), mSoundsPlaying.end(), rainSnd) == mSoundsPlaying.end()) + { + mSoundsPlaying.push_back(rainSnd); + mEnvironment->mSoundManager->playSound(rainSnd, 1.0, 1.0, true); + } + } + + // stop sounds + std::vector::iterator it=mSoundsPlaying.begin(); + while (it!=mSoundsPlaying.end()) + { + if ( *it != ambientSnd && *it != rainSnd) + { + mEnvironment->mSoundManager->stopSound(*it); + it = mSoundsPlaying.erase(it); + } + else + ++it; + } } void WeatherManager::setHour(const float hour) { - // accelerate a bit for testing - /* - mHour += 0.005; - - if (mHour >= 24.f) mHour = 0.f; - - std::cout << "hour " << mHour << std::endl; - */ - mHour = hour; } diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 9353f7cd1..b9b40e6fa 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -243,8 +243,10 @@ namespace MWWorld MWWorld::Environment* mEnvironment; std::map mWeatherSettings; - + std::map mRegionOverrides; + + std::vector mSoundsPlaying; Ogre::String mCurrentWeather; Ogre::String mNextWeather; diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index 1a69f4d7b..a636ce288 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -161,9 +161,9 @@ namespace MWWorld { mPhysics = new PhysicsSystem(renderer); mPhysEngine = mPhysics->getEngine(); - + mRendering = new MWRender::RenderingManager(renderer, resDir, mPhysEngine, environment); - + mWeatherManager = new MWWorld::WeatherManager(mRendering, &environment); boost::filesystem::path masterPath (fileCollections.getCollection (".esm").getPath (master)); @@ -381,7 +381,7 @@ namespace MWWorld mGlobalVariables->setFloat ("gamehour", hour); mRendering->skySetHour (hour); - + mWeatherManager->setHour (hour); if (days>0) @@ -418,10 +418,10 @@ namespace MWWorld mGlobalVariables->setInt ("month", month); mRendering->skySetDate (day, month); - + mWeatherManager->setDate (day, month); - - + + } void World::setMonth (int month) @@ -478,7 +478,7 @@ namespace MWWorld float World::getTimeScaleFactor() const { - return mGlobalVariables->getInt ("timescale"); + return mGlobalVariables->getFloat ("timescale"); } void World::changeToInteriorCell (const std::string& cellName, const ESM::Position& position) @@ -702,9 +702,9 @@ namespace MWWorld void World::update (float duration) { mWorldScene->update (duration); - + mWeatherManager->update (duration); - + // cast a ray from player to sun to detect if the sun is visible // this is temporary until we find a better place to put this code // currently its here because we need to access the physics system @@ -713,7 +713,7 @@ namespace MWWorld sun = Vector3(sun.x, -sun.z, sun.y); mRendering->getSkyManager()->setGlare(!mPhysics->castRay(Ogre::Vector3(p[0], p[1], p[2]), sun)); } - + bool World::isCellExterior() const { Ptr::CellStore *currentCell = mWorldScene->getCurrentCell(); @@ -726,7 +726,7 @@ namespace MWWorld } return false; } - + bool World::isCellQuasiExterior() const { Ptr::CellStore *currentCell = mWorldScene->getCurrentCell(); @@ -739,17 +739,17 @@ namespace MWWorld } return false; } - + int World::getCurrentWeather() const { return mWeatherManager->getWeatherID(); } - + void World::changeWeather(const std::string& region, const unsigned int id) { mWeatherManager->changeWeather(region, id); } - + OEngine::Render::Fader* World::getFader() { return mRendering->getFader(); diff --git a/cmake/FindCg.cmake b/cmake/FindCg.cmake new file mode 100644 index 000000000..4bd348c46 --- /dev/null +++ b/cmake/FindCg.cmake @@ -0,0 +1,53 @@ +#------------------------------------------------------------------- +# This file is part of the CMake build system for OGRE +# (Object-oriented Graphics Rendering Engine) +# For the latest info, see http://www.ogre3d.org/ +# +# The contents of this file are placed in the public domain. Feel +# free to make use of it in any way you like. +#------------------------------------------------------------------- + +# - Try to find Cg +# Once done, this will define +# +# Cg_FOUND - system has Cg +# Cg_INCLUDE_DIRS - the Cg include directories +# Cg_LIBRARIES - link these to use Cg + +include(FindPkgMacros) +findpkg_begin(Cg) + +# Get path, convert backslashes as ${ENV_${var}} +getenv_path(Cg_HOME) +getenv_path(OGRE_SOURCE) +getenv_path(OGRE_HOME) + +# construct search paths +set(Cg_PREFIX_PATH ${Cg_HOME} ${ENV_Cg_HOME} + ${OGRE_SOURCE}/Dependencies + ${ENV_OGRE_SOURCE}/Dependencies + ${OGRE_HOME} ${ENV_OGRE_HOME} + /opt/nvidia-cg-toolkit) +create_search_paths(Cg) +# redo search if prefix path changed +clear_if_changed(Cg_PREFIX_PATH + Cg_LIBRARY_FWK + Cg_LIBRARY_REL + Cg_LIBRARY_DBG + Cg_INCLUDE_DIR +) + +set(Cg_LIBRARY_NAMES Cg) +get_debug_names(Cg_LIBRARY_NAMES) + +use_pkgconfig(Cg_PKGC Cg) + +findpkg_framework(Cg) + +find_path(Cg_INCLUDE_DIR NAMES cg.h HINTS ${Cg_FRAMEWORK_INCLUDES} ${Cg_INC_SEARCH_PATH} ${Cg_PKGC_INCLUDE_DIRS} PATH_SUFFIXES Cg) +find_library(Cg_LIBRARY_REL NAMES ${Cg_LIBRARY_NAMES} HINTS ${Cg_LIB_SEARCH_PATH} ${Cg_PKGC_LIBRARY_DIRS} PATH_SUFFIXES "" release relwithdebinfo minsizerel) +find_library(Cg_LIBRARY_DBG NAMES ${Cg_LIBRARY_NAMES_DBG} HINTS ${Cg_LIB_SEARCH_PATH} ${Cg_PKGC_LIBRARY_DIRS} PATH_SUFFIXES "" debug) +make_library_set(Cg_LIBRARY) + +findpkg_finish(Cg) +add_parent_dir(Cg_INCLUDE_DIRS Cg_INCLUDE_DIR) diff --git a/cmake/FindFreeImage.cmake b/cmake/FindFreeImage.cmake new file mode 100644 index 000000000..3b21a17d6 --- /dev/null +++ b/cmake/FindFreeImage.cmake @@ -0,0 +1,47 @@ +#------------------------------------------------------------------- +# This file is part of the CMake build system for OGRE +# (Object-oriented Graphics Rendering Engine) +# For the latest info, see http://www.ogre3d.org/ +# +# The contents of this file are placed in the public domain. Feel +# free to make use of it in any way you like. +#------------------------------------------------------------------- + +# - Try to find FreeImage +# Once done, this will define +# +# FreeImage_FOUND - system has FreeImage +# FreeImage_INCLUDE_DIRS - the FreeImage include directories +# FreeImage_LIBRARIES - link these to use FreeImage + +include(FindPkgMacros) +findpkg_begin(FreeImage) + +# Get path, convert backslashes as ${ENV_${var}} +getenv_path(FREEIMAGE_HOME) + +# construct search paths +set(FreeImage_PREFIX_PATH ${FREEIMAGE_HOME} ${ENV_FREEIMAGE_HOME}) +create_search_paths(FreeImage) +# redo search if prefix path changed +clear_if_changed(FreeImage_PREFIX_PATH + FreeImage_LIBRARY_FWK + FreeImage_LIBRARY_REL + FreeImage_LIBRARY_DBG + FreeImage_INCLUDE_DIR +) + +set(FreeImage_LIBRARY_NAMES freeimage) +get_debug_names(FreeImage_LIBRARY_NAMES) + +use_pkgconfig(FreeImage_PKGC freeimage) + +findpkg_framework(FreeImage) + +find_path(FreeImage_INCLUDE_DIR NAMES FreeImage.h HINTS ${FreeImage_INC_SEARCH_PATH} ${FreeImage_PKGC_INCLUDE_DIRS}) +find_library(FreeImage_LIBRARY_REL NAMES ${FreeImage_LIBRARY_NAMES} HINTS ${FreeImage_LIB_SEARCH_PATH} ${FreeImage_PKGC_LIBRARY_DIRS} PATH_SUFFIXES "" release relwithdebinfo minsizerel) +find_library(FreeImage_LIBRARY_DBG NAMES ${FreeImage_LIBRARY_NAMES_DBG} HINTS ${FreeImage_LIB_SEARCH_PATH} ${FreeImage_PKGC_LIBRARY_DIRS} PATH_SUFFIXES "" debug) +make_library_set(FreeImage_LIBRARY) + +findpkg_finish(FreeImage) + diff --git a/cmake/FindOGRE.cmake b/cmake/FindOGRE.cmake index 917a8653e..fb4a090c6 100644 --- a/cmake/FindOGRE.cmake +++ b/cmake/FindOGRE.cmake @@ -18,7 +18,7 @@ # Once done, this will define # # OGRE_FOUND - system has OGRE -# OGRE_INCLUDE_DIRS - the OGRE include directories +# OGRE_INCLUDE_DIRS - the OGRE include directories # OGRE_LIBRARIES - link these to use the OGRE core # OGRE_BINARY_REL - location of the main Ogre binary (win32 non-static only, release) # OGRE_BINARY_DBG - location of the main Ogre binaries (win32 non-static only, debug) @@ -28,15 +28,14 @@ # Plugin_BSPSceneManager, Plugin_CgProgramManager, # Plugin_OctreeSceneManager, Plugin_OctreeZone, # Plugin_ParticleFX, Plugin_PCZSceneManager, -# RenderSystem_GL, RenderSystem_Direct3D9, +# RenderSystem_GL, RenderSystem_Direct3D9, RenderSystem_Direct3D10, # Paging, Terrain # # For each of these components, the following variables are defined: # - # OGRE_${COMPONENT}_FOUND - ${COMPONENT} is available # OGRE_${COMPONENT}_INCLUDE_DIRS - additional include directories for ${COMPONENT} -# OGRE_${COMPONENT}_LIBRARIES - link these to use ${COMPONENT} +# OGRE_${COMPONENT}_LIBRARIES - link these to use ${COMPONENT} # OGRE_${COMPONENT}_BINARY_REL - location of the component binary (win32 non-static only, release) # OGRE_${COMPONENT}_BINARY_DBG - location of the component binary (win32 non-static only, debug) # @@ -113,7 +112,7 @@ if (OGRE_PREFIX_SOURCE AND OGRE_PREFIX_BUILD) set(OGRE_BIN_SEARCH_PATH ${dir}/bin ${OGRE_BIN_SEARCH_PATH}) set(OGRE_BIN_SEARCH_PATH ${dir}/Samples/Common/bin ${OGRE_BIN_SEARCH_PATH}) endforeach(dir) - + if (OGRE_PREFIX_DEPENDENCIES_DIR) set(OGRE_INC_SEARCH_PATH ${OGRE_PREFIX_DEPENDENCIES_DIR}/include ${OGRE_INC_SEARCH_PATH}) set(OGRE_LIB_SEARCH_PATH ${OGRE_PREFIX_DEPENDENCIES_DIR}/lib ${OGRE_LIB_SEARCH_PATH}) @@ -125,12 +124,12 @@ else() endif () # redo search if any of the environmental hints changed -set(OGRE_COMPONENTS Paging Terrain +set(OGRE_COMPONENTS Paging Terrain Plugin_BSPSceneManager Plugin_CgProgramManager Plugin_OctreeSceneManager Plugin_OctreeZone Plugin_PCZSceneManager Plugin_ParticleFX - RenderSystem_Direct3D11 RenderSystem_Direct3D9 RenderSystem_GL RenderSystem_GLES RenderSystem_GLES2) -set(OGRE_RESET_VARS - OGRE_CONFIG_INCLUDE_DIR OGRE_INCLUDE_DIR + RenderSystem_Direct3D10 RenderSystem_Direct3D9 RenderSystem_GL RenderSystem_GLES) +set(OGRE_RESET_VARS + OGRE_CONFIG_INCLUDE_DIR OGRE_INCLUDE_DIR OGRE_LIBRARY_FWK OGRE_LIBRARY_REL OGRE_LIBRARY_DBG OGRE_PLUGIN_DIR_DBG OGRE_PLUGIN_DIR_REL OGRE_MEDIA_DIR) foreach (comp ${OGRE_COMPONENTS}) @@ -145,7 +144,7 @@ clear_if_changed(OGRE_PREFIX_WATCH ${OGRE_RESET_VARS}) # try to locate Ogre via pkg-config use_pkgconfig(OGRE_PKGC "OGRE${OGRE_LIB_SUFFIX}") -if(NOT OGRE_BUILD_PLATFORM_APPLE_IOS) +if(NOT OGRE_BUILD_PLATFORM_IPHONE AND APPLE) # try to find framework on OSX findpkg_framework(OGRE) else() @@ -236,7 +235,6 @@ if (OGRE_STATIC) find_package(Freetype QUIET) find_package(OpenGL QUIET) find_package(OpenGLES QUIET) - find_package(OpenGLES2 QUIET) find_package(ZLIB QUIET) find_package(ZZip QUIET) if (UNIX AND NOT APPLE) @@ -246,26 +244,24 @@ if (OGRE_STATIC) set(X11_FOUND FALSE) endif () endif () - if (APPLE AND NOT OGRE_BUILD_PLATFORM_APPLE_IOS) + if (APPLE AND NOT OGRE_BUILD_PLATFORM_IPHONE) find_package(Cocoa QUIET) find_package(Carbon QUIET) - find_package(CoreVideo QUIET) - if (NOT Cocoa_FOUND OR NOT Carbon_FOUND OR NOT CoreVideo_FOUND) + if (NOT Cocoa_FOUND OR NOT Carbon_FOUND) set(OGRE_DEPS_FOUND FALSE) endif () endif () - if (APPLE AND OGRE_BUILD_PLATFORM_APPLE_IOS) + if (APPLE AND OGRE_BUILD_PLATFORM_IPHONE) find_package(iPhoneSDK QUIET) if (NOT iPhoneSDK_FOUND) set(OGRE_DEPS_FOUND FALSE) endif () endif () - set(OGRE_LIBRARIES ${OGRE_LIBRARIES} ${ZZip_LIBRARIES} ${ZLIB_LIBRARIES} ${FreeImage_LIBRARIES} ${FREETYPE_LIBRARIES} ) - - if (APPLE AND NOT OGRE_BUILD_PLATFORM_APPLE_IOS) - set(OGRE_LIBRARIES ${OGRE_LIBRARIES} ${X11_LIBRARIES} ${X11_Xt_LIBRARIES} ${XAW_LIBRARY} ${X11_Xrandr_LIB} ${Carbon_LIBRARIES} ${Cocoa_LIBRARIES}) - endif() + set(OGRE_LIBRARIES ${OGRE_LIBRARIES} ${OGRE_LIBRARY_FWK} ${ZZip_LIBRARIES} ${ZLIB_LIBRARIES} + ${FreeImage_LIBRARIES} ${FREETYPE_LIBRARIES} + ${X11_LIBRARIES} ${X11_Xt_LIBRARIES} ${XAW_LIBRARY} ${X11_Xrandr_LIB} + ${Cocoa_LIBRARIES} ${Carbon_LIBRARIES}) if (NOT ZLIB_FOUND OR NOT ZZip_FOUND) set(OGRE_DEPS_FOUND FALSE) @@ -309,7 +305,7 @@ if (OGRE_STATIC) endif () endif () endif () - + if (NOT OGRE_DEPS_FOUND) pkg_message(OGRE "Could not find all required dependencies for the Ogre package.") set(OGRE_FOUND FALSE) @@ -341,7 +337,7 @@ endif() # Find Ogre components ######################################################### -set(OGRE_COMPONENT_SEARCH_PATH_REL +set(OGRE_COMPONENT_SEARCH_PATH_REL ${OGRE_LIBRARY_DIR_REL}/.. ${OGRE_LIBRARY_DIR_REL}/../.. ${OGRE_BIN_SEARCH_PATH} @@ -393,26 +389,38 @@ macro(ogre_find_plugin PLUGIN HEADER) set(TMP_CMAKE_LIB_PREFIX ${CMAKE_FIND_LIBRARY_PREFIXES}) set(CMAKE_FIND_LIBRARY_PREFIXES ${CMAKE_FIND_LIBRARY_PREFIXES} "") endif() - + # strip RenderSystem_ or Plugin_ prefix from plugin name string(REPLACE "RenderSystem_" "" PLUGIN_TEMP ${PLUGIN}) string(REPLACE "Plugin_" "" PLUGIN_NAME ${PLUGIN_TEMP}) - + # header files for plugins are not usually needed, but find them anyway if they are present set(OGRE_PLUGIN_PATH_SUFFIXES - PlugIns PlugIns/${PLUGIN_NAME} Plugins Plugins/${PLUGIN_NAME} ${PLUGIN} + PlugIns PlugIns/${PLUGIN_NAME} Plugins Plugins/${PLUGIN_NAME} ${PLUGIN} RenderSystems RenderSystems/${PLUGIN_NAME} ${ARGN}) - find_path(OGRE_${PLUGIN}_INCLUDE_DIR NAMES ${HEADER} - HINTS ${OGRE_INCLUDE_DIRS} ${OGRE_PREFIX_SOURCE} + find_path(OGRE_${PLUGIN}_INCLUDE_DIR NAMES ${HEADER} + HINTS ${OGRE_INCLUDE_DIRS} ${OGRE_PREFIX_SOURCE} PATH_SUFFIXES ${OGRE_PLUGIN_PATH_SUFFIXES}) # find link libraries for plugins set(OGRE_${PLUGIN}_LIBRARY_NAMES "${PLUGIN}${OGRE_LIB_SUFFIX}") get_debug_names(OGRE_${PLUGIN}_LIBRARY_NAMES) set(OGRE_${PLUGIN}_LIBRARY_FWK ${OGRE_LIBRARY_FWK}) + # Search for release plugins in OGRE dir with version suffix find_library(OGRE_${PLUGIN}_LIBRARY_REL NAMES ${OGRE_${PLUGIN}_LIBRARY_NAMES} - HINTS ${OGRE_LIBRARY_DIRS} PATH_SUFFIXES "" OGRE opt release release/opt relwithdebinfo relwithdebinfo/opt minsizerel minsizerel/opt) + HINTS ${OGRE_LIBRARY_DIRS} PATH_SUFFIXES "" OGRE-${OGRE_VERSION} opt release release/opt relwithdebinfo relwithdebinfo/opt minsizerel minsizerel/opt) + if(NOT EXISTS "${OGRE_${PLUGIN}_LIBRARY_REL}") + # Search for release plugins in OGRE dir without version suffix + find_library(OGRE_${PLUGIN}_LIBRARY_REL NAMES ${OGRE_${PLUGIN}_LIBRARY_NAMES} + HINTS ${OGRE_LIBRARY_DIRS} PATH_SUFFIXES "" OGRE opt release release/opt relwithdebinfo relwithdebinfo/opt minsizerel minsizerel/opt) + endif() + # Search for debug plugins in OGRE dir with version suffix find_library(OGRE_${PLUGIN}_LIBRARY_DBG NAMES ${OGRE_${PLUGIN}_LIBRARY_NAMES_DBG} - HINTS ${OGRE_LIBRARY_DIRS} PATH_SUFFIXES "" OGRE opt debug debug/opt) + HINTS ${OGRE_LIBRARY_DIRS} PATH_SUFFIXES "" OGRE-${OGRE_VERSION} opt debug debug/opt) + if(NOT EXISTS "${OGRE_${PLUGIN}_LIBRARY_DBG}") + # Search for debug plugins in OGRE dir without version suffix + find_library(OGRE_${PLUGIN}_LIBRARY_DBG NAMES ${OGRE_${PLUGIN}_LIBRARY_NAMES_DBG} + HINTS ${OGRE_LIBRARY_DIRS} PATH_SUFFIXES "" OGRE opt debug debug/opt) + endif() make_library_set(OGRE_${PLUGIN}_LIBRARY) if (OGRE_${PLUGIN}_LIBRARY OR OGRE_${PLUGIN}_INCLUDE_DIR) @@ -429,7 +437,7 @@ macro(ogre_find_plugin PLUGIN HEADER) if (OGRE_${PLUGIN}_FOUND) if (NOT OGRE_PLUGIN_DIR_REL OR NOT OGRE_PLUGIN_DIR_DBG) if (WIN32) - set(OGRE_PLUGIN_SEARCH_PATH_REL + set(OGRE_PLUGIN_SEARCH_PATH_REL ${OGRE_LIBRARY_DIR_REL}/.. ${OGRE_LIBRARY_DIR_REL}/../.. ${OGRE_BIN_SEARCH_PATH} @@ -445,12 +453,16 @@ macro(ogre_find_plugin PLUGIN HEADER) PATH_SUFFIXES "" bin bin/debug debug) elseif (UNIX) get_filename_component(OGRE_PLUGIN_DIR_TMP ${OGRE_${PLUGIN}_LIBRARY_REL} PATH) - set(OGRE_PLUGIN_DIR_REL ${OGRE_PLUGIN_DIR_TMP} CACHE STRING "Ogre plugin dir (release)" FORCE) + # For some reason this fails + #set(OGRE_PLUGIN_DIR_REL ${OGRE_PLUGIN_DIR_TMP} CACHE STRING "Ogre plugin dir (release)") + set(OGRE_PLUGIN_DIR_REL ${OGRE_PLUGIN_DIR_TMP}) get_filename_component(OGRE_PLUGIN_DIR_TMP ${OGRE_${PLUGIN}_LIBRARY_DBG} PATH) - set(OGRE_PLUGIN_DIR_DBG ${OGRE_PLUGIN_DIR_TMP} CACHE STRING "Ogre plugin dir (debug)" FORCE) + # Same here + #set(OGRE_PLUGIN_DIR_DBG ${OGRE_PLUGIN_DIR_TMP} CACHE STRING "Ogre plugin dir (debug)") + set(OGRE_PLUGIN_DIR_DBG ${OGRE_PLUGIN_DIR_TMP}) endif () endif () - + # find binaries if (NOT OGRE_STATIC) if (WIN32) @@ -459,7 +471,7 @@ macro(ogre_find_plugin PLUGIN HEADER) endif() mark_as_advanced(OGRE_${PLUGIN}_REL OGRE_${PLUGIN}_DBG) endif() - + endif () if (TMP_CMAKE_LIB_PREFIX) @@ -475,8 +487,8 @@ ogre_find_plugin(Plugin_OctreeSceneManager OgreOctreeSceneManager.h PlugIns/Octr ogre_find_plugin(Plugin_ParticleFX OgreParticleFXPrerequisites.h PlugIns/ParticleFX/include) ogre_find_plugin(RenderSystem_GL OgreGLRenderSystem.h RenderSystems/GL/include) ogre_find_plugin(RenderSystem_GLES OgreGLESRenderSystem.h RenderSystems/GLES/include) -ogre_find_plugin(RenderSystem_GLES2 OgreGLES2RenderSystem.h RenderSystems/GLES2/include) ogre_find_plugin(RenderSystem_Direct3D9 OgreD3D9RenderSystem.h RenderSystems/Direct3D9/include) +ogre_find_plugin(RenderSystem_Direct3D10 OgreD3D10RenderSystem.h RenderSystems/Direct3D10/include) ogre_find_plugin(RenderSystem_Direct3D11 OgreD3D11RenderSystem.h RenderSystems/Direct3D11/include) if (OGRE_STATIC) @@ -484,26 +496,28 @@ if (OGRE_STATIC) if (NOT DirectX_FOUND) set(OGRE_RenderSystem_Direct3D9_FOUND FALSE) endif () + if (NOT DirectX_D3D10_FOUND) + set(OGRE_RenderSystem_Direct3D10_FOUND FALSE) + endif () if (NOT DirectX_D3D11_FOUND) set(OGRE_RenderSystem_Direct3D11_FOUND FALSE) endif () if (NOT OPENGL_FOUND) set(OGRE_RenderSystem_GL_FOUND FALSE) endif () - if (NOT OPENGLES_FOUND) + if (NOT OPENGLES_FOUND AND NOT OPENGLES2_FOUND) set(OGRE_RenderSystem_GLES_FOUND FALSE) endif () - if (NOT OPENGLES2_FOUND) - set(OGRE_RenderSystem_GLES2_FOUND FALSE) - endif () if (NOT Cg_FOUND) set(OGRE_Plugin_CgProgramManager_FOUND FALSE) endif () - + set(OGRE_RenderSystem_Direct3D9_LIBRARIES ${OGRE_RenderSystem_Direct3D9_LIBRARIES} ${DirectX_LIBRARIES} ) - + set(OGRE_RenderSystem_Direct3D10_LIBRARIES ${OGRE_RenderSystem_Direct3D10_LIBRARIES} + ${DirectX_D3D10_LIBRARIES} + ) set(OGRE_RenderSystem_Direct3D11_LIBRARIES ${OGRE_RenderSystem_Direct3D11_LIBRARIES} ${DirectX_D3D11_LIBRARIES} ) @@ -513,9 +527,6 @@ if (OGRE_STATIC) set(OGRE_RenderSystem_GLES_LIBRARIES ${OGRE_RenderSystem_GLES_LIBRARIES} ${OPENGLES_LIBRARIES} ) - set(OGRE_RenderSystem_GLES2_LIBRARIES ${OGRE_RenderSystem_GLES2_LIBRARIES} - ${OPENGLES2_LIBRARIES} - ) set(OGRE_Plugin_CgProgramManager_LIBRARIES ${OGRE_Plugin_CgProgramManager_LIBRARIES} ${Cg_LIBRARIES} ) @@ -540,3 +551,4 @@ set(OGRE_MEDIA_SEARCH_SUFFIX clear_if_changed(OGRE_PREFIX_WATCH OGRE_MEDIA_DIR) find_path(OGRE_MEDIA_DIR NAMES packs/cubemapsJS.zip HINTS ${OGRE_MEDIA_SEARCH_PATH} PATHS ${OGRE_PREFIX_PATH} PATH_SUFFIXES ${OGRE_MEDIA_SEARCH_SUFFIX}) + diff --git a/cmake/FindZZip.cmake b/cmake/FindZZip.cmake new file mode 100644 index 000000000..68fe043f3 --- /dev/null +++ b/cmake/FindZZip.cmake @@ -0,0 +1,48 @@ +#------------------------------------------------------------------- +# This file is part of the CMake build system for OGRE +# (Object-oriented Graphics Rendering Engine) +# For the latest info, see http://www.ogre3d.org/ +# +# The contents of this file are placed in the public domain. Feel +# free to make use of it in any way you like. +#------------------------------------------------------------------- + +# - Try to find zziplib +# Once done, this will define +# +# ZZip_FOUND - system has ZZip +# ZZip_INCLUDE_DIRS - the ZZip include directories +# ZZip_LIBRARIES - link these to use ZZip + +include(FindPkgMacros) +findpkg_begin(ZZip) + +# Get path, convert backslashes as ${ENV_${var}} +getenv_path(ZZIP_HOME) + + +# construct search paths +set(ZZip_PREFIX_PATH ${ZZIP_HOME} ${ENV_ZZIP_HOME}) +create_search_paths(ZZip) +# redo search if prefix path changed +clear_if_changed(ZZip_PREFIX_PATH + ZZip_LIBRARY_FWK + ZZip_LIBRARY_REL + ZZip_LIBRARY_DBG + ZZip_INCLUDE_DIR +) + +set(ZZip_LIBRARY_NAMES zzip zziplib) +get_debug_names(ZZip_LIBRARY_NAMES) + +use_pkgconfig(ZZip_PKGC zziplib) + +findpkg_framework(ZZip) + +find_path(ZZip_INCLUDE_DIR NAMES zzip/zzip.h HINTS ${ZZip_INC_SEARCH_PATH} ${ZZip_PKGC_INCLUDE_DIRS}) +find_library(ZZip_LIBRARY_REL NAMES ${ZZip_LIBRARY_NAMES} HINTS ${ZZip_LIB_SEARCH_PATH} ${ZZip_PKGC_LIBRARY_DIRS} PATH_SUFFIXES "" release relwithdebinfo minsizerel) +find_library(ZZip_LIBRARY_DBG NAMES ${ZZip_LIBRARY_NAMES_DBG} HINTS ${ZZip_LIB_SEARCH_PATH} ${ZZip_PKGC_LIBRARY_DIRS} PATH_SUFFIXES "" debug) +make_library_set(ZZip_LIBRARY) + +findpkg_finish(ZZip) + diff --git a/components/compiler/controlparser.cpp b/components/compiler/controlparser.cpp index c255154b5..5d74ee9d4 100644 --- a/components/compiler/controlparser.cpp +++ b/components/compiler/controlparser.cpp @@ -95,8 +95,6 @@ namespace Compiler return true; } - - return false; } bool ControlParser::parseWhileBody (int keyword, const TokenLoc& loc, Scanner& scanner) @@ -108,7 +106,7 @@ namespace Compiler Codes expr; mExprParser.append (expr); - Generator::jump (loop, -mCodeBlock.size()-expr.size()); + Generator::jump (loop, -static_cast (mCodeBlock.size()-expr.size())); std::copy (expr.begin(), expr.end(), std::back_inserter (mCode)); @@ -122,7 +120,7 @@ namespace Compiler Codes loop2; - Generator::jump (loop2, -mCodeBlock.size()-expr.size()-skip.size()); + Generator::jump (loop2, -static_cast (mCodeBlock.size()-expr.size()-skip.size())); if (loop.size()!=loop2.size()) throw std::logic_error ( @@ -153,8 +151,6 @@ namespace Compiler return true; } - - return false; } ControlParser::ControlParser (ErrorHandler& errorHandler, Context& context, Locals& locals, diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 06c3207e2..95480c023 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -639,7 +639,7 @@ namespace Compiler std::vector& code, bool invert) { bool optional = false; - bool optionalCount = 0; + int optionalCount = 0; ExprParser parser (getErrorHandler(), getContext(), mLocals, mLiterals, true); StringParser stringParser (getErrorHandler(), getContext(), mLiterals); diff --git a/components/compiler/scriptparser.cpp b/components/compiler/scriptparser.cpp index ce142847f..ac0ee63f1 100644 --- a/components/compiler/scriptparser.cpp +++ b/components/compiler/scriptparser.cpp @@ -24,7 +24,7 @@ namespace Compiler mLineParser.reset(); if (mLineParser.parseName (name, loc, scanner)) scanner.scan (mLineParser); - + return true; } @@ -34,22 +34,22 @@ namespace Compiler { mControlParser.reset(); if (mControlParser.parseKeyword (keyword, loc, scanner)) - scanner.scan (mControlParser); - + scanner.scan (mControlParser); + mControlParser.appendCode (mOutput.getCode()); - + return true; } - + if (keyword==Scanner::K_end && mEnd) { return false; } - + mLineParser.reset(); if (mLineParser.parseKeyword (keyword, loc, scanner)) scanner.scan (mLineParser); - + return true; } @@ -57,11 +57,11 @@ namespace Compiler { if (code==Scanner::S_newline) // empty line return true; - + mLineParser.reset(); if (mLineParser.parseSpecial (code, loc, scanner)) scanner.scan (mLineParser); - + return true; } @@ -77,4 +77,3 @@ namespace Compiler mOutput.clear(); } } - diff --git a/components/compiler/stringparser.cpp b/components/compiler/stringparser.cpp index 396a88c78..fe7bd30b9 100644 --- a/components/compiler/stringparser.cpp +++ b/components/compiler/stringparser.cpp @@ -39,6 +39,11 @@ namespace Compiler mState = CommaState; return true; } + else if (code==Scanner::S_newline && mState==StartState) + { + scanner.putbackSpecial (code, loc); + return false; + } return Parser::parseSpecial (code, loc, scanner); } diff --git a/components/esm/loadpgrd.cpp b/components/esm/loadpgrd.cpp index b0727b0c0..dc63ce335 100644 --- a/components/esm/loadpgrd.cpp +++ b/components/esm/loadpgrd.cpp @@ -3,32 +3,68 @@ namespace ESM { -void PathGrid::load(ESMReader &esm) +void Pathgrid::load(ESMReader &esm) { esm.getHNT(data, "DATA", 12); cell = esm.getHNString("NAME"); - // Remember this file position - context = esm.getContext(); + // keep track of total connections so we can reserve edge vector size + int edgeCount = 0; - // Check that the sizes match up. Size = 16 * s2 (path points?) if (esm.isNextSub("PGRP")) { - esm.skipHSub(); + esm.getSubHeader(); int size = esm.getSubSize(); - if (size != 16 * data.s2) - esm.fail("Path grid table size mismatch"); + // Check that the sizes match up. Size = 16 * s2 (path points) + if (size != static_cast (sizeof(Point) * data.s2)) + esm.fail("Path point subrecord size mismatch"); + else + { + int pointCount = data.s2; + points.reserve(pointCount); + for (int i = 0; i < pointCount; ++i) + { + Point p; + esm.getExact(&p, sizeof(Point)); + points.push_back(p); + edgeCount += p.connectionNum; + } + } } - // Size varies. Path grid chances? Connections? Multiples of 4 - // suggest either int or two shorts, or perhaps a float. Study - // it later. if (esm.isNextSub("PGRC")) { - esm.skipHSub(); + esm.getSubHeader(); int size = esm.getSubSize(); - if (size % 4 != 0) + if (size % sizeof(int) != 0) esm.fail("PGRC size not a multiple of 4"); + else + { + int rawConnNum = size / sizeof(int); + std::vector rawConnections; + rawConnections.reserve(rawConnNum); + for (int i = 0; i < rawConnNum; ++i) + { + int currentValue; + esm.getT(currentValue); + rawConnections.push_back(currentValue); + } + + std::vector::const_iterator rawIt = rawConnections.begin(); + int pointIndex = 0; + edges.reserve(edgeCount); + for(PointList::const_iterator it = points.begin(); it != points.end(); it++, pointIndex++) + { + unsigned char connectionNum = (*it).connectionNum; + for (int i = 0; i < connectionNum; ++i) { + Edge edge; + edge.v0 = pointIndex; + edge.v1 = *rawIt; + rawIt++; + edges.push_back(edge); + } + } + } } } diff --git a/components/esm/loadpgrd.hpp b/components/esm/loadpgrd.hpp index 8c030d314..6e2c6e134 100644 --- a/components/esm/loadpgrd.hpp +++ b/components/esm/loadpgrd.hpp @@ -9,20 +9,37 @@ namespace ESM /* * Path grid. */ -struct PathGrid +struct Pathgrid { struct DATAstruct { int x, y; // Grid location, matches cell for exterior cells short s1; // ?? Usually but not always a power of 2. Doesn't seem // to have any relation to the size of PGRC. - short s2; // Number of path points? Size of PGRP block is always 16 * s2; + short s2; // Number of path points. }; // 12 bytes + struct Point // path grid point + { + int x, y, z; // Location of point + unsigned char autogenerated; // autogenerated vs. user coloring flag? + unsigned char connectionNum; // number of connections for this point + short unknown; + }; // 16 bytes + + struct Edge // path grid edge + { + int v0, v1; // index of points connected with this edge + }; // 8 bytes + std::string cell; // Cell name DATAstruct data; - ESM_Context context; // Context so we can return here later and - // finish the job + + typedef std::vector PointList; + PointList points; + + typedef std::vector EdgeList; + EdgeList edges; void load(ESMReader &esm); }; diff --git a/components/esm_store/reclists.hpp b/components/esm_store/reclists.hpp index 20a2e8ff9..678f794c8 100644 --- a/components/esm_store/reclists.hpp +++ b/components/esm_store/reclists.hpp @@ -22,6 +22,8 @@ namespace ESMS struct RecList { + virtual ~RecList() {} + virtual void load(ESMReader &esm, const std::string &id) = 0; virtual int getSize() = 0; virtual void listIdentifier (std::vector& identifier) const = 0; @@ -42,6 +44,8 @@ namespace ESMS template struct RecListT : RecList { + virtual ~RecListT() {} + typedef std::map MapType; MapType list; @@ -90,6 +94,8 @@ namespace ESMS template struct RecListWithIDT : RecList { + virtual ~RecListWithIDT() {} + typedef std::map MapType; MapType list; @@ -139,6 +145,8 @@ namespace ESMS template struct RecIDListT : RecList { + virtual ~RecIDListT() {} + typedef std::map MapType; MapType list; @@ -189,6 +197,8 @@ namespace ESMS */ struct LTexList : RecList { + virtual ~LTexList() {} + // TODO: For multiple ESM/ESP files we need one list per file. std::vector ltex; int count; @@ -223,6 +233,8 @@ namespace ESMS */ struct LandList : RecList { + virtual ~LandList() {} + // Map containing all landscapes typedef std::map LandsCol; typedef std::map Lands; @@ -296,7 +308,7 @@ namespace ESMS identifier.push_back (iter->first); } - ~CellList() + virtual ~CellList() { for (IntCells::iterator it = intCells.begin(); it!=intCells.end(); ++it) delete it->second; @@ -390,9 +402,100 @@ namespace ESMS } }; + struct PathgridList : RecList + { + int count; + + // List of grids for interior cells. Indexed by cell name. + typedef std::map IntGrids; + IntGrids intGrids; + + // List of grids for exterior cells. Indexed as extCells[gridX][gridY]. + typedef std::map, ESM::Pathgrid*> ExtGrids; + ExtGrids extGrids; + + PathgridList() : count(0) {} + + virtual ~PathgridList() + { + for (IntGrids::iterator it = intGrids.begin(); it!=intGrids.end(); ++it) + delete it->second; + + for (ExtGrids::iterator it = extGrids.begin(); it!=extGrids.end(); ++it) + delete it->second; + } + + int getSize() { return count; } + + virtual void listIdentifier (std::vector& identifier) const + { + // do nothing + } + + void load(ESMReader &esm, const std::string &id) + { + count++; + ESM::Pathgrid *grid = new ESM::Pathgrid; + grid->load(esm); + if (grid->data.x == 0 && grid->data.y == 0) + { + intGrids[grid->cell] = grid; + } + else + { + extGrids[std::make_pair(grid->data.x, grid->data.y)] = grid; + } + } + + Pathgrid *find(int cellX, int cellY, std::string cellName) const + { + Pathgrid *result = search(cellX, cellY, cellName); + if (!result) + { + throw std::runtime_error("no pathgrid found for cell " + cellName); + } + return result; + } + + Pathgrid *search(int cellX, int cellY, std::string cellName) const + { + Pathgrid *result = NULL; + if (cellX == 0 && cellY == 0) // possibly interior + { + IntGrids::const_iterator it = intGrids.find(cellName); + if (it != intGrids.end()) + result = it->second; + } + else + { + ExtGrids::const_iterator it = extGrids.find(std::make_pair(cellX, cellY)); + if (it != extGrids.end()) + result = it->second; + } + return result; + } + + Pathgrid *search(const ESM::Cell &cell) const + { + int cellX, cellY; + if (cell.data.flags & ESM::Cell::Interior) + { + cellX = cellY = 0; + } + else + { + cellX = cell.data.gridX; + cellY = cell.data.gridY; + } + return search(cellX, cellY, cell.name); + } + }; + template struct ScriptListT : RecList { + virtual ~ScriptListT() {} + typedef std::map MapType; MapType list; @@ -444,6 +547,8 @@ namespace ESMS template struct IndexListT { + virtual ~IndexListT() {} + typedef std::map MapType; MapType list; diff --git a/components/esm_store/store.hpp b/components/esm_store/store.hpp index e3bbf9e82..fab04d3e9 100644 --- a/components/esm_store/store.hpp +++ b/components/esm_store/store.hpp @@ -74,7 +74,8 @@ namespace ESMS ScriptListT