From 25cd9ebf452867ef5bc21e5a307ae8850f5c73a9 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov <corrmage@gmail.com> Date: Sun, 15 Sep 2013 21:56:47 +0400 Subject: [PATCH 01/94] Plugins are frameworks in Ogre 1.9. Version hack removed. --- components/files/ogreplugin.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/components/files/ogreplugin.cpp b/components/files/ogreplugin.cpp index c319f77589..6070c43a87 100644 --- a/components/files/ogreplugin.cpp +++ b/components/files/ogreplugin.cpp @@ -6,18 +6,12 @@ namespace Files { bool loadOgrePlugin(const std::string &pluginDir, std::string pluginName, Ogre::Root &ogreRoot) { -#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE - std::ostringstream verStream; - verStream << "." << OGRE_VERSION_MAJOR << "." << OGRE_VERSION_MINOR << "." << OGRE_VERSION_PATCH; - pluginName = pluginName + verStream.str(); -#endif - std::string pluginExt; #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 pluginExt = ".dll"; #endif #if OGRE_PLATFORM == OGRE_PLATFORM_APPLE - pluginExt = ".dylib"; + pluginExt = ".framework"; #endif #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX pluginExt = ".so"; From 36fb89c6cdb203257e65d882123c13cf6c3d9829 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov <corrmage@gmail.com> Date: Sun, 15 Sep 2013 23:03:07 +0400 Subject: [PATCH 02/94] Cleanup --- CMakeLists.txt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ec306e5a5..96b0e1a327 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -262,8 +262,6 @@ if (APPLE) set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_DBG}) endif () - #set(OGRE_PLUGIN_DIR "${OGRE_PLUGIN_DIR}/") - configure_file(${OpenMW_SOURCE_DIR}/files/mac/Info.plist "${APP_BUNDLE_DIR}/Contents/Info.plist") @@ -664,7 +662,7 @@ if (APPLE) set(CPACK_GENERATOR "DragNDrop") set(CPACK_PACKAGE_VERSION ${OPENMW_VERSION}) set(CPACK_PACKAGE_VERSION_MAJOR ${OPENMW_VERSION_MAJOR}) - set(CPACK_PACKAGE_VERSION_MINOR ${OPENMW_VERSION_MINO}) + set(CPACK_PACKAGE_VERSION_MINOR ${OPENMW_VERSION_MINOR}) set(CPACK_PACKAGE_VERSION_PATCH ${OPENMW_VERSION_RELEASE}) set(APPS "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}") From a18e3c9cc17dc69d085c376435e263f139a641bb Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov <corrmage@gmail.com> Date: Sun, 15 Sep 2013 23:10:21 +0400 Subject: [PATCH 03/94] Fixed packaging when building against Ogre 1.9 --- CMakeLists.txt | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 96b0e1a327..fa62d508f1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -283,7 +283,7 @@ endif() add_definitions(-DOGRE_PLUGIN_DIR_REL="${OGRE_PLUGIN_DIR_REL}") add_definitions(-DOGRE_PLUGIN_DIR_DBG="${OGRE_PLUGIN_DIR_DBG}") if (APPLE AND OPENMW_OSX_DEPLOYMENT) - add_definitions(-DOGRE_PLUGIN_DIR="${APP_BUNDLE_NAME}/Contents/Plugins") + add_definitions(-DOGRE_PLUGIN_DIR="${APP_BUNDLE_NAME}/Contents/Frameworks") else() add_definitions(-DOGRE_PLUGIN_DIR="${OGRE_PLUGIN_DIR}") endif() @@ -666,7 +666,7 @@ if (APPLE) set(CPACK_PACKAGE_VERSION_PATCH ${OPENMW_VERSION_RELEASE}) set(APPS "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}") - set(PLUGINS "") + set(ABSOLUTE_PLUGINS "") foreach (PLUGIN ${USED_OGRE_PLUGINS}) @@ -674,11 +674,9 @@ if (APPLE) set(ABSOLUTE_PLUGINS ${PLUGIN_ABS} ${ABSOLUTE_PLUGINS}) endforeach () - set(PLUGIN_INSTALL_BASE "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}/Contents/Plugins") - install(FILES ${ABSOLUTE_PLUGINS} DESTINATION "${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}/Contents/Plugins" COMPONENT Runtime) + set(PLUGIN_INSTALL_BASE "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}/Contents/Frameworks") foreach (PLUGIN ${ABSOLUTE_PLUGINS}) - get_filename_component(PLUGIN_RELATIVE ${PLUGIN} NAME) - set(PLUGINS ${PLUGINS} "${PLUGIN_INSTALL_BASE}/${PLUGIN_RELATIVE}") + install(DIRECTORY ${PLUGIN} DESTINATION "${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}/Contents/Frameworks" COMPONENT Runtime) endforeach () #For now, search unresolved dependencies only in default system paths, so if you put unresolveable (i.e. with @executable_path in id name) lib or framework somewhere else, it would fail @@ -726,7 +724,7 @@ if (APPLE) cmake_policy(SET CMP0009 OLD) set(BU_CHMOD_BUNDLE_ITEMS ON) include(BundleUtilities) - fixup_bundle(\"${APPS}\" \"${PLUGINS}\" \"${DIRS}\") + fixup_bundle(\"${APPS}\" \"\" \"${DIRS}\") " COMPONENT Runtime) include(CPack) endif (APPLE) From 99cfb8cda28217710369cda38bb18c0a51c3f3d7 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov <corrmage@gmail.com> Date: Thu, 12 Dec 2013 13:48:23 +0400 Subject: [PATCH 04/94] OS X: this CMake parameters can be set in CMake invocation, no need to hardcode them in CMakeLists.txt --- CMakeLists.txt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f6014dff6e..2665ebdabe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,10 +4,6 @@ if (APPLE) set(APP_BUNDLE_NAME "${CMAKE_PROJECT_NAME}.app") set(APP_BUNDLE_DIR "${OpenMW_BINARY_DIR}/${APP_BUNDLE_NAME}") - - set(CMAKE_EXE_LINKER_FLAGS "-F /Library/Frameworks") - set(CMAKE_SHARED_LINKER_FLAGS "-F /Library/Frameworks") - set(CMAKE_MODULE_LINKER_FLAGS "-F /Library/Frameworks") endif (APPLE) # Macros From 87853f406626310554210976bfb84301c643cf30 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov <corrmage@gmail.com> Date: Thu, 12 Dec 2013 13:52:57 +0400 Subject: [PATCH 05/94] =?UTF-8?q?OS=20X:=20consider=20Ogre=20CG=20plugin?= =?UTF-8?q?=20as=20used=20only=20if=20it=E2=80=99s=20found?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2665ebdabe..9f4523d4fb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -246,8 +246,12 @@ if (APPLE) # List used Ogre plugins SET(USED_OGRE_PLUGINS ${OGRE_RenderSystem_GL_LIBRARY_REL} ${OGRE_Plugin_OctreeSceneManager_LIBRARY_REL} - ${OGRE_Plugin_CgProgramManager_LIBRARY_REL} ${OGRE_Plugin_ParticleFX_LIBRARY_REL}) + + if (OGRE_Plugin_CgProgramManager_FOUND) + set(USED_OGRE_PLUGINS ${USED_OGRE_PLUGINS} + ${OGRE_Plugin_CgProgramManager_LIBRARY_REL}) + endif () if (${OGRE_PLUGIN_DIR_REL}}) set(OGRE_PLUGINS_REL_FOUND TRUE) From 89c60b065c1fa4ea7e728d250af1001383c7544d Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov <corrmage@gmail.com> Date: Thu, 12 Dec 2013 14:19:48 +0400 Subject: [PATCH 06/94] OS X: looks like OGRE_Plugin_CgProgramManager_FOUND is not reliable --- CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9f4523d4fb..e1a591b27c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -248,7 +248,9 @@ if (APPLE) ${OGRE_Plugin_OctreeSceneManager_LIBRARY_REL} ${OGRE_Plugin_ParticleFX_LIBRARY_REL}) - if (OGRE_Plugin_CgProgramManager_FOUND) + # Actually we must use OGRE_Plugin_CgProgramManager_FOUND but it's + # not reliable and equals TRUE even if there's no Ogre Cg plugin + if (Cg_FOUND) set(USED_OGRE_PLUGINS ${USED_OGRE_PLUGINS} ${OGRE_Plugin_CgProgramManager_LIBRARY_REL}) endif () From 874ecee079d509b9d173a35c724a660b380f5642 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov <corrmage@gmail.com> Date: Thu, 12 Dec 2013 14:20:13 +0400 Subject: [PATCH 07/94] OS X: do not enforce static boost, this can be set externally anyway --- CMakeLists.txt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e1a591b27c..61c6f1f58a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -190,10 +190,6 @@ if (MSVC10) set(PLATFORM_INCLUDE_DIR "") endif() -if (APPLE) - set(Boost_USE_STATIC_LIBS ON) -endif (APPLE) - # Dependencies # Fix for not visible pthreads functions for linker with glibc 2.15 From 73c6aba4d05370e6433c42ea4af534224e4e3377 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov <corrmage@gmail.com> Date: Thu, 12 Dec 2013 15:20:04 +0400 Subject: [PATCH 08/94] OS X: Ogre plugins are now installed in OpenCS bundle too. Generalized plugin install routine. --- CMakeLists.txt | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 61c6f1f58a..f53d738132 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -689,9 +689,9 @@ if (APPLE) set(OPENMW_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}") - set(OPENCS_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/OpenCS.app") + set(OPENCS_BUNDLE_NAME "OpenCS.app") + set(OPENCS_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}") - set(PLUGINS "") set(ABSOLUTE_PLUGINS "") foreach (PLUGIN ${USED_OGRE_PLUGINS}) @@ -699,12 +699,25 @@ if (APPLE) set(ABSOLUTE_PLUGINS ${PLUGIN_ABS} ${ABSOLUTE_PLUGINS}) endforeach () - set(PLUGIN_INSTALL_BASE "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}/Contents/Plugins") - install(FILES ${ABSOLUTE_PLUGINS} DESTINATION "${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}/Contents/Plugins" COMPONENT Runtime) - foreach (PLUGIN ${ABSOLUTE_PLUGINS}) - get_filename_component(PLUGIN_RELATIVE ${PLUGIN} NAME) - set(PLUGINS ${PLUGINS} "${PLUGIN_INSTALL_BASE}/${PLUGIN_RELATIVE}") - endforeach () + # installs used plugins in bundle at given path (bundle_path must be relative to ${CMAKE_INSTALL_PREFIX}) + # and returns list of install paths for all installed plugins + function (install_plugins_for_bundle bundle_path plugins_var) + set(RELATIVE_PLUGIN_INSTALL_BASE "${bundle_path}/Contents/Plugins") + install(FILES ${ABSOLUTE_PLUGINS} DESTINATION ${RELATIVE_PLUGIN_INSTALL_BASE} COMPONENT Runtime) + + set(PLUGINS "") + set(PLUGIN_INSTALL_BASE "\${CMAKE_INSTALL_PREFIX}/${RELATIVE_PLUGIN_INSTALL_BASE}") + + foreach (PLUGIN ${ABSOLUTE_PLUGINS}) + get_filename_component(PLUGIN_RELATIVE ${PLUGIN} NAME) + set(PLUGINS ${PLUGINS} "${PLUGIN_INSTALL_BASE}/${PLUGIN_RELATIVE}") + endforeach () + + set(${plugins_var} ${PLUGINS} PARENT_SCOPE) + endfunction (install_plugins_for_bundle) + + install_plugins_for_bundle("${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}" PLUGINS) + install_plugins_for_bundle("${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}" OPENCS_PLUGINS) #For now, search unresolved dependencies only in default system paths, so if you put unresolveable (i.e. with @executable_path in id name) lib or framework somewhere else, it would fail set(DIRS "") @@ -752,7 +765,7 @@ if (APPLE) set(BU_CHMOD_BUNDLE_ITEMS ON) include(BundleUtilities) fixup_bundle(\"${OPENMW_APP}\" \"${PLUGINS}\" \"${DIRS}\") - fixup_bundle(\"${OPENCS_APP}\" \"\" \"${DIRS}\") + fixup_bundle(\"${OPENCS_APP}\" \"${OPENCS_PLUGINS}\" \"${DIRS}\") " COMPONENT Runtime) include(CPack) endif (APPLE) From fc21dd1f3afc44ba13a3c868690964b6b636daf9 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov <corrmage@gmail.com> Date: Sat, 14 Dec 2013 17:21:20 +0400 Subject: [PATCH 09/94] Music playback on OS X >= 10.9 works again. Fixes bug #1041. --- apps/openmw/mwsound/openal_output.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 4ee754b35d..868b4bdbd1 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -316,8 +316,23 @@ void OpenAL_SoundStream::play() throwALerror(); mSamplesQueued = 0; - for(ALuint i = 0;i < sNumBuffers;i++) - alBufferData(mBuffers[i], mFormat, this, 0, mSampleRate); + int srate; + ChannelConfig chans; + SampleType sampleType; + + mDecoder->getInfo(&srate, &chans, &sampleType); + + // Use exactly one sample of silence. + // This is required for OpenAL implementations that don't accept empty buffer data. + // (like one in OS X 10.9) + ALuint sampleSize = framesToBytes(1, chans, sampleType); + std::vector<char> silenceSample(sampleSize); + + if (sampleType == SampleType_UInt8) + std::fill(silenceSample.begin(), silenceSample.end(), 0x80); + + for(ALuint i = 0;i < sNumBuffers;i++) + alBufferData(mBuffers[i], mFormat, &silenceSample[0], sampleSize, mSampleRate); throwALerror(); alSourceQueueBuffers(mSource, sNumBuffers, mBuffers); From 892ff93489fc21ab731e1fe5663f2db8c3babf03 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov <corrmage@gmail.com> Date: Tue, 24 Dec 2013 23:28:12 +0400 Subject: [PATCH 10/94] OS X: attempt to fix #1045 --- CMakeLists.txt | 3 ++- components/ogreinit/ogreinit.cpp | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f53d738132..04e75e94e6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -288,7 +288,8 @@ endif() add_definitions(-DOGRE_PLUGIN_DIR_REL="${OGRE_PLUGIN_DIR_REL}") add_definitions(-DOGRE_PLUGIN_DIR_DBG="${OGRE_PLUGIN_DIR_DBG}") if (APPLE AND OPENMW_OSX_DEPLOYMENT) - add_definitions(-DOGRE_PLUGIN_DIR="${APP_BUNDLE_NAME}/Contents/Plugins") + # make it empty so plugin loading code can check this and try to find plugins inside app bundle + add_definitions(-DOGRE_PLUGIN_DIR="") else() add_definitions(-DOGRE_PLUGIN_DIR="${OGRE_PLUGIN_DIR}") endif() diff --git a/components/ogreinit/ogreinit.cpp b/components/ogreinit/ogreinit.cpp index c8fc621c78..46424a29af 100644 --- a/components/ogreinit/ogreinit.cpp +++ b/components/ogreinit/ogreinit.cpp @@ -6,6 +6,10 @@ #include <OgreParticleEmitterFactory.h> #include <OgreParticleSystemManager.h> +#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE +#include <OSX/macUtils.h> +#endif + #include <components/nifogre/particles.hpp> #include "ogreplugin.hpp" @@ -127,6 +131,9 @@ namespace OgreInit #endif #if OGRE_PLATFORM == OGRE_PLATFORM_APPLE pluginDir = OGRE_PLUGIN_DIR; + // if path is not specified try to find plugins inside the app bundle + if (pluginDir.empty()) + pluginDir = Ogre::macPluginPath(); #endif #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX pluginDir = OGRE_PLUGIN_DIR_REL; From 9fabae51981ca43eca252336ab9d3bdcf5ef8190 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov <corrmage@gmail.com> Date: Tue, 24 Dec 2013 23:59:59 +0400 Subject: [PATCH 11/94] OS X: force Cocoa API for Ogre windows in OpenCS --- apps/opencs/editor.cpp | 3 +++ apps/opencs/view/render/scenewidget.cpp | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 1c1e37c2d4..a1de750535 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -225,6 +225,9 @@ int CS::Editor::run() params.insert(std::make_pair("FSAA", "0")); params.insert(std::make_pair("vsync", "false")); params.insert(std::make_pair("hidden", "true")); +#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE + params.insert(std::make_pair("macAPI", "cocoa")); +#endif Ogre::RenderWindow* hiddenWindow = Ogre::Root::getSingleton().createRenderWindow("InactiveHidden", 1, 1, false, ¶ms); hiddenWindow->setActive(false); diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index c8b37e9bb0..8cbfc72c60 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -66,6 +66,10 @@ namespace CSVRender params.insert(std::make_pair("title", windowTitle.str())); params.insert(std::make_pair("FSAA", "0")); // TODO setting params.insert(std::make_pair("vsync", "false")); // TODO setting +#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE + params.insert(std::make_pair("macAPI", "cocoa")); + params.insert(std::make_pair("macAPICocoaUseNSView", "true")); +#endif mWindow = Ogre::Root::getSingleton().createRenderWindow(windowTitle.str(), this->width(), this->height(), false, ¶ms); mWindow->addViewport(mCamera)->setBackgroundColour(Ogre::ColourValue(0.3,0.3,0.3,1)); From fe34c9cf1faf3d41cb725e1c832cfa19d0e1c434 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Wed, 1 Jan 2014 15:06:31 +0100 Subject: [PATCH 12/94] increased version number --- CMakeLists.txt | 4 ++-- readme.txt | 38 +++++++++++++++++++------------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ee4a0246b2..c1eca064e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,7 +19,7 @@ include (OpenMWMacros) # Version set (OPENMW_VERSION_MAJOR 0) -set (OPENMW_VERSION_MINOR 27) +set (OPENMW_VERSION_MINOR 28) set (OPENMW_VERSION_RELEASE 0) set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}") @@ -323,7 +323,7 @@ configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg configure_file(${OpenMW_SOURCE_DIR}/files/opencs.cfg "${OpenMW_BINARY_DIR}/opencs.cfg") - + configure_file(${OpenMW_SOURCE_DIR}/files/opencs/defaultfilters "${OpenMW_BINARY_DIR}/resources/defaultfilters" COPYONLY) diff --git a/readme.txt b/readme.txt index 5b9aafcb34..946df64caa 100644 --- a/readme.txt +++ b/readme.txt @@ -3,7 +3,7 @@ OpenMW: A reimplementation of The Elder Scrolls III: Morrowind OpenMW is an attempt at recreating the engine for the popular role-playing game Morrowind by Bethesda Softworks. You need to own and install the original game for OpenMW to work. -Version: 0.27.0 +Version: 0.28.0 License: GPL (see GPL3.txt for more information) Website: http://www.openmw.org @@ -48,42 +48,42 @@ Allowed options: --version print version information and quit --data arg (=data) set data directories (later directories have higher priority) - --data-local arg set local data directory (highest + --data-local arg set local data directory (highest priority) --fallback-archive arg (=fallback-archive) - set fallback BSA archives (later + set fallback BSA archives (later archives have higher priority) --resources arg (=resources) set resources directory --start arg (=Beshara) set initial cell - --content arg content file(s): esm/esp, or + --content arg content file(s): esm/esp, or omwgame/omwaddon --anim-verbose [=arg(=1)] (=0) output animation indices files --no-sound [=arg(=1)] (=0) disable all sounds --script-verbose [=arg(=1)] (=0) verbose script output --script-all [=arg(=1)] (=0) compile all scripts (excluding dialogue scripts) at startup - --script-console [=arg(=1)] (=0) enable console-only script + --script-console [=arg(=1)] (=0) enable console-only script functionality - --script-run arg select a file containing a list of - console commands that is executed on + --script-run arg select a file containing a list of + console commands that is executed on startup --new-game [=arg(=1)] (=0) activate char gen/new game mechanics - --fs-strict [=arg(=1)] (=0) strict file system handling (no case + --fs-strict [=arg(=1)] (=0) strict file system handling (no case folding) - --encoding arg (=win1252) Character encoding used in OpenMW game + --encoding arg (=win1252) Character encoding used in OpenMW game messages: - - win1250 - Central and Eastern European - such as Polish, Czech, Slovak, - Hungarian, Slovene, Bosnian, Croatian, - Serbian (Latin script), Romanian and + + win1250 - Central and Eastern European + such as Polish, Czech, Slovak, + Hungarian, Slovene, Bosnian, Croatian, + Serbian (Latin script), Romanian and Albanian languages - - win1251 - Cyrillic alphabet such as - Russian, Bulgarian, Serbian Cyrillic + + win1251 - Cyrillic alphabet such as + Russian, Bulgarian, Serbian Cyrillic and other languages - - win1252 - Western European (Latin) + + win1252 - Western European (Latin) alphabet, used by default --fallback arg fallback values --no-grab Don't grab mouse cursor From b19b277f182ef4dbe2d2445d4d53754acc0dffb4 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Wed, 1 Jan 2014 15:16:51 +0100 Subject: [PATCH 13/94] temporarily disable OGRE-integration in OpenCS (need to sort out path problem first) --- apps/opencs/editor.cpp | 3 +++ apps/opencs/main.cpp | 3 +++ apps/opencs/view/world/scenesubview.cpp | 16 +++++++++++++++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 44926610b3..37f06c8c73 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -210,6 +210,8 @@ int CS::Editor::run() if (mLocal.empty()) return 1; +// temporarily disable OGRE-integration (need to fix path problem first) +#if 0 // TODO: setting Ogre::Root::getSingleton().setRenderSystem(Ogre::Root::getSingleton().getRenderSystemByName("OpenGL Rendering Subsystem")); @@ -223,6 +225,7 @@ int CS::Editor::run() params.insert(std::make_pair("hidden", "true")); Ogre::RenderWindow* hiddenWindow = Ogre::Root::getSingleton().createRenderWindow("InactiveHidden", 1, 1, false, ¶ms); hiddenWindow->setActive(false); +#endif mStartup.show(); diff --git a/apps/opencs/main.cpp b/apps/opencs/main.cpp index 57eaf2d253..931d633127 100644 --- a/apps/opencs/main.cpp +++ b/apps/opencs/main.cpp @@ -44,8 +44,11 @@ int main(int argc, char *argv[]) // SceneWidget destructor will delete the created render window, which would be called _after_ Root has shut down :( Application mApplication (argc, argv); +// temporarily disable OGRE-integration (need to fix path problem first) +#if 0 OgreInit::OgreInit ogreInit; ogreInit.init("./opencsOgre.log"); // TODO log path? +#endif #ifdef Q_OS_MAC QDir dir(QCoreApplication::applicationDirPath()); diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index 83b30be133..33ae327a0d 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -43,12 +43,26 @@ toolbar->addTool (new SceneToolMode (toolbar)); toolbar->addTool (new SceneToolMode (toolbar)); layout2->addWidget (toolbar, 0); - +// temporarily disable OGRE-integration (need to fix path problem first) +#if 0 CSVRender::SceneWidget* sceneWidget = new CSVRender::SceneWidget(this); layout2->addWidget (sceneWidget, 1); layout->insertLayout (0, layout2, 1); +#endif + /// \todo replace with rendering widget + QPalette palette2 (palette()); + palette2.setColor (QPalette::Background, Qt::white); + QLabel *placeholder = new QLabel ("Here goes the 3D scene", this); + placeholder->setAutoFillBackground (true); + placeholder->setPalette (palette2); + placeholder->setAlignment (Qt::AlignHCenter); + + layout2->addWidget (placeholder, 1); + + layout->insertLayout (0, layout2, 1); + CSVFilter::FilterBox *filterBox = new CSVFilter::FilterBox (document.getData(), this); From e4c802eac402cfc77e07bc4ea233aac097eae7ed Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Thu, 2 Jan 2014 14:17:59 +0100 Subject: [PATCH 14/94] updated changelog --- readme.txt | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/readme.txt b/readme.txt index 946df64caa..132485119d 100644 --- a/readme.txt +++ b/readme.txt @@ -91,6 +91,92 @@ Allowed options: CHANGELOG +0.28.0 + +Bug #399: Inventory changes are not visible immediately +Bug #417: Apply weather instantly when teleporting +Bug #566: Global Map position marker not updated for interior cells +Bug #712: Looting corpse delay +Bug #716: Problem with the "Vurt's Ascadian Isles Mod" mod +Bug #805: Two TR meshes appear black (v0.24RC) +Bug #841: Third-person activation distance taken from camera rather than head +Bug #845: NPCs hold torches during the day +Bug #855: Vvardenfell Visages Volume I some hairs donĀ“t appear since 0,24 +Bug #856: Maormer race by Mac Kom - The heads are way up +Bug #864: Walk locks during loading in 3rd person +Bug #871: active weapon/magic item icon is not immediately made blank if item is removed during dialog +Bug #882: Hircine's Ring doesn't always work +Bug #909: [Tamriel Rebuilt] crashes in Akamora +Bug #922: Launcher writing merged openmw.cfg files +Bug #943: Random magnitude should be calculated per effect +Bug #948: Negative fatigue level should be allowed +Bug #949: Particles in world space +Bug #950: Hard crash on x64 Linux running --new-game (on startup) +Bug #951: setMagicka and setFatigue have no effect +Bug #954: Problem with equipping inventory items when using a keyboard shortcut +Bug #955: Issues with equipping torches +Bug #966: Shield is visible when casting spell +Bug #967: Game crashes when equipping silver candlestick +Bug #970: Segmentation fault when starting at Bal Isra +Bug #977: Pressing down key in console doesn't go forward in history +Bug #979: Tooltip disappears when changing inventory +Bug #980: Barter: item category is remembered, but not shown +Bug #981: Mod: replacing model has wrong position/orientation +Bug #982: Launcher: Addon unchecking is not saved +Bug #983: Fix controllers to affect objects attached to the base node +Bug #985: Player can talk to NPCs who are in combat +Bug #989: OpenMW crashes when trying to include mod with capital .ESP +Bug #991: Merchants equip items with harmful constant effect enchantments +Bug #994: Don't cap skills/attributes when set via console +Bug #998: Setting the max health should also set the current health +Bug #1005: Torches are visible when casting spells and during hand to hand combat. +Bug #1006: Many NPCs have 0 skill +Bug #1007: Console fills up with text +Bug #1013: Player randomly loses health or dies +Bug #1014: Persuasion window is not centered in maximized window +Bug #1015: Player status window scroll state resets on status change +Bug #1016: Notification window not big enough for all skill level ups +Bug #1020: Saved window positions are not rescaled appropriately on resolution change +Bug #1022: Messages stuck permanently on screen when they pile up +Bug #1023: Journals doesn't open +Bug #1026: Game loses track of torch usage. +Bug #1028: Crash on pickup of jug in Unexplored Shipwreck, Upper level +Bug #1029: Quick keys menu: Select compatible replacement when tool used up +Bug #1041: Music playback issues on OS X >= 10.9 +Bug #1042: TES3 header data wrong encoding +Bug #1045: OS X: deployed OpenCS won't launch +Bug #1046: All damaged weaponry is worth 1 gold +Bug #1048: Links in "locked" dialogue are still clickable +Bug #1052: Using color codes when naming your character actually changes the name's color +Bug #1054: Spell effects not visible in front of water +Bug #1055: Power-Spell animation starts even though you already casted it that day +Bug #1059: Cure disease potion removes all effects from player, even your race bonus and race ability +Bug #1063: Crash upon checking out game start ship area in Seyda Neen +Bug #1064: openmw binaries link to unnecessary libraries +Bug #1065: Landing from a high place in water still causes fall damage +Feature #43: Visuals for Magic Effects +Feature #51: Ranged Magic +Feature #52: Touch Range Magic +Feature #53: Self Range Magic +Feature #54: Spell Casting +Feature #70: Vampirism +Feature #100: Combat AI +Feature #171: Implement NIF record NiFlipController +Feature #410: Window to restore enchanted item charge +Feature #647: Enchanted item glow +Feature #723: Invisibility/Chameleon magic effects +Feature #737: Resist Magicka magic effect +Feature #758: GetLOS +Feature #926: Editor: Info-Record tables +Feature #958: Material controllers +Feature #959: Terrain bump, specular, & parallax mapping +Feature #990: Request: unlock mouse when in any menu +Feature #1018: Do not allow view mode switching while performing an action +Feature #1027: Vertex morph animation (NiGeomMorpherController) +Feature #1031: Handle NiBillboardNode +Feature #1051: Implement NIF texture slot DarkTexture +Task #873: Unify OGRE initialisation + 0.27.0 Bug #597: Assertion `dialogue->mId == id' failed in esmstore.cpp From 0ded85893b042cf987ddefe881d56a5ef2982ae3 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Thu, 2 Jan 2014 20:47:43 +0100 Subject: [PATCH 15/94] updated changelog again --- readme.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/readme.txt b/readme.txt index 132485119d..5a74770f2b 100644 --- a/readme.txt +++ b/readme.txt @@ -154,6 +154,8 @@ Bug #1059: Cure disease potion removes all effects from player, even your race b Bug #1063: Crash upon checking out game start ship area in Seyda Neen Bug #1064: openmw binaries link to unnecessary libraries Bug #1065: Landing from a high place in water still causes fall damage +Bug #1072: Drawing weapon increases torch brightness +Bug #1073: Merchants sell stacks of gold Feature #43: Visuals for Magic Effects Feature #51: Ranged Magic Feature #52: Touch Range Magic From 46931d85a0fcb3f84d55ac07e6dfcd1107fb8a00 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Sun, 5 Jan 2014 11:51:31 +0100 Subject: [PATCH 16/94] changed changelog --- readme.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/readme.txt b/readme.txt index 5a74770f2b..21422a8da8 100644 --- a/readme.txt +++ b/readme.txt @@ -142,9 +142,7 @@ Bug #1023: Journals doesn't open Bug #1026: Game loses track of torch usage. Bug #1028: Crash on pickup of jug in Unexplored Shipwreck, Upper level Bug #1029: Quick keys menu: Select compatible replacement when tool used up -Bug #1041: Music playback issues on OS X >= 10.9 Bug #1042: TES3 header data wrong encoding -Bug #1045: OS X: deployed OpenCS won't launch Bug #1046: All damaged weaponry is worth 1 gold Bug #1048: Links in "locked" dialogue are still clickable Bug #1052: Using color codes when naming your character actually changes the name's color From bc90443aeb0b98e18787918e3f289af84b9e39d0 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov <corrmage@gmail.com> Date: Wed, 8 Jan 2014 18:07:58 +0400 Subject: [PATCH 17/94] Revert "Music playback on OS X >= 10.9 works again. Fixes bug #1041." This reverts commit fc21dd1f3afc44ba13a3c868690964b6b636daf9. --- apps/openmw/mwsound/openal_output.cpp | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 868b4bdbd1..4ee754b35d 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -316,23 +316,8 @@ void OpenAL_SoundStream::play() throwALerror(); mSamplesQueued = 0; - int srate; - ChannelConfig chans; - SampleType sampleType; - - mDecoder->getInfo(&srate, &chans, &sampleType); - - // Use exactly one sample of silence. - // This is required for OpenAL implementations that don't accept empty buffer data. - // (like one in OS X 10.9) - ALuint sampleSize = framesToBytes(1, chans, sampleType); - std::vector<char> silenceSample(sampleSize); - - if (sampleType == SampleType_UInt8) - std::fill(silenceSample.begin(), silenceSample.end(), 0x80); - - for(ALuint i = 0;i < sNumBuffers;i++) - alBufferData(mBuffers[i], mFormat, &silenceSample[0], sampleSize, mSampleRate); + for(ALuint i = 0;i < sNumBuffers;i++) + alBufferData(mBuffers[i], mFormat, this, 0, mSampleRate); throwALerror(); alSourceQueueBuffers(mSource, sNumBuffers, mBuffers); From 92521bd23d1d973ba31b62b24cd2db3a0f7b966c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Wed, 8 Jan 2014 20:27:33 +0100 Subject: [PATCH 18/94] updated changelog --- readme.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.txt b/readme.txt index 21422a8da8..242dcb5c0c 100644 --- a/readme.txt +++ b/readme.txt @@ -143,6 +143,7 @@ Bug #1026: Game loses track of torch usage. Bug #1028: Crash on pickup of jug in Unexplored Shipwreck, Upper level Bug #1029: Quick keys menu: Select compatible replacement when tool used up Bug #1042: TES3 header data wrong encoding +Bug #1045: OS X: deployed OpenCS won't launch Bug #1046: All damaged weaponry is worth 1 gold Bug #1048: Links in "locked" dialogue are still clickable Bug #1052: Using color codes when naming your character actually changes the name's color From 8bcdf54570bc01659d06f8691d089ad5864bc1dd Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Sun, 2 Feb 2014 13:55:03 +0100 Subject: [PATCH 19/94] added warning mode to script compiler error handler --- components/compiler/errorhandler.cpp | 16 +++++++++++++--- components/compiler/errorhandler.hpp | 6 +++++- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/components/compiler/errorhandler.cpp b/components/compiler/errorhandler.cpp index ee13c837d1..fe58836cca 100644 --- a/components/compiler/errorhandler.cpp +++ b/components/compiler/errorhandler.cpp @@ -5,7 +5,7 @@ namespace Compiler { // constructor - ErrorHandler::ErrorHandler() : mWarnings (0), mErrors (0) {} + ErrorHandler::ErrorHandler() : mWarnings (0), mErrors (0), mWarningsMode (1) {} // destructor @@ -36,8 +36,13 @@ namespace Compiler void ErrorHandler::warning (const std::string& message, const TokenLoc& loc) { - ++mWarnings; - report (message, loc, WarningMessage); + if (mWarningsMode==1) + { + ++mWarnings; + report (message, loc, WarningMessage); + } + else if (mWarningsMode==2) + error (message, loc); } // Generate an error message. @@ -62,4 +67,9 @@ namespace Compiler { mErrors = mWarnings = 0; } + + void ErrorHandler::setWarningsMode (int mode) + { + mWarningsMode = mode; + } } diff --git a/components/compiler/errorhandler.hpp b/components/compiler/errorhandler.hpp index 256065854a..e5922a6be5 100644 --- a/components/compiler/errorhandler.hpp +++ b/components/compiler/errorhandler.hpp @@ -16,6 +16,7 @@ namespace Compiler { int mWarnings; int mErrors; + int mWarningsMode; protected: @@ -60,8 +61,11 @@ namespace Compiler void endOfFile(); ///< Generate an error message for an unexpected EOF. - virtual void reset(); + virtual void reset(); ///< Remove all previous error/warning events + + void setWarningsMode (int mode); + ///< // 0 ignore, 1 rate as warning, 2 rate as error }; } From 4ee43612f66915ea1dc768b63a012c3cb06e9d89 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Sun, 2 Feb 2014 14:09:59 +0100 Subject: [PATCH 20/94] added new switch: --script-warn --- apps/openmw/engine.cpp | 9 +++-- apps/openmw/engine.hpp | 3 ++ apps/openmw/main.cpp | 8 +++++ apps/openmw/mwscript/scriptmanagerimp.cpp | 6 ++-- apps/openmw/mwscript/scriptmanagerimp.hpp | 2 +- readme.txt | 42 +++++++++++++---------- 6 files changed, 47 insertions(+), 23 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index bf1cca5e0f..e80bd954e3 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -155,6 +155,7 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) , mSkipMenu (false) , mUseSound (true) , mCompileAll (false) + , mWarningsMode (1) , mScriptContext (0) , mFSStrict (false) , mScriptConsoleMode (false) @@ -424,7 +425,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mScriptContext->setExtensions (&mExtensions); mEnvironment.setScriptManager (new MWScript::ScriptManager (MWBase::Environment::get().getWorld()->getStore(), - mVerboseScripts, *mScriptContext)); + mVerboseScripts, *mScriptContext, mWarningsMode)); // Create game mechanics system MWMechanics::MechanicsManager* mechanics = new MWMechanics::MechanicsManager; @@ -612,8 +613,12 @@ void OMW::Engine::setStartupScript (const std::string& path) mStartupScript = path; } - void OMW::Engine::setActivationDistanceOverride (int distance) { mActivationDistanceOverride = distance; } + +void OMW::Engine::setWarningsMode (int mode) +{ + mWarningsMode = mode; +} \ No newline at end of file diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 8b2a65b7ed..5c15ddf6fc 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -74,6 +74,7 @@ namespace OMW bool mSkipMenu; bool mUseSound; bool mCompileAll; + int mWarningsMode; std::string mFocusName; std::map<std::string,std::string> mFallbackMap; bool mScriptConsoleMode; @@ -181,6 +182,8 @@ namespace OMW /// Override the game setting specified activation distance. void setActivationDistanceOverride (int distance); + void setWarningsMode (int mode); + private: Files::ConfigurationManager& mCfgMgr; }; diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 570c2b1983..764c4f39b8 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -137,6 +137,13 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ("script-run", bpo::value<std::string>()->default_value(""), "select a file containing a list of console commands that is executed on startup") + ("script-warn", bpo::value<int>()->implicit_value (1) + ->default_value (1), + "handling of warnings when compiling scripts\n" + "\t0 - ignore warning\n" + "\t1 - show warning but consider script as correctly compiled anyway\n" + "\t2 - treat warnings as errors") + ("skip-menu", bpo::value<bool>()->implicit_value(true) ->default_value(false), "skip main menu on game startup") @@ -242,6 +249,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat engine.setScriptConsoleMode (variables["script-console"].as<bool>()); engine.setStartupScript (variables["script-run"].as<std::string>()); engine.setActivationDistanceOverride (variables["activate-dist"].as<int>()); + engine.setWarningsMode (variables["script-warn"].as<int>()); return true; } diff --git a/apps/openmw/mwscript/scriptmanagerimp.cpp b/apps/openmw/mwscript/scriptmanagerimp.cpp index a3e0615467..6862b9f830 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.cpp +++ b/apps/openmw/mwscript/scriptmanagerimp.cpp @@ -18,11 +18,13 @@ namespace MWScript { ScriptManager::ScriptManager (const MWWorld::ESMStore& store, bool verbose, - Compiler::Context& compilerContext) + Compiler::Context& compilerContext, int warningsMode) : mErrorHandler (std::cerr), mStore (store), mVerbose (verbose), mCompilerContext (compilerContext), mParser (mErrorHandler, mCompilerContext), mOpcodesInstalled (false), mGlobalScripts (store) - {} + { + mErrorHandler.setWarningsMode (warningsMode); + } bool ScriptManager::compile (const std::string& name) { diff --git a/apps/openmw/mwscript/scriptmanagerimp.hpp b/apps/openmw/mwscript/scriptmanagerimp.hpp index 1a856e0c58..da3abc60b5 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.hpp +++ b/apps/openmw/mwscript/scriptmanagerimp.hpp @@ -52,7 +52,7 @@ namespace MWScript public: ScriptManager (const MWWorld::ESMStore& store, bool verbose, - Compiler::Context& compilerContext); + Compiler::Context& compilerContext, int warningsMode); virtual void run (const std::string& name, Interpreter::Context& interpreterContext); ///< Run the script with the given name (compile first, if not compiled yet) diff --git a/readme.txt b/readme.txt index 6b388dc724..f4d0c0b8f7 100644 --- a/readme.txt +++ b/readme.txt @@ -48,42 +48,48 @@ Allowed options: --version print version information and quit --data arg (=data) set data directories (later directories have higher priority) - --data-local arg set local data directory (highest + --data-local arg set local data directory (highest priority) --fallback-archive arg (=fallback-archive) - set fallback BSA archives (later + set fallback BSA archives (later archives have higher priority) --resources arg (=resources) set resources directory --start arg (=Beshara) set initial cell - --content arg content file(s): esm/esp, or + --content arg content file(s): esm/esp, or omwgame/omwaddon --anim-verbose [=arg(=1)] (=0) output animation indices files --no-sound [=arg(=1)] (=0) disable all sounds --script-verbose [=arg(=1)] (=0) verbose script output --script-all [=arg(=1)] (=0) compile all scripts (excluding dialogue scripts) at startup - --script-console [=arg(=1)] (=0) enable console-only script + --script-console [=arg(=1)] (=0) enable console-only script functionality - --script-run arg select a file containing a list of - console commands that is executed on + --script-run arg select a file containing a list of + console commands that is executed on startup + --script-warn [=arg(=1)] (=1) handling of warnings when compiling + scripts + 0 - ignore warning + 1 - show warning but consider script as + correctly compiled anyway + 2 - treat warnings as errors --new-game [=arg(=1)] (=0) activate char gen/new game mechanics - --fs-strict [=arg(=1)] (=0) strict file system handling (no case + --fs-strict [=arg(=1)] (=0) strict file system handling (no case folding) - --encoding arg (=win1252) Character encoding used in OpenMW game + --encoding arg (=win1252) Character encoding used in OpenMW game messages: - - win1250 - Central and Eastern European - such as Polish, Czech, Slovak, - Hungarian, Slovene, Bosnian, Croatian, - Serbian (Latin script), Romanian and + + win1250 - Central and Eastern European + such as Polish, Czech, Slovak, + Hungarian, Slovene, Bosnian, Croatian, + Serbian (Latin script), Romanian and Albanian languages - - win1251 - Cyrillic alphabet such as - Russian, Bulgarian, Serbian Cyrillic + + win1251 - Cyrillic alphabet such as + Russian, Bulgarian, Serbian Cyrillic and other languages - - win1252 - Western European (Latin) + + win1252 - Western European (Latin) alphabet, used by default --fallback arg fallback values --no-grab Don't grab mouse cursor From 858dc80292a31c7359fc728f6d2c964a64f0f838 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Sun, 2 Feb 2014 14:10:57 +0100 Subject: [PATCH 21/94] corrected command line switch documentation in readme file --- readme.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.txt b/readme.txt index f4d0c0b8f7..b1fef2d097 100644 --- a/readme.txt +++ b/readme.txt @@ -73,7 +73,7 @@ Allowed options: 1 - show warning but consider script as correctly compiled anyway 2 - treat warnings as errors - --new-game [=arg(=1)] (=0) activate char gen/new game mechanics + --skip-menu [=arg(=1)] (=0) skip main menu on game startup --fs-strict [=arg(=1)] (=0) strict file system handling (no case folding) --encoding arg (=win1252) Character encoding used in OpenMW game From cd9b13712921be4c61968e7959cff2b287f6fc17 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Sun, 2 Feb 2014 14:24:58 +0100 Subject: [PATCH 22/94] allow elseif without matching if (grrrrr) --- components/compiler/controlparser.cpp | 6 +++++- components/compiler/scriptparser.cpp | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/components/compiler/controlparser.cpp b/components/compiler/controlparser.cpp index 5d74ee9d42..3be470c273 100644 --- a/components/compiler/controlparser.cpp +++ b/components/compiler/controlparser.cpp @@ -7,6 +7,7 @@ #include "scanner.hpp" #include "generator.hpp" +#include "errorhandler.hpp" namespace Compiler { @@ -186,8 +187,11 @@ namespace Compiler { if (mState==StartState) { - if (keyword==Scanner::K_if) + if (keyword==Scanner::K_if || keyword==Scanner::K_elseif) { + if (keyword==Scanner::K_elseif) + getErrorHandler().warning ("elseif without matching if", loc); + mExprParser.reset(); scanner.scan (mExprParser); diff --git a/components/compiler/scriptparser.cpp b/components/compiler/scriptparser.cpp index 5b3d244b0d..1b613595a6 100644 --- a/components/compiler/scriptparser.cpp +++ b/components/compiler/scriptparser.cpp @@ -32,7 +32,7 @@ namespace Compiler bool ScriptParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner) { - if (keyword==Scanner::K_while || keyword==Scanner::K_if) + if (keyword==Scanner::K_while || keyword==Scanner::K_if || keyword==Scanner::K_elseif) { mControlParser.reset(); if (mControlParser.parseKeyword (keyword, loc, scanner)) From 914ab1b8ab689f1462d2f396d936ab0377bb2b2f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Sun, 2 Feb 2014 15:08:27 +0100 Subject: [PATCH 23/94] allow 'x' instead of 'getjournalindex x' --- apps/opencs/model/world/scriptcontext.cpp | 6 ++++++ apps/opencs/model/world/scriptcontext.hpp | 3 +++ apps/openmw/mwscript/compilercontext.cpp | 12 ++++++++++++ apps/openmw/mwscript/compilercontext.hpp | 3 +++ components/compiler/context.hpp | 3 +++ components/compiler/exprparser.cpp | 19 ++++++++++++++++++- 6 files changed, 45 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/scriptcontext.cpp b/apps/opencs/model/world/scriptcontext.cpp index 86689d823b..8190c68eb7 100644 --- a/apps/opencs/model/world/scriptcontext.cpp +++ b/apps/opencs/model/world/scriptcontext.cpp @@ -38,6 +38,12 @@ bool CSMWorld::ScriptContext::isId (const std::string& name) const return std::binary_search (mIds.begin(), mIds.end(), Misc::StringUtils::lowerCase (name)); } +bool CSMWorld::ScriptContext::isJournalId (const std::string& name) const +{ + /// \todo fix this after isId is fixed + return isId (name); +} + void CSMWorld::ScriptContext::invalidateIds() { mIdsUpdated = false; diff --git a/apps/opencs/model/world/scriptcontext.hpp b/apps/opencs/model/world/scriptcontext.hpp index b839b5a432..961da9143b 100644 --- a/apps/opencs/model/world/scriptcontext.hpp +++ b/apps/opencs/model/world/scriptcontext.hpp @@ -32,6 +32,9 @@ namespace CSMWorld virtual bool isId (const std::string& name) const; ///< Does \a name match an ID, that can be referenced? + virtual bool isJournalId (const std::string& name) const; + ///< Does \a name match a journal ID? + void invalidateIds(); }; } diff --git a/apps/openmw/mwscript/compilercontext.cpp b/apps/openmw/mwscript/compilercontext.cpp index 7e63a33b25..b094e54147 100644 --- a/apps/openmw/mwscript/compilercontext.cpp +++ b/apps/openmw/mwscript/compilercontext.cpp @@ -3,6 +3,8 @@ #include "../mwworld/esmstore.hpp" +#include <components/esm/loaddial.hpp> + #include <components/compiler/locals.hpp> #include "../mwbase/environment.hpp" @@ -67,4 +69,14 @@ namespace MWScript store.get<ESM::Static>().search (name) || store.get<ESM::Weapon>().search (name); } + + bool CompilerContext::isJournalId (const std::string& name) const + { + const MWWorld::ESMStore &store = + MWBase::Environment::get().getWorld()->getStore(); + + const ESM::Dialogue *topic = store.get<ESM::Dialogue>().search (name); + + return topic && topic->mType==ESM::Dialogue::Journal; + } } diff --git a/apps/openmw/mwscript/compilercontext.hpp b/apps/openmw/mwscript/compilercontext.hpp index 5ec98e09a7..50256f9422 100644 --- a/apps/openmw/mwscript/compilercontext.hpp +++ b/apps/openmw/mwscript/compilercontext.hpp @@ -35,6 +35,9 @@ namespace MWScript virtual bool isId (const std::string& name) const; ///< Does \a name match an ID, that can be referenced? + + virtual bool isJournalId (const std::string& name) const; + ///< Does \a name match a journal ID? }; } diff --git a/components/compiler/context.hpp b/components/compiler/context.hpp index 1b02613c59..69146e285f 100644 --- a/components/compiler/context.hpp +++ b/components/compiler/context.hpp @@ -38,6 +38,9 @@ namespace Compiler virtual bool isId (const std::string& name) const = 0; ///< Does \a name match an ID, that can be referenced? + + virtual bool isJournalId (const std::string& name) const = 0; + ///< Does \a name match a journal ID? }; } diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 94240c5eb9..42c88b75ab 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -7,6 +7,8 @@ #include <stack> #include <iterator> +#include <components/misc/stringops.hpp> + #include "generator.hpp" #include "scanner.hpp" #include "errorhandler.hpp" @@ -14,7 +16,6 @@ #include "stringparser.hpp" #include "extensions.hpp" #include "context.hpp" -#include <components/misc/stringops.hpp> namespace Compiler { @@ -308,6 +309,22 @@ namespace Compiler return true; } + // die in a fire, Morrowind script compiler! + if (const Extensions *extensions = getContext().getExtensions()) + { + if (getContext().isJournalId (name2)) + { + // JournalID used as an argument. Use the index of that JournalID + Generator::pushString (mCode, mLiterals, name2); + int keyword = extensions->searchKeyword ("getjournalindex"); + extensions->generateFunctionCode (keyword, mCode, mLiterals, mExplicit, 0); + mNextOperand = false; + mOperands.push_back ('l'); + + return 2; + } + } + if (mExplicit.empty() && getContext().isId (name2)) { mExplicit = name2; From 32860a05e38f7b67afc8725beed30254d4c69dc1 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Sun, 2 Feb 2014 15:35:18 +0100 Subject: [PATCH 24/94] added dummy implementations for getPcInJail and getPcTraveling --- apps/openmw/mwscript/docs/vmformat.txt | 4 +++- apps/openmw/mwscript/miscextensions.cpp | 24 ++++++++++++++++++++++++ components/compiler/extensions0.cpp | 4 +++- components/compiler/opcodes.hpp | 2 ++ 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 25f3c38aa7..2fe4c768ba 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -381,5 +381,7 @@ op 0x200023a: StartCombat op 0x200023b: StartCombatExplicit op 0x200023c: StopCombat op 0x200023d: StopCombatExplicit +op 0x200023e: GetPcInJail +op 0x200023f: GetPcTraveling -opcodes 0x200023e-0x3ffffff unused +opcodes 0x2000240-0x3ffffff unused diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index d117c8dede..aa0e775af2 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -818,6 +818,28 @@ namespace MWScript } }; + class OpGetPcInJail : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime &runtime) + { + /// \todo implement jail check + runtime.push (0); + } + }; + + class OpGetPcTraveling : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime &runtime) + { + /// \todo implement traveling check + runtime.push (0); + } + }; + void installOpcodes (Interpreter::Interpreter& interpreter) { interpreter.installSegment5 (Compiler::Misc::opcodeXBox, new OpXBox); @@ -888,6 +910,8 @@ namespace MWScript interpreter.installSegment5 (Compiler::Misc::opcodeCastExplicit, new OpCast<ExplicitRef>); interpreter.installSegment5 (Compiler::Misc::opcodeExplodeSpell, new OpExplodeSpell<ImplicitRef>); interpreter.installSegment5 (Compiler::Misc::opcodeExplodeSpellExplicit, new OpExplodeSpell<ExplicitRef>); + interpreter.installSegment5 (Compiler::Misc::opcodeGetPcInJail, new OpGetPcInJail); + interpreter.installSegment5 (Compiler::Misc::opcodeGetPcTraveling, new OpGetPcTraveling); } } } diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index baec9987fa..ebe46d2826 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -190,7 +190,7 @@ namespace Compiler extensions.registerInstruction ("enableclassmenu", "", opcodeEnableClassMenu); extensions.registerInstruction ("enablenamemenu", "", opcodeEnableNameMenu); extensions.registerInstruction ("enableracemenu", "", opcodeEnableRaceMenu); - extensions.registerInstruction ("enablestatreviewmenu", "", + extensions.registerInstruction ("enablestatreviewmenu", "", opcodeEnableStatsReviewMenu); extensions.registerInstruction ("enableinventorymenu", "", opcodeEnableInventoryMenu); @@ -276,6 +276,8 @@ namespace Compiler extensions.registerInstruction("togglegodmode", "", opcodeToggleGodMode); extensions.registerInstruction ("disablelevitation", "", opcodeDisableLevitation); extensions.registerInstruction ("enablelevitation", "", opcodeEnableLevitation); + extensions.registerFunction ("getpcinjail", 'l', "", opcodeGetPcInJail); + extensions.registerFunction ("getpctraveling", 'l', "", opcodeGetPcTraveling); } } diff --git a/components/compiler/opcodes.hpp b/components/compiler/opcodes.hpp index 57d86e62bf..583cf4eea3 100644 --- a/components/compiler/opcodes.hpp +++ b/components/compiler/opcodes.hpp @@ -245,6 +245,8 @@ namespace Compiler const int opcodeCastExplicit = 0x2000228; const int opcodeExplodeSpell = 0x2000229; const int opcodeExplodeSpellExplicit = 0x200022a; + const int opcodeGetPcInJail = 0x200023e; + const int opcodeGetPcTraveling = 0x200023f; } namespace Sky From 2b2ac6f62b7db5972fbf461056d06576e9e4557f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Sun, 2 Feb 2014 15:43:48 +0100 Subject: [PATCH 25/94] allow declaration of local variables with keywords as names --- components/compiler/lineparser.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 3d9ac0a93a..2904df6e1b 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -370,6 +370,12 @@ namespace Compiler mState = EndState; return true; } + else if (mState==ShortState || mState==LongState || mState==FloatState) + { + // allow keywords to be used as local variable names. MW script compiler, you suck! + /// \todo option to disable this atrocity. + return parseName (loc.mLiteral, loc, scanner); + } if (mAllowExpression) { From 632834ce1094fb5e0b56910797e049455e71cea4 Mon Sep 17 00:00:00 2001 From: gus <gus_512@hotmail.com> Date: Wed, 5 Feb 2014 16:12:50 +0100 Subject: [PATCH 26/94] WIP --- apps/openmw/mwmechanics/aiactivate.cpp | 103 ++++++++++++++++++++++++- apps/openmw/mwmechanics/aiactivate.hpp | 6 ++ apps/openmw/mwmechanics/aitravel.cpp | 10 +-- apps/openmw/mwmechanics/aitravel.hpp | 4 +- 4 files changed, 113 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwmechanics/aiactivate.cpp b/apps/openmw/mwmechanics/aiactivate.cpp index 531ba55686..e751140c08 100644 --- a/apps/openmw/mwmechanics/aiactivate.cpp +++ b/apps/openmw/mwmechanics/aiactivate.cpp @@ -1,8 +1,24 @@ #include "aiactivate.hpp" #include <iostream> +#include "movement.hpp" + +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" +#include "../mwworld/class.hpp" + +namespace +{ + float sgn(float a) + { + if(a > 0) + return 1.0; + return -1.0; + } +} + MWMechanics::AiActivate::AiActivate(const std::string &objectId) -: mObjectId(objectId) + : mObjectId(objectId) { } MWMechanics::AiActivate *MWMechanics::AiActivate::clone() const @@ -11,8 +27,89 @@ MWMechanics::AiActivate *MWMechanics::AiActivate::clone() const } bool MWMechanics::AiActivate::execute (const MWWorld::Ptr& actor,float duration) { - std::cout << "AiActivate completed.\n"; - return true; + MWBase::World *world = MWBase::Environment::get().getWorld(); + ESM::Position pos = actor.getRefData().getPosition(); + Movement &movement = actor.getClass().getMovementSettings(actor); + const ESM::Cell *cell = actor.getCell()->mCell; + + MWWorld::Ptr player = world->getPlayerPtr(); + if(cell->mData.mX != player.getCell()->mCell->mData.mX) + { + int sideX = sgn(cell->mData.mX - player.getCell()->mCell->mData.mX); + //check if actor is near the border of an inactive cell. If so, stop walking. + if(sideX * (pos.pos[0] - cell->mData.mX*ESM::Land::REAL_SIZE) > + sideX * (ESM::Land::REAL_SIZE/2.0f - 200.0f)) + { + movement.mPosition[1] = 0; + return false; + } + } + if(cell->mData.mY != player.getCell()->mCell->mData.mY) + { + int sideY = sgn(cell->mData.mY - player.getCell()->mCell->mData.mY); + //check if actor is near the border of an inactive cell. If so, stop walking. + if(sideY * (pos.pos[1] - cell->mData.mY*ESM::Land::REAL_SIZE) > + sideY * (ESM::Land::REAL_SIZE/2.0f - 200.0f)) + { + movement.mPosition[1] = 0; + return false; + } + } + + MWWorld::Ptr target = world->getPtr(mObjectId,false); + ESM::Position targetPos = target.getRefData().getPosition(); + + bool cellChange = cell->mData.mX != mCellX || cell->mData.mY != mCellY; + if(!mPathFinder.isPathConstructed() || cellChange) + { + mCellX = cell->mData.mX; + mCellY = cell->mData.mY; + float xCell = 0; + float yCell = 0; + + if(cell->isExterior()) + { + xCell = cell->mData.mX * ESM::Land::REAL_SIZE; + yCell = cell->mData.mY * ESM::Land::REAL_SIZE; + } + + ESM::Pathgrid::Point dest; + dest.mX = targetPos.pos[0]; + dest.mY = targetPos.pos[0]; + dest.mZ = targetPos.pos[0]; + + ESM::Pathgrid::Point start; + start.mX = pos.pos[0]; + start.mY = pos.pos[1]; + start.mZ = pos.pos[2]; + + mPathFinder.buildPath(start, dest, actor.getCell(), true); + } + + if((pos.pos[0]-targetPos.pos[0])*(pos.pos[0]-targetPos.pos[0])+ + (pos.pos[1]-targetPos.pos[1])*(pos.pos[1]-targetPos.pos[1])+ + (pos.pos[2]-targetPos.pos[2])*(pos.pos[2]-targetPos.pos[2]) < 200*200) + { + movement.mPosition[1] = 0; + MWWorld::Ptr target = world->getPtr(mObjectId,false); + MWWorld::Class::get(target).activate(target,actor); + return true; + } + + if(mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2])) + { + movement.mPosition[1] = 0; + MWWorld::Ptr target = world->getPtr(mObjectId,false); + MWWorld::Class::get(target).activate(target,actor); + return true; + } + + float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]); + // TODO: use movement settings instead of rotating directly + world->rotateObject(actor, 0, 0, zAngle, false); + movement.mPosition[1] = 1; + + return false; } int MWMechanics::AiActivate::getTypeId() const diff --git a/apps/openmw/mwmechanics/aiactivate.hpp b/apps/openmw/mwmechanics/aiactivate.hpp index f922e238c2..7c94c25896 100644 --- a/apps/openmw/mwmechanics/aiactivate.hpp +++ b/apps/openmw/mwmechanics/aiactivate.hpp @@ -4,6 +4,8 @@ #include "aipackage.hpp" #include <string> +#include "pathfinding.hpp" + namespace MWMechanics { @@ -18,6 +20,10 @@ namespace MWMechanics private: std::string mObjectId; + + PathFinder mPathFinder; + int mCellX; + int mCellY; }; } #endif // GAME_MWMECHANICS_AIACTIVATE_H diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index ba75cb4186..377f9de0f8 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -20,8 +20,8 @@ namespace MWMechanics { AiTravel::AiTravel(float x, float y, float z) : mX(x),mY(y),mZ(z),mPathFinder() - , cellX(std::numeric_limits<int>::max()) - , cellY(std::numeric_limits<int>::max()) + , mCellX(std::numeric_limits<int>::max()) + , mCellY(std::numeric_limits<int>::max()) { } @@ -61,11 +61,11 @@ namespace MWMechanics } } - bool cellChange = cell->mData.mX != cellX || cell->mData.mY != cellY; + bool cellChange = cell->mData.mX != mCellX || cell->mData.mY != mCellY; if(!mPathFinder.isPathConstructed() || cellChange) { - cellX = cell->mData.mX; - cellY = cell->mData.mY; + mCellX = cell->mData.mX; + mCellY = cell->mData.mY; float xCell = 0; float yCell = 0; diff --git a/apps/openmw/mwmechanics/aitravel.hpp b/apps/openmw/mwmechanics/aitravel.hpp index b479dfd431..72f3e02983 100644 --- a/apps/openmw/mwmechanics/aitravel.hpp +++ b/apps/openmw/mwmechanics/aitravel.hpp @@ -23,8 +23,8 @@ namespace MWMechanics float mY; float mZ; - int cellX; - int cellY; + int mCellX; + int mCellY; PathFinder mPathFinder; }; From 8f949c6ae217c662e61f926fda0c5f9812b7fe09 Mon Sep 17 00:00:00 2001 From: scrawl <scrawl@baseoftrash.de> Date: Sat, 8 Feb 2014 07:35:34 +0100 Subject: [PATCH 27/94] Fix lockpicks --- apps/openmw/mwrender/npcanimation.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index bcbcbc737e..d07aad31d4 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -697,7 +697,8 @@ void NpcAnimation::showWeapons(bool showWeapon) addOrReplaceIndividualPart(ESM::PRT_Weapon, MWWorld::InventoryStore::Slot_CarriedRight, 1, mesh, !weapon->getClass().getEnchantment(*weapon).empty(), &glowColor); - if (weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) + if (weapon->getTypeName() == typeid(ESM::Weapon).name() && + weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) { MWWorld::ContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition); if (ammo != inv.end() && ammo->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::Bolt) From 3147aebf7501cc1fc7c64d3b93832261c2eed47c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Mon, 10 Feb 2014 13:01:52 +0100 Subject: [PATCH 28/94] factored out declaration parser --- components/CMakeLists.txt | 2 +- components/compiler/declarationparser.cpp | 79 +++++++++++++++++++++++ components/compiler/declarationparser.hpp | 41 ++++++++++++ components/compiler/lineparser.cpp | 64 +++++++----------- components/compiler/lineparser.hpp | 1 - 5 files changed, 144 insertions(+), 43 deletions(-) create mode 100644 components/compiler/declarationparser.cpp create mode 100644 components/compiler/declarationparser.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index f2b16d4d53..4f6639e9bc 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -55,7 +55,7 @@ add_component_dir (files add_component_dir (compiler context controlparser errorhandler exception exprparser extensions fileparser generator lineparser literals locals output parser scanner scriptparser skipparser streamerrorhandler - stringparser tokenloc nullerrorhandler opcodes extensions0 + stringparser tokenloc nullerrorhandler opcodes extensions0 declarationparser ) add_component_dir (interpreter diff --git a/components/compiler/declarationparser.cpp b/components/compiler/declarationparser.cpp new file mode 100644 index 0000000000..586b28bc29 --- /dev/null +++ b/components/compiler/declarationparser.cpp @@ -0,0 +1,79 @@ + +#include "declarationparser.hpp" + +#include <components/misc/stringops.hpp> + +#include "scanner.hpp" +#include "errorhandler.hpp" +#include "skipparser.hpp" +#include "locals.hpp" + +Compiler::DeclarationParser::DeclarationParser (ErrorHandler& errorHandler, Context& context, + Locals& locals) +: Parser (errorHandler, context), mLocals (locals), mState (State_Begin), mType (0) +{} + +bool Compiler::DeclarationParser::parseName (const std::string& name, const TokenLoc& loc, + Scanner& scanner) +{ + if (mState==State_Name) + { + std::string name2 = Misc::StringUtils::lowerCase (name); + + char type = mLocals.getType (name2); + + if (type!=' ') + { + /// \todo add option to make re-declared local variables an error + getErrorHandler().warning ("can't re-declare local variable (ignoring declaration)", + loc); + SkipParser skip (getErrorHandler(), getContext()); + scanner.scan (skip); + mState = State_End; + return true; + } + + mLocals.declare (mType, name2); + + mState = State_End; + return true; + } + + return Parser::parseName (name, loc, scanner); +} + +bool Compiler::DeclarationParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner) +{ + if (mState==State_Begin) + { + switch (keyword) + { + case Scanner::K_short: mType = 's'; break; + case Scanner::K_long: mType = 'l'; break; + case Scanner::K_float: mType = 'f'; break; + default: mType = 0; + } + + if (mType) + { + mState = State_Name; + return true; + } + } + else if (mState==State_Name) + { + // allow keywords to be used as local variable names. MW script compiler, you suck! + /// \todo option to disable this atrocity. + return parseName (loc.mLiteral, loc, scanner); + } + + return Parser::parseKeyword (keyword, loc, scanner); +} + +bool Compiler::DeclarationParser::parseSpecial (int code, const TokenLoc& loc, Scanner& scanner) +{ + if (code==Scanner::S_newline && mState==State_End) + return false; + + return Parser::parseSpecial (code, loc, scanner); +} \ No newline at end of file diff --git a/components/compiler/declarationparser.hpp b/components/compiler/declarationparser.hpp new file mode 100644 index 0000000000..3e0ac57c34 --- /dev/null +++ b/components/compiler/declarationparser.hpp @@ -0,0 +1,41 @@ +#ifndef COMPILER_DECLARATIONPARSER_H_INCLUDED +#define COMPILER_DECLARATIONPARSER_H_INCLUDED + +#include "parser.hpp" + +namespace Compiler +{ + class Locals; + + class DeclarationParser : public Parser + { + enum State + { + State_Begin, State_Name, State_End + }; + + Locals& mLocals; + State mState; + char mType; + + public: + + DeclarationParser (ErrorHandler& errorHandler, Context& context, Locals& locals); + + virtual bool parseName (const std::string& name, const TokenLoc& loc, + Scanner& scanner); + ///< Handle a name token. + /// \return fetch another token? + + virtual bool parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner); + ///< Handle a keyword token. + /// \return fetch another token? + + virtual bool parseSpecial (int code, const TokenLoc& loc, Scanner& scanner); + ///< Handle a special character token. + /// \return fetch another token? + + }; +} + +#endif diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 2904df6e1b..368152fd93 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -1,6 +1,8 @@ #include "lineparser.hpp" +#include <components/misc/stringops.hpp> + #include "scanner.hpp" #include "context.hpp" #include "errorhandler.hpp" @@ -8,7 +10,7 @@ #include "locals.hpp" #include "generator.hpp" #include "extensions.hpp" -#include <components/misc/stringops.hpp> +#include "declarationparser.hpp" namespace Compiler { @@ -82,37 +84,6 @@ namespace Compiler bool LineParser::parseName (const std::string& name, const TokenLoc& loc, Scanner& scanner) { - if (mState==ShortState || mState==LongState || mState==FloatState) - { - if (!getContext().canDeclareLocals()) - { - getErrorHandler().error ("local variables can't be declared in this context", loc); - SkipParser skip (getErrorHandler(), getContext()); - scanner.scan (skip); - return false; - } - - std::string name2 = Misc::StringUtils::lowerCase (name); - - char type = mLocals.getType (name2); - - if (type!=' ') - { - /// \todo add option to make re-declared local variables an error - getErrorHandler().warning ("can't re-declare local variable", loc); - SkipParser skip (getErrorHandler(), getContext()); - scanner.scan (skip); - mState = EndState; - return true; - } - - mLocals.declare (mState==ShortState ? 's' : (mState==LongState ? 'l' : 'f'), - name2); - - mState = EndState; - return true; - } - if (mState==SetState) { std::string name2 = Misc::StringUtils::lowerCase (name); @@ -303,9 +274,26 @@ namespace Compiler { switch (keyword) { - case Scanner::K_short: mState = ShortState; return true; - case Scanner::K_long: mState = LongState; return true; - case Scanner::K_float: mState = FloatState; return true; + case Scanner::K_short: + case Scanner::K_long: + case Scanner::K_float: + { + if (!getContext().canDeclareLocals()) + { + getErrorHandler().error ( + "local variables can't be declared in this context", loc); + SkipParser skip (getErrorHandler(), getContext()); + scanner.scan (skip); + return true; + } + + DeclarationParser declaration (getErrorHandler(), getContext(), mLocals); + if (declaration.parseKeyword (keyword, loc, scanner)) + scanner.scan (declaration); + + return true; + } + case Scanner::K_set: mState = SetState; return true; case Scanner::K_messagebox: mState = MessageState; return true; @@ -370,12 +358,6 @@ namespace Compiler mState = EndState; return true; } - else if (mState==ShortState || mState==LongState || mState==FloatState) - { - // allow keywords to be used as local variable names. MW script compiler, you suck! - /// \todo option to disable this atrocity. - return parseName (loc.mLiteral, loc, scanner); - } if (mAllowExpression) { diff --git a/components/compiler/lineparser.hpp b/components/compiler/lineparser.hpp index aa74cd232f..cf72f26a83 100644 --- a/components/compiler/lineparser.hpp +++ b/components/compiler/lineparser.hpp @@ -20,7 +20,6 @@ namespace Compiler enum State { BeginState, - ShortState, LongState, FloatState, SetState, SetLocalVarState, SetGlobalVarState, SetPotentialMemberVarState, SetMemberVarState, SetMemberVarState2, MessageState, MessageCommaState, MessageButtonState, MessageButtonCommaState, From 3b990795c4da85fcbf7373b47ff4914aa17b5635 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Mon, 10 Feb 2014 14:45:55 +0100 Subject: [PATCH 29/94] added access to remote access of local variables of global scripts --- apps/opencs/model/world/scriptcontext.cpp | 5 +- apps/opencs/model/world/scriptcontext.hpp | 8 +- apps/openmw/mwscript/compilercontext.cpp | 27 ++++- apps/openmw/mwscript/compilercontext.hpp | 8 +- apps/openmw/mwscript/globalscripts.cpp | 21 ++++ apps/openmw/mwscript/globalscripts.hpp | 4 + apps/openmw/mwscript/interpretercontext.cpp | 123 +++++++++++++------- apps/openmw/mwscript/interpretercontext.hpp | 44 ++++--- components/compiler/context.hpp | 8 +- components/compiler/exprparser.cpp | 9 +- components/compiler/generator.cpp | 41 +++---- components/compiler/generator.hpp | 6 +- components/compiler/lineparser.cpp | 10 +- components/compiler/lineparser.hpp | 1 + components/interpreter/context.hpp | 36 +++--- components/interpreter/docs/vmformat.txt | 8 +- components/interpreter/installopcodes.cpp | 18 ++- components/interpreter/localopcodes.hpp | 36 +++++- 18 files changed, 277 insertions(+), 136 deletions(-) diff --git a/apps/opencs/model/world/scriptcontext.cpp b/apps/opencs/model/world/scriptcontext.cpp index 8190c68eb7..1b30281595 100644 --- a/apps/opencs/model/world/scriptcontext.cpp +++ b/apps/opencs/model/world/scriptcontext.cpp @@ -19,9 +19,10 @@ char CSMWorld::ScriptContext::getGlobalType (const std::string& name) const return ' '; } -char CSMWorld::ScriptContext::getMemberType (const std::string& name, const std::string& id) const +std::pair<char, bool> CSMWorld::ScriptContext::getMemberType (const std::string& name, + const std::string& id) const { - return ' '; + return std::make_pair (' ', false); } bool CSMWorld::ScriptContext::isId (const std::string& name) const diff --git a/apps/opencs/model/world/scriptcontext.hpp b/apps/opencs/model/world/scriptcontext.hpp index 961da9143b..3baca99b24 100644 --- a/apps/opencs/model/world/scriptcontext.hpp +++ b/apps/opencs/model/world/scriptcontext.hpp @@ -26,8 +26,12 @@ namespace CSMWorld virtual char getGlobalType (const std::string& name) const; ///< 'l: long, 's': short, 'f': float, ' ': does not exist. - virtual char getMemberType (const std::string& name, const std::string& id) const; - ///< 'l: long, 's': short, 'f': float, ' ': does not exist. + virtual std::pair<char, bool> getMemberType (const std::string& name, + const std::string& id) const; + ///< Return type of member variable \a name in script \a id or in script of reference of + /// \a id + /// \return first: 'l: long, 's': short, 'f': float, ' ': does not exist. + /// second: true: script of reference virtual bool isId (const std::string& name) const; ///< Does \a name match an ID, that can be referenced? diff --git a/apps/openmw/mwscript/compilercontext.cpp b/apps/openmw/mwscript/compilercontext.cpp index b094e54147..8018b86e02 100644 --- a/apps/openmw/mwscript/compilercontext.cpp +++ b/apps/openmw/mwscript/compilercontext.cpp @@ -30,16 +30,31 @@ namespace MWScript return MWBase::Environment::get().getWorld()->getGlobalVariableType (name); } - char CompilerContext::getMemberType (const std::string& name, const std::string& id) const + std::pair<char, bool> CompilerContext::getMemberType (const std::string& name, + const std::string& id) const { - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPtr (id, false); + std::string script; + bool reference = false; - std::string script = MWWorld::Class::get (ptr).getScript (ptr); + if (const ESM::Script *scriptRecord = + MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().search (id)) + { + script = scriptRecord->mId; + } + else + { + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPtr (id, false); - if (script.empty()) - return ' '; + script = MWWorld::Class::get (ptr).getScript (ptr); + reference = true; + } - return MWBase::Environment::get().getScriptManager()->getLocals (script).getType (name); + char type = ' '; + + if (!script.empty()) + type = MWBase::Environment::get().getScriptManager()->getLocals (script).getType (name); + + return std::make_pair (type, reference); } bool CompilerContext::isId (const std::string& name) const diff --git a/apps/openmw/mwscript/compilercontext.hpp b/apps/openmw/mwscript/compilercontext.hpp index 50256f9422..95719ab692 100644 --- a/apps/openmw/mwscript/compilercontext.hpp +++ b/apps/openmw/mwscript/compilercontext.hpp @@ -30,8 +30,12 @@ namespace MWScript /// 'l: long, 's': short, 'f': float, ' ': does not exist. virtual char getGlobalType (const std::string& name) const; - virtual char getMemberType (const std::string& name, const std::string& id) const; - ///< 'l: long, 's': short, 'f': float, ' ': does not exist. + virtual std::pair<char, bool> getMemberType (const std::string& name, + const std::string& id) const; + ///< Return type of member variable \a name in script \a id or in script of reference of + /// \a id + /// \return first: 'l: long, 's': short, 'f': float, ' ': does not exist. + /// second: true: script of reference virtual bool isId (const std::string& name) const; ///< Does \a name match an ID, that can be referenced? diff --git a/apps/openmw/mwscript/globalscripts.cpp b/apps/openmw/mwscript/globalscripts.cpp index 8f269a0153..179e2bb0bb 100644 --- a/apps/openmw/mwscript/globalscripts.cpp +++ b/apps/openmw/mwscript/globalscripts.cpp @@ -148,4 +148,25 @@ namespace MWScript return false; } + + Locals& GlobalScripts::getLocals (const std::string& name) + { + std::string name2 = Misc::StringUtils::lowerCase (name); + std::map<std::string, std::pair<bool, Locals> >::iterator iter = + mScripts.find (name2); + + if (iter==mScripts.end()) + { + if (const ESM::Script *script = mStore.get<ESM::Script>().find (name)) + { + Locals locals; + + locals.configure (*script); + + iter = mScripts.insert (std::make_pair (name, std::make_pair (false, locals))).first; + } + } + + return iter->second.second; + } } diff --git a/apps/openmw/mwscript/globalscripts.hpp b/apps/openmw/mwscript/globalscripts.hpp index cf716c8e42..a4a7662263 100644 --- a/apps/openmw/mwscript/globalscripts.hpp +++ b/apps/openmw/mwscript/globalscripts.hpp @@ -52,6 +52,10 @@ namespace MWScript ///< Records for variables that do not exist are dropped silently. /// /// \return Known type? + + Locals& getLocals (const std::string& name); + ///< If the script \a name has not been added as a global script yet, it is added + /// automatically, but is not set to running state. }; } diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index 10e98e3988..17092b41ca 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -54,6 +54,47 @@ namespace MWScript } } + const Locals& InterpreterContext::getMemberLocals (std::string& id, bool global) + const + { + if (global) + { + return MWBase::Environment::get().getScriptManager()->getGlobalScripts(). + getLocals (id); + } + else + { + const MWWorld::Ptr ptr = getReference (id, false); + + std::string id = MWWorld::Class::get (ptr).getScript (ptr); + + ptr.getRefData().setLocals ( + *MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (id)); + + return ptr.getRefData().getLocals(); + } + } + + Locals& InterpreterContext::getMemberLocals (std::string& id, bool global) + { + if (global) + { + return MWBase::Environment::get().getScriptManager()->getGlobalScripts(). + getLocals (id); + } + else + { + const MWWorld::Ptr ptr = getReference (id, false); + + std::string id = MWWorld::Class::get (ptr).getScript (ptr); + + ptr.getRefData().setLocals ( + *MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (id)); + + return ptr.getRefData().getLocals(); + } + } + InterpreterContext::InterpreterContext ( MWScript::Locals *locals, MWWorld::Ptr reference) : mLocals (locals), mReference (reference), @@ -407,82 +448,80 @@ namespace MWScript MWBase::Environment::get().getWorld()->disable (ref); } - int InterpreterContext::getMemberShort (const std::string& id, const std::string& name) const + int InterpreterContext::getMemberShort (const std::string& id, const std::string& name, + bool global) const { - const MWWorld::Ptr ptr = getReference (id, false); + std::string scriptId (id); - std::string scriptId = MWWorld::Class::get (ptr).getScript (ptr); + const Locals& locals = getMemberLocals (scriptId, global); - int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 's'); + int index = MWBase::Environment::get().getScriptManager()->getLocalIndex ( + scriptId, name, 's'); - ptr.getRefData().setLocals ( - *MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (scriptId)); - return ptr.getRefData().getLocals().mShorts[index]; + return locals.mShorts[index]; } - int InterpreterContext::getMemberLong (const std::string& id, const std::string& name) const + int InterpreterContext::getMemberLong (const std::string& id, const std::string& name, + bool global) const { - const MWWorld::Ptr ptr = getReference (id, false); + std::string scriptId (id); - std::string scriptId = MWWorld::Class::get (ptr).getScript (ptr); + const Locals& locals = getMemberLocals (scriptId, global); - int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'l'); + int index = MWBase::Environment::get().getScriptManager()->getLocalIndex ( + scriptId, name, 'l'); - ptr.getRefData().setLocals ( - *MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (scriptId)); - return ptr.getRefData().getLocals().mLongs[index]; + return locals.mLongs[index]; } - float InterpreterContext::getMemberFloat (const std::string& id, const std::string& name) const + float InterpreterContext::getMemberFloat (const std::string& id, const std::string& name, + bool global) const { - const MWWorld::Ptr ptr = getReference (id, false); + std::string scriptId (id); - std::string scriptId = MWWorld::Class::get (ptr).getScript (ptr); + const Locals& locals = getMemberLocals (scriptId, global); - int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'f'); + int index = MWBase::Environment::get().getScriptManager()->getLocalIndex ( + scriptId, name, 'f'); - ptr.getRefData().setLocals ( - *MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (scriptId)); - return ptr.getRefData().getLocals().mFloats[index]; + return locals.mFloats[index]; } - void InterpreterContext::setMemberShort (const std::string& id, const std::string& name, int value) + void InterpreterContext::setMemberShort (const std::string& id, const std::string& name, + int value, bool global) { - const MWWorld::Ptr ptr = getReference (id, false); + std::string scriptId (id); - std::string scriptId = MWWorld::Class::get (ptr).getScript (ptr); + Locals& locals = getMemberLocals (scriptId, global); - int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 's'); + int index = + MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 's'); - ptr.getRefData().setLocals ( - *MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (scriptId)); - ptr.getRefData().getLocals().mShorts[index] = value; + locals.mShorts[index] = value; } - void InterpreterContext::setMemberLong (const std::string& id, const std::string& name, int value) + void InterpreterContext::setMemberLong (const std::string& id, const std::string& name, int value, bool global) { - const MWWorld::Ptr ptr = getReference (id, false); + std::string scriptId (id); - std::string scriptId = MWWorld::Class::get (ptr).getScript (ptr); + Locals& locals = getMemberLocals (scriptId, global); - int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'l'); + int index = + MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'l'); - ptr.getRefData().setLocals ( - *MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (scriptId)); - ptr.getRefData().getLocals().mLongs[index] = value; + locals.mLongs[index] = value; } - void InterpreterContext::setMemberFloat (const std::string& id, const std::string& name, float value) + void InterpreterContext::setMemberFloat (const std::string& id, const std::string& name, float value, bool global) { - const MWWorld::Ptr ptr = getReference (id, false); + std::string scriptId (id); - std::string scriptId = MWWorld::Class::get (ptr).getScript (ptr); + Locals& locals = getMemberLocals (scriptId, global); - int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'f'); + int index = + MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'f'); - ptr.getRefData().setLocals ( - *MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (scriptId)); - ptr.getRefData().getLocals().mFloats[index] = value; + locals.mFloats[index] = value; } MWWorld::Ptr InterpreterContext::getReference(bool required) diff --git a/apps/openmw/mwscript/interpretercontext.hpp b/apps/openmw/mwscript/interpretercontext.hpp index 04546faed7..9fb7fa2bf8 100644 --- a/apps/openmw/mwscript/interpretercontext.hpp +++ b/apps/openmw/mwscript/interpretercontext.hpp @@ -37,6 +37,12 @@ namespace MWScript const MWWorld::Ptr getReference (const std::string& id, bool activeOnly, bool doThrow=true) const; + const Locals& getMemberLocals (std::string& id, bool global) const; + ///< \a id is changed to the respective script ID, if \a id wasn't a script ID before + + Locals& getMemberLocals (std::string& id, bool global); + ///< \a id is changed to the respective script ID, if \a id wasn't a script ID before + public: InterpreterContext (MWScript::Locals *locals, MWWorld::Ptr reference); @@ -75,35 +81,35 @@ namespace MWScript virtual void setGlobalLong (const std::string& name, int value); virtual void setGlobalFloat (const std::string& name, float value); - + virtual std::vector<std::string> getGlobals () const; virtual char getGlobalType (const std::string& name) const; - + virtual std::string getActionBinding(const std::string& action) const; - + virtual std::string getNPCName() const; - + virtual std::string getNPCRace() const; - + virtual std::string getNPCClass() const; - + virtual std::string getNPCFaction() const; virtual std::string getNPCRank() const; - + virtual std::string getPCName() const; - + virtual std::string getPCRace() const; - + virtual std::string getPCClass() const; - + virtual std::string getPCRank() const; - + virtual std::string getPCNextRank() const; - + virtual int getPCBounty() const; - + virtual std::string getCurrentCellName() const; virtual bool isScriptRunning (const std::string& name) const; @@ -138,17 +144,17 @@ namespace MWScript virtual void disable (const std::string& id = ""); - virtual int getMemberShort (const std::string& id, const std::string& name) const; + virtual int getMemberShort (const std::string& id, const std::string& name, bool global) const; - virtual int getMemberLong (const std::string& id, const std::string& name) const; + virtual int getMemberLong (const std::string& id, const std::string& name, bool global) const; - virtual float getMemberFloat (const std::string& id, const std::string& name) const; + virtual float getMemberFloat (const std::string& id, const std::string& name, bool global) const; - virtual void setMemberShort (const std::string& id, const std::string& name, int value); + virtual void setMemberShort (const std::string& id, const std::string& name, int value, bool global); - virtual void setMemberLong (const std::string& id, const std::string& name, int value); + virtual void setMemberLong (const std::string& id, const std::string& name, int value, bool global); - virtual void setMemberFloat (const std::string& id, const std::string& name, float value); + virtual void setMemberFloat (const std::string& id, const std::string& name, float value, bool global); MWWorld::Ptr getReference(bool required=true); ///< Reference, that the script is running from (can be empty) diff --git a/components/compiler/context.hpp b/components/compiler/context.hpp index 69146e285f..84bb89bdc4 100644 --- a/components/compiler/context.hpp +++ b/components/compiler/context.hpp @@ -33,8 +33,12 @@ namespace Compiler virtual char getGlobalType (const std::string& name) const = 0; ///< 'l: long, 's': short, 'f': float, ' ': does not exist. - virtual char getMemberType (const std::string& name, const std::string& id) const = 0; - ///< 'l: long, 's': short, 'f': float, ' ': does not exist. + virtual std::pair<char, bool> getMemberType (const std::string& name, + const std::string& id) const = 0; + ///< Return type of member variable \a name in script \a id or in script of reference of + /// \a id + /// \return first: 'l: long, 's': short, 'f': float, ' ': does not exist. + /// second: true: script of reference virtual bool isId (const std::string& name) const = 0; ///< Does \a name match an ID, that can be referenced? diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 42c88b75ab..283da854c9 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -204,14 +204,15 @@ namespace Compiler std::string name2 = Misc::StringUtils::lowerCase (name); std::string id = Misc::StringUtils::lowerCase (mExplicit); - char type = getContext().getMemberType (name2, id); + std::pair<char, bool> type = getContext().getMemberType (name2, id); - if (type!=' ') + if (type.first!=' ') { - Generator::fetchMember (mCode, mLiterals, type, name2, id); + Generator::fetchMember (mCode, mLiterals, type.first, name2, id, !type.second); + mNextOperand = false; mExplicit.clear(); - mOperands.push_back (type=='f' ? 'f' : 'l'); + mOperands.push_back (type.first=='f' ? 'f' : 'l'); return true; } diff --git a/components/compiler/generator.cpp b/components/compiler/generator.cpp index 9b02e4273f..83e46d5f7b 100644 --- a/components/compiler/generator.cpp +++ b/components/compiler/generator.cpp @@ -260,34 +260,34 @@ namespace code.push_back (Compiler::Generator::segment5 (44)); } - void opStoreMemberShort (Compiler::Generator::CodeContainer& code) + void opStoreMemberShort (Compiler::Generator::CodeContainer& code, bool global) { - code.push_back (Compiler::Generator::segment5 (59)); + code.push_back (Compiler::Generator::segment5 (global ? 65 : 59)); } - void opStoreMemberLong (Compiler::Generator::CodeContainer& code) + void opStoreMemberLong (Compiler::Generator::CodeContainer& code, bool global) { - code.push_back (Compiler::Generator::segment5 (60)); + code.push_back (Compiler::Generator::segment5 (global ? 66 : 60)); } - void opStoreMemberFloat (Compiler::Generator::CodeContainer& code) + void opStoreMemberFloat (Compiler::Generator::CodeContainer& code, bool global) { - code.push_back (Compiler::Generator::segment5 (61)); + code.push_back (Compiler::Generator::segment5 (global ? 67 : 61)); } - void opFetchMemberShort (Compiler::Generator::CodeContainer& code) + void opFetchMemberShort (Compiler::Generator::CodeContainer& code, bool global) { - code.push_back (Compiler::Generator::segment5 (62)); + code.push_back (Compiler::Generator::segment5 (global ? 68 : 62)); } - void opFetchMemberLong (Compiler::Generator::CodeContainer& code) + void opFetchMemberLong (Compiler::Generator::CodeContainer& code, bool global) { - code.push_back (Compiler::Generator::segment5 (63)); + code.push_back (Compiler::Generator::segment5 (global ? 69 : 63)); } - void opFetchMemberFloat (Compiler::Generator::CodeContainer& code) + void opFetchMemberFloat (Compiler::Generator::CodeContainer& code, bool global) { - code.push_back (Compiler::Generator::segment5 (64)); + code.push_back (Compiler::Generator::segment5 (global ? 70 : 64)); } void opRandom (Compiler::Generator::CodeContainer& code) @@ -738,7 +738,8 @@ namespace Compiler } void assignToMember (CodeContainer& code, Literals& literals, char localType, - const std::string& name, const std::string& id, const CodeContainer& value, char valueType) + const std::string& name, const std::string& id, const CodeContainer& value, + char valueType, bool global) { int index = literals.addString (name); @@ -766,17 +767,17 @@ namespace Compiler { case 'f': - opStoreMemberFloat (code); + opStoreMemberFloat (code, global); break; case 's': - opStoreMemberShort (code); + opStoreMemberShort (code, global); break; case 'l': - opStoreMemberLong (code); + opStoreMemberLong (code, global); break; default: @@ -786,7 +787,7 @@ namespace Compiler } void fetchMember (CodeContainer& code, Literals& literals, char localType, - const std::string& name, const std::string& id) + const std::string& name, const std::string& id, bool global) { int index = literals.addString (name); @@ -800,17 +801,17 @@ namespace Compiler { case 'f': - opFetchMemberFloat (code); + opFetchMemberFloat (code, global); break; case 's': - opFetchMemberShort (code); + opFetchMemberShort (code, global); break; case 'l': - opFetchMemberLong (code); + opFetchMemberLong (code, global); break; default: diff --git a/components/compiler/generator.hpp b/components/compiler/generator.hpp index feab26c93d..b511161225 100644 --- a/components/compiler/generator.hpp +++ b/components/compiler/generator.hpp @@ -102,10 +102,12 @@ namespace Compiler const std::string& name); void assignToMember (CodeContainer& code, Literals& literals, char memberType, - const std::string& name, const std::string& id, const CodeContainer& value, char valueType); + const std::string& name, const std::string& id, const CodeContainer& value, char valueType, bool global); + ///< \param global Member of a global script instead of a script of a reference. void fetchMember (CodeContainer& code, Literals& literals, char memberType, - const std::string& name, const std::string& id); + const std::string& name, const std::string& id, bool global); + ///< \param global Member of a global script instead of a script of a reference. void random (CodeContainer& code); diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 368152fd93..5987a48031 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -113,12 +113,13 @@ namespace Compiler if (mState==SetMemberVarState) { mMemberName = name; - char type = getContext().getMemberType (mMemberName, mName); + std::pair<char, bool> type = getContext().getMemberType (mMemberName, mName); - if (type!=' ') + if (type.first!=' ') { mState = SetMemberVarState2; - mType = type; + mType = type.first; + mReferenceMember = type.second; return true; } @@ -353,7 +354,8 @@ namespace Compiler std::vector<Interpreter::Type_Code> code; char type = mExprParser.append (code); - Generator::assignToMember (mCode, mLiterals, mType, mMemberName, mName, code, type); + Generator::assignToMember (mCode, mLiterals, mType, mMemberName, mName, code, type, + !mReferenceMember); mState = EndState; return true; diff --git a/components/compiler/lineparser.hpp b/components/compiler/lineparser.hpp index cf72f26a83..0aba30d4b5 100644 --- a/components/compiler/lineparser.hpp +++ b/components/compiler/lineparser.hpp @@ -33,6 +33,7 @@ namespace Compiler State mState; std::string mName; std::string mMemberName; + bool mReferenceMember; int mButtons; std::string mExplicit; char mType; diff --git a/components/interpreter/context.hpp b/components/interpreter/context.hpp index bdba7b6af9..97e4fad4fc 100644 --- a/components/interpreter/context.hpp +++ b/components/interpreter/context.hpp @@ -50,33 +50,33 @@ namespace Interpreter virtual void setGlobalFloat (const std::string& name, float value) = 0; virtual std::vector<std::string> getGlobals () const = 0; - + virtual char getGlobalType (const std::string& name) const = 0; virtual std::string getActionBinding(const std::string& action) const = 0; - + virtual std::string getNPCName() const = 0; - + virtual std::string getNPCRace() const = 0; - + virtual std::string getNPCClass() const = 0; - + virtual std::string getNPCFaction() const = 0; - + virtual std::string getNPCRank() const = 0; virtual std::string getPCName() const = 0; - + virtual std::string getPCRace() const = 0; - + virtual std::string getPCClass() const = 0; - + virtual std::string getPCRank() const = 0; - + virtual std::string getPCNextRank() const = 0; - + virtual int getPCBounty() const = 0; - + virtual std::string getCurrentCellName() const = 0; virtual bool isScriptRunning (const std::string& name) const = 0; @@ -96,17 +96,17 @@ namespace Interpreter virtual void disable (const std::string& id = "") = 0; - virtual int getMemberShort (const std::string& id, const std::string& name) const = 0; + virtual int getMemberShort (const std::string& id, const std::string& name, bool global) const = 0; - virtual int getMemberLong (const std::string& id, const std::string& name) const = 0; + virtual int getMemberLong (const std::string& id, const std::string& name, bool global) const = 0; - virtual float getMemberFloat (const std::string& id, const std::string& name) const = 0; + virtual float getMemberFloat (const std::string& id, const std::string& name, bool global) const = 0; - virtual void setMemberShort (const std::string& id, const std::string& name, int value) = 0; + virtual void setMemberShort (const std::string& id, const std::string& name, int value, bool global) = 0; - virtual void setMemberLong (const std::string& id, const std::string& name, int value) = 0; + virtual void setMemberLong (const std::string& id, const std::string& name, int value, bool global) = 0; - virtual void setMemberFloat (const std::string& id, const std::string& name, float value) + virtual void setMemberFloat (const std::string& id, const std::string& name, float value, bool global) = 0; }; } diff --git a/components/interpreter/docs/vmformat.txt b/components/interpreter/docs/vmformat.txt index 91e0c060e7..990762268f 100644 --- a/components/interpreter/docs/vmformat.txt +++ b/components/interpreter/docs/vmformat.txt @@ -127,5 +127,11 @@ op 61: store stack[0] in member float stack[2] of object with ID stack[1] op 62: replace stack[0] with member short stack[1] of object with ID stack[0] op 63: replace stack[0] with member short stack[1] of object with ID stack[0] op 64: replace stack[0] with member short stack[1] of object with ID stack[0] -opcodes 65-33554431 unused +op 65: store stack[0] in member short stack[2] of global script with ID stack[1] +op 66: store stack[0] in member long stack[2] of global script with ID stack[1] +op 67: store stack[0] in member float stack[2] of global script with ID stack[1] +op 68: replace stack[0] with member short stack[1] of global script with ID stack[0] +op 69: replace stack[0] with member short stack[1] of global script with ID stack[0] +op 70: replace stack[0] with member short stack[1] of global script with ID stack[0] +opcodes 71-33554431 unused opcodes 33554432-67108863 reserved for extensions diff --git a/components/interpreter/installopcodes.cpp b/components/interpreter/installopcodes.cpp index 05f71f1cca..721cde3d8d 100644 --- a/components/interpreter/installopcodes.cpp +++ b/components/interpreter/installopcodes.cpp @@ -40,12 +40,18 @@ namespace Interpreter interpreter.installSegment5 (42, new OpFetchGlobalShort); interpreter.installSegment5 (43, new OpFetchGlobalLong); interpreter.installSegment5 (44, new OpFetchGlobalFloat); - interpreter.installSegment5 (59, new OpStoreMemberShort); - interpreter.installSegment5 (60, new OpStoreMemberLong); - interpreter.installSegment5 (61, new OpStoreMemberFloat); - interpreter.installSegment5 (62, new OpFetchMemberShort); - interpreter.installSegment5 (63, new OpFetchMemberLong); - interpreter.installSegment5 (64, new OpFetchMemberFloat); + interpreter.installSegment5 (59, new OpStoreMemberShort (false)); + interpreter.installSegment5 (60, new OpStoreMemberLong (false)); + interpreter.installSegment5 (61, new OpStoreMemberFloat (false)); + interpreter.installSegment5 (62, new OpFetchMemberShort (false)); + interpreter.installSegment5 (63, new OpFetchMemberLong (false)); + interpreter.installSegment5 (64, new OpFetchMemberFloat (false)); + interpreter.installSegment5 (65, new OpStoreMemberShort (true)); + interpreter.installSegment5 (66, new OpStoreMemberLong (true)); + interpreter.installSegment5 (67, new OpStoreMemberFloat (true)); + interpreter.installSegment5 (68, new OpFetchMemberShort (true)); + interpreter.installSegment5 (69, new OpFetchMemberLong (true)); + interpreter.installSegment5 (70, new OpFetchMemberFloat (true)); // math interpreter.installSegment5 (9, new OpAddInt<Type_Integer>); diff --git a/components/interpreter/localopcodes.hpp b/components/interpreter/localopcodes.hpp index 731c16276d..7844a9ea73 100644 --- a/components/interpreter/localopcodes.hpp +++ b/components/interpreter/localopcodes.hpp @@ -208,8 +208,12 @@ namespace Interpreter class OpStoreMemberShort : public Opcode0 { + bool mGlobal; + public: + OpStoreMemberShort (bool global) : mGlobal (global) {} + virtual void execute (Runtime& runtime) { Type_Integer data = runtime[0].mInteger; @@ -218,7 +222,7 @@ namespace Interpreter index = runtime[2].mInteger; std::string variable = runtime.getStringLiteral (index); - runtime.getContext().setMemberShort (id, variable, data); + runtime.getContext().setMemberShort (id, variable, data, mGlobal); runtime.pop(); runtime.pop(); @@ -228,8 +232,12 @@ namespace Interpreter class OpStoreMemberLong : public Opcode0 { + bool mGlobal; + public: + OpStoreMemberLong (bool global) : mGlobal (global) {} + virtual void execute (Runtime& runtime) { Type_Integer data = runtime[0].mInteger; @@ -238,7 +246,7 @@ namespace Interpreter index = runtime[2].mInteger; std::string variable = runtime.getStringLiteral (index); - runtime.getContext().setMemberLong (id, variable, data); + runtime.getContext().setMemberLong (id, variable, data, mGlobal); runtime.pop(); runtime.pop(); @@ -248,8 +256,12 @@ namespace Interpreter class OpStoreMemberFloat : public Opcode0 { + bool mGlobal; + public: + OpStoreMemberFloat (bool global) : mGlobal (global) {} + virtual void execute (Runtime& runtime) { Type_Float data = runtime[0].mFloat; @@ -258,7 +270,7 @@ namespace Interpreter index = runtime[2].mInteger; std::string variable = runtime.getStringLiteral (index); - runtime.getContext().setMemberFloat (id, variable, data); + runtime.getContext().setMemberFloat (id, variable, data, mGlobal); runtime.pop(); runtime.pop(); @@ -268,8 +280,12 @@ namespace Interpreter class OpFetchMemberShort : public Opcode0 { + bool mGlobal; + public: + OpFetchMemberShort (bool global) : mGlobal (global) {} + virtual void execute (Runtime& runtime) { Type_Integer index = runtime[0].mInteger; @@ -278,15 +294,19 @@ namespace Interpreter std::string variable = runtime.getStringLiteral (index); runtime.pop(); - int value = runtime.getContext().getMemberShort (id, variable); + int value = runtime.getContext().getMemberShort (id, variable, mGlobal); runtime[0].mInteger = value; } }; class OpFetchMemberLong : public Opcode0 { + bool mGlobal; + public: + OpFetchMemberLong (bool global) : mGlobal (global) {} + virtual void execute (Runtime& runtime) { Type_Integer index = runtime[0].mInteger; @@ -295,15 +315,19 @@ namespace Interpreter std::string variable = runtime.getStringLiteral (index); runtime.pop(); - int value = runtime.getContext().getMemberLong (id, variable); + int value = runtime.getContext().getMemberLong (id, variable, mGlobal); runtime[0].mInteger = value; } }; class OpFetchMemberFloat : public Opcode0 { + bool mGlobal; + public: + OpFetchMemberFloat (bool global) : mGlobal (global) {} + virtual void execute (Runtime& runtime) { Type_Integer index = runtime[0].mInteger; @@ -312,7 +336,7 @@ namespace Interpreter std::string variable = runtime.getStringLiteral (index); runtime.pop(); - float value = runtime.getContext().getMemberFloat (id, variable); + float value = runtime.getContext().getMemberFloat (id, variable, mGlobal); runtime[0].mFloat = value; } }; From 5c0071f3205b1e796bcb27a83e451d043a24bd6e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Mon, 10 Feb 2014 14:59:20 +0100 Subject: [PATCH 30/94] fixed spelling of an error message --- components/compiler/generator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/compiler/generator.cpp b/components/compiler/generator.cpp index 83e46d5f7b..c67e51e572 100644 --- a/components/compiler/generator.cpp +++ b/components/compiler/generator.cpp @@ -593,7 +593,7 @@ namespace Compiler else if (offset<0) opJumpBackward (code, -offset); else - throw std::logic_error ("inifite loop"); + throw std::logic_error ("infinite loop"); } void jumpOnZero (CodeContainer& code, int offset) From f26aa4f6455fe5e8b2fe110ba1a5df3a95a200db Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Tue, 11 Feb 2014 13:31:04 +0100 Subject: [PATCH 31/94] fixed while loop implementation --- components/compiler/controlparser.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/components/compiler/controlparser.cpp b/components/compiler/controlparser.cpp index 3be470c273..ba2db62b66 100644 --- a/components/compiler/controlparser.cpp +++ b/components/compiler/controlparser.cpp @@ -9,6 +9,7 @@ #include "generator.hpp" #include "errorhandler.hpp" +#include <iostream> namespace Compiler { bool ControlParser::parseIfBody (int keyword, const TokenLoc& loc, Scanner& scanner) @@ -107,7 +108,7 @@ namespace Compiler Codes expr; mExprParser.append (expr); - Generator::jump (loop, -static_cast<int> (mCodeBlock.size()-expr.size())); + Generator::jump (loop, -static_cast<int> (mCodeBlock.size()+expr.size())); std::copy (expr.begin(), expr.end(), std::back_inserter (mCode)); @@ -121,7 +122,7 @@ namespace Compiler Codes loop2; - Generator::jump (loop2, -static_cast<int> (mCodeBlock.size()-expr.size()-skip.size())); + Generator::jump (loop2, -static_cast<int> (mCodeBlock.size()+expr.size()+skip.size())); if (loop.size()!=loop2.size()) throw std::logic_error ( From 9de2922d22c310ae41a6d80ae5374bc4e6296c2f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Tue, 11 Feb 2014 13:56:56 +0100 Subject: [PATCH 32/94] fixed case problem in remote member variable access --- apps/openmw/mwscript/scriptmanagerimp.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwscript/scriptmanagerimp.cpp b/apps/openmw/mwscript/scriptmanagerimp.cpp index 6862b9f830..11e094a843 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.cpp +++ b/apps/openmw/mwscript/scriptmanagerimp.cpp @@ -7,12 +7,15 @@ #include <exception> #include <components/esm/loadscpt.hpp> -#include "../mwworld/esmstore.hpp" + +#include <components/misc/stringops.hpp> #include <components/compiler/scanner.hpp> #include <components/compiler/context.hpp> #include <components/compiler/exception.hpp> +#include "../mwworld/esmstore.hpp" + #include "extensions.hpp" namespace MWScript @@ -140,15 +143,17 @@ namespace MWScript Compiler::Locals& ScriptManager::getLocals (const std::string& name) { + std::string name2 = Misc::StringUtils::lowerCase (name); + { - ScriptCollection::iterator iter = mScripts.find (name); + ScriptCollection::iterator iter = mScripts.find (name2); if (iter!=mScripts.end()) return iter->second.second; } { - std::map<std::string, Compiler::Locals>::iterator iter = mOtherLocals.find (name); + std::map<std::string, Compiler::Locals>::iterator iter = mOtherLocals.find (name2); if (iter!=mOtherLocals.end()) return iter->second; @@ -156,7 +161,7 @@ namespace MWScript Compiler::Locals locals; - if (const ESM::Script *script = mStore.get<ESM::Script>().find (name)) + if (const ESM::Script *script = mStore.get<ESM::Script>().find (name2)) { int index = 0; @@ -170,7 +175,7 @@ namespace MWScript locals.declare ('f', script->mVarNames[index++]); std::map<std::string, Compiler::Locals>::iterator iter = - mOtherLocals.insert (std::make_pair (name, locals)).first; + mOtherLocals.insert (std::make_pair (name2, locals)).first; return iter->second; } From 697bda63719add550ef35d3144592f278b1b86c6 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Tue, 11 Feb 2014 14:55:31 +0100 Subject: [PATCH 33/94] allow (and discard) explicit reference on instructions that do not accept explicit references --- components/compiler/extensions.cpp | 4 ++-- components/compiler/extensions.hpp | 4 +++- components/compiler/lineparser.cpp | 17 ++++++++++++++++- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/components/compiler/extensions.cpp b/components/compiler/extensions.cpp index c6a74b234b..6f5c2fc897 100644 --- a/components/compiler/extensions.cpp +++ b/components/compiler/extensions.cpp @@ -38,7 +38,7 @@ namespace Compiler } bool Extensions::isInstruction (int keyword, std::string& argumentType, - bool explicitReference) const + bool& explicitReference) const { std::map<int, Instruction>::const_iterator iter = mInstructions.find (keyword); @@ -46,7 +46,7 @@ namespace Compiler return false; if (explicitReference && iter->second.mCodeExplicit==-1) - return false; + explicitReference = false; argumentType = iter->second.mArguments; return true; diff --git a/components/compiler/extensions.hpp b/components/compiler/extensions.hpp index 53ebfa31b5..585c42681c 100644 --- a/components/compiler/extensions.hpp +++ b/components/compiler/extensions.hpp @@ -52,8 +52,10 @@ namespace Compiler /// types. bool isInstruction (int keyword, std::string& argumentType, - bool explicitReference) const; + bool& explicitReference) const; ///< Is this keyword registered with a function? If yes, return argument types. + /// \param explicitReference In: has explicit reference; Out: set to false, if + /// explicit reference is not available for this instruction. void registerFunction (const std::string& keyword, char returnType, const std::string& argumentType, int code, int codeExplicit = -1); diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 5987a48031..3b27905d46 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -234,8 +234,15 @@ namespace Compiler { std::string argumentType; - if (extensions->isInstruction (keyword, argumentType, mState==ExplicitState)) + bool hasExplicit = mState==ExplicitState; + if (extensions->isInstruction (keyword, argumentType, hasExplicit)) { + if (!hasExplicit && mState==ExplicitState) + { + getErrorHandler().warning ("stray explicit reference (ignoring it)", loc); + mExplicit.clear(); + } + int optionals = mExprParser.parseArguments (argumentType, scanner, mCode, true); extensions->generateInstructionCode (keyword, mCode, mLiterals, mExplicit, optionals); @@ -271,6 +278,14 @@ namespace Compiler } } + if (mState==ExplicitState) + { + // drop stray explicit reference + getErrorHandler().warning ("stray explicit reference (ignoring it)", loc); + mState = BeginState; + mExplicit.clear(); + } + if (mState==BeginState) { switch (keyword) From 6a5d88b640c0ba26f8431e14e891411dcca505c2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Wed, 12 Feb 2014 08:42:42 +0100 Subject: [PATCH 34/94] ignore stray else and endif in scripts --- components/compiler/lineparser.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 3b27905d46..4a5e1cbd09 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -332,6 +332,18 @@ namespace Compiler Generator::stopScript (mCode); mState = EndState; return true; + + case Scanner::K_else: + + getErrorHandler().warning ("stay else (ignoring it)", loc); + mState = EndState; + return true; + + case Scanner::K_endif: + + getErrorHandler().warning ("stay endif (ignoring it)", loc); + mState = EndState; + return true; } } else if (mState==SetLocalVarState && keyword==Scanner::K_to) From 61626e90da98641db5da0e33457977311ec30c6f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Wed, 12 Feb 2014 08:53:37 +0100 Subject: [PATCH 35/94] allow additional string argument for stopcombat and addspell (ignored) --- components/compiler/exprparser.cpp | 25 ++++++++++++++----------- components/compiler/exprparser.hpp | 1 + components/compiler/extensions0.cpp | 4 ++-- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 283da854c9..4af11ec2be 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -705,11 +705,11 @@ namespace Compiler { optional = true; } - else if (*iter=='S' || *iter=='c') + else if (*iter=='S' || *iter=='c' || *iter=='x') { stringParser.reset(); - if (optional) + if (optional || *iter=='x') stringParser.setOptional (true); if (*iter=='c') stringParser.smashCase(); @@ -718,18 +718,21 @@ namespace Compiler if (optional && stringParser.isEmpty()) break; - if (invert) + if (*iter!='x') { - std::vector<Interpreter::Type_Code> tmp; - stringParser.append (tmp); + if (invert) + { + std::vector<Interpreter::Type_Code> tmp; + stringParser.append (tmp); - stack.push (tmp); + stack.push (tmp); + } + else + stringParser.append (code); + + if (optional) + ++optionalCount; } - else - stringParser.append (code); - - if (optional) - ++optionalCount; } else { diff --git a/components/compiler/exprparser.hpp b/components/compiler/exprparser.hpp index 8ce5409d23..905f0d454f 100644 --- a/components/compiler/exprparser.hpp +++ b/components/compiler/exprparser.hpp @@ -101,6 +101,7 @@ namespace Compiler /// \param arguments Each character represents one arguments ('l': integer, /// 'f': float, 'S': string, 'c': string (case smashed), '/': following arguments are /// optional) + /// 'x': optional string that will be ignored (die in a fire, MW script compiler!) /// \param invert Store arguments in reverted order. /// \return number of optional arguments }; diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index ebe46d2826..53f1baaf9d 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -62,7 +62,7 @@ namespace Compiler extensions.registerInstruction ("toggleai", "", opcodeToggleAI, opcodeToggleAI); extensions.registerInstruction ("tai", "", opcodeToggleAI, opcodeToggleAI); extensions.registerInstruction("startcombat", "c", opcodeStartCombat, opcodeStartCombatExplicit); - extensions.registerInstruction("stopcombat", "", opcodeStopCombat, opcodeStopCombatExplicit); + extensions.registerInstruction("stopcombat", "x", opcodeStopCombat, opcodeStopCombatExplicit); extensions.registerFunction ("gethello", 'l', "", opcodeGetHello, opcodeGetHelloExplicit); extensions.registerFunction ("getfight", 'l', "", opcodeGetFight, opcodeGetFightExplicit); extensions.registerFunction ("getflee", 'l', "", opcodeGetFlee, opcodeGetFleeExplicit); @@ -398,7 +398,7 @@ namespace Compiler extensions.registerInstruction ("setpccrimelevel", "f", opcodeSetPCCrimeLevel); extensions.registerInstruction ("modpccrimelevel", "f", opcodeModPCCrimeLevel); - extensions.registerInstruction ("addspell", "c", opcodeAddSpell, opcodeAddSpellExplicit); + extensions.registerInstruction ("addspell", "cx", opcodeAddSpell, opcodeAddSpellExplicit); extensions.registerInstruction ("removespell", "c", opcodeRemoveSpell, opcodeRemoveSpellExplicit); extensions.registerInstruction ("removespelleffects", "c", opcodeRemoveSpellEffects, From bfb0e62c4ab2fc3b6cb391e40ba8a70adc6c3c28 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Wed, 12 Feb 2014 09:10:05 +0100 Subject: [PATCH 36/94] ignore additional string argument after enable/disable --- components/compiler/lineparser.cpp | 14 +++++++++++--- components/compiler/lineparser.hpp | 2 +- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 4a5e1cbd09..3b2b1f11b3 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -84,6 +84,13 @@ namespace Compiler bool LineParser::parseName (const std::string& name, const TokenLoc& loc, Scanner& scanner) { + if (mState==PotentialEndState) + { + getErrorHandler().warning ("stay string argument (ignoring it)", loc); + mState = EndState; + return true; + } + if (mState==SetState) { std::string name2 = Misc::StringUtils::lowerCase (name); @@ -219,13 +226,13 @@ namespace Compiler case Scanner::K_enable: Generator::enable (mCode, mLiterals, mExplicit); - mState = EndState; + mState = PotentialEndState; return true; case Scanner::K_disable: Generator::disable (mCode, mLiterals, mExplicit); - mState = EndState; + mState = PotentialEndState; return true; } @@ -406,7 +413,8 @@ namespace Compiler bool LineParser::parseSpecial (int code, const TokenLoc& loc, Scanner& scanner) { - if (code==Scanner::S_newline && (mState==EndState || mState==BeginState)) + if (code==Scanner::S_newline && + (mState==EndState || mState==BeginState || mState==PotentialEndState)) return false; if (code==Scanner::S_comma && mState==MessageState) diff --git a/components/compiler/lineparser.hpp b/components/compiler/lineparser.hpp index 0aba30d4b5..c54c764bce 100644 --- a/components/compiler/lineparser.hpp +++ b/components/compiler/lineparser.hpp @@ -23,7 +23,7 @@ namespace Compiler SetState, SetLocalVarState, SetGlobalVarState, SetPotentialMemberVarState, SetMemberVarState, SetMemberVarState2, MessageState, MessageCommaState, MessageButtonState, MessageButtonCommaState, - EndState, + EndState, PotentialEndState /* may have a stray string argument */, PotentialExplicitState, ExplicitState, MemberState }; From b1b0877122a21d48898b46ef49c3062168a5b8fc Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Wed, 12 Feb 2014 09:14:32 +0100 Subject: [PATCH 37/94] allow additional numeric argument for AiFollow and ignore it --- components/compiler/extensions0.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index 53f1baaf9d..5079a6064e 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -41,7 +41,7 @@ namespace Compiler opcodeAiEscortCellExplicit); extensions.registerInstruction ("aiwander", "fff/llllllllll", opcodeAiWander, opcodeAiWanderExplicit); - extensions.registerInstruction ("aifollow", "cffff/l", opcodeAiFollow, + extensions.registerInstruction ("aifollow", "cffff/ll", opcodeAiFollow, opcodeAiFollowExplicit); extensions.registerInstruction ("aifollowcell", "ccffff/l", opcodeAiFollowCell, opcodeAiFollowCellExplicit); From c0a6acfe6cb7cf3ea6277c2539de571d6e55ad1e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Wed, 12 Feb 2014 09:23:23 +0100 Subject: [PATCH 38/94] allow the use of keywords as variable names in more places --- components/compiler/lineparser.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 3b2b1f11b3..3ae24bfb75 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -219,6 +219,12 @@ namespace Compiler bool LineParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner) { + if (mState==SetState) + { + // allow keywords to be used as variable names when assigning a value to a variable. + return parseName (loc.mLiteral, loc, scanner); + } + if (mState==BeginState || mState==ExplicitState) { switch (keyword) From 93d47430125be4d766d6937541ba826138a790a2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Wed, 12 Feb 2014 09:56:25 +0100 Subject: [PATCH 39/94] interpret instruction keywords as names within expressions --- components/compiler/exprparser.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 4af11ec2be..319bb44988 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -344,6 +344,17 @@ namespace Compiler bool ExprParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner) { + if (const Extensions *extensions = getContext().getExtensions()) + { + std::string argumentType; // ignored + bool hasExplicit = false; // ignored + if (extensions->isInstruction (keyword, argumentType, hasExplicit)) + { + // pretend this is not a keyword + return parseName (loc.mLiteral, loc, scanner); + } + } + mFirst = false; if (!mExplicit.empty()) From 388735046fdb75b34744f1c292a8a349f4ab4f40 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Wed, 12 Feb 2014 13:35:24 +0100 Subject: [PATCH 40/94] fixed broken remote member variable access --- apps/openmw/mwscript/interpretercontext.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index 17092b41ca..b79808d08b 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -66,7 +66,7 @@ namespace MWScript { const MWWorld::Ptr ptr = getReference (id, false); - std::string id = MWWorld::Class::get (ptr).getScript (ptr); + id = MWWorld::Class::get (ptr).getScript (ptr); ptr.getRefData().setLocals ( *MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (id)); @@ -86,7 +86,7 @@ namespace MWScript { const MWWorld::Ptr ptr = getReference (id, false); - std::string id = MWWorld::Class::get (ptr).getScript (ptr); + id = MWWorld::Class::get (ptr).getScript (ptr); ptr.getRefData().setLocals ( *MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (id)); From dc433a3c093c1a060e2c71c31a9d09a061834093 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Wed, 12 Feb 2014 13:38:16 +0100 Subject: [PATCH 41/94] fixed case handling problem for local variable access --- apps/openmw/mwscript/scriptmanagerimp.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/scriptmanagerimp.cpp b/apps/openmw/mwscript/scriptmanagerimp.cpp index 11e094a843..5e18151da4 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.cpp +++ b/apps/openmw/mwscript/scriptmanagerimp.cpp @@ -221,8 +221,10 @@ namespace MWScript throw std::runtime_error ("invalid variable type"); } + std::string variable2 = Misc::StringUtils::lowerCase (variable); + for (int i=0; i<size; ++i) - if (script->mVarNames.at (i+offset)==variable) + if (Misc::StringUtils::lowerCase (script->mVarNames.at (i+offset))==variable2) return i; throw std::runtime_error ("unable to access local variable " + variable + " of " + scriptId); From 6e2e4d1adf9000a81a49c3f7f1bee2245edf933d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Wed, 12 Feb 2014 13:45:01 +0100 Subject: [PATCH 42/94] ignore stray begin --- components/compiler/lineparser.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 3ae24bfb75..1407d0e956 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -357,6 +357,12 @@ namespace Compiler getErrorHandler().warning ("stay endif (ignoring it)", loc); mState = EndState; return true; + + case Scanner::K_begin: + + getErrorHandler().warning ("stay begin (ignoring it)", loc); + mState = EndState; + return true; } } else if (mState==SetLocalVarState && keyword==Scanner::K_to) From a85d3c7dcb52db79ad8ab0314063e134153e6742 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Wed, 12 Feb 2014 13:53:59 +0100 Subject: [PATCH 43/94] ignore unused explicit references for functions --- components/compiler/exprparser.cpp | 13 +++++++++++-- components/compiler/extensions.cpp | 4 ++-- components/compiler/extensions.hpp | 4 +++- components/compiler/lineparser.cpp | 11 +++++++++-- 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 319bb44988..07f576006f 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -397,8 +397,15 @@ namespace Compiler char returnType; std::string argumentType; - if (extensions->isFunction (keyword, returnType, argumentType, true)) + bool hasExplicit = true; + if (extensions->isFunction (keyword, returnType, argumentType, hasExplicit)) { + if (!hasExplicit) + { + getErrorHandler().warning ("stray explicit reference (ignoring it)", loc); + mExplicit.clear(); + } + start(); mTokenLoc = loc; @@ -519,7 +526,9 @@ namespace Compiler char returnType; std::string argumentType; - if (extensions->isFunction (keyword, returnType, argumentType, false)) + bool hasExplicit = false; + + if (extensions->isFunction (keyword, returnType, argumentType, hasExplicit)) { mTokenLoc = loc; int optionals = parseArguments (argumentType, scanner); diff --git a/components/compiler/extensions.cpp b/components/compiler/extensions.cpp index 6f5c2fc897..c09abcbafd 100644 --- a/components/compiler/extensions.cpp +++ b/components/compiler/extensions.cpp @@ -22,7 +22,7 @@ namespace Compiler } bool Extensions::isFunction (int keyword, char& returnType, std::string& argumentType, - bool explicitReference) const + bool& explicitReference) const { std::map<int, Function>::const_iterator iter = mFunctions.find (keyword); @@ -30,7 +30,7 @@ namespace Compiler return false; if (explicitReference && iter->second.mCodeExplicit==-1) - return false; + explicitReference = false; returnType = iter->second.mReturn; argumentType = iter->second.mArguments; diff --git a/components/compiler/extensions.hpp b/components/compiler/extensions.hpp index 585c42681c..79cfed9e86 100644 --- a/components/compiler/extensions.hpp +++ b/components/compiler/extensions.hpp @@ -47,9 +47,11 @@ namespace Compiler /// - keyword must be all lower case. bool isFunction (int keyword, char& returnType, std::string& argumentType, - bool explicitReference) const; + bool& explicitReference) const; ///< Is this keyword registered with a function? If yes, return return and argument /// types. + /// \param explicitReference In: has explicit reference; Out: set to false, if + /// explicit reference is not available for this instruction. bool isInstruction (int keyword, std::string& argumentType, bool& explicitReference) const; diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 1407d0e956..e435b936c3 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -279,9 +279,16 @@ namespace Compiler char returnType; std::string argumentType; - if (extensions->isFunction (keyword, returnType, argumentType, - !mExplicit.empty())) + bool hasExplicit = !mExplicit.empty(); + + if (extensions->isFunction (keyword, returnType, argumentType, hasExplicit)) { + if (!hasExplicit && !mExplicit.empty()) + { + getErrorHandler().warning ("stray explicit reference (ignoring it)", loc); + mExplicit.clear(); + } + scanner.putbackKeyword (keyword, loc); parseExpression (scanner, loc); mState = EndState; From b3412b7eec1c19ae427201c544d778d18cff7a1a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Wed, 12 Feb 2014 15:22:17 +0100 Subject: [PATCH 44/94] another case fix (remote member access again) --- apps/openmw/mwscript/compilercontext.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/compilercontext.cpp b/apps/openmw/mwscript/compilercontext.cpp index 8018b86e02..1b3e769bf1 100644 --- a/apps/openmw/mwscript/compilercontext.cpp +++ b/apps/openmw/mwscript/compilercontext.cpp @@ -52,7 +52,8 @@ namespace MWScript char type = ' '; if (!script.empty()) - type = MWBase::Environment::get().getScriptManager()->getLocals (script).getType (name); + type = MWBase::Environment::get().getScriptManager()->getLocals (script).getType ( + Misc::StringUtils::lowerCase (name)); return std::make_pair (type, reference); } From 749136bf3394df4498eb1f672313124b3365c1cc Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Wed, 12 Feb 2014 20:23:47 +0100 Subject: [PATCH 45/94] ignore attempts to set non-existing variables --- components/compiler/lineparser.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index e435b936c3..495e7e25e5 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -219,6 +219,14 @@ namespace Compiler bool LineParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner) { + if (mState==SetPotentialMemberVarState && keyword==Scanner::K_to) + { + getErrorHandler().warning ("unknown variable (ignoring set instruction)", loc); + SkipParser skip (getErrorHandler(), getContext()); + scanner.scan (skip); + return false; + } + if (mState==SetState) { // allow keywords to be used as variable names when assigning a value to a variable. From 2eeb0eb4f3fcc60ee206b7fb53786a66a3d2d04c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Thu, 13 Feb 2014 08:38:26 +0100 Subject: [PATCH 46/94] allow lines to continue with other instructions after an legit else --- components/compiler/controlparser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/compiler/controlparser.cpp b/components/compiler/controlparser.cpp index ba2db62b66..60d17a8216 100644 --- a/components/compiler/controlparser.cpp +++ b/components/compiler/controlparser.cpp @@ -72,7 +72,7 @@ namespace Compiler } else if (keyword==Scanner::K_else) { - mState = IfElseEndState; + mState = IfElseBodyState; /// \todo should be IfElseEndState; add an option for that } return true; From 0313876d88f9eb55c8ed43a9b79787ec17866b05 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Thu, 13 Feb 2014 08:49:40 +0100 Subject: [PATCH 47/94] allow leaving out if in a top-level if-statement --- components/compiler/scriptparser.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/compiler/scriptparser.cpp b/components/compiler/scriptparser.cpp index 1b613595a6..f34313969a 100644 --- a/components/compiler/scriptparser.cpp +++ b/components/compiler/scriptparser.cpp @@ -71,6 +71,12 @@ namespace Compiler if (code==Scanner::S_newline) // empty line return true; + if (code==Scanner::S_open) /// \todo Option to switch this off + { + scanner.putbackSpecial (code, loc); + return parseKeyword (Scanner::K_if, loc, scanner); + } + mLineParser.reset(); if (mLineParser.parseSpecial (code, loc, scanner)) scanner.scan (mLineParser); From c03bd8ebb6c3b18869c75350f1c276ed03dfdb0e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Thu, 13 Feb 2014 08:59:33 +0100 Subject: [PATCH 48/94] allow [] as aliases for () --- components/compiler/scanner.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/compiler/scanner.cpp b/components/compiler/scanner.cpp index 816443c447..46e50a2e9b 100644 --- a/components/compiler/scanner.cpp +++ b/components/compiler/scanner.cpp @@ -370,9 +370,9 @@ namespace Compiler if (c=='\n') special = S_newline; - else if (c=='(') + else if (c=='(' || c=='[') /// \todo option to disable the use of [ as alias for ( special = S_open; - else if (c==')') + else if (c==')' || c==']') /// \todo option to disable the use of ] as alias for ) special = S_close; else if (c=='.') { From 87b51e47a9d1357d3e1c6968ea3add6ddd58d8d5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Thu, 13 Feb 2014 09:40:07 +0100 Subject: [PATCH 49/94] fixed another case issue in remote member access --- components/compiler/controlparser.cpp | 1 - components/compiler/locals.cpp | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/components/compiler/controlparser.cpp b/components/compiler/controlparser.cpp index 60d17a8216..499358ca02 100644 --- a/components/compiler/controlparser.cpp +++ b/components/compiler/controlparser.cpp @@ -9,7 +9,6 @@ #include "generator.hpp" #include "errorhandler.hpp" -#include <iostream> namespace Compiler { bool ControlParser::parseIfBody (int keyword, const TokenLoc& loc, Scanner& scanner) diff --git a/components/compiler/locals.cpp b/components/compiler/locals.cpp index e2b1c5c966..60a5704bf3 100644 --- a/components/compiler/locals.cpp +++ b/components/compiler/locals.cpp @@ -7,6 +7,8 @@ #include <ostream> #include <iterator> +#include <components/misc/stringops.hpp> + namespace Compiler { const std::vector<std::string>& Locals::get (char type) const @@ -97,7 +99,7 @@ namespace Compiler void Locals::declare (char type, const std::string& name) { - get (type).push_back (name); + get (type).push_back (Misc::StringUtils::lowerCase (name)); } void Locals::clear() From dde4fbd8184211700be7d5e5bd1651acafeeb1cb Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Thu, 13 Feb 2014 09:52:44 +0100 Subject: [PATCH 50/94] allow one more integer argument in RemoveSoulGem and up to 6 more in AiFollow and then throw them all away --- apps/openmw/mwscript/docs/vmformat.txt | 8 +++++--- apps/openmw/mwscript/miscextensions.cpp | 12 ++++++++---- components/compiler/extensions0.cpp | 4 ++-- components/compiler/opcodes.hpp | 4 ++-- 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 2fe4c768ba..70186a089b 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -52,7 +52,9 @@ op 0x20023: AiFollow, explicit reference op 0x20024: AiFollowCell op 0x20025: AiFollowCell, explicit reference op 0x20026: ModRegion -opcodes 0x20027-0x3ffff unused +op 0x20027: RemoveSoulGem +op 0x20028: RemoveSoulGem, explicit reference +opcodes 0x20029-0x3ffff unused Segment 4: (not implemented yet) @@ -308,8 +310,8 @@ op 0x20001f1: GetDetected op 0x20001f2: GetDetected, explicit reference op 0x20001f3: AddSoulGem op 0x20001f4: AddSoulGem, explicit reference -op 0x20001f5: RemoveSoulGem -op 0x20001f6: RemoveSoulGem, explicit reference +op 0x20001f5: unused +op 0x20001f6: unused op 0x20001f7: PlayBink op 0x20001f8: Drop op 0x20001f9: Drop, explicit reference diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index aa0e775af2..0c60e1c940 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -365,17 +365,21 @@ namespace MWScript }; template<class R> - class OpRemoveSoulGem : public Interpreter::Opcode0 + class OpRemoveSoulGem : public Interpreter::Opcode1 { public: - virtual void execute (Interpreter::Runtime& runtime) + virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) { MWWorld::Ptr ptr = R()(runtime); std::string soul = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); + // throw away additional arguments + for (unsigned int i=0; i<arg0; ++i) + runtime.pop(); + MWWorld::ContainerStore& store = MWWorld::Class::get (ptr).getContainerStore (ptr); for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) { @@ -872,8 +876,8 @@ namespace MWScript interpreter.installSegment5 (Compiler::Misc::opcodeGetEffectExplicit, new OpGetEffect<ExplicitRef>); interpreter.installSegment5 (Compiler::Misc::opcodeAddSoulGem, new OpAddSoulGem<ImplicitRef>); interpreter.installSegment5 (Compiler::Misc::opcodeAddSoulGemExplicit, new OpAddSoulGem<ExplicitRef>); - interpreter.installSegment5 (Compiler::Misc::opcodeRemoveSoulGem, new OpRemoveSoulGem<ImplicitRef>); - interpreter.installSegment5 (Compiler::Misc::opcodeRemoveSoulGemExplicit, new OpRemoveSoulGem<ExplicitRef>); + interpreter.installSegment3 (Compiler::Misc::opcodeRemoveSoulGem, new OpRemoveSoulGem<ImplicitRef>); + interpreter.installSegment3 (Compiler::Misc::opcodeRemoveSoulGemExplicit, new OpRemoveSoulGem<ExplicitRef>); interpreter.installSegment5 (Compiler::Misc::opcodeDrop, new OpDrop<ImplicitRef>); interpreter.installSegment5 (Compiler::Misc::opcodeDropExplicit, new OpDrop<ExplicitRef>); interpreter.installSegment5 (Compiler::Misc::opcodeDropSoulGem, new OpDropSoulGem<ImplicitRef>); diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index 5079a6064e..78b6409f22 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -41,7 +41,7 @@ namespace Compiler opcodeAiEscortCellExplicit); extensions.registerInstruction ("aiwander", "fff/llllllllll", opcodeAiWander, opcodeAiWanderExplicit); - extensions.registerInstruction ("aifollow", "cffff/ll", opcodeAiFollow, + extensions.registerInstruction ("aifollow", "cffff/llllllll", opcodeAiFollow, opcodeAiFollowExplicit); extensions.registerInstruction ("aifollowcell", "ccffff/l", opcodeAiFollowCell, opcodeAiFollowCellExplicit); @@ -253,7 +253,7 @@ namespace Compiler extensions.registerFunction ("getlocked", 'l', "", opcodeGetLocked, opcodeGetLockedExplicit); extensions.registerFunction ("geteffect", 'l', "S", opcodeGetEffect, opcodeGetEffectExplicit); extensions.registerInstruction ("addsoulgem", "cc", opcodeAddSoulGem, opcodeAddSoulGemExplicit); - extensions.registerInstruction ("removesoulgem", "c", opcodeRemoveSoulGem, opcodeRemoveSoulGemExplicit); + extensions.registerInstruction ("removesoulgem", "c/l", opcodeRemoveSoulGem, opcodeRemoveSoulGemExplicit); extensions.registerInstruction ("drop", "cl", opcodeDrop, opcodeDropExplicit); extensions.registerInstruction ("dropsoulgem", "c", opcodeDropSoulGem, opcodeDropSoulGemExplicit); extensions.registerFunction ("getattacked", 'l', "", opcodeGetAttacked, opcodeGetAttackedExplicit); diff --git a/components/compiler/opcodes.hpp b/components/compiler/opcodes.hpp index 583cf4eea3..1dbdbf7e72 100644 --- a/components/compiler/opcodes.hpp +++ b/components/compiler/opcodes.hpp @@ -203,8 +203,8 @@ namespace Compiler const int opcodeGetEffectExplicit = 0x20001d0; const int opcodeAddSoulGem = 0x20001f3; const int opcodeAddSoulGemExplicit = 0x20001f4; - const int opcodeRemoveSoulGem = 0x20001f5; - const int opcodeRemoveSoulGemExplicit = 0x20001f6; + const int opcodeRemoveSoulGem = 0x20027; + const int opcodeRemoveSoulGemExplicit = 0x20028; const int opcodeDrop = 0x20001f8; const int opcodeDropExplicit = 0x20001f9; const int opcodeDropSoulGem = 0x20001fa; From ac8290c4d3b329073a49369fde82a33d023998a2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Thu, 13 Feb 2014 09:59:22 +0100 Subject: [PATCH 51/94] fixed problem with line endings in case of a local variable redeclaration --- components/compiler/declarationparser.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/components/compiler/declarationparser.cpp b/components/compiler/declarationparser.cpp index 586b28bc29..9c4e4f631b 100644 --- a/components/compiler/declarationparser.cpp +++ b/components/compiler/declarationparser.cpp @@ -27,8 +27,7 @@ bool Compiler::DeclarationParser::parseName (const std::string& name, const Toke /// \todo add option to make re-declared local variables an error getErrorHandler().warning ("can't re-declare local variable (ignoring declaration)", loc); - SkipParser skip (getErrorHandler(), getContext()); - scanner.scan (skip); + mState = State_End; return true; } From fb0c5be536de767a14deb5a2a34c7744269db826 Mon Sep 17 00:00:00 2001 From: scrawl <scrawl@baseoftrash.de> Date: Thu, 13 Feb 2014 10:13:03 +0100 Subject: [PATCH 52/94] Don't suppress git error output --- cmake/GetGitRevisionDescription.cmake | 2 -- 1 file changed, 2 deletions(-) diff --git a/cmake/GetGitRevisionDescription.cmake b/cmake/GetGitRevisionDescription.cmake index f70f64261f..fecd1654db 100644 --- a/cmake/GetGitRevisionDescription.cmake +++ b/cmake/GetGitRevisionDescription.cmake @@ -122,7 +122,6 @@ function(git_describe _var) res OUTPUT_VARIABLE out - ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) if(NOT res EQUAL 0) @@ -147,7 +146,6 @@ function(get_git_tag_revision _var) res OUTPUT_VARIABLE out - ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) if(NOT res EQUAL 0) set(out "${out}-${res}-NOTFOUND") From c6fb0f2d9bf2540d8c23817174d8066485a7f5f1 Mon Sep 17 00:00:00 2001 From: scrawl <scrawl@baseoftrash.de> Date: Thu, 13 Feb 2014 10:13:53 +0100 Subject: [PATCH 53/94] Removed terrain component's dependency on ESM --- apps/openmw/mwrender/terrainstorage.cpp | 514 ++++++++++++++++++++++++ apps/openmw/mwrender/terrainstorage.hpp | 69 +++- components/terrain/chunk.cpp | 6 +- components/terrain/quadtreenode.cpp | 6 +- components/terrain/quadtreenode.hpp | 2 +- components/terrain/storage.cpp | 509 ----------------------- components/terrain/storage.hpp | 37 +- components/terrain/world.cpp | 101 ++--- 8 files changed, 650 insertions(+), 594 deletions(-) diff --git a/apps/openmw/mwrender/terrainstorage.cpp b/apps/openmw/mwrender/terrainstorage.cpp index 318627fc70..197572db9d 100644 --- a/apps/openmw/mwrender/terrainstorage.cpp +++ b/apps/openmw/mwrender/terrainstorage.cpp @@ -1,5 +1,14 @@ #include "terrainstorage.hpp" +#include <OgreVector2.h> +#include <OgreTextureManager.h> +#include <OgreStringConverter.h> +#include <OgreRenderSystem.h> +#include <OgreResourceGroupManager.h> +#include <OgreRoot.h> + +#include <boost/algorithm/string.hpp> + #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwworld/esmstore.hpp" @@ -53,4 +62,509 @@ namespace MWRender return esmStore.get<ESM::LandTexture>().find(index, plugin); } + bool TerrainStorage::getMinMaxHeights(float size, const Ogre::Vector2 ¢er, float &min, float &max) + { + assert (size <= 1 && "TerrainStorage::getMinMaxHeights, chunk size should be <= 1 cell"); + + /// \todo investigate if min/max heights should be stored at load time in ESM::Land instead + + Ogre::Vector2 origin = center - Ogre::Vector2(size/2.f, size/2.f); + + assert(origin.x == (int) origin.x); + assert(origin.y == (int) origin.y); + + int cellX = origin.x; + int cellY = origin.y; + + const ESM::Land* land = getLand(cellX, cellY); + if (!land) + return false; + + min = std::numeric_limits<float>().max(); + max = -std::numeric_limits<float>().max(); + for (int row=0; row<ESM::Land::LAND_SIZE; ++row) + { + for (int col=0; col<ESM::Land::LAND_SIZE; ++col) + { + float h = land->mLandData->mHeights[col*ESM::Land::LAND_SIZE+row]; + if (h > max) + max = h; + if (h < min) + min = h; + } + } + return true; + } + + void TerrainStorage::fixNormal (Ogre::Vector3& normal, int cellX, int cellY, int col, int row) + { + while (col >= ESM::Land::LAND_SIZE-1) + { + ++cellY; + col -= ESM::Land::LAND_SIZE-1; + } + while (row >= ESM::Land::LAND_SIZE-1) + { + ++cellX; + row -= ESM::Land::LAND_SIZE-1; + } + while (col < 0) + { + --cellY; + col += ESM::Land::LAND_SIZE-1; + } + while (row < 0) + { + --cellX; + row += ESM::Land::LAND_SIZE-1; + } + ESM::Land* land = getLand(cellX, cellY); + if (land && land->mHasData) + { + normal.x = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3]; + normal.y = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+1]; + normal.z = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+2]; + normal.normalise(); + } + else + normal = Ogre::Vector3(0,0,1); + } + + void TerrainStorage::averageNormal(Ogre::Vector3 &normal, int cellX, int cellY, int col, int row) + { + Ogre::Vector3 n1,n2,n3,n4; + fixNormal(n1, cellX, cellY, col+1, row); + fixNormal(n2, cellX, cellY, col-1, row); + fixNormal(n3, cellX, cellY, col, row+1); + fixNormal(n4, cellX, cellY, col, row-1); + normal = (n1+n2+n3+n4); + normal.normalise(); + } + + void TerrainStorage::fixColour (Ogre::ColourValue& color, int cellX, int cellY, int col, int row) + { + if (col == ESM::Land::LAND_SIZE-1) + { + ++cellY; + col = 0; + } + if (row == ESM::Land::LAND_SIZE-1) + { + ++cellX; + row = 0; + } + ESM::Land* land = getLand(cellX, cellY); + if (land && land->mLandData->mUsingColours) + { + color.r = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3] / 255.f; + color.g = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+1] / 255.f; + color.b = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+2] / 255.f; + } + else + { + color.r = 1; + color.g = 1; + color.b = 1; + } + + } + + void TerrainStorage::fillVertexBuffers (int lodLevel, float size, const Ogre::Vector2& center, + Ogre::HardwareVertexBufferSharedPtr vertexBuffer, + Ogre::HardwareVertexBufferSharedPtr normalBuffer, + Ogre::HardwareVertexBufferSharedPtr colourBuffer) + { + // LOD level n means every 2^n-th vertex is kept + size_t increment = 1 << lodLevel; + + Ogre::Vector2 origin = center - Ogre::Vector2(size/2.f, size/2.f); + assert(origin.x == (int) origin.x); + assert(origin.y == (int) origin.y); + + int startX = origin.x; + int startY = origin.y; + + size_t numVerts = size*(ESM::Land::LAND_SIZE-1)/increment + 1; + + std::vector<uint8_t> colors; + colors.resize(numVerts*numVerts*4); + std::vector<float> positions; + positions.resize(numVerts*numVerts*3); + std::vector<float> normals; + normals.resize(numVerts*numVerts*3); + + Ogre::Vector3 normal; + Ogre::ColourValue color; + + float vertY; + float vertX; + + float vertY_ = 0; // of current cell corner + for (int cellY = startY; cellY < startY + std::ceil(size); ++cellY) + { + float vertX_ = 0; // of current cell corner + for (int cellX = startX; cellX < startX + std::ceil(size); ++cellX) + { + ESM::Land* land = getLand(cellX, cellY); + if (land && !land->mHasData) + land = NULL; + bool hasColors = land && land->mLandData->mUsingColours; + + int rowStart = 0; + int colStart = 0; + // Skip the first row / column unless we're at a chunk edge, + // since this row / column is already contained in a previous cell + if (colStart == 0 && vertY_ != 0) + colStart += increment; + if (rowStart == 0 && vertX_ != 0) + rowStart += increment; + + vertY = vertY_; + for (int col=colStart; col<ESM::Land::LAND_SIZE; col += increment) + { + vertX = vertX_; + for (int row=rowStart; row<ESM::Land::LAND_SIZE; row += increment) + { + positions[vertX*numVerts*3 + vertY*3] = ((vertX/float(numVerts-1)-0.5) * size * 8192); + positions[vertX*numVerts*3 + vertY*3 + 1] = ((vertY/float(numVerts-1)-0.5) * size * 8192); + if (land) + positions[vertX*numVerts*3 + vertY*3 + 2] = land->mLandData->mHeights[col*ESM::Land::LAND_SIZE+row]; + else + positions[vertX*numVerts*3 + vertY*3 + 2] = -2048; + + if (land) + { + normal.x = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3]; + normal.y = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+1]; + normal.z = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+2]; + normal.normalise(); + } + else + normal = Ogre::Vector3(0,0,1); + + // Normals apparently don't connect seamlessly between cells + if (col == ESM::Land::LAND_SIZE-1 || row == ESM::Land::LAND_SIZE-1) + fixNormal(normal, cellX, cellY, col, row); + + // some corner normals appear to be complete garbage (z < 0) + if ((row == 0 || row == ESM::Land::LAND_SIZE-1) && (col == 0 || col == ESM::Land::LAND_SIZE-1)) + averageNormal(normal, cellX, cellY, col, row); + + assert(normal.z > 0); + + normals[vertX*numVerts*3 + vertY*3] = normal.x; + normals[vertX*numVerts*3 + vertY*3 + 1] = normal.y; + normals[vertX*numVerts*3 + vertY*3 + 2] = normal.z; + + if (hasColors) + { + color.r = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3] / 255.f; + color.g = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+1] / 255.f; + color.b = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+2] / 255.f; + } + else + { + color.r = 1; + color.g = 1; + color.b = 1; + } + + // Unlike normals, colors mostly connect seamlessly between cells, but not always... + if (col == ESM::Land::LAND_SIZE-1 || row == ESM::Land::LAND_SIZE-1) + fixColour(color, cellX, cellY, col, row); + + color.a = 1; + Ogre::uint32 rsColor; + Ogre::Root::getSingleton().getRenderSystem()->convertColourValue(color, &rsColor); + memcpy(&colors[vertX*numVerts*4 + vertY*4], &rsColor, sizeof(Ogre::uint32)); + + ++vertX; + } + ++vertY; + } + vertX_ = vertX; + } + vertY_ = vertY; + + assert(vertX_ == numVerts); // Ensure we covered whole area + } + assert(vertY_ == numVerts); // Ensure we covered whole area + + vertexBuffer->writeData(0, vertexBuffer->getSizeInBytes(), &positions[0], true); + normalBuffer->writeData(0, normalBuffer->getSizeInBytes(), &normals[0], true); + colourBuffer->writeData(0, colourBuffer->getSizeInBytes(), &colors[0], true); + } + + TerrainStorage::UniqueTextureId TerrainStorage::getVtexIndexAt(int cellX, int cellY, + int x, int y) + { + // For the first/last row/column, we need to get the texture from the neighbour cell + // to get consistent blending at the borders + --x; + if (x < 0) + { + --cellX; + x += ESM::Land::LAND_TEXTURE_SIZE; + } + if (y >= ESM::Land::LAND_TEXTURE_SIZE) // Y appears to be wrapped from the other side because why the hell not? + { + ++cellY; + y -= ESM::Land::LAND_TEXTURE_SIZE; + } + + assert(x<ESM::Land::LAND_TEXTURE_SIZE); + assert(y<ESM::Land::LAND_TEXTURE_SIZE); + + ESM::Land* land = getLand(cellX, cellY); + if (land) + { + if (!land->isDataLoaded(ESM::Land::DATA_VTEX)) + land->loadData(ESM::Land::DATA_VTEX); + + int tex = land->mLandData->mTextures[y * ESM::Land::LAND_TEXTURE_SIZE + x]; + if (tex == 0) + return std::make_pair(0,0); // vtex 0 is always the base texture, regardless of plugin + return std::make_pair(tex, land->mPlugin); + } + else + return std::make_pair(0,0); + } + + std::string TerrainStorage::getTextureName(UniqueTextureId id) + { + if (id.first == 0) + return "_land_default.dds"; // Not sure if the default texture floatly is hardcoded? + + // NB: All vtex ids are +1 compared to the ltex ids + const ESM::LandTexture* ltex = getLandTexture(id.first-1, id.second); + + std::string texture = ltex->mTexture; + //TODO this is needed due to MWs messed up texture handling + texture = texture.substr(0, texture.rfind(".")) + ".dds"; + + return texture; + } + + void TerrainStorage::getBlendmaps(float chunkSize, const Ogre::Vector2 &chunkCenter, + bool pack, std::vector<Ogre::TexturePtr> &blendmaps, std::vector<Terrain::LayerInfo> &layerList) + { + // TODO - blending isn't completely right yet; the blending radius appears to be + // different at a cell transition (2 vertices, not 4), so we may need to create a larger blendmap + // and interpolate the rest of the cell by hand? :/ + + Ogre::Vector2 origin = chunkCenter - Ogre::Vector2(chunkSize/2.f, chunkSize/2.f); + int cellX = origin.x; + int cellY = origin.y; + + // Save the used texture indices so we know the total number of textures + // and number of required blend maps + std::set<UniqueTextureId> textureIndices; + // Due to the way the blending works, the base layer will always shine through in between + // blend transitions (eg halfway between two texels, both blend values will be 0.5, so 25% of base layer visible). + // To get a consistent look, we need to make sure to use the same base layer in all cells. + // So we're always adding _land_default.dds as the base layer here, even if it's not referenced in this cell. + textureIndices.insert(std::make_pair(0,0)); + + for (int y=0; y<ESM::Land::LAND_TEXTURE_SIZE+1; ++y) + for (int x=0; x<ESM::Land::LAND_TEXTURE_SIZE+1; ++x) + { + UniqueTextureId id = getVtexIndexAt(cellX, cellY, x, y); + textureIndices.insert(id); + } + + // Makes sure the indices are sorted, or rather, + // retrieved as sorted. This is important to keep the splatting order + // consistent across cells. + std::map<UniqueTextureId, int> textureIndicesMap; + for (std::set<UniqueTextureId>::iterator it = textureIndices.begin(); it != textureIndices.end(); ++it) + { + int size = textureIndicesMap.size(); + textureIndicesMap[*it] = size; + layerList.push_back(getLayerInfo(getTextureName(*it))); + } + + int numTextures = textureIndices.size(); + // numTextures-1 since the base layer doesn't need blending + int numBlendmaps = pack ? std::ceil((numTextures-1) / 4.f) : (numTextures-1); + + int channels = pack ? 4 : 1; + + // Second iteration - create and fill in the blend maps + const int blendmapSize = ESM::Land::LAND_TEXTURE_SIZE+1; + std::vector<Ogre::uchar> data; + data.resize(blendmapSize * blendmapSize * channels, 0); + + for (int i=0; i<numBlendmaps; ++i) + { + Ogre::PixelFormat format = pack ? Ogre::PF_A8B8G8R8 : Ogre::PF_A8; + static int count=0; + Ogre::TexturePtr map = Ogre::TextureManager::getSingleton().createManual("terrain/blend/" + + Ogre::StringConverter::toString(count++), Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, + Ogre::TEX_TYPE_2D, blendmapSize, blendmapSize, 0, format); + + for (int y=0; y<blendmapSize; ++y) + { + for (int x=0; x<blendmapSize; ++x) + { + UniqueTextureId id = getVtexIndexAt(cellX, cellY, x, y); + int layerIndex = textureIndicesMap.find(id)->second; + int blendIndex = (pack ? std::floor((layerIndex-1)/4.f) : layerIndex-1); + int channel = pack ? std::max(0, (layerIndex-1) % 4) : 0; + + if (blendIndex == i) + data[y*blendmapSize*channels + x*channels + channel] = 255; + else + data[y*blendmapSize*channels + x*channels + channel] = 0; + } + } + + // All done, upload to GPU + Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(&data[0], data.size())); + map->loadRawData(stream, blendmapSize, blendmapSize, format); + blendmaps.push_back(map); + } + } + + float TerrainStorage::getHeightAt(const Ogre::Vector3 &worldPos) + { + int cellX = std::floor(worldPos.x / 8192.f); + int cellY = std::floor(worldPos.y / 8192.f); + + ESM::Land* land = getLand(cellX, cellY); + if (!land) + return -2048; + + // Mostly lifted from Ogre::Terrain::getHeightAtTerrainPosition + + // Normalized position in the cell + float nX = (worldPos.x - (cellX * 8192))/8192.f; + float nY = (worldPos.y - (cellY * 8192))/8192.f; + + // get left / bottom points (rounded down) + float factor = ESM::Land::LAND_SIZE - 1.0f; + float invFactor = 1.0f / factor; + + int startX = static_cast<int>(nX * factor); + int startY = static_cast<int>(nY * factor); + int endX = startX + 1; + int endY = startY + 1; + + assert(endX < ESM::Land::LAND_SIZE); + assert(endY < ESM::Land::LAND_SIZE); + + // now get points in terrain space (effectively rounding them to boundaries) + float startXTS = startX * invFactor; + float startYTS = startY * invFactor; + float endXTS = endX * invFactor; + float endYTS = endY * invFactor; + + // get parametric from start coord to next point + float xParam = (nX - startXTS) * factor; + float yParam = (nY - startYTS) * factor; + + /* For even / odd tri strip rows, triangles are this shape: + even odd + 3---2 3---2 + | / | | \ | + 0---1 0---1 + */ + + // Build all 4 positions in normalized cell space, using point-sampled height + Ogre::Vector3 v0 (startXTS, startYTS, getVertexHeight(land, startX, startY) / 8192.f); + Ogre::Vector3 v1 (endXTS, startYTS, getVertexHeight(land, endX, startY) / 8192.f); + Ogre::Vector3 v2 (endXTS, endYTS, getVertexHeight(land, endX, endY) / 8192.f); + Ogre::Vector3 v3 (startXTS, endYTS, getVertexHeight(land, startX, endY) / 8192.f); + // define this plane in terrain space + Ogre::Plane plane; + // (At the moment, all rows have the same triangle alignment) + if (true) + { + // odd row + bool secondTri = ((1.0 - yParam) > xParam); + if (secondTri) + plane.redefine(v0, v1, v3); + else + plane.redefine(v1, v2, v3); + } + else + { + // even row + bool secondTri = (yParam > xParam); + if (secondTri) + plane.redefine(v0, v2, v3); + else + plane.redefine(v0, v1, v2); + } + + // Solve plane equation for z + return (-plane.normal.x * nX + -plane.normal.y * nY + - plane.d) / plane.normal.z * 8192; + + } + + float TerrainStorage::getVertexHeight(const ESM::Land *land, int x, int y) + { + assert(x < ESM::Land::LAND_SIZE); + assert(y < ESM::Land::LAND_SIZE); + return land->mLandData->mHeights[y * ESM::Land::LAND_SIZE + x]; + } + + Terrain::LayerInfo TerrainStorage::getLayerInfo(const std::string& texture) + { + // Already have this cached? + if (mLayerInfoMap.find(texture) != mLayerInfoMap.end()) + return mLayerInfoMap[texture]; + + Terrain::LayerInfo info; + info.mParallax = false; + info.mSpecular = false; + info.mDiffuseMap = "textures\\" + texture; + std::string texture_ = texture; + boost::replace_last(texture_, ".", "_nh."); + if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup("textures\\" + texture_)) + { + info.mNormalMap = "textures\\" + texture_; + info.mParallax = true; + } + else + { + texture_ = texture; + boost::replace_last(texture_, ".", "_n."); + if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup("textures\\" + texture_)) + info.mNormalMap = "textures\\" + texture_; + } + + texture_ = texture; + boost::replace_last(texture_, ".", "_diffusespec."); + if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup("textures\\" + texture_)) + { + info.mDiffuseMap = "textures\\" + texture_; + info.mSpecular = true; + } + + mLayerInfoMap[texture] = info; + + return info; + } + + Terrain::LayerInfo TerrainStorage::getDefaultLayer() + { + Terrain::LayerInfo info; + info.mDiffuseMap = "textures\\_land_default.dds"; + info.mParallax = false; + info.mSpecular = false; + return info; + } + + float TerrainStorage::getCellWorldSize() + { + return ESM::Land::REAL_SIZE; + } + + int TerrainStorage::getCellVertices() + { + return ESM::Land::LAND_SIZE; + } + } diff --git a/apps/openmw/mwrender/terrainstorage.hpp b/apps/openmw/mwrender/terrainstorage.hpp index ebf5e26ab7..5c20359527 100644 --- a/apps/openmw/mwrender/terrainstorage.hpp +++ b/apps/openmw/mwrender/terrainstorage.hpp @@ -12,8 +12,75 @@ namespace MWRender virtual ESM::Land* getLand (int cellX, int cellY); virtual const ESM::LandTexture* getLandTexture(int index, short plugin); public: + + /// Get bounds of the whole terrain in cell units virtual Ogre::AxisAlignedBox getBounds(); - ///< Get bounds in cell units + + /// Get the minimum and maximum heights of a terrain chunk. + /// @note Should only be called for chunks <= 1 cell, i.e. leafs of the quad tree. + /// Larger chunks can simply merge AABB of children. + /// @param size size of the chunk in cell units + /// @param center center of the chunk in cell units + /// @param min min height will be stored here + /// @param max max height will be stored here + /// @return true if there was data available for this terrain chunk + virtual bool getMinMaxHeights (float size, const Ogre::Vector2& center, float& min, float& max); + + /// Fill vertex buffers for a terrain chunk. + /// @param lodLevel LOD level, 0 = most detailed + /// @param size size of the terrain chunk in cell units + /// @param center center of the chunk in cell units + /// @param vertexBuffer buffer to write vertices + /// @param normalBuffer buffer to write vertex normals + /// @param colourBuffer buffer to write vertex colours + virtual void fillVertexBuffers (int lodLevel, float size, const Ogre::Vector2& center, + Ogre::HardwareVertexBufferSharedPtr vertexBuffer, + Ogre::HardwareVertexBufferSharedPtr normalBuffer, + Ogre::HardwareVertexBufferSharedPtr colourBuffer); + + /// Create textures holding layer blend values for a terrain chunk. + /// @note The terrain chunk shouldn't be larger than one cell since otherwise we might + /// have to do a ridiculous amount of different layers. For larger chunks, composite maps should be used. + /// @param chunkSize size of the terrain chunk in cell units + /// @param chunkCenter center of the chunk in cell units + /// @param pack Whether to pack blend values for up to 4 layers into one texture (one in each channel) - + /// otherwise, each texture contains blend values for one layer only. Shader-based rendering + /// can utilize packing, FFP can't. + /// @param blendmaps created blendmaps will be written here + /// @param layerList names of the layer textures used will be written here + virtual void getBlendmaps (float chunkSize, const Ogre::Vector2& chunkCenter, bool pack, + std::vector<Ogre::TexturePtr>& blendmaps, + std::vector<Terrain::LayerInfo>& layerList); + + virtual float getHeightAt (const Ogre::Vector3& worldPos); + + virtual Terrain::LayerInfo getDefaultLayer(); + + /// Get the transformation factor for mapping cell units to world units. + virtual float getCellWorldSize(); + + /// Get the number of vertices on one side for each cell. Should be (power of two)+1 + virtual int getCellVertices(); + + private: + void fixNormal (Ogre::Vector3& normal, int cellX, int cellY, int col, int row); + void fixColour (Ogre::ColourValue& colour, int cellX, int cellY, int col, int row); + void averageNormal (Ogre::Vector3& normal, int cellX, int cellY, int col, int row); + + float getVertexHeight (const ESM::Land* land, int x, int y); + + // Since plugins can define new texture palettes, we need to know the plugin index too + // in order to retrieve the correct texture name. + // pair <texture id, plugin id> + typedef std::pair<short, short> UniqueTextureId; + + UniqueTextureId getVtexIndexAt(int cellX, int cellY, + int x, int y); + std::string getTextureName (UniqueTextureId id); + + std::map<std::string, Terrain::LayerInfo> mLayerInfoMap; + + Terrain::LayerInfo getLayerInfo(const std::string& texture); }; } diff --git a/components/terrain/chunk.cpp b/components/terrain/chunk.cpp index ce2118cdbd..a5c6290884 100644 --- a/components/terrain/chunk.cpp +++ b/components/terrain/chunk.cpp @@ -18,11 +18,13 @@ namespace Terrain mVertexData = OGRE_NEW Ogre::VertexData; mVertexData->vertexStart = 0; + unsigned int verts = mNode->getTerrain()->getStorage()->getCellVertices(); + // Set the total number of vertices - size_t numVertsOneSide = mNode->getSize() * (ESM::Land::LAND_SIZE-1); + size_t numVertsOneSide = mNode->getSize() * (verts-1); numVertsOneSide /= 1 << lodLevel; numVertsOneSide += 1; - assert((int)numVertsOneSide == ESM::Land::LAND_SIZE); + assert(numVertsOneSide == verts); mVertexData->vertexCount = numVertsOneSide * numVertsOneSide; // Set up the vertex declaration, which specifies the info for each vertex (normals, colors, UVs, etc) diff --git a/components/terrain/quadtreenode.cpp b/components/terrain/quadtreenode.cpp index 7fc452fbf4..a4fdd5e13f 100644 --- a/components/terrain/quadtreenode.cpp +++ b/components/terrain/quadtreenode.cpp @@ -430,11 +430,7 @@ void QuadTreeNode::prepareForCompositeMap(Ogre::TRect<float> area) // TODO - store this default material somewhere instead of creating one for each empty cell MaterialGenerator matGen(mTerrain->getShadersEnabled()); std::vector<LayerInfo> layer; - LayerInfo info; - info.mDiffuseMap = "textures\\_land_default.dds"; - info.mParallax = false; - info.mSpecular = false; - layer.push_back(info); + layer.push_back(mTerrain->getStorage()->getDefaultLayer()); matGen.setLayerList(layer); makeQuad(sceneMgr, area.left, area.top, area.right, area.bottom, matGen.generateForCompositeMapRTT(Ogre::MaterialPtr())); return; diff --git a/components/terrain/quadtreenode.hpp b/components/terrain/quadtreenode.hpp index 9f6fb5d242..ea299c096d 100644 --- a/components/terrain/quadtreenode.hpp +++ b/components/terrain/quadtreenode.hpp @@ -108,7 +108,7 @@ namespace Terrain void destroyChunks(bool children); /// Get the effective LOD level if this node was rendered in one chunk - /// with ESM::Land::LAND_SIZE^2 vertices + /// with Storage::getCellVertices^2 vertices size_t getNativeLodLevel() { return mLodLevel; } /// Get the effective current LOD level used by the chunk rendering this node diff --git a/components/terrain/storage.cpp b/components/terrain/storage.cpp index 398ebac014..e69de29bb2 100644 --- a/components/terrain/storage.cpp +++ b/components/terrain/storage.cpp @@ -1,509 +0,0 @@ -#include "storage.hpp" - -#include <OgreVector2.h> -#include <OgreTextureManager.h> -#include <OgreStringConverter.h> -#include <OgreRenderSystem.h> -#include <OgreResourceGroupManager.h> -#include <OgreRoot.h> - -#include <boost/algorithm/string.hpp> - -namespace Terrain -{ - - struct VertexElement - { - Ogre::Vector3 pos; - Ogre::Vector3 normal; - Ogre::ColourValue colour; - }; - - bool Storage::getMinMaxHeights(float size, const Ogre::Vector2 ¢er, float &min, float &max) - { - assert (size <= 1 && "Storage::getMinMaxHeights, chunk size should be <= 1 cell"); - - /// \todo investigate if min/max heights should be stored at load time in ESM::Land instead - - Ogre::Vector2 origin = center - Ogre::Vector2(size/2.f, size/2.f); - - assert(origin.x == (int) origin.x); - assert(origin.y == (int) origin.y); - - int cellX = origin.x; - int cellY = origin.y; - - const ESM::Land* land = getLand(cellX, cellY); - if (!land) - return false; - - min = std::numeric_limits<float>().max(); - max = -std::numeric_limits<float>().max(); - for (int row=0; row<ESM::Land::LAND_SIZE; ++row) - { - for (int col=0; col<ESM::Land::LAND_SIZE; ++col) - { - float h = land->mLandData->mHeights[col*ESM::Land::LAND_SIZE+row]; - if (h > max) - max = h; - if (h < min) - min = h; - } - } - return true; - } - - void Storage::fixNormal (Ogre::Vector3& normal, int cellX, int cellY, int col, int row) - { - while (col >= ESM::Land::LAND_SIZE-1) - { - ++cellY; - col -= ESM::Land::LAND_SIZE-1; - } - while (row >= ESM::Land::LAND_SIZE-1) - { - ++cellX; - row -= ESM::Land::LAND_SIZE-1; - } - while (col < 0) - { - --cellY; - col += ESM::Land::LAND_SIZE-1; - } - while (row < 0) - { - --cellX; - row += ESM::Land::LAND_SIZE-1; - } - ESM::Land* land = getLand(cellX, cellY); - if (land && land->mHasData) - { - normal.x = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3]; - normal.y = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+1]; - normal.z = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+2]; - normal.normalise(); - } - else - normal = Ogre::Vector3(0,0,1); - } - - void Storage::averageNormal(Ogre::Vector3 &normal, int cellX, int cellY, int col, int row) - { - Ogre::Vector3 n1,n2,n3,n4; - fixNormal(n1, cellX, cellY, col+1, row); - fixNormal(n2, cellX, cellY, col-1, row); - fixNormal(n3, cellX, cellY, col, row+1); - fixNormal(n4, cellX, cellY, col, row-1); - normal = (n1+n2+n3+n4); - normal.normalise(); - } - - void Storage::fixColour (Ogre::ColourValue& color, int cellX, int cellY, int col, int row) - { - if (col == ESM::Land::LAND_SIZE-1) - { - ++cellY; - col = 0; - } - if (row == ESM::Land::LAND_SIZE-1) - { - ++cellX; - row = 0; - } - ESM::Land* land = getLand(cellX, cellY); - if (land && land->mLandData->mUsingColours) - { - color.r = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3] / 255.f; - color.g = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+1] / 255.f; - color.b = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+2] / 255.f; - } - else - { - color.r = 1; - color.g = 1; - color.b = 1; - } - - } - - void Storage::fillVertexBuffers (int lodLevel, float size, const Ogre::Vector2& center, - Ogre::HardwareVertexBufferSharedPtr vertexBuffer, - Ogre::HardwareVertexBufferSharedPtr normalBuffer, - Ogre::HardwareVertexBufferSharedPtr colourBuffer) - { - // LOD level n means every 2^n-th vertex is kept - size_t increment = 1 << lodLevel; - - Ogre::Vector2 origin = center - Ogre::Vector2(size/2.f, size/2.f); - assert(origin.x == (int) origin.x); - assert(origin.y == (int) origin.y); - - int startX = origin.x; - int startY = origin.y; - - size_t numVerts = size*(ESM::Land::LAND_SIZE-1)/increment + 1; - - std::vector<uint8_t> colors; - colors.resize(numVerts*numVerts*4); - std::vector<float> positions; - positions.resize(numVerts*numVerts*3); - std::vector<float> normals; - normals.resize(numVerts*numVerts*3); - - Ogre::Vector3 normal; - Ogre::ColourValue color; - - float vertY; - float vertX; - - float vertY_ = 0; // of current cell corner - for (int cellY = startY; cellY < startY + std::ceil(size); ++cellY) - { - float vertX_ = 0; // of current cell corner - for (int cellX = startX; cellX < startX + std::ceil(size); ++cellX) - { - ESM::Land* land = getLand(cellX, cellY); - if (land && !land->mHasData) - land = NULL; - bool hasColors = land && land->mLandData->mUsingColours; - - int rowStart = 0; - int colStart = 0; - // Skip the first row / column unless we're at a chunk edge, - // since this row / column is already contained in a previous cell - if (colStart == 0 && vertY_ != 0) - colStart += increment; - if (rowStart == 0 && vertX_ != 0) - rowStart += increment; - - vertY = vertY_; - for (int col=colStart; col<ESM::Land::LAND_SIZE; col += increment) - { - vertX = vertX_; - for (int row=rowStart; row<ESM::Land::LAND_SIZE; row += increment) - { - positions[vertX*numVerts*3 + vertY*3] = ((vertX/float(numVerts-1)-0.5) * size * 8192); - positions[vertX*numVerts*3 + vertY*3 + 1] = ((vertY/float(numVerts-1)-0.5) * size * 8192); - if (land) - positions[vertX*numVerts*3 + vertY*3 + 2] = land->mLandData->mHeights[col*ESM::Land::LAND_SIZE+row]; - else - positions[vertX*numVerts*3 + vertY*3 + 2] = -2048; - - if (land) - { - normal.x = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3]; - normal.y = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+1]; - normal.z = land->mLandData->mNormals[col*ESM::Land::LAND_SIZE*3+row*3+2]; - normal.normalise(); - } - else - normal = Ogre::Vector3(0,0,1); - - // Normals apparently don't connect seamlessly between cells - if (col == ESM::Land::LAND_SIZE-1 || row == ESM::Land::LAND_SIZE-1) - fixNormal(normal, cellX, cellY, col, row); - - // some corner normals appear to be complete garbage (z < 0) - if ((row == 0 || row == ESM::Land::LAND_SIZE-1) && (col == 0 || col == ESM::Land::LAND_SIZE-1)) - averageNormal(normal, cellX, cellY, col, row); - - assert(normal.z > 0); - - normals[vertX*numVerts*3 + vertY*3] = normal.x; - normals[vertX*numVerts*3 + vertY*3 + 1] = normal.y; - normals[vertX*numVerts*3 + vertY*3 + 2] = normal.z; - - if (hasColors) - { - color.r = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3] / 255.f; - color.g = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+1] / 255.f; - color.b = land->mLandData->mColours[col*ESM::Land::LAND_SIZE*3+row*3+2] / 255.f; - } - else - { - color.r = 1; - color.g = 1; - color.b = 1; - } - - // Unlike normals, colors mostly connect seamlessly between cells, but not always... - if (col == ESM::Land::LAND_SIZE-1 || row == ESM::Land::LAND_SIZE-1) - fixColour(color, cellX, cellY, col, row); - - color.a = 1; - Ogre::uint32 rsColor; - Ogre::Root::getSingleton().getRenderSystem()->convertColourValue(color, &rsColor); - memcpy(&colors[vertX*numVerts*4 + vertY*4], &rsColor, sizeof(Ogre::uint32)); - - ++vertX; - } - ++vertY; - } - vertX_ = vertX; - } - vertY_ = vertY; - - assert(vertX_ == numVerts); // Ensure we covered whole area - } - assert(vertY_ == numVerts); // Ensure we covered whole area - - vertexBuffer->writeData(0, vertexBuffer->getSizeInBytes(), &positions[0], true); - normalBuffer->writeData(0, normalBuffer->getSizeInBytes(), &normals[0], true); - colourBuffer->writeData(0, colourBuffer->getSizeInBytes(), &colors[0], true); - } - - Storage::UniqueTextureId Storage::getVtexIndexAt(int cellX, int cellY, - int x, int y) - { - // For the first/last row/column, we need to get the texture from the neighbour cell - // to get consistent blending at the borders - --x; - if (x < 0) - { - --cellX; - x += ESM::Land::LAND_TEXTURE_SIZE; - } - if (y >= ESM::Land::LAND_TEXTURE_SIZE) // Y appears to be wrapped from the other side because why the hell not? - { - ++cellY; - y -= ESM::Land::LAND_TEXTURE_SIZE; - } - - assert(x<ESM::Land::LAND_TEXTURE_SIZE); - assert(y<ESM::Land::LAND_TEXTURE_SIZE); - - ESM::Land* land = getLand(cellX, cellY); - if (land) - { - if (!land->isDataLoaded(ESM::Land::DATA_VTEX)) - land->loadData(ESM::Land::DATA_VTEX); - - int tex = land->mLandData->mTextures[y * ESM::Land::LAND_TEXTURE_SIZE + x]; - if (tex == 0) - return std::make_pair(0,0); // vtex 0 is always the base texture, regardless of plugin - return std::make_pair(tex, land->mPlugin); - } - else - return std::make_pair(0,0); - } - - std::string Storage::getTextureName(UniqueTextureId id) - { - if (id.first == 0) - return "_land_default.dds"; // Not sure if the default texture floatly is hardcoded? - - // NB: All vtex ids are +1 compared to the ltex ids - const ESM::LandTexture* ltex = getLandTexture(id.first-1, id.second); - - std::string texture = ltex->mTexture; - //TODO this is needed due to MWs messed up texture handling - texture = texture.substr(0, texture.rfind(".")) + ".dds"; - - return texture; - } - - void Storage::getBlendmaps(float chunkSize, const Ogre::Vector2 &chunkCenter, - bool pack, std::vector<Ogre::TexturePtr> &blendmaps, std::vector<LayerInfo> &layerList) - { - // TODO - blending isn't completely right yet; the blending radius appears to be - // different at a cell transition (2 vertices, not 4), so we may need to create a larger blendmap - // and interpolate the rest of the cell by hand? :/ - - Ogre::Vector2 origin = chunkCenter - Ogre::Vector2(chunkSize/2.f, chunkSize/2.f); - int cellX = origin.x; - int cellY = origin.y; - - // Save the used texture indices so we know the total number of textures - // and number of required blend maps - std::set<UniqueTextureId> textureIndices; - // Due to the way the blending works, the base layer will always shine through in between - // blend transitions (eg halfway between two texels, both blend values will be 0.5, so 25% of base layer visible). - // To get a consistent look, we need to make sure to use the same base layer in all cells. - // So we're always adding _land_default.dds as the base layer here, even if it's not referenced in this cell. - textureIndices.insert(std::make_pair(0,0)); - - for (int y=0; y<ESM::Land::LAND_TEXTURE_SIZE+1; ++y) - for (int x=0; x<ESM::Land::LAND_TEXTURE_SIZE+1; ++x) - { - UniqueTextureId id = getVtexIndexAt(cellX, cellY, x, y); - textureIndices.insert(id); - } - - // Makes sure the indices are sorted, or rather, - // retrieved as sorted. This is important to keep the splatting order - // consistent across cells. - std::map<UniqueTextureId, int> textureIndicesMap; - for (std::set<UniqueTextureId>::iterator it = textureIndices.begin(); it != textureIndices.end(); ++it) - { - int size = textureIndicesMap.size(); - textureIndicesMap[*it] = size; - layerList.push_back(getLayerInfo(getTextureName(*it))); - } - - int numTextures = textureIndices.size(); - // numTextures-1 since the base layer doesn't need blending - int numBlendmaps = pack ? std::ceil((numTextures-1) / 4.f) : (numTextures-1); - - int channels = pack ? 4 : 1; - - // Second iteration - create and fill in the blend maps - const int blendmapSize = ESM::Land::LAND_TEXTURE_SIZE+1; - std::vector<Ogre::uchar> data; - data.resize(blendmapSize * blendmapSize * channels, 0); - - for (int i=0; i<numBlendmaps; ++i) - { - Ogre::PixelFormat format = pack ? Ogre::PF_A8B8G8R8 : Ogre::PF_A8; - static int count=0; - Ogre::TexturePtr map = Ogre::TextureManager::getSingleton().createManual("terrain/blend/" - + Ogre::StringConverter::toString(count++), Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - Ogre::TEX_TYPE_2D, blendmapSize, blendmapSize, 0, format); - - for (int y=0; y<blendmapSize; ++y) - { - for (int x=0; x<blendmapSize; ++x) - { - UniqueTextureId id = getVtexIndexAt(cellX, cellY, x, y); - int layerIndex = textureIndicesMap.find(id)->second; - int blendIndex = (pack ? std::floor((layerIndex-1)/4.f) : layerIndex-1); - int channel = pack ? std::max(0, (layerIndex-1) % 4) : 0; - - if (blendIndex == i) - data[y*blendmapSize*channels + x*channels + channel] = 255; - else - data[y*blendmapSize*channels + x*channels + channel] = 0; - } - } - - // All done, upload to GPU - Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(&data[0], data.size())); - map->loadRawData(stream, blendmapSize, blendmapSize, format); - blendmaps.push_back(map); - } - } - - float Storage::getHeightAt(const Ogre::Vector3 &worldPos) - { - int cellX = std::floor(worldPos.x / 8192.f); - int cellY = std::floor(worldPos.y / 8192.f); - - ESM::Land* land = getLand(cellX, cellY); - if (!land) - return -2048; - - // Mostly lifted from Ogre::Terrain::getHeightAtTerrainPosition - - // Normalized position in the cell - float nX = (worldPos.x - (cellX * 8192))/8192.f; - float nY = (worldPos.y - (cellY * 8192))/8192.f; - - // get left / bottom points (rounded down) - float factor = ESM::Land::LAND_SIZE - 1.0f; - float invFactor = 1.0f / factor; - - int startX = static_cast<int>(nX * factor); - int startY = static_cast<int>(nY * factor); - int endX = startX + 1; - int endY = startY + 1; - - assert(endX < ESM::Land::LAND_SIZE); - assert(endY < ESM::Land::LAND_SIZE); - - // now get points in terrain space (effectively rounding them to boundaries) - float startXTS = startX * invFactor; - float startYTS = startY * invFactor; - float endXTS = endX * invFactor; - float endYTS = endY * invFactor; - - // get parametric from start coord to next point - float xParam = (nX - startXTS) * factor; - float yParam = (nY - startYTS) * factor; - - /* For even / odd tri strip rows, triangles are this shape: - even odd - 3---2 3---2 - | / | | \ | - 0---1 0---1 - */ - - // Build all 4 positions in normalized cell space, using point-sampled height - Ogre::Vector3 v0 (startXTS, startYTS, getVertexHeight(land, startX, startY) / 8192.f); - Ogre::Vector3 v1 (endXTS, startYTS, getVertexHeight(land, endX, startY) / 8192.f); - Ogre::Vector3 v2 (endXTS, endYTS, getVertexHeight(land, endX, endY) / 8192.f); - Ogre::Vector3 v3 (startXTS, endYTS, getVertexHeight(land, startX, endY) / 8192.f); - // define this plane in terrain space - Ogre::Plane plane; - // (At the moment, all rows have the same triangle alignment) - if (true) - { - // odd row - bool secondTri = ((1.0 - yParam) > xParam); - if (secondTri) - plane.redefine(v0, v1, v3); - else - plane.redefine(v1, v2, v3); - } - else - { - // even row - bool secondTri = (yParam > xParam); - if (secondTri) - plane.redefine(v0, v2, v3); - else - plane.redefine(v0, v1, v2); - } - - // Solve plane equation for z - return (-plane.normal.x * nX - -plane.normal.y * nY - - plane.d) / plane.normal.z * 8192; - - } - - float Storage::getVertexHeight(const ESM::Land *land, int x, int y) - { - assert(x < ESM::Land::LAND_SIZE); - assert(y < ESM::Land::LAND_SIZE); - return land->mLandData->mHeights[y * ESM::Land::LAND_SIZE + x]; - } - - LayerInfo Storage::getLayerInfo(const std::string& texture) - { - // Already have this cached? - if (mLayerInfoMap.find(texture) != mLayerInfoMap.end()) - return mLayerInfoMap[texture]; - - LayerInfo info; - info.mParallax = false; - info.mSpecular = false; - info.mDiffuseMap = "textures\\" + texture; - std::string texture_ = texture; - boost::replace_last(texture_, ".", "_nh."); - if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup("textures\\" + texture_)) - { - info.mNormalMap = "textures\\" + texture_; - info.mParallax = true; - } - else - { - texture_ = texture; - boost::replace_last(texture_, ".", "_n."); - if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup("textures\\" + texture_)) - info.mNormalMap = "textures\\" + texture_; - } - - texture_ = texture; - boost::replace_last(texture_, ".", "_diffusespec."); - if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup("textures\\" + texture_)) - { - info.mDiffuseMap = "textures\\" + texture_; - info.mSpecular = true; - } - - mLayerInfoMap[texture] = info; - - return info; - } - - -} diff --git a/components/terrain/storage.hpp b/components/terrain/storage.hpp index 18d05b100c..021e01c7e0 100644 --- a/components/terrain/storage.hpp +++ b/components/terrain/storage.hpp @@ -24,9 +24,6 @@ namespace Terrain { public: virtual ~Storage() {} - private: - virtual ESM::Land* getLand (int cellX, int cellY) = 0; - virtual const ESM::LandTexture* getLandTexture(int index, short plugin) = 0; public: /// Get bounds of the whole terrain in cell units @@ -40,7 +37,7 @@ namespace Terrain /// @param min min height will be stored here /// @param max max height will be stored here /// @return true if there was data available for this terrain chunk - bool getMinMaxHeights (float size, const Ogre::Vector2& center, float& min, float& max); + virtual bool getMinMaxHeights (float size, const Ogre::Vector2& center, float& min, float& max) = 0; /// Fill vertex buffers for a terrain chunk. /// @param lodLevel LOD level, 0 = most detailed @@ -49,10 +46,10 @@ namespace Terrain /// @param vertexBuffer buffer to write vertices /// @param normalBuffer buffer to write vertex normals /// @param colourBuffer buffer to write vertex colours - void fillVertexBuffers (int lodLevel, float size, const Ogre::Vector2& center, + virtual void fillVertexBuffers (int lodLevel, float size, const Ogre::Vector2& center, Ogre::HardwareVertexBufferSharedPtr vertexBuffer, Ogre::HardwareVertexBufferSharedPtr normalBuffer, - Ogre::HardwareVertexBufferSharedPtr colourBuffer); + Ogre::HardwareVertexBufferSharedPtr colourBuffer) = 0; /// Create textures holding layer blend values for a terrain chunk. /// @note The terrain chunk shouldn't be larger than one cell since otherwise we might @@ -64,31 +61,19 @@ namespace Terrain /// can utilize packing, FFP can't. /// @param blendmaps created blendmaps will be written here /// @param layerList names of the layer textures used will be written here - void getBlendmaps (float chunkSize, const Ogre::Vector2& chunkCenter, bool pack, + virtual void getBlendmaps (float chunkSize, const Ogre::Vector2& chunkCenter, bool pack, std::vector<Ogre::TexturePtr>& blendmaps, - std::vector<LayerInfo>& layerList); + std::vector<LayerInfo>& layerList) = 0; - float getHeightAt (const Ogre::Vector3& worldPos); + virtual float getHeightAt (const Ogre::Vector3& worldPos) = 0; - private: - void fixNormal (Ogre::Vector3& normal, int cellX, int cellY, int col, int row); - void fixColour (Ogre::ColourValue& colour, int cellX, int cellY, int col, int row); - void averageNormal (Ogre::Vector3& normal, int cellX, int cellY, int col, int row); + virtual LayerInfo getDefaultLayer() = 0; - float getVertexHeight (const ESM::Land* land, int x, int y); + /// Get the transformation factor for mapping cell units to world units. + virtual float getCellWorldSize() = 0; - // Since plugins can define new texture palettes, we need to know the plugin index too - // in order to retrieve the correct texture name. - // pair <texture id, plugin id> - typedef std::pair<short, short> UniqueTextureId; - - UniqueTextureId getVtexIndexAt(int cellX, int cellY, - int x, int y); - std::string getTextureName (UniqueTextureId id); - - std::map<std::string, LayerInfo> mLayerInfoMap; - - LayerInfo getLayerInfo(const std::string& texture); + /// Get the number of vertices on one side for each cell. Should be (power of two)+1 + virtual int getCellVertices() = 0; }; } diff --git a/components/terrain/world.cpp b/components/terrain/world.cpp index 711ebbc8fa..dac960fbb6 100644 --- a/components/terrain/world.cpp +++ b/components/terrain/world.cpp @@ -6,7 +6,6 @@ #include <OgreHardwarePixelBuffer.h> #include <OgreRoot.h> -#include <components/esm/loadland.hpp> #include <components/loadinglistener/loadinglistener.hpp> #include "storage.hpp" @@ -208,6 +207,8 @@ namespace Terrain Ogre::HardwareIndexBufferSharedPtr World::getIndexBuffer(int flags, size_t& numIndices) { + unsigned int verts = mStorage->getCellVertices(); + if (mIndexBufferMap.find(flags) != mIndexBufferMap.end()) { numIndices = mIndexBufferMap[flags]->getNumIndexes(); @@ -224,11 +225,11 @@ namespace Terrain bool anyDeltas = (lodDeltas[North] || lodDeltas[South] || lodDeltas[West] || lodDeltas[East]); size_t increment = 1 << lodLevel; - assert((int)increment < ESM::Land::LAND_SIZE); + assert(increment < verts); std::vector<short> indices; - indices.reserve((ESM::Land::LAND_SIZE-1)*(ESM::Land::LAND_SIZE-1)*2*3 / increment); + indices.reserve((verts-1)*(verts-1)*2*3 / increment); - size_t rowStart = 0, colStart = 0, rowEnd = ESM::Land::LAND_SIZE-1, colEnd = ESM::Land::LAND_SIZE-1; + size_t rowStart = 0, colStart = 0, rowEnd = verts-1, colEnd = verts-1; // If any edge needs stitching we'll skip all edges at this point, // mainly because stitching one edge would have an effect on corners and on the adjacent edges if (anyDeltas) @@ -242,13 +243,13 @@ namespace Terrain { for (size_t col = colStart; col < colEnd; col += increment) { - indices.push_back(ESM::Land::LAND_SIZE*col+row); - indices.push_back(ESM::Land::LAND_SIZE*(col+increment)+row+increment); - indices.push_back(ESM::Land::LAND_SIZE*col+row+increment); + indices.push_back(verts*col+row); + indices.push_back(verts*(col+increment)+row+increment); + indices.push_back(verts*col+row+increment); - indices.push_back(ESM::Land::LAND_SIZE*col+row); - indices.push_back(ESM::Land::LAND_SIZE*(col+increment)+row); - indices.push_back(ESM::Land::LAND_SIZE*(col+increment)+row+increment); + indices.push_back(verts*col+row); + indices.push_back(verts*(col+increment)+row); + indices.push_back(verts*(col+increment)+row+increment); } } @@ -261,96 +262,96 @@ namespace Terrain // South size_t row = 0; size_t outerStep = 1 << (lodDeltas[South] + lodLevel); - for (size_t col = 0; col < ESM::Land::LAND_SIZE-1; col += outerStep) + for (size_t col = 0; col < verts-1; col += outerStep) { - indices.push_back(ESM::Land::LAND_SIZE*col+row); - indices.push_back(ESM::Land::LAND_SIZE*(col+outerStep)+row); + indices.push_back(verts*col+row); + indices.push_back(verts*(col+outerStep)+row); // Make sure not to touch the right edge - if (col+outerStep == ESM::Land::LAND_SIZE-1) - indices.push_back(ESM::Land::LAND_SIZE*(col+outerStep-innerStep)+row+innerStep); + if (col+outerStep == verts-1) + indices.push_back(verts*(col+outerStep-innerStep)+row+innerStep); else - indices.push_back(ESM::Land::LAND_SIZE*(col+outerStep)+row+innerStep); + indices.push_back(verts*(col+outerStep)+row+innerStep); for (size_t i = 0; i < outerStep; i += innerStep) { // Make sure not to touch the left or right edges - if (col+i == 0 || col+i == ESM::Land::LAND_SIZE-1-innerStep) + if (col+i == 0 || col+i == verts-1-innerStep) continue; - indices.push_back(ESM::Land::LAND_SIZE*(col)+row); - indices.push_back(ESM::Land::LAND_SIZE*(col+i+innerStep)+row+innerStep); - indices.push_back(ESM::Land::LAND_SIZE*(col+i)+row+innerStep); + indices.push_back(verts*(col)+row); + indices.push_back(verts*(col+i+innerStep)+row+innerStep); + indices.push_back(verts*(col+i)+row+innerStep); } } // North - row = ESM::Land::LAND_SIZE-1; + row = verts-1; outerStep = 1 << (lodDeltas[North] + lodLevel); - for (size_t col = 0; col < ESM::Land::LAND_SIZE-1; col += outerStep) + for (size_t col = 0; col < verts-1; col += outerStep) { - indices.push_back(ESM::Land::LAND_SIZE*(col+outerStep)+row); - indices.push_back(ESM::Land::LAND_SIZE*col+row); + indices.push_back(verts*(col+outerStep)+row); + indices.push_back(verts*col+row); // Make sure not to touch the left edge if (col == 0) - indices.push_back(ESM::Land::LAND_SIZE*(col+innerStep)+row-innerStep); + indices.push_back(verts*(col+innerStep)+row-innerStep); else - indices.push_back(ESM::Land::LAND_SIZE*col+row-innerStep); + indices.push_back(verts*col+row-innerStep); for (size_t i = 0; i < outerStep; i += innerStep) { // Make sure not to touch the left or right edges - if (col+i == 0 || col+i == ESM::Land::LAND_SIZE-1-innerStep) + if (col+i == 0 || col+i == verts-1-innerStep) continue; - indices.push_back(ESM::Land::LAND_SIZE*(col+i)+row-innerStep); - indices.push_back(ESM::Land::LAND_SIZE*(col+i+innerStep)+row-innerStep); - indices.push_back(ESM::Land::LAND_SIZE*(col+outerStep)+row); + indices.push_back(verts*(col+i)+row-innerStep); + indices.push_back(verts*(col+i+innerStep)+row-innerStep); + indices.push_back(verts*(col+outerStep)+row); } } // West size_t col = 0; outerStep = 1 << (lodDeltas[West] + lodLevel); - for (size_t row = 0; row < ESM::Land::LAND_SIZE-1; row += outerStep) + for (size_t row = 0; row < verts-1; row += outerStep) { - indices.push_back(ESM::Land::LAND_SIZE*col+row+outerStep); - indices.push_back(ESM::Land::LAND_SIZE*col+row); + indices.push_back(verts*col+row+outerStep); + indices.push_back(verts*col+row); // Make sure not to touch the top edge - if (row+outerStep == ESM::Land::LAND_SIZE-1) - indices.push_back(ESM::Land::LAND_SIZE*(col+innerStep)+row+outerStep-innerStep); + if (row+outerStep == verts-1) + indices.push_back(verts*(col+innerStep)+row+outerStep-innerStep); else - indices.push_back(ESM::Land::LAND_SIZE*(col+innerStep)+row+outerStep); + indices.push_back(verts*(col+innerStep)+row+outerStep); for (size_t i = 0; i < outerStep; i += innerStep) { // Make sure not to touch the top or bottom edges - if (row+i == 0 || row+i == ESM::Land::LAND_SIZE-1-innerStep) + if (row+i == 0 || row+i == verts-1-innerStep) continue; - indices.push_back(ESM::Land::LAND_SIZE*col+row); - indices.push_back(ESM::Land::LAND_SIZE*(col+innerStep)+row+i); - indices.push_back(ESM::Land::LAND_SIZE*(col+innerStep)+row+i+innerStep); + indices.push_back(verts*col+row); + indices.push_back(verts*(col+innerStep)+row+i); + indices.push_back(verts*(col+innerStep)+row+i+innerStep); } } // East - col = ESM::Land::LAND_SIZE-1; + col = verts-1; outerStep = 1 << (lodDeltas[East] + lodLevel); - for (size_t row = 0; row < ESM::Land::LAND_SIZE-1; row += outerStep) + for (size_t row = 0; row < verts-1; row += outerStep) { - indices.push_back(ESM::Land::LAND_SIZE*col+row); - indices.push_back(ESM::Land::LAND_SIZE*col+row+outerStep); + indices.push_back(verts*col+row); + indices.push_back(verts*col+row+outerStep); // Make sure not to touch the bottom edge if (row == 0) - indices.push_back(ESM::Land::LAND_SIZE*(col-innerStep)+row+innerStep); + indices.push_back(verts*(col-innerStep)+row+innerStep); else - indices.push_back(ESM::Land::LAND_SIZE*(col-innerStep)+row); + indices.push_back(verts*(col-innerStep)+row); for (size_t i = 0; i < outerStep; i += innerStep) { // Make sure not to touch the top or bottom edges - if (row+i == 0 || row+i == ESM::Land::LAND_SIZE-1-innerStep) + if (row+i == 0 || row+i == verts-1-innerStep) continue; - indices.push_back(ESM::Land::LAND_SIZE*col+row+outerStep); - indices.push_back(ESM::Land::LAND_SIZE*(col-innerStep)+row+i+innerStep); - indices.push_back(ESM::Land::LAND_SIZE*(col-innerStep)+row+i); + indices.push_back(verts*col+row+outerStep); + indices.push_back(verts*(col-innerStep)+row+i+innerStep); + indices.push_back(verts*(col-innerStep)+row+i); } } } From d4a755d1aa53bc37661bc41ac390ce682e821346 Mon Sep 17 00:00:00 2001 From: scrawl <scrawl@baseoftrash.de> Date: Thu, 13 Feb 2014 11:15:55 +0100 Subject: [PATCH 54/94] Fix some hardcoded literals --- components/terrain/quadtreenode.cpp | 12 +++++++----- components/terrain/world.cpp | 10 ++++++---- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/components/terrain/quadtreenode.cpp b/components/terrain/quadtreenode.cpp index a4fdd5e13f..82ccc7c89a 100644 --- a/components/terrain/quadtreenode.cpp +++ b/components/terrain/quadtreenode.cpp @@ -168,7 +168,8 @@ QuadTreeNode::QuadTreeNode(World* terrain, ChildDirection dir, float size, const if (mParent) pos = mParent->getCenter(); pos = mCenter - pos; - mSceneNode->setPosition(Ogre::Vector3(pos.x*8192, pos.y*8192, 0)); + float cellWorldSize = mTerrain->getStorage()->getCellWorldSize(); + mSceneNode->setPosition(Ogre::Vector3(pos.x*cellWorldSize, pos.y*cellWorldSize, 0)); mMaterialGenerator = new MaterialGenerator(mTerrain->getShadersEnabled()); } @@ -203,6 +204,7 @@ void QuadTreeNode::initNeighbours() void QuadTreeNode::initAabb() { + float cellWorldSize = mTerrain->getStorage()->getCellWorldSize(); if (hasChildren()) { for (int i=0; i<4; ++i) @@ -210,11 +212,11 @@ void QuadTreeNode::initAabb() mChildren[i]->initAabb(); mBounds.merge(mChildren[i]->getBoundingBox()); } - mBounds = Ogre::AxisAlignedBox (Ogre::Vector3(-mSize/2*8192, -mSize/2*8192, mBounds.getMinimum().z), - Ogre::Vector3(mSize/2*8192, mSize/2*8192, mBounds.getMaximum().z)); + mBounds = Ogre::AxisAlignedBox (Ogre::Vector3(-mSize/2*cellWorldSize, -mSize/2*cellWorldSize, mBounds.getMinimum().z), + Ogre::Vector3(mSize/2*cellWorldSize, mSize/2*cellWorldSize, mBounds.getMaximum().z)); } - mWorldBounds = Ogre::AxisAlignedBox(mBounds.getMinimum() + Ogre::Vector3(mCenter.x*8192, mCenter.y*8192, 0), - mBounds.getMaximum() + Ogre::Vector3(mCenter.x*8192, mCenter.y*8192, 0)); + mWorldBounds = Ogre::AxisAlignedBox(mBounds.getMinimum() + Ogre::Vector3(mCenter.x*cellWorldSize, mCenter.y*cellWorldSize, 0), + mBounds.getMaximum() + Ogre::Vector3(mCenter.x*cellWorldSize, mCenter.y*cellWorldSize, 0)); } void QuadTreeNode::setBoundingBox(const Ogre::AxisAlignedBox &box) diff --git a/components/terrain/world.cpp b/components/terrain/world.cpp index dac960fbb6..f4070393d7 100644 --- a/components/terrain/world.cpp +++ b/components/terrain/world.cpp @@ -113,9 +113,10 @@ namespace Terrain // We arrived at a leaf float minZ,maxZ; Ogre::Vector2 center = node->getCenter(); + float cellWorldSize = getStorage()->getCellWorldSize(); if (mStorage->getMinMaxHeights(node->getSize(), center, minZ, maxZ)) - node->setBoundingBox(Ogre::AxisAlignedBox(Ogre::Vector3(-halfSize*8192, -halfSize*8192, minZ), - Ogre::Vector3(halfSize*8192, halfSize*8192, maxZ))); + node->setBoundingBox(Ogre::AxisAlignedBox(Ogre::Vector3(-halfSize*cellWorldSize, -halfSize*cellWorldSize, minZ), + Ogre::Vector3(halfSize*cellWorldSize, halfSize*cellWorldSize, maxZ))); else node->markAsDummy(); // no data available for this node, skip it return; @@ -168,8 +169,9 @@ namespace Terrain return Ogre::AxisAlignedBox::BOX_NULL; QuadTreeNode* node = findNode(center, mRootNode); Ogre::AxisAlignedBox box = node->getBoundingBox(); - box.setExtents(box.getMinimum() + Ogre::Vector3(center.x, center.y, 0) * 8192, - box.getMaximum() + Ogre::Vector3(center.x, center.y, 0) * 8192); + float cellWorldSize = getStorage()->getCellWorldSize(); + box.setExtents(box.getMinimum() + Ogre::Vector3(center.x, center.y, 0) * cellWorldSize, + box.getMaximum() + Ogre::Vector3(center.x, center.y, 0) * cellWorldSize); return box; } From 4e6507248bf58e552f331e26fb3c5cc03fa55745 Mon Sep 17 00:00:00 2001 From: scrawl <scrawl@baseoftrash.de> Date: Thu, 13 Feb 2014 12:19:21 +0100 Subject: [PATCH 55/94] Fix travis build --- .travis.yml | 2 +- CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 04d019c0d8..693db6f116 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ branches: - next before_install: - pwd - - git submodule update --init --recursive + - git fetch --tags - echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse" - echo "yes" | sudo apt-add-repository ppa:openmw/openmw - sudo apt-get update -qq diff --git a/CMakeLists.txt b/CMakeLists.txt index 01ac9b23f3..6f209552cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,7 @@ include(OpenMWMacros) include(GetGitRevisionDescription) -get_git_tag_revision(TAGHASH --tags --max-count=1) +get_git_tag_revision(TAGHASH --tags --max-count=1 "HEAD...") get_git_head_revision(REFSPEC COMMITHASH) git_describe(VERSION --tags ${TAGHASH}) From 0fcec24c9b02b9a5924907891f5fa34296f16c12 Mon Sep 17 00:00:00 2001 From: scrawl <scrawl@baseoftrash.de> Date: Thu, 13 Feb 2014 12:24:15 +0100 Subject: [PATCH 56/94] Remove some bogus dependencies for travis build --- .travis.yml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 693db6f116..bc60f3ca63 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,17 +4,16 @@ compiler: branches: only: - master - - next before_install: - pwd - git fetch --tags - echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse" - echo "yes" | sudo apt-add-repository ppa:openmw/openmw - sudo apt-get update -qq - - sudo apt-get install -qq libboost-all-dev libgtest-dev google-mock libzzip-dev uuid-dev - - sudo apt-get install -qq libqt4-dev libxaw7-dev libxrandr-dev libfreeimage-dev libpng-dev - - sudo apt-get install -qq libopenal-dev libmpg123-dev libsndfile1-dev - - sudo apt-get install -qq libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev libpostproc-dev + - sudo apt-get install -qq libboost-all-dev libgtest-dev google-mock + - sudo apt-get install -qq libqt4-dev + - sudo apt-get install -qq libopenal-dev + - sudo apt-get install -qq libavcodec-dev libavformat-dev libavutil-dev libswscale-dev - sudo apt-get install -qq libbullet-dev libogre-1.9-dev libmygui-dev libsdl2-dev libunshield-dev - sudo mkdir /usr/src/gtest/build - cd /usr/src/gtest/build From 1ed1b432961223122346d4ea0e4304d28a5d1578 Mon Sep 17 00:00:00 2001 From: scrawl <scrawl@baseoftrash.de> Date: Thu, 13 Feb 2014 12:30:53 +0100 Subject: [PATCH 57/94] Enable release branches in Travis CI --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index bc60f3ca63..b7a5d61ad4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,7 @@ compiler: branches: only: - master + - /openmw-.*$/ before_install: - pwd - git fetch --tags From ea90035eca1892a503666ab988eaba2eac0a3fb7 Mon Sep 17 00:00:00 2001 From: scrawl <scrawl@baseoftrash.de> Date: Thu, 13 Feb 2014 12:35:33 +0100 Subject: [PATCH 58/94] Enable irc notification for travis --- .travis.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.travis.yml b/.travis.yml index b7a5d61ad4..39a02de63e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -37,3 +37,9 @@ notifications: email: on_success: change on_failure: always + irc: + channels: + - "chat.freenode.net#openmw" + on_success: change + on_failure: always + From 309573a3ac01f38fe27ce3a3d00b2e0e90187814 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Thu, 13 Feb 2014 14:15:48 +0100 Subject: [PATCH 59/94] allow the use of the keyword end as a variable name in an expression --- components/compiler/exprparser.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 07f576006f..474de856a4 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -355,6 +355,11 @@ namespace Compiler } } + if (keyword==Scanner::K_end) + { + return parseName (loc.mLiteral, loc, scanner); + } + mFirst = false; if (!mExplicit.empty()) From e9238b456d8e830421b140f0bdb60552144ab2a2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Thu, 13 Feb 2014 15:01:10 +0100 Subject: [PATCH 60/94] use case-insensitive sorting in columns --- apps/opencs/model/world/idtableproxymodel.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/idtableproxymodel.cpp b/apps/opencs/model/world/idtableproxymodel.cpp index 2b757adfe5..f51b7f818f 100644 --- a/apps/opencs/model/world/idtableproxymodel.cpp +++ b/apps/opencs/model/world/idtableproxymodel.cpp @@ -33,7 +33,9 @@ bool CSMWorld::IdTableProxyModel::filterAcceptsRow (int sourceRow, const QModelI CSMWorld::IdTableProxyModel::IdTableProxyModel (QObject *parent) : QSortFilterProxyModel (parent) -{} +{ + setSortCaseSensitivity (Qt::CaseInsensitive); +} QModelIndex CSMWorld::IdTableProxyModel::getModelIndex (const std::string& id, int column) const { From f7ff4fbd51178825a1199ae4b5a5b7cabc765e16 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Thu, 13 Feb 2014 15:31:07 +0100 Subject: [PATCH 61/94] allow disable as an alias for getDisabled (in most cases) --- components/compiler/exprparser.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 474de856a4..6b451292a9 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -366,7 +366,8 @@ namespace Compiler { if (mRefOp && mNextOperand) { - if (keyword==Scanner::K_getdisabled) + if (keyword==Scanner::K_getdisabled || + keyword==Scanner::K_disable) /// \todo add option to disable this { start(); @@ -509,7 +510,8 @@ namespace Compiler mNextOperand = false; return true; } - else if (keyword==Scanner::K_getdisabled) + else if (keyword==Scanner::K_getdisabled || + keyword==Scanner::K_disable) /// \todo add option to disable this { start(); From e597328b6b6ae483f69adcc4878ca3ff92c0f50f Mon Sep 17 00:00:00 2001 From: Emanuel Guevel <guevel.emanuel@gmail.com> Date: Thu, 13 Feb 2014 20:24:27 +0100 Subject: [PATCH 62/94] Make enable/disable a no-op for items in containers --- apps/openmw/mwworld/worldimp.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 4e240195ad..95bf65d088 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -610,6 +610,10 @@ namespace MWWorld void World::enable (const Ptr& reference) { + // enable is a no-op for items in containers + if (!reference.isInCell()) + return; + if (!reference.getRefData().isEnabled()) { reference.getRefData().enable(); @@ -640,6 +644,10 @@ namespace MWWorld void World::disable (const Ptr& reference) { + // disable is a no-op for items in containers + if (!reference.isInCell()) + return; + if (reference.getRefData().isEnabled()) { reference.getRefData().disable(); From 7c981587fca5b2671dd59e9cf9b6b2ccdcf83627 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel <guevel.emanuel@gmail.com> Date: Thu, 13 Feb 2014 22:58:12 +0100 Subject: [PATCH 63/94] When searching object by id, search in active cells before searching in the player's inventory --- apps/openmw/mwworld/worldimp.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 95bf65d088..be6c0b338f 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -529,12 +529,6 @@ namespace MWWorld return mPlayer->getPlayer(); } - Ptr ptr = Class::get (mPlayer->getPlayer()). - getContainerStore (mPlayer->getPlayer()).search (name); - - if (!ptr.isEmpty()) - return ptr; - std::string lowerCaseName = Misc::StringUtils::lowerCase(name); // active cells @@ -548,6 +542,12 @@ namespace MWWorld return ptr; } + Ptr ptr = Class::get (mPlayer->getPlayer()). + getContainerStore (mPlayer->getPlayer()).search (lowerCaseName); + + if (!ptr.isEmpty()) + return ptr; + if (!activeOnly) { ret = mCells.getPtr (lowerCaseName); From b01c6dad375375864f5b667b9d31ce8b310ff482 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Fri, 14 Feb 2014 08:29:18 +0100 Subject: [PATCH 64/94] Revert "allow disable as an alias for getDisabled (in most cases)" This reverts commit f7ff4fbd51178825a1199ae4b5a5b7cabc765e16. --- components/compiler/exprparser.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 6b451292a9..474de856a4 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -366,8 +366,7 @@ namespace Compiler { if (mRefOp && mNextOperand) { - if (keyword==Scanner::K_getdisabled || - keyword==Scanner::K_disable) /// \todo add option to disable this + if (keyword==Scanner::K_getdisabled) { start(); @@ -510,8 +509,7 @@ namespace Compiler mNextOperand = false; return true; } - else if (keyword==Scanner::K_getdisabled || - keyword==Scanner::K_disable) /// \todo add option to disable this + else if (keyword==Scanner::K_getdisabled) { start(); From 2086ebe4104a00d00ede72c174138640a43948fa Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Fri, 14 Feb 2014 08:48:26 +0100 Subject: [PATCH 65/94] fix for inappropriate disable (2nd attempt) --- components/compiler/exprparser.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 474de856a4..7d310617ce 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -355,7 +355,16 @@ namespace Compiler } } - if (keyword==Scanner::K_end) + if (keyword==Scanner::K_end || keyword==Scanner::K_begin || + keyword==Scanner::K_short || keyword==Scanner::K_long || + keyword==Scanner::K_float || keyword==Scanner::K_if || + keyword==Scanner::K_endif || keyword==Scanner::K_else || + keyword==Scanner::K_elseif || keyword==Scanner::K_while || + keyword==Scanner::K_endwhile || keyword==Scanner::K_return || + keyword==Scanner::K_messagebox || keyword==Scanner::K_set || + keyword==Scanner::K_to || keyword==Scanner::K_startscript || + keyword==Scanner::K_stopscript || keyword==Scanner::K_enable || + keyword==Scanner::K_disable) { return parseName (loc.mLiteral, loc, scanner); } From e76ef9266995a83fad40f3ebc2b74a54d5d6ff17 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Fri, 14 Feb 2014 09:06:06 +0100 Subject: [PATCH 66/94] also allow the use of keywords as remote local variables in set statements --- components/compiler/lineparser.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 495e7e25e5..b1956e6283 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -219,6 +219,20 @@ namespace Compiler bool LineParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner) { + if (mState==SetMemberVarState) + { + mMemberName = loc.mLiteral; + std::pair<char, bool> type = getContext().getMemberType (mMemberName, mName); + + if (type.first!=' ') + { + mState = SetMemberVarState2; + mType = type.first; + mReferenceMember = type.second; + return true; + } + } + if (mState==SetPotentialMemberVarState && keyword==Scanner::K_to) { getErrorHandler().warning ("unknown variable (ignoring set instruction)", loc); From 451e1f413ba33170ba01e96788443a51b1c5a113 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Fri, 14 Feb 2014 11:15:16 +0100 Subject: [PATCH 67/94] instead of using pre-compiled variable lists for remote member access get the variable list from the remote script on the fly --- apps/openmw/mwscript/scriptmanagerimp.cpp | 17 +++----- components/CMakeLists.txt | 1 + components/compiler/declarationparser.cpp | 5 +++ components/compiler/declarationparser.hpp | 2 + components/compiler/quickfileparser.cpp | 52 +++++++++++++++++++++++ components/compiler/quickfileparser.hpp | 39 +++++++++++++++++ 6 files changed, 105 insertions(+), 11 deletions(-) create mode 100644 components/compiler/quickfileparser.cpp create mode 100644 components/compiler/quickfileparser.hpp diff --git a/apps/openmw/mwscript/scriptmanagerimp.cpp b/apps/openmw/mwscript/scriptmanagerimp.cpp index 5e18151da4..74c85dbbf7 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.cpp +++ b/apps/openmw/mwscript/scriptmanagerimp.cpp @@ -13,6 +13,7 @@ #include <components/compiler/scanner.hpp> #include <components/compiler/context.hpp> #include <components/compiler/exception.hpp> +#include <components/compiler/quickfileparser.hpp> #include "../mwworld/esmstore.hpp" @@ -159,20 +160,14 @@ namespace MWScript return iter->second; } - Compiler::Locals locals; - if (const ESM::Script *script = mStore.get<ESM::Script>().find (name2)) { - int index = 0; + Compiler::Locals locals; - for (int i=0; i<script->mData.mNumShorts; ++i) - locals.declare ('s', script->mVarNames[index++]); - - for (int i=0; i<script->mData.mNumLongs; ++i) - locals.declare ('l', script->mVarNames[index++]); - - for (int i=0; i<script->mData.mNumFloats; ++i) - locals.declare ('f', script->mVarNames[index++]); + std::istringstream stream (script->mScriptText); + Compiler::QuickFileParser parser (mErrorHandler, mCompilerContext, locals); + Compiler::Scanner scanner (mErrorHandler, stream, mCompilerContext.getExtensions()); + scanner.scan (parser); std::map<std::string, Compiler::Locals>::iterator iter = mOtherLocals.insert (std::make_pair (name2, locals)).first; diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index fbe9ad5bd3..45a91f368c 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -60,6 +60,7 @@ add_component_dir (compiler context controlparser errorhandler exception exprparser extensions fileparser generator lineparser literals locals output parser scanner scriptparser skipparser streamerrorhandler stringparser tokenloc nullerrorhandler opcodes extensions0 declarationparser + quickfileparser ) add_component_dir (interpreter diff --git a/components/compiler/declarationparser.cpp b/components/compiler/declarationparser.cpp index 9c4e4f631b..357f0259be 100644 --- a/components/compiler/declarationparser.cpp +++ b/components/compiler/declarationparser.cpp @@ -75,4 +75,9 @@ bool Compiler::DeclarationParser::parseSpecial (int code, const TokenLoc& loc, S return false; return Parser::parseSpecial (code, loc, scanner); +} + +void Compiler::DeclarationParser::reset() +{ + mState = State_Begin; } \ No newline at end of file diff --git a/components/compiler/declarationparser.hpp b/components/compiler/declarationparser.hpp index 3e0ac57c34..f85b31ba15 100644 --- a/components/compiler/declarationparser.hpp +++ b/components/compiler/declarationparser.hpp @@ -35,6 +35,8 @@ namespace Compiler ///< Handle a special character token. /// \return fetch another token? + void reset(); + }; } diff --git a/components/compiler/quickfileparser.cpp b/components/compiler/quickfileparser.cpp new file mode 100644 index 0000000000..157e152490 --- /dev/null +++ b/components/compiler/quickfileparser.cpp @@ -0,0 +1,52 @@ + +#include "quickfileparser.hpp" + +#include "skipparser.hpp" +#include "scanner.hpp" + +Compiler::QuickFileParser::QuickFileParser (ErrorHandler& errorHandler, Context& context, + Locals& locals) +: Parser (errorHandler, context), mDeclarationParser (errorHandler, context, locals) +{} + +bool Compiler::QuickFileParser::parseName (const std::string& name, const TokenLoc& loc, + Scanner& scanner) +{ + SkipParser skip (getErrorHandler(), getContext()); + scanner.scan (skip); + return true; +} + +bool Compiler::QuickFileParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner) +{ + if (keyword==Scanner::K_end) + return false; + + if (keyword==Scanner::K_short || keyword==Scanner::K_long || keyword==Scanner::K_float) + { + mDeclarationParser.reset(); + scanner.putbackKeyword (keyword, loc); + scanner.scan (mDeclarationParser); + return true; + } + + SkipParser skip (getErrorHandler(), getContext()); + scanner.scan (skip); + return true; +} + +bool Compiler::QuickFileParser::parseSpecial (int code, const TokenLoc& loc, Scanner& scanner) +{ + if (code!=Scanner::S_newline) + { + SkipParser skip (getErrorHandler(), getContext()); + scanner.scan (skip); + } + + return true; +} + +void Compiler::QuickFileParser::parseEOF (Scanner& scanner) +{ + +} \ No newline at end of file diff --git a/components/compiler/quickfileparser.hpp b/components/compiler/quickfileparser.hpp new file mode 100644 index 0000000000..d2dfafb346 --- /dev/null +++ b/components/compiler/quickfileparser.hpp @@ -0,0 +1,39 @@ +#ifndef COMPILER_QUICKFILEPARSER_H_INCLUDED +#define COMPILER_QUICKFILEPARSER_H_INCLUDED + +#include "parser.hpp" +#include "declarationparser.hpp" + +namespace Compiler +{ + class Locals; + + /// \brief File parser variant that ignores everything but variable declarations + class QuickFileParser : public Parser + { + DeclarationParser mDeclarationParser; + + public: + + QuickFileParser (ErrorHandler& errorHandler, Context& context, Locals& locals); + + virtual bool parseName (const std::string& name, const TokenLoc& loc, + Scanner& scanner); + ///< Handle a name token. + /// \return fetch another token? + + virtual bool parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner); + ///< Handle a keyword token. + /// \return fetch another token? + + virtual bool parseSpecial (int code, const TokenLoc& loc, Scanner& scanner); + ///< Handle a special character token. + /// \return fetch another token? + + virtual void parseEOF (Scanner& scanner); + ///< Handle EOF token. + }; +} + +#endif + From 910d62e4b84e701e4da58ac83e0d882804eb6c6f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Fri, 14 Feb 2014 11:59:33 +0100 Subject: [PATCH 68/94] added missing implementation for CSMWorld::ScriptContext::getGlobalType --- apps/opencs/model/world/scriptcontext.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/apps/opencs/model/world/scriptcontext.cpp b/apps/opencs/model/world/scriptcontext.cpp index 1b30281595..2627c49f3e 100644 --- a/apps/opencs/model/world/scriptcontext.cpp +++ b/apps/opencs/model/world/scriptcontext.cpp @@ -16,6 +16,20 @@ bool CSMWorld::ScriptContext::canDeclareLocals() const char CSMWorld::ScriptContext::getGlobalType (const std::string& name) const { + int index = mData.getGlobals().searchId (name); + + if (index!=-1) + { + switch (mData.getGlobals().getRecord (index).get().mValue.getType()) + { + case ESM::VT_Short: return 's'; + case ESM::VT_Long: return 'l'; + case ESM::VT_Float: return 'f'; + + default: return ' '; + } + } + return ' '; } From d213c6c36a48f3435e1b42aa9d4101eb0618ebc0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Fri, 14 Feb 2014 12:23:00 +0100 Subject: [PATCH 69/94] fixed a constness-issue --- components/compiler/controlparser.cpp | 2 +- components/compiler/controlparser.hpp | 2 +- components/compiler/declarationparser.cpp | 2 +- components/compiler/declarationparser.hpp | 2 +- components/compiler/exprparser.cpp | 2 +- components/compiler/exprparser.hpp | 2 +- components/compiler/lineparser.cpp | 2 +- components/compiler/lineparser.hpp | 2 +- components/compiler/parser.cpp | 4 ++-- components/compiler/parser.hpp | 6 +++--- components/compiler/quickfileparser.cpp | 2 +- components/compiler/quickfileparser.hpp | 2 +- components/compiler/scriptparser.cpp | 2 +- components/compiler/scriptparser.hpp | 14 +++++++------- components/compiler/skipparser.cpp | 4 ++-- components/compiler/skipparser.hpp | 8 ++++---- components/compiler/stringparser.cpp | 2 +- components/compiler/stringparser.hpp | 18 +++++++++--------- 18 files changed, 39 insertions(+), 39 deletions(-) diff --git a/components/compiler/controlparser.cpp b/components/compiler/controlparser.cpp index 499358ca02..58542bd739 100644 --- a/components/compiler/controlparser.cpp +++ b/components/compiler/controlparser.cpp @@ -154,7 +154,7 @@ namespace Compiler } } - ControlParser::ControlParser (ErrorHandler& errorHandler, Context& context, Locals& locals, + ControlParser::ControlParser (ErrorHandler& errorHandler, const Context& context, Locals& locals, Literals& literals) : Parser (errorHandler, context), mLocals (locals), mLiterals (literals), mLineParser (errorHandler, context, locals, literals, mCodeBlock), diff --git a/components/compiler/controlparser.hpp b/components/compiler/controlparser.hpp index 50fd2d1f9e..24bc7bec75 100644 --- a/components/compiler/controlparser.hpp +++ b/components/compiler/controlparser.hpp @@ -47,7 +47,7 @@ namespace Compiler public: - ControlParser (ErrorHandler& errorHandler, Context& context, Locals& locals, + ControlParser (ErrorHandler& errorHandler, const Context& context, Locals& locals, Literals& literals); void appendCode (std::vector<Interpreter::Type_Code>& code) const; diff --git a/components/compiler/declarationparser.cpp b/components/compiler/declarationparser.cpp index 357f0259be..d17f49caf0 100644 --- a/components/compiler/declarationparser.cpp +++ b/components/compiler/declarationparser.cpp @@ -8,7 +8,7 @@ #include "skipparser.hpp" #include "locals.hpp" -Compiler::DeclarationParser::DeclarationParser (ErrorHandler& errorHandler, Context& context, +Compiler::DeclarationParser::DeclarationParser (ErrorHandler& errorHandler, const Context& context, Locals& locals) : Parser (errorHandler, context), mLocals (locals), mState (State_Begin), mType (0) {} diff --git a/components/compiler/declarationparser.hpp b/components/compiler/declarationparser.hpp index f85b31ba15..43dd835705 100644 --- a/components/compiler/declarationparser.hpp +++ b/components/compiler/declarationparser.hpp @@ -20,7 +20,7 @@ namespace Compiler public: - DeclarationParser (ErrorHandler& errorHandler, Context& context, Locals& locals); + DeclarationParser (ErrorHandler& errorHandler, const Context& context, Locals& locals); virtual bool parseName (const std::string& name, const TokenLoc& loc, Scanner& scanner); diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 7d310617ce..6d26ef403c 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -219,7 +219,7 @@ namespace Compiler return false; } - ExprParser::ExprParser (ErrorHandler& errorHandler, Context& context, Locals& locals, + ExprParser::ExprParser (ErrorHandler& errorHandler, const Context& context, Locals& locals, Literals& literals, bool argument) : Parser (errorHandler, context), mLocals (locals), mLiterals (literals), mNextOperand (true), mFirst (true), mArgument (argument), mRefOp (false), mMemberOp (false) diff --git a/components/compiler/exprparser.hpp b/components/compiler/exprparser.hpp index 905f0d454f..6a4e1be2ff 100644 --- a/components/compiler/exprparser.hpp +++ b/components/compiler/exprparser.hpp @@ -58,7 +58,7 @@ namespace Compiler public: - ExprParser (ErrorHandler& errorHandler, Context& context, Locals& locals, + ExprParser (ErrorHandler& errorHandler, const Context& context, Locals& locals, Literals& literals, bool argument = false); ///< constructor /// \param argument Parser is used to parse function- or instruction- diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index b1956e6283..5457d76255 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -50,7 +50,7 @@ namespace Compiler } } - LineParser::LineParser (ErrorHandler& errorHandler, Context& context, Locals& locals, + LineParser::LineParser (ErrorHandler& errorHandler, const Context& context, Locals& locals, Literals& literals, std::vector<Interpreter::Type_Code>& code, bool allowExpression) : Parser (errorHandler, context), mLocals (locals), mLiterals (literals), mCode (code), mState (BeginState), mExprParser (errorHandler, context, locals, literals), diff --git a/components/compiler/lineparser.hpp b/components/compiler/lineparser.hpp index c54c764bce..4f2d33bde5 100644 --- a/components/compiler/lineparser.hpp +++ b/components/compiler/lineparser.hpp @@ -44,7 +44,7 @@ namespace Compiler public: - LineParser (ErrorHandler& errorHandler, Context& context, Locals& locals, + LineParser (ErrorHandler& errorHandler, const Context& context, Locals& locals, Literals& literals, std::vector<Interpreter::Type_Code>& code, bool allowExpression = false); ///< \param allowExpression Allow lines consisting of a naked expression diff --git a/components/compiler/parser.cpp b/components/compiler/parser.cpp index 8d11c4086d..781fbad8cb 100644 --- a/components/compiler/parser.cpp +++ b/components/compiler/parser.cpp @@ -52,7 +52,7 @@ namespace Compiler // Return context - Context& Parser::getContext() + const Context& Parser::getContext() const { return mContext; } @@ -64,7 +64,7 @@ namespace Compiler return lowerCase; } - Parser::Parser (ErrorHandler& errorHandler, Context& context) + Parser::Parser (ErrorHandler& errorHandler, const Context& context) : mErrorHandler (errorHandler), mContext (context), mOptional (false), mEmpty (true) {} diff --git a/components/compiler/parser.hpp b/components/compiler/parser.hpp index 4fec570e9f..54e913b202 100644 --- a/components/compiler/parser.hpp +++ b/components/compiler/parser.hpp @@ -17,7 +17,7 @@ namespace Compiler class Parser { ErrorHandler& mErrorHandler; - Context& mContext; + const Context& mContext; bool mOptional; bool mEmpty; @@ -38,14 +38,14 @@ namespace Compiler ErrorHandler& getErrorHandler(); ///< Return error handler - Context& getContext(); + const Context& getContext() const; ///< Return context static std::string toLower (const std::string& name); public: - Parser (ErrorHandler& errorHandler, Context& context); + Parser (ErrorHandler& errorHandler, const Context& context); ///< constructor virtual ~Parser(); diff --git a/components/compiler/quickfileparser.cpp b/components/compiler/quickfileparser.cpp index 157e152490..f3d8063b2f 100644 --- a/components/compiler/quickfileparser.cpp +++ b/components/compiler/quickfileparser.cpp @@ -4,7 +4,7 @@ #include "skipparser.hpp" #include "scanner.hpp" -Compiler::QuickFileParser::QuickFileParser (ErrorHandler& errorHandler, Context& context, +Compiler::QuickFileParser::QuickFileParser (ErrorHandler& errorHandler, const Context& context, Locals& locals) : Parser (errorHandler, context), mDeclarationParser (errorHandler, context, locals) {} diff --git a/components/compiler/quickfileparser.hpp b/components/compiler/quickfileparser.hpp index d2dfafb346..440d910387 100644 --- a/components/compiler/quickfileparser.hpp +++ b/components/compiler/quickfileparser.hpp @@ -15,7 +15,7 @@ namespace Compiler public: - QuickFileParser (ErrorHandler& errorHandler, Context& context, Locals& locals); + QuickFileParser (ErrorHandler& errorHandler, const Context& context, Locals& locals); virtual bool parseName (const std::string& name, const TokenLoc& loc, Scanner& scanner); diff --git a/components/compiler/scriptparser.cpp b/components/compiler/scriptparser.cpp index f34313969a..ea11be5f03 100644 --- a/components/compiler/scriptparser.cpp +++ b/components/compiler/scriptparser.cpp @@ -7,7 +7,7 @@ namespace Compiler { - ScriptParser::ScriptParser (ErrorHandler& errorHandler, Context& context, + ScriptParser::ScriptParser (ErrorHandler& errorHandler, const Context& context, Locals& locals, bool end) : Parser (errorHandler, context), mOutput (locals), mLineParser (errorHandler, context, locals, mOutput.getLiterals(), mOutput.getCode()), diff --git a/components/compiler/scriptparser.hpp b/components/compiler/scriptparser.hpp index bb4809dabd..000244c793 100644 --- a/components/compiler/scriptparser.hpp +++ b/components/compiler/scriptparser.hpp @@ -12,7 +12,7 @@ namespace Compiler class Locals; // Script parser, to be used in dialogue scripts and as part of FileParser - + class ScriptParser : public Parser { Output mOutput; @@ -21,14 +21,14 @@ namespace Compiler bool mEnd; public: - + /// \param end of script is marked by end keyword. - ScriptParser (ErrorHandler& errorHandler, Context& context, Locals& locals, + ScriptParser (ErrorHandler& errorHandler, const Context& context, Locals& locals, bool end = false); - + void getCode (std::vector<Interpreter::Type_Code>& code) const; ///< store generated code in \Ʀ code. - + virtual bool parseName (const std::string& name, const TokenLoc& loc, Scanner& scanner); ///< Handle a name token. @@ -43,8 +43,8 @@ namespace Compiler /// \return fetch another token? virtual void parseEOF (Scanner& scanner); - ///< Handle EOF token. - + ///< Handle EOF token. + void reset(); ///< Reset parser to clean state. }; diff --git a/components/compiler/skipparser.cpp b/components/compiler/skipparser.cpp index 2d09b63ba0..c7cb31f58e 100644 --- a/components/compiler/skipparser.cpp +++ b/components/compiler/skipparser.cpp @@ -5,7 +5,7 @@ namespace Compiler { - SkipParser::SkipParser (ErrorHandler& errorHandler, Context& context) + SkipParser::SkipParser (ErrorHandler& errorHandler, const Context& context) : Parser (errorHandler, context) {} @@ -34,7 +34,7 @@ namespace Compiler { if (code==Scanner::S_newline) return false; - + return true; } } diff --git a/components/compiler/skipparser.hpp b/components/compiler/skipparser.hpp index 17f1c8d988..239c8bb02c 100644 --- a/components/compiler/skipparser.hpp +++ b/components/compiler/skipparser.hpp @@ -8,13 +8,13 @@ namespace Compiler // \brief Skip parser for skipping a line // // This parser is mainly intended for skipping the rest of a faulty line. - + class SkipParser : public Parser { public: - - SkipParser (ErrorHandler& errorHandler, Context& context); - + + SkipParser (ErrorHandler& errorHandler, const Context& context); + virtual bool parseInt (int value, const TokenLoc& loc, Scanner& scanner); ///< Handle an int token. /// \return fetch another token? diff --git a/components/compiler/stringparser.cpp b/components/compiler/stringparser.cpp index 09c902131a..a86c15794f 100644 --- a/components/compiler/stringparser.cpp +++ b/components/compiler/stringparser.cpp @@ -10,7 +10,7 @@ namespace Compiler { - StringParser::StringParser (ErrorHandler& errorHandler, Context& context, Literals& literals) + StringParser::StringParser (ErrorHandler& errorHandler, const Context& context, Literals& literals) : Parser (errorHandler, context), mLiterals (literals), mState (StartState), mSmashCase (false) { diff --git a/components/compiler/stringparser.hpp b/components/compiler/stringparser.hpp index f692c650b8..3859a24965 100644 --- a/components/compiler/stringparser.hpp +++ b/components/compiler/stringparser.hpp @@ -10,22 +10,22 @@ namespace Compiler { class Literals; - + class StringParser : public Parser { enum State { StartState, CommaState }; - + Literals& mLiterals; State mState; std::vector<Interpreter::Type_Code> mCode; bool mSmashCase; - + public: - - StringParser (ErrorHandler& errorHandler, Context& context, Literals& literals); + + StringParser (ErrorHandler& errorHandler, const Context& context, Literals& literals); virtual bool parseName (const std::string& name, const TokenLoc& loc, Scanner& scanner); @@ -35,15 +35,15 @@ namespace Compiler virtual bool parseSpecial (int code, const TokenLoc& loc, Scanner& scanner); ///< Handle a special character token. /// \return fetch another token? - + void append (std::vector<Interpreter::Type_Code>& code); ///< Append code for parsed string. - + void smashCase(); ///< Transform all scanned strings to lower case - + void reset(); - ///< Reset parser to clean state (this includes the smashCase function). + ///< Reset parser to clean state (this includes the smashCase function). }; } From 0a8ffbfb1d67080b1e22b0f7756794fa6134b94c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Fri, 14 Feb 2014 12:46:54 +0100 Subject: [PATCH 70/94] added missing implementation for CSMWorld::ScriptContext::getMemberType --- apps/opencs/model/world/scriptcontext.cpp | 56 ++++++++++++++++++++++- apps/opencs/model/world/scriptcontext.hpp | 3 ++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/scriptcontext.cpp b/apps/opencs/model/world/scriptcontext.cpp index 2627c49f3e..ee95f06c86 100644 --- a/apps/opencs/model/world/scriptcontext.cpp +++ b/apps/opencs/model/world/scriptcontext.cpp @@ -5,6 +5,10 @@ #include <components/misc/stringops.hpp> +#include <components/compiler/quickfileparser.hpp> +#include <components/compiler/nullerrorhandler.hpp> +#include <components/compiler/scanner.hpp> + #include "data.hpp" CSMWorld::ScriptContext::ScriptContext (const Data& data) : mData (data), mIdsUpdated (false) {} @@ -36,7 +40,57 @@ char CSMWorld::ScriptContext::getGlobalType (const std::string& name) const std::pair<char, bool> CSMWorld::ScriptContext::getMemberType (const std::string& name, const std::string& id) const { - return std::make_pair (' ', false); + /// \todo invalidate locals cache on change to scripts + + std::string id2 = Misc::StringUtils::lowerCase (id); + + int index = mData.getScripts().searchId (id2); + bool reference = false; + + if (index!=-1) + { + // ID is not a script ID. Search for a matching referenceable instead. + index = mData.getReferenceables().searchId (id2); + + if (index!=-1) + { + // Referenceable found. + int columnIndex = mData.getReferenceables().searchColumnIndex (Columns::ColumnId_Script); + + if (columnIndex!=-1) + { + id2 = Misc::StringUtils::lowerCase (mData.getReferenceables(). + getData (index, columnIndex).toString().toUtf8().constData()); + + if (!id2.empty()) + { + // Referenceable has a script -> use it. + index = mData.getScripts().searchId (id2); + reference = true; + } + } + } + } + + if (index==-1) + return std::make_pair (' ', false); + + std::map<std::string, Compiler::Locals>::iterator iter = mLocals.find (id2); + + if (iter==mLocals.end()) + { + Compiler::Locals locals; + + Compiler::NullErrorHandler errorHandler; + std::istringstream stream (mData.getScripts().getRecord (index).get().mScriptText); + Compiler::QuickFileParser parser (errorHandler, *this, locals); + Compiler::Scanner scanner (errorHandler, stream, getExtensions()); + scanner.scan (parser); + + iter = mLocals.insert (std::make_pair (id2, locals)).first; + } + + return std::make_pair (iter->second.getType (Misc::StringUtils::lowerCase (name)), reference); } bool CSMWorld::ScriptContext::isId (const std::string& name) const diff --git a/apps/opencs/model/world/scriptcontext.hpp b/apps/opencs/model/world/scriptcontext.hpp index 3baca99b24..400748e5fa 100644 --- a/apps/opencs/model/world/scriptcontext.hpp +++ b/apps/opencs/model/world/scriptcontext.hpp @@ -3,8 +3,10 @@ #include <string> #include <vector> +#include <map> #include <components/compiler/context.hpp> +#include <components/compiler/locals.hpp> namespace CSMWorld { @@ -15,6 +17,7 @@ namespace CSMWorld const Data& mData; mutable std::vector<std::string> mIds; mutable bool mIdsUpdated; + mutable std::map<std::string, Compiler::Locals> mLocals; public: From a315d5cc2b501d7c8b766ad7a603f80ce2366507 Mon Sep 17 00:00:00 2001 From: gus <gus_512@hotmail.com> Date: Fri, 14 Feb 2014 12:55:14 +0100 Subject: [PATCH 71/94] aiactivate works. Bug when you try to use it on a reference that doesn't exist. Need to clran up door.cpp --- apps/openmw/mwclass/door.cpp | 8 ++++---- apps/openmw/mwmechanics/aiactivate.cpp | 19 +++++++------------ 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index f99cffe04a..a846a84923 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -117,19 +117,19 @@ namespace MWClass { // teleport door /// \todo remove this if clause once ActionTeleport can also support other actors - if (MWBase::Environment::get().getWorld()->getPlayerPtr()==actor) - { + //if (MWBase::Environment::get().getWorld()->getPlayerPtr()==actor) + //{ boost::shared_ptr<MWWorld::Action> action(new MWWorld::ActionTeleport (ref->mRef.mDestCell, ref->mRef.mDoorDest)); action->setSound(openSound); return action; - } + /*} else { // another NPC or a creature is using the door return boost::shared_ptr<MWWorld::Action> (new MWWorld::FailedAction); - } + }*/ } else { diff --git a/apps/openmw/mwmechanics/aiactivate.cpp b/apps/openmw/mwmechanics/aiactivate.cpp index e751140c08..667ebea889 100644 --- a/apps/openmw/mwmechanics/aiactivate.cpp +++ b/apps/openmw/mwmechanics/aiactivate.cpp @@ -6,6 +6,7 @@ #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwworld/class.hpp" +#include "../mwworld/action.hpp" namespace { @@ -64,19 +65,11 @@ bool MWMechanics::AiActivate::execute (const MWWorld::Ptr& actor,float duration) { mCellX = cell->mData.mX; mCellY = cell->mData.mY; - float xCell = 0; - float yCell = 0; - - if(cell->isExterior()) - { - xCell = cell->mData.mX * ESM::Land::REAL_SIZE; - yCell = cell->mData.mY * ESM::Land::REAL_SIZE; - } ESM::Pathgrid::Point dest; dest.mX = targetPos.pos[0]; - dest.mY = targetPos.pos[0]; - dest.mZ = targetPos.pos[0]; + dest.mY = targetPos.pos[1]; + dest.mZ = targetPos.pos[2]; ESM::Pathgrid::Point start; start.mX = pos.pos[0]; @@ -92,7 +85,8 @@ bool MWMechanics::AiActivate::execute (const MWWorld::Ptr& actor,float duration) { movement.mPosition[1] = 0; MWWorld::Ptr target = world->getPtr(mObjectId,false); - MWWorld::Class::get(target).activate(target,actor); + MWWorld::Class::get(target).activate(target,actor).get()->execute(actor); + std::cout << "activated"; return true; } @@ -100,7 +94,8 @@ bool MWMechanics::AiActivate::execute (const MWWorld::Ptr& actor,float duration) { movement.mPosition[1] = 0; MWWorld::Ptr target = world->getPtr(mObjectId,false); - MWWorld::Class::get(target).activate(target,actor); + MWWorld::Class::get(target).activate(target,actor).get()->execute(actor); + std::cout << "activated"; return true; } From 0ff744c2ff801aee8bd635924d4eaaeca5f25b03 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Fri, 14 Feb 2014 12:56:05 +0100 Subject: [PATCH 72/94] fixed CSMWorld::ScriptContext::isJournalId --- apps/opencs/model/world/scriptcontext.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/opencs/model/world/scriptcontext.cpp b/apps/opencs/model/world/scriptcontext.cpp index ee95f06c86..688c33d308 100644 --- a/apps/opencs/model/world/scriptcontext.cpp +++ b/apps/opencs/model/world/scriptcontext.cpp @@ -109,8 +109,7 @@ bool CSMWorld::ScriptContext::isId (const std::string& name) const bool CSMWorld::ScriptContext::isJournalId (const std::string& name) const { - /// \todo fix this after isId is fixed - return isId (name); + return mData.getJournals().searchId (name)!=-1; } void CSMWorld::ScriptContext::invalidateIds() From e17af4231a9e16eb554a7b2fa56d3ca18fb99ead Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Fri, 14 Feb 2014 13:38:30 +0100 Subject: [PATCH 73/94] added script verifier --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/tools/scriptcheck.cpp | 98 +++++++++++++++++++++++ apps/opencs/model/tools/scriptcheck.hpp | 40 +++++++++ apps/opencs/model/tools/tools.cpp | 3 + apps/opencs/model/world/scriptcontext.cpp | 9 ++- apps/opencs/model/world/scriptcontext.hpp | 3 + 6 files changed, 153 insertions(+), 2 deletions(-) create mode 100644 apps/opencs/model/tools/scriptcheck.cpp create mode 100644 apps/opencs/model/tools/scriptcheck.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 5c3cd0dcc1..82313b7ed1 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -38,7 +38,7 @@ opencs_units (model/tools opencs_units_noqt (model/tools mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck - birthsigncheck spellcheck referenceablecheck + birthsigncheck spellcheck referenceablecheck scriptcheck ) diff --git a/apps/opencs/model/tools/scriptcheck.cpp b/apps/opencs/model/tools/scriptcheck.cpp new file mode 100644 index 0000000000..8ed41ec02d --- /dev/null +++ b/apps/opencs/model/tools/scriptcheck.cpp @@ -0,0 +1,98 @@ + +#include "scriptcheck.hpp" + +#include <components/compiler/tokenloc.hpp> +#include <components/compiler/scanner.hpp> +#include <components/compiler/fileparser.hpp> +#include <components/compiler/exception.hpp> +#include <components/compiler/extensions0.hpp> + +#include "../world/data.hpp" + +void CSMTools::ScriptCheckStage::report (const std::string& message, const Compiler::TokenLoc& loc, + Type type) +{ + std::ostringstream stream; + + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId); + + stream << id.toString() << "|"; + + if (type==ErrorMessage) + stream << "error "; + else + stream << "warning "; + + stream + << "line " << loc.mLine << ", column " << loc.mColumn + << " (" << loc.mLiteral << "): " << message; + + mMessages->push_back (stream.str()); +} + +void CSMTools::ScriptCheckStage::report (const std::string& message, Type type) +{ + std::ostringstream stream; + + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId); + + stream << id.toString() << "|"; + + if (type==ErrorMessage) + stream << "error: "; + else + stream << "warning: "; + + stream << message; + + mMessages->push_back (stream.str()); +} + +CSMTools::ScriptCheckStage::ScriptCheckStage (const CSMWorld::Data& data) +: mData (data), mContext (data), mMessages (0) +{ + Compiler::registerExtensions (mExtensions); + mContext.setExtensions (&mExtensions); +} + +int CSMTools::ScriptCheckStage::setup() +{ + mContext.clear(); + mMessages = 0; + mId.clear(); + + return mData.getScripts().getSize(); +} + +void CSMTools::ScriptCheckStage::perform (int stage, std::vector<std::string>& messages) +{ + mMessages = &messages; + mId = mData.getScripts().getId (stage); + + try + { + std::istringstream input (mData.getScripts().getRecord (stage).get().mScriptText); + + Compiler::Scanner scanner (*this, input, mContext.getExtensions()); + + Compiler::FileParser parser (*this, mContext); + + scanner.scan (parser); + } + catch (const Compiler::SourceException&) + { + // error has already been reported via error handler + } + catch (const std::exception& error) + { + std::ostringstream stream; + + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId); + + stream << id.toString() << "|Critical compile error: " << error.what(); + + messages.push_back (stream.str()); + } + + mMessages = 0; +} \ No newline at end of file diff --git a/apps/opencs/model/tools/scriptcheck.hpp b/apps/opencs/model/tools/scriptcheck.hpp new file mode 100644 index 0000000000..325280d7ff --- /dev/null +++ b/apps/opencs/model/tools/scriptcheck.hpp @@ -0,0 +1,40 @@ +#ifndef CSM_TOOLS_SCRIPTCHECK_H +#define CSM_TOOLS_SCRIPTCHECK_H + +#include <components/compiler/errorhandler.hpp> +#include <components/compiler/extensions.hpp> + +#include "../doc/stage.hpp" + +#include "../world/scriptcontext.hpp" + +namespace CSMTools +{ + /// \brief VerifyStage: make sure that scripts compile + class ScriptCheckStage : public CSMDoc::Stage, private Compiler::ErrorHandler + { + const CSMWorld::Data& mData; + Compiler::Extensions mExtensions; + CSMWorld::ScriptContext mContext; + std::string mId; + std::vector<std::string> *mMessages; + + virtual void report (const std::string& message, const Compiler::TokenLoc& loc, Type type); + ///< Report error to the user. + + virtual void report (const std::string& message, Type type); + ///< Report a file related error + + public: + + ScriptCheckStage (const CSMWorld::Data& data); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, std::vector<std::string>& messages); + ///< Messages resulting from this tage will be appended to \a messages. + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 64e39ad2f6..79a09dcb48 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -20,6 +20,7 @@ #include "birthsigncheck.hpp" #include "spellcheck.hpp" #include "referenceablecheck.hpp" +#include "scriptcheck.hpp" CSMDoc::Operation *CSMTools::Tools::get (int type) { @@ -77,6 +78,8 @@ CSMDoc::Operation *CSMTools::Tools::getVerifier() mVerifier->appendStage (new SpellCheckStage (mData.getSpells())); mVerifier->appendStage (new ReferenceableCheckStage (mData.getReferenceables().getDataSet(), mData.getRaces(), mData.getClasses(), mData.getFactions())); + + mVerifier->appendStage (new ScriptCheckStage (mData)); } return mVerifier; diff --git a/apps/opencs/model/world/scriptcontext.cpp b/apps/opencs/model/world/scriptcontext.cpp index 688c33d308..8a4670ed2e 100644 --- a/apps/opencs/model/world/scriptcontext.cpp +++ b/apps/opencs/model/world/scriptcontext.cpp @@ -15,7 +15,7 @@ CSMWorld::ScriptContext::ScriptContext (const Data& data) : mData (data), mIdsUp bool CSMWorld::ScriptContext::canDeclareLocals() const { - return false; + return true; } char CSMWorld::ScriptContext::getGlobalType (const std::string& name) const @@ -115,4 +115,11 @@ bool CSMWorld::ScriptContext::isJournalId (const std::string& name) const void CSMWorld::ScriptContext::invalidateIds() { mIdsUpdated = false; +} + +void CSMWorld::ScriptContext::clear() +{ + mIds.clear(); + mIdsUpdated = false; + mLocals.clear(); } \ No newline at end of file diff --git a/apps/opencs/model/world/scriptcontext.hpp b/apps/opencs/model/world/scriptcontext.hpp index 400748e5fa..29ee42645a 100644 --- a/apps/opencs/model/world/scriptcontext.hpp +++ b/apps/opencs/model/world/scriptcontext.hpp @@ -43,6 +43,9 @@ namespace CSMWorld ///< Does \a name match a journal ID? void invalidateIds(); + + void clear(); + ///< Remove all cached data. }; } From fd665a19941d072b6bdc3a44eab9aa26b74e1f40 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Sat, 15 Feb 2014 12:45:50 +0100 Subject: [PATCH 74/94] ignore conditions after an else (only works if condition is put in parentheses) --- components/compiler/controlparser.cpp | 15 ++++++++++++--- components/compiler/controlparser.hpp | 3 ++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/components/compiler/controlparser.cpp b/components/compiler/controlparser.cpp index 58542bd739..aefe6d16da 100644 --- a/components/compiler/controlparser.cpp +++ b/components/compiler/controlparser.cpp @@ -8,6 +8,7 @@ #include "scanner.hpp" #include "generator.hpp" #include "errorhandler.hpp" +#include "skipparser.hpp" namespace Compiler { @@ -71,7 +72,7 @@ namespace Compiler } else if (keyword==Scanner::K_else) { - mState = IfElseBodyState; /// \todo should be IfElseEndState; add an option for that + mState = IfElseJunkState; /// \todo should be IfElseEndState; add an option for that } return true; @@ -207,7 +208,8 @@ namespace Compiler return true; } } - else if (mState==IfBodyState || mState==IfElseifBodyState || mState==IfElseBodyState) + else if (mState==IfBodyState || mState==IfElseifBodyState || mState==IfElseBodyState || + mState==IfElseJunkState) { if (parseIfBody (keyword, loc, scanner)) return true; @@ -230,6 +232,7 @@ namespace Compiler case IfEndState: mState = IfBodyState; return true; case IfElseifEndState: mState = IfElseifBodyState; return true; case IfElseEndState: mState = IfElseBodyState; return true; + case IfElseJunkState: mState = IfElseBodyState; return true; case WhileEndState: mState = WhileBodyState; return true; @@ -247,7 +250,13 @@ namespace Compiler default: ; } - + } + else if (code==Scanner::S_open && mState==IfElseJunkState) + { + SkipParser skip (getErrorHandler(), getContext()); + scanner.scan (skip); + mState = IfElseBodyState; + return true; } return Parser::parseSpecial (code, loc, scanner); diff --git a/components/compiler/controlparser.hpp b/components/compiler/controlparser.hpp index 24bc7bec75..1175a0ed58 100644 --- a/components/compiler/controlparser.hpp +++ b/components/compiler/controlparser.hpp @@ -26,7 +26,8 @@ namespace Compiler IfElseEndState, IfElseBodyState, IfEndifState, WhileEndState, WhileBodyState, - WhileEndwhileState + WhileEndwhileState, + IfElseJunkState }; typedef std::vector<Interpreter::Type_Code> Codes; From 0d84adb2c601345bb9a782624a9caaa88d0fedbb Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Sat, 15 Feb 2014 12:50:40 +0100 Subject: [PATCH 75/94] allow x->(y) instead of (x->y) --- components/compiler/exprparser.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 6d26ef403c..0c013b18f1 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -570,6 +570,14 @@ namespace Compiler { if (!mExplicit.empty()) { + if (mRefOp && code==Scanner::S_open) + { + /// \todo add option to disable this workaround + mOperators.push_back ('('); + mTokenLoc = loc; + return true; + } + if (!mRefOp && code==Scanner::S_ref) { mRefOp = true; From 2130ec39d698ad92994b216185cf9fbc238ef944 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Sat, 15 Feb 2014 12:58:34 +0100 Subject: [PATCH 76/94] disable warnings by default in script verifier --- apps/opencs/model/tools/scriptcheck.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/opencs/model/tools/scriptcheck.cpp b/apps/opencs/model/tools/scriptcheck.cpp index 8ed41ec02d..2ed8fe6579 100644 --- a/apps/opencs/model/tools/scriptcheck.cpp +++ b/apps/opencs/model/tools/scriptcheck.cpp @@ -51,6 +51,9 @@ void CSMTools::ScriptCheckStage::report (const std::string& message, Type type) CSMTools::ScriptCheckStage::ScriptCheckStage (const CSMWorld::Data& data) : mData (data), mContext (data), mMessages (0) { + /// \todo add an option to configure warning mode + setWarningsMode (0); + Compiler::registerExtensions (mExtensions); mContext.setExtensions (&mExtensions); } From 4e041319578a310e2d6be5be4c118d0e83155b27 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Sat, 15 Feb 2014 13:09:43 +0100 Subject: [PATCH 77/94] fixing case broke sorting in script context --- apps/opencs/model/world/scriptcontext.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/model/world/scriptcontext.cpp b/apps/opencs/model/world/scriptcontext.cpp index 8a4670ed2e..9da49defe7 100644 --- a/apps/opencs/model/world/scriptcontext.cpp +++ b/apps/opencs/model/world/scriptcontext.cpp @@ -100,6 +100,7 @@ bool CSMWorld::ScriptContext::isId (const std::string& name) const mIds = mData.getIds(); std::for_each (mIds.begin(), mIds.end(), &Misc::StringUtils::lowerCase); + std::sort (mIds.begin(), mIds.end()); mIdsUpdated = true; } From 2007a3e9027c640f1dc6d5ad4259ed632f04d1b8 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Sat, 15 Feb 2014 13:25:38 +0100 Subject: [PATCH 78/94] improved script check error messages --- apps/opencs/model/tools/scriptcheck.cpp | 4 +++- apps/opencs/model/tools/scriptcheck.hpp | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/tools/scriptcheck.cpp b/apps/opencs/model/tools/scriptcheck.cpp index 2ed8fe6579..a5154d2926 100644 --- a/apps/opencs/model/tools/scriptcheck.cpp +++ b/apps/opencs/model/tools/scriptcheck.cpp @@ -24,7 +24,8 @@ void CSMTools::ScriptCheckStage::report (const std::string& message, const Compi stream << "warning "; stream - << "line " << loc.mLine << ", column " << loc.mColumn + << "script " << mFile + << ", line " << loc.mLine << ", column " << loc.mColumn << " (" << loc.mLiteral << "): " << message; mMessages->push_back (stream.str()); @@ -74,6 +75,7 @@ void CSMTools::ScriptCheckStage::perform (int stage, std::vector<std::string>& m try { + mFile = mData.getScripts().getRecord (stage).get().mId; std::istringstream input (mData.getScripts().getRecord (stage).get().mScriptText); Compiler::Scanner scanner (*this, input, mContext.getExtensions()); diff --git a/apps/opencs/model/tools/scriptcheck.hpp b/apps/opencs/model/tools/scriptcheck.hpp index 325280d7ff..8de8e1a667 100644 --- a/apps/opencs/model/tools/scriptcheck.hpp +++ b/apps/opencs/model/tools/scriptcheck.hpp @@ -17,6 +17,7 @@ namespace CSMTools Compiler::Extensions mExtensions; CSMWorld::ScriptContext mContext; std::string mId; + std::string mFile; std::vector<std::string> *mMessages; virtual void report (const std::string& message, const Compiler::TokenLoc& loc, Type type); From 0afa61eed56264fea4af81fcfe78502700e2711c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Sat, 15 Feb 2014 15:50:17 +0100 Subject: [PATCH 79/94] fixed referenceable-loading in case of more than one content file --- apps/opencs/model/world/refidcollection.cpp | 8 +++---- apps/opencs/model/world/refiddata.cpp | 4 ++-- apps/opencs/model/world/refiddata.hpp | 23 ++++++++++++--------- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 89a917139b..f515e34d8e 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -432,7 +432,7 @@ void CSMWorld::RefIdCollection::removeRows (int index, int count) void CSMWorld::RefIdCollection::appendBlankRecord (const std::string& id, UniversalId::Type type) { - mData.appendRecord (type, id); + mData.appendRecord (type, id, false); } int CSMWorld::RefIdCollection::searchId (const std::string& id) const @@ -450,7 +450,7 @@ void CSMWorld::RefIdCollection::replace (int index, const RecordBase& record) mData.getRecord (mData.globalToLocalIndex (index)).assign (record); } -void CSMWorld::RefIdCollection::cloneRecord(const std::string& origin, +void CSMWorld::RefIdCollection::cloneRecord(const std::string& origin, const std::string& destination, const CSMWorld::UniversalId::Type type) { @@ -467,7 +467,7 @@ void CSMWorld::RefIdCollection::appendRecord (const RecordBase& record, int index = mData.getAppendIndex (type); - mData.appendRecord (type, id); + mData.appendRecord (type, id, false); mData.getRecord (mData.globalToLocalIndex (index)).assign (record); } @@ -515,7 +515,7 @@ void CSMWorld::RefIdCollection::load (ESM::ESMReader& reader, bool base, Univers { // new record int index = mData.getAppendIndex (type); - mData.appendRecord (type, id); + mData.appendRecord (type, id, base); RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (index); diff --git a/apps/opencs/model/world/refiddata.cpp b/apps/opencs/model/world/refiddata.cpp index 9d980a99cd..f67ab21526 100644 --- a/apps/opencs/model/world/refiddata.cpp +++ b/apps/opencs/model/world/refiddata.cpp @@ -131,7 +131,7 @@ CSMWorld::RecordBase& CSMWorld::RefIdData::getRecord (const LocalIndex& index) return iter->second->getRecord (index.first); } -void CSMWorld::RefIdData::appendRecord (UniversalId::Type type, const std::string& id) +void CSMWorld::RefIdData::appendRecord (UniversalId::Type type, const std::string& id, bool base) { std::map<UniversalId::Type, RefIdDataContainerBase *>::iterator iter = mRecordContainers.find (type); @@ -139,7 +139,7 @@ void CSMWorld::RefIdData::appendRecord (UniversalId::Type type, const std::strin if (iter==mRecordContainers.end()) throw std::logic_error ("invalid local index type"); - iter->second->appendRecord (id); + iter->second->appendRecord (id, base); mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (id), LocalIndex (iter->second->getSize()-1, type))); diff --git a/apps/opencs/model/world/refiddata.hpp b/apps/opencs/model/world/refiddata.hpp index cf98fee213..1b600364c7 100644 --- a/apps/opencs/model/world/refiddata.hpp +++ b/apps/opencs/model/world/refiddata.hpp @@ -45,8 +45,8 @@ namespace CSMWorld virtual RecordBase& getRecord (int index)= 0; - virtual void appendRecord (const std::string& id) = 0; - + virtual void appendRecord (const std::string& id, bool base) = 0; + virtual void insertRecord (RecordBase& record) = 0; virtual void load (int index, ESM::ESMReader& reader, bool base) = 0; @@ -69,8 +69,8 @@ namespace CSMWorld virtual RecordBase& getRecord (int index); - virtual void appendRecord (const std::string& id); - + virtual void appendRecord (const std::string& id, bool base); + virtual void insertRecord (RecordBase& record); virtual void load (int index, ESM::ESMReader& reader, bool base); @@ -88,7 +88,7 @@ namespace CSMWorld Record<RecordT>& newRecord = dynamic_cast<Record<RecordT>& >(record); mContainer.push_back(newRecord); } - + template<typename RecordT> int RefIdDataContainer<RecordT>::getSize() const { @@ -108,12 +108,15 @@ namespace CSMWorld } template<typename RecordT> - void RefIdDataContainer<RecordT>::appendRecord (const std::string& id) + void RefIdDataContainer<RecordT>::appendRecord (const std::string& id, bool base) { Record<RecordT> record; + + record.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly; + + record.mBase.mId = id; record.mModified.mId = id; - record.mModified.blank(); - record.mState = RecordBase::State_ModifiedOnly; + (base ? record.mBase : record.mModified).blank(); mContainer.push_back (record); } @@ -206,14 +209,14 @@ namespace CSMWorld LocalIndex searchId (const std::string& id) const; void erase (int index, int count); - + void insertRecord(CSMWorld::RecordBase& record, CSMWorld::UniversalId::Type type, const std::string& id); const RecordBase& getRecord (const LocalIndex& index) const; RecordBase& getRecord (const LocalIndex& index); - void appendRecord (UniversalId::Type type, const std::string& id); + void appendRecord (UniversalId::Type type, const std::string& id, bool base); int getAppendIndex (UniversalId::Type type) const; From 3d8ca02479d42d9bd856d31254512dfb70f2428c Mon Sep 17 00:00:00 2001 From: Emanuel Guevel <guevel.emanuel@gmail.com> Date: Sat, 15 Feb 2014 17:39:11 +0100 Subject: [PATCH 80/94] Fix breaking of enchanted items casting --- apps/openmw/mwinput/inputmanagerimp.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 7ed3007ffd..66d93469c7 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -17,6 +17,7 @@ #include "../mwworld/player.hpp" #include "../mwworld/class.hpp" +#include "../mwworld/inventorystore.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/soundmanager.hpp" @@ -647,7 +648,9 @@ namespace MWInput return; // Not allowed if no spell selected - if (MWBase::Environment::get().getWindowManager()->getSelectedSpell().empty()) + MWWorld::InventoryStore& inventory = MWWorld::Class::get(mPlayer->getPlayer()).getInventoryStore(mPlayer->getPlayer()); + if (MWBase::Environment::get().getWindowManager()->getSelectedSpell().empty() && + inventory.getSelectedEnchantItem() == inventory.end()) return; MWMechanics::DrawState_ state = mPlayer->getDrawState(); From 3c281c6a62e0fd000245956b89737ae1997472b3 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov <corrmage@gmail.com> Date: Sun, 16 Feb 2014 14:12:45 +0400 Subject: [PATCH 81/94] OS X: specify path to framework binary, not to framework directory --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f9d5329107..e279109583 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -680,7 +680,8 @@ if (APPLE) foreach (PLUGIN ${ABSOLUTE_PLUGINS}) get_filename_component(PLUGIN_RELATIVE ${PLUGIN} NAME) - set(PLUGINS ${PLUGINS} "${PLUGIN_INSTALL_BASE}/${PLUGIN_RELATIVE}") + get_filename_component(PLUGIN_RELATIVE_WE ${PLUGIN} NAME_WE) + set(PLUGINS ${PLUGINS} "${PLUGIN_INSTALL_BASE}/${PLUGIN_RELATIVE}/${PLUGIN_RELATIVE_WE}") endforeach () set(${plugins_var} ${PLUGINS} PARENT_SCOPE) From 8f99da084b11036793dd4154802792fd98f29fc2 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov <corrmage@gmail.com> Date: Sun, 16 Feb 2014 14:12:59 +0400 Subject: [PATCH 82/94] OS X: plugins are now in Frameworks dir, not in Plugins --- components/ogreinit/ogreinit.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/ogreinit/ogreinit.cpp b/components/ogreinit/ogreinit.cpp index 46424a29af..840cf4bb05 100644 --- a/components/ogreinit/ogreinit.cpp +++ b/components/ogreinit/ogreinit.cpp @@ -133,7 +133,7 @@ namespace OgreInit pluginDir = OGRE_PLUGIN_DIR; // if path is not specified try to find plugins inside the app bundle if (pluginDir.empty()) - pluginDir = Ogre::macPluginPath(); + pluginDir = Ogre::macFrameworksPath(); #endif #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX pluginDir = OGRE_PLUGIN_DIR_REL; From e4017b8bfe706f881b5aa9c41edea2225491b880 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov <corrmage@gmail.com> Date: Sun, 16 Feb 2014 14:16:45 +0400 Subject: [PATCH 83/94] It seems that OctreeSceneManager is not required anymore --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e279109583..024527ae55 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -252,7 +252,6 @@ link_directories(${SDL2_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR} ${MY if (APPLE) # List used Ogre plugins SET(USED_OGRE_PLUGINS ${OGRE_RenderSystem_GL_LIBRARY_REL} - ${OGRE_Plugin_OctreeSceneManager_LIBRARY_REL} ${OGRE_Plugin_ParticleFX_LIBRARY_REL}) # Actually we must use OGRE_Plugin_CgProgramManager_FOUND but it's From 9f721fd14463bf849133514b60217b4411d736d8 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Sun, 16 Feb 2014 12:54:27 +0100 Subject: [PATCH 84/94] store list of known topics in saved game files --- apps/openmw/mwbase/dialoguemanager.hpp | 14 ++++++++ apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 36 +++++++++++++++++++ apps/openmw/mwdialogue/dialoguemanagerimp.hpp | 6 ++++ apps/openmw/mwstate/statemanagerimp.cpp | 9 ++++- components/CMakeLists.txt | 2 +- components/esm/defs.hpp | 1 + components/esm/dialoguestate.cpp | 21 +++++++++++ components/esm/dialoguestate.hpp | 23 ++++++++++++ 8 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 components/esm/dialoguestate.cpp create mode 100644 components/esm/dialoguestate.hpp diff --git a/apps/openmw/mwbase/dialoguemanager.hpp b/apps/openmw/mwbase/dialoguemanager.hpp index 971bc3b4e9..33bba07e15 100644 --- a/apps/openmw/mwbase/dialoguemanager.hpp +++ b/apps/openmw/mwbase/dialoguemanager.hpp @@ -3,6 +3,14 @@ #include <string> +#include <libs/platform/stdint.h> + +namespace ESM +{ + class ESMReader; + class ESMWriter; +} + namespace MWWorld { class Ptr; @@ -52,6 +60,12 @@ namespace MWBase virtual void persuade (int type) = 0; virtual int getTemporaryDispositionChange () const = 0; virtual void applyDispositionChange (int delta) = 0; + + virtual int countSavedGameRecords() const = 0; + + virtual void write (ESM::ESMWriter& writer) const = 0; + + virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0; }; } diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 845c3c07be..c9e8ad9551 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -8,6 +8,7 @@ #include <components/esm/loaddial.hpp> #include <components/esm/loadinfo.hpp> +#include <components/esm/dialoguestate.hpp> #include <components/compiler/exception.hpp> #include <components/compiler/errorhandler.hpp> @@ -591,6 +592,41 @@ namespace MWDialogue } } + int DialogueManager::countSavedGameRecords() const + { + return 1; // known topics + } + + void DialogueManager::write (ESM::ESMWriter& writer) const + { + ESM::DialogueState state; + + for (std::map<std::string, bool>::const_iterator iter (mKnownTopics.begin()); + iter!=mKnownTopics.end(); ++iter) + if (iter->second) + state.mKnownTopics.push_back (iter->first); + + writer.startRecord (ESM::REC_DIAS); + state.save (writer); + writer.endRecord (ESM::REC_DIAS); + } + + void DialogueManager::readRecord (ESM::ESMReader& reader, int32_t type) + { + if (type==ESM::REC_DIAS) + { + const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + + ESM::DialogueState state; + state.load (reader); + + for (std::vector<std::string>::const_iterator iter (state.mKnownTopics.begin()); + iter!=state.mKnownTopics.end(); ++iter) + if (store.get<ESM::Dialogue>().search (*iter)) + mKnownTopics.insert (std::make_pair (*iter, true)); + } + } + std::vector<HyperTextToken> ParseHyperText(const std::string& text) { diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index c32a5dbd89..cf8ea11764 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -78,6 +78,12 @@ namespace MWDialogue virtual void persuade (int type); virtual int getTemporaryDispositionChange () const; virtual void applyDispositionChange (int delta); + + virtual int countSavedGameRecords() const; + + virtual void write (ESM::ESMWriter& writer) const; + + virtual void readRecord (ESM::ESMReader& reader, int32_t type); }; diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index f68a01bf4f..ba0e1d056f 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -193,7 +193,8 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot +MWBase::Environment::get().getJournal()->countSavedGameRecords() +MWBase::Environment::get().getWorld()->countSavedGameRecords() +MWBase::Environment::get().getScriptManager()->getGlobalScripts().countSavedGameRecords() - + 1 // global map + +MWBase::Environment::get().getDialogueManager()->countSavedGameRecords() + +1 // global map ); writer.save (stream); @@ -203,6 +204,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot writer.endRecord (ESM::REC_SAVE); MWBase::Environment::get().getJournal()->write (writer); + MWBase::Environment::get().getDialogueManager()->write (writer); MWBase::Environment::get().getWorld()->write (writer); MWBase::Environment::get().getScriptManager()->getGlobalScripts().write (writer); MWBase::Environment::get().getWindowManager()->write(writer); @@ -245,6 +247,11 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl MWBase::Environment::get().getJournal()->readRecord (reader, n.val); break; + case ESM::REC_DIAS: + + MWBase::Environment::get().getDialogueManager()->readRecord (reader, n.val); + break; + case ESM::REC_ALCH: case ESM::REC_ARMO: case ESM::REC_BOOK: diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 45a91f368c..e6b89c08e9 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -44,7 +44,7 @@ add_component_dir (esm loadinfo loadingr loadland loadlevlist loadligh loadlock loadprob loadrepa loadltex loadmgef loadmisc loadnpcc loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter - savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap lightstate inventorystate containerstate npcstate creaturestate + savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap lightstate inventorystate containerstate npcstate creaturestate dialoguestate ) add_component_dir (misc diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index 1b0125e78b..c1f1679924 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -91,6 +91,7 @@ enum RecNameInts REC_PLAY = 0x59414c50, REC_CSTA = 0x41545343, REC_GMAP = 0x50414d47, + REC_DIAS = 0x53414944, // format 1 REC_FILT = 0x544C4946 diff --git a/components/esm/dialoguestate.cpp b/components/esm/dialoguestate.cpp new file mode 100644 index 0000000000..b3544c85ce --- /dev/null +++ b/components/esm/dialoguestate.cpp @@ -0,0 +1,21 @@ + +#include "dialoguestate.hpp" + +#include "esmreader.hpp" +#include "esmwriter.hpp" + +void ESM::DialogueState::load (ESMReader &esm) +{ + while (esm.isNextSub ("TOPI")) + mKnownTopics.push_back (esm.getHString()); +} + +void ESM::DialogueState::save (ESMWriter &esm) const +{ + for (std::vector<std::string>::const_iterator iter (mKnownTopics.begin()); + iter!=mKnownTopics.end(); ++iter) + { + esm.writeHNString ("TOPI", *iter); + + } +} \ No newline at end of file diff --git a/components/esm/dialoguestate.hpp b/components/esm/dialoguestate.hpp new file mode 100644 index 0000000000..9aa9eaefd3 --- /dev/null +++ b/components/esm/dialoguestate.hpp @@ -0,0 +1,23 @@ +#ifndef OPENMW_ESM_DIALOGUESTATE_H +#define OPENMW_ESM_DIALOGUESTATE_H + +#include <string> +#include <vector> + +namespace ESM +{ + class ESMReader; + class ESMWriter; + + // format 0, saved games only + + struct DialogueState + { + std::vector<std::string> mKnownTopics; + + void load (ESMReader &esm); + void save (ESMWriter &esm) const; + }; +} + +#endif \ No newline at end of file From b0532e0c8528828bcaf6d3af5ffdaccf00dc509b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Sun, 16 Feb 2014 15:06:34 +0100 Subject: [PATCH 85/94] store NPC state in saved game files --- apps/openmw/mwclass/npc.cpp | 12 ++- apps/openmw/mwmechanics/npcstats.cpp | 77 ++++++++++++++++ apps/openmw/mwmechanics/npcstats.hpp | 5 + apps/openmw/mwmechanics/stat.cpp | 29 ++++++ apps/openmw/mwmechanics/stat.hpp | 10 ++ components/CMakeLists.txt | 3 +- components/esm/npcstate.cpp | 8 ++ components/esm/npcstate.hpp | 4 + components/esm/npcstats.cpp | 133 +++++++++++++++++++++++++++ components/esm/npcstats.hpp | 54 +++++++++++ components/esm/statstate.hpp | 53 +++++++++++ 11 files changed, 383 insertions(+), 5 deletions(-) create mode 100644 apps/openmw/mwmechanics/stat.cpp create mode 100644 components/esm/npcstats.cpp create mode 100644 components/esm/npcstats.hpp create mode 100644 components/esm/statstate.hpp diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 34ea515bab..7e67738d44 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1278,8 +1278,10 @@ namespace MWClass ensureCustomData (ptr); - dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mInventoryStore. - readState (state2.mInventory); + CustomData& customData = dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()); + + customData.mInventoryStore.readState (state2.mInventory); + customData.mNpcStats.readState (state2.mNpcStats); } void Npc::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) @@ -1289,8 +1291,10 @@ namespace MWClass ensureCustomData (ptr); - dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mInventoryStore. - writeState (state2.mInventory); + CustomData& customData = dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()); + + customData.mInventoryStore.writeState (state2.mInventory); + customData.mNpcStats.writeState (state2.mNpcStats); } const ESM::GameSetting *Npc::fMinWalkSpeed; diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index 63b4467f6d..786d35b9cb 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -12,6 +12,7 @@ #include <components/esm/loadclas.hpp> #include <components/esm/loadgmst.hpp> #include <components/esm/loadfact.hpp> +#include <components/esm/npcstats.hpp> #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" @@ -423,3 +424,79 @@ void MWMechanics::NpcStats::setTimeToStartDrowning(float time) assert(time>=0 && time<=20); mTimeToStartDrowning=time; } + +void MWMechanics::NpcStats::writeState (ESM::NpcStats& state) const +{ + for (std::map<std::string, int>::const_iterator iter (mFactionRank.begin()); + iter!=mFactionRank.end(); ++iter) + state.mFactions[iter->first].mRank = iter->second; + + state.mDisposition = mDisposition; + + for (int i=0; i<27; ++i) + { + mSkill[i].writeState (state.mSkills[i].mRegular); + mWerewolfSkill[i].writeState (state.mSkills[i].mWerewolf); + state.mSkills[i].mIncrease = mSkillIncreases[i]; + } + + state.mBounty = mBounty; + + for (std::set<std::string>::const_iterator iter (mExpelled.begin()); + iter!=mExpelled.end(); ++iter) + state.mFactions[*iter].mExpelled = true; + + for (std::map<std::string, int>::const_iterator iter (mFactionReputation.begin()); + iter!=mFactionReputation.end(); ++iter) + state.mFactions[iter->first].mReputation = iter->second; + + state.mReputation = mReputation; + state.mWerewolfKills = mWerewolfKills; + state.mProfit = mProfit; + state.mAttackStrength = mAttackStrength; + state.mLevelProgress = mLevelProgress; + + std::copy (mUsedIds.begin(), mUsedIds.end(), std::back_inserter (state.mUsedIds)); + + state.mTimeToStartDrowning = mTimeToStartDrowning; + state.mLastDrowningHit = mLastDrowningHit; + state.mLevelHealthBonus = mLevelHealthBonus; +} + +void MWMechanics::NpcStats::readState (const ESM::NpcStats& state) +{ + for (std::map<std::string, ESM::NpcStats::Faction>::const_iterator iter (state.mFactions.begin()); + iter!=state.mFactions.end(); ++iter) + { + if (iter->second.mExpelled) + mExpelled.insert (iter->first); + + if (iter->second.mRank) + mFactionRank.insert (std::make_pair (iter->first, iter->second.mRank)); + + if (iter->second.mReputation) + mFactionReputation.insert (std::make_pair (iter->first, iter->second.mReputation)); + } + + mDisposition = state.mDisposition; + + for (int i=0; i<27; ++i) + { + mSkill[i].readState (state.mSkills[i].mRegular); + mWerewolfSkill[i].readState (state.mSkills[i].mWerewolf); + mSkillIncreases[i] = state.mSkills[i].mIncrease; + } + + mBounty = state.mBounty; + mReputation = state.mReputation; + mWerewolfKills = state.mWerewolfKills; + mProfit = state.mProfit; + mAttackStrength = state.mAttackStrength; + mLevelProgress = state.mLevelProgress; + + std::copy (state.mUsedIds.begin(), state.mUsedIds.end(), std::inserter (mUsedIds, mUsedIds.begin())); + + mTimeToStartDrowning = state.mTimeToStartDrowning; + mLastDrowningHit = state.mLastDrowningHit; + mLevelHealthBonus = state.mLevelHealthBonus; +} \ No newline at end of file diff --git a/apps/openmw/mwmechanics/npcstats.hpp b/apps/openmw/mwmechanics/npcstats.hpp index d7db999e45..ad493be3c1 100644 --- a/apps/openmw/mwmechanics/npcstats.hpp +++ b/apps/openmw/mwmechanics/npcstats.hpp @@ -13,6 +13,7 @@ namespace ESM { struct Class; + struct NpcStats; } namespace MWMechanics @@ -128,6 +129,10 @@ namespace MWMechanics /// Sets time left for the creature to drown if it stays underwater. /// @param time value from [0,20] void setTimeToStartDrowning(float time); + + void writeState (ESM::NpcStats& state) const; + + void readState (const ESM::NpcStats& state); }; } diff --git a/apps/openmw/mwmechanics/stat.cpp b/apps/openmw/mwmechanics/stat.cpp new file mode 100644 index 0000000000..61b6d60ad4 --- /dev/null +++ b/apps/openmw/mwmechanics/stat.cpp @@ -0,0 +1,29 @@ + +#include "stat.hpp" + +void MWMechanics::AttributeValue::writeState (ESM::StatState<int>& state) const +{ + state.mBase = mBase; + state.mMod = mModifier; + state.mDamage = mDamage; +} + +void MWMechanics::AttributeValue::readState (const ESM::StatState<int>& state) +{ + mBase = state.mBase; + mModifier = state.mMod; + mDamage = state.mDamage; +} + + +void MWMechanics::SkillValue::writeState (ESM::StatState<int>& state) const +{ + AttributeValue::writeState (state); + state.mProgress = mProgress; +} + +void MWMechanics::SkillValue::readState (const ESM::StatState<int>& state) +{ + AttributeValue::readState (state); + mProgress = state.mProgress; +} \ No newline at end of file diff --git a/apps/openmw/mwmechanics/stat.hpp b/apps/openmw/mwmechanics/stat.hpp index 75ac6939aa..28005966a0 100644 --- a/apps/openmw/mwmechanics/stat.hpp +++ b/apps/openmw/mwmechanics/stat.hpp @@ -6,6 +6,8 @@ #include <limits> +#include <components/esm/statstate.hpp> + namespace MWMechanics { template<typename T> @@ -225,6 +227,10 @@ namespace MWMechanics void damage(int damage) { mDamage += damage; } void restore(int amount) { mDamage -= std::min(mDamage, amount); } int getDamage() const { return mDamage; } + + void writeState (ESM::StatState<int>& state) const; + + void readState (const ESM::StatState<int>& state); }; class SkillValue : public AttributeValue @@ -234,6 +240,10 @@ namespace MWMechanics SkillValue() : mProgress(0) {} float getProgress() const { return mProgress; } void setProgress(float progress) { mProgress = progress; } + + void writeState (ESM::StatState<int>& state) const; + + void readState (const ESM::StatState<int>& state); }; inline bool operator== (const AttributeValue& left, const AttributeValue& right) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index e6b89c08e9..8665938630 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -44,7 +44,8 @@ add_component_dir (esm loadinfo loadingr loadland loadlevlist loadligh loadlock loadprob loadrepa loadltex loadmgef loadmisc loadnpcc loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter - savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap lightstate inventorystate containerstate npcstate creaturestate dialoguestate + savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap lightstate inventorystate containerstate npcstate creaturestate dialoguestate statstate + npcstats ) add_component_dir (misc diff --git a/components/esm/npcstate.cpp b/components/esm/npcstate.cpp index c452611a0a..e59ec3e268 100644 --- a/components/esm/npcstate.cpp +++ b/components/esm/npcstate.cpp @@ -6,6 +6,10 @@ void ESM::NpcState::load (ESMReader &esm) ObjectState::load (esm); mInventory.load (esm); + + mNpcStats.load (esm); + + mCreatureStats.load (esm); } void ESM::NpcState::save (ESMWriter &esm, bool inInventory) const @@ -13,4 +17,8 @@ void ESM::NpcState::save (ESMWriter &esm, bool inInventory) const ObjectState::save (esm, inInventory); mInventory.save (esm); + + mNpcStats.save (esm); + + mCreatureStats.save (esm); } \ No newline at end of file diff --git a/components/esm/npcstate.hpp b/components/esm/npcstate.hpp index ceb18b88b6..39858d5533 100644 --- a/components/esm/npcstate.hpp +++ b/components/esm/npcstate.hpp @@ -3,6 +3,8 @@ #include "objectstate.hpp" #include "inventorystate.hpp" +#include "npcstats.hpp" +#include "creaturestats.hpp" namespace ESM { @@ -11,6 +13,8 @@ namespace ESM struct NpcState : public ObjectState { InventoryState mInventory; + NpcStats mNpcStats; + CreatureStats mCreatureStats; virtual void load (ESMReader &esm); virtual void save (ESMWriter &esm, bool inInventory = false) const; diff --git a/components/esm/npcstats.cpp b/components/esm/npcstats.cpp new file mode 100644 index 0000000000..531424ab23 --- /dev/null +++ b/components/esm/npcstats.cpp @@ -0,0 +1,133 @@ + +#include "npcstats.hpp" + +#include "esmreader.hpp" +#include "esmwriter.hpp" + +ESM::NpcStats::Faction::Faction() : mExpelled (false), mRank (0), mReputation (0) {} + +void ESM::NpcStats::load (ESMReader &esm) +{ + while (esm.isNextSub ("FACT")) + { + std::string id = esm.getHString(); + + Faction faction; + + int expelled = 0; + esm.getHNOT (expelled, "FAEX"); + + if (expelled) + faction.mExpelled = true; + + esm.getHNOT (faction.mRank, "FARA"); + + esm.getHNOT (faction.mReputation, "FARE"); + + mFactions.insert (std::make_pair (id, faction)); + } + + mDisposition = 0; + esm.getHNOT (mDisposition, "DISP"); + + for (int i=0; i<27; ++i) + { + mSkills[i].mRegular.load (esm); + mSkills[i].mWerewolf.load (esm); + } + + mBounty = 0; + esm.getHNOT (mBounty, "BOUN"); + + mReputation = 0; + esm.getHNOT (mReputation, "REPU"); + + mWerewolfKills = 0; + esm.getHNOT (mWerewolfKills, "WKIL"); + + mProfit = 0; + esm.getHNOT (mProfit, "PROF"); + + mAttackStrength = 0; + esm.getHNOT (mAttackStrength, "ASTR"); + + mLevelProgress = 0; + esm.getHNOT (mLevelProgress, "LPRO"); + + esm.getHNT (mSkillIncrease, "INCR"); + + while (esm.isNextSub ("USED")) + mUsedIds.push_back (esm.getHString()); + + mTimeToStartDrowning = 0; + esm.getHNOT (mTimeToStartDrowning, "DRTI"); + + mLastDrowningHit = 0; + esm.getHNOT (mLastDrowningHit, "DRLH"); + + mLevelHealthBonus = 0; + esm.getHNOT (mLevelHealthBonus, "LVLH"); +} + +void ESM::NpcStats::save (ESMWriter &esm) const +{ + for (std::map<std::string, Faction>::const_iterator iter (mFactions.begin()); + iter!=mFactions.end(); ++iter) + { + esm.writeHNString ("FACT", iter->first); + + if (iter->second.mExpelled) + { + int expelled = 1; + esm.writeHNT ("FAEX", expelled); + } + + if (iter->second.mRank) + esm.writeHNT ("FARA", iter->second.mRank); + + if (iter->second.mReputation) + esm.writeHNT ("FARE", iter->second.mReputation); + } + + if (mDisposition) + esm.writeHNT ("DISP", mDisposition); + + for (int i=0; i<27; ++i) + { + mSkills[i].mRegular.save (esm); + mSkills[i].mWerewolf.save (esm); + } + + if (mBounty) + esm.writeHNT ("BOUN", mBounty); + + if (mReputation) + esm.writeHNT ("REPU", mReputation); + + if (mWerewolfKills) + esm.writeHNT ("WKIL", mWerewolfKills); + + if (mProfit) + esm.writeHNT ("PROF", mProfit); + + if (mAttackStrength) + esm.writeHNT ("ASTR", mAttackStrength); + + if (mLevelProgress) + esm.writeHNT ("LPRO", mLevelProgress); + + esm.writeHNT ("INCR", mSkillIncrease); + + for (std::vector<std::string>::const_iterator iter (mUsedIds.begin()); iter!=mUsedIds.end(); + ++iter) + esm.writeHNT ("USED", *iter); + + if (mTimeToStartDrowning) + esm.writeHNT ("DRTI", mTimeToStartDrowning); + + if (mLastDrowningHit) + esm.writeHNT ("DRLH", mLastDrowningHit); + + if (mLevelHealthBonus) + esm.writeHNT ("LVLH", mLevelHealthBonus); +} \ No newline at end of file diff --git a/components/esm/npcstats.hpp b/components/esm/npcstats.hpp new file mode 100644 index 0000000000..b3f70db252 --- /dev/null +++ b/components/esm/npcstats.hpp @@ -0,0 +1,54 @@ +#ifndef OPENMW_ESM_NPCSTATS_H +#define OPENMW_ESM_NPCSTATS_H + +#include <string> +#include <vector> +#include <map> + +#include "statstate.hpp" + +namespace ESM +{ + class ESMReader; + class ESMWriter; + + // format 0, saved games only + + struct NpcStats + { + struct Skill + { + StatState<int> mRegular; + StatState<int> mWerewolf; + }; + + struct Faction + { + bool mExpelled; + int mRank; + int mReputation; + + Faction(); + }; + + std::map<std::string, Faction> mFactions; + int mDisposition; + Skill mSkills[27]; + int mBounty; + int mReputation; + int mWerewolfKills; + int mProfit; + float mAttackStrength; + int mLevelProgress; + int mSkillIncrease[8]; + std::vector<std::string> mUsedIds; + float mTimeToStartDrowning; + float mLastDrowningHit; + float mLevelHealthBonus; + + void load (ESMReader &esm); + void save (ESMWriter &esm) const; + }; +} + +#endif \ No newline at end of file diff --git a/components/esm/statstate.hpp b/components/esm/statstate.hpp new file mode 100644 index 0000000000..c8b0d6a4d9 --- /dev/null +++ b/components/esm/statstate.hpp @@ -0,0 +1,53 @@ +#ifndef OPENMW_ESM_STATSTATE_H +#define OPENMW_ESM_STATSTATE_H + +#include "esmreader.hpp" +#include "esmwriter.hpp" + +namespace ESM +{ + // format 0, saved games only + + template<typename T> + struct StatState + { + T mBase; + T mMod; + T mDamage; + float mProgress; + + StatState(); + + void load (ESMReader &esm); + void save (ESMWriter &esm) const; + }; + + template<typename T> + StatState<T>::StatState() : mBase (0), mMod (0), mDamage (0), mProgress (0) {} + + template<typename T> + void StatState<T>::load (ESMReader &esm) + { + esm.getHNT (mBase, "STBA"); + esm.getHNT (mMod, "STMO"); + mDamage = 0; + esm.getHNOT (mDamage, "STDA"); + mProgress = 0; + esm.getHNOT (mProgress, "STPR"); + } + + template<typename T> + void StatState<T>::save (ESMWriter &esm) const + { + esm.writeHNT ("STBA", mBase); + esm.writeHNT ("STMO", mMod); + + if (mDamage) + esm.writeHNT ("STDA", mDamage); + + if (mProgress) + esm.writeHNT ("STPR", mProgress); + } +} + +#endif \ No newline at end of file From 9788bbcab962b8d72f91c3b762ed6d90035e2bec Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Sun, 16 Feb 2014 15:56:36 +0100 Subject: [PATCH 86/94] partially store creature state in saved game files (only attributes and dynamics for now) --- apps/openmw/mwclass/creature.cpp | 13 +++++++---- apps/openmw/mwclass/npc.cpp | 2 ++ apps/openmw/mwmechanics/creaturestats.cpp | 19 ++++++++++++++++ apps/openmw/mwmechanics/creaturestats.hpp | 9 ++++++++ apps/openmw/mwmechanics/npcstats.cpp | 8 +++++-- apps/openmw/mwmechanics/stat.hpp | 24 ++++++++++++++++++++ components/CMakeLists.txt | 2 +- components/esm/creaturestate.cpp | 4 ++++ components/esm/creaturestate.hpp | 2 ++ components/esm/creaturestats.cpp | 20 +++++++++++++++++ components/esm/creaturestats.hpp | 27 +++++++++++++++++++++++ components/esm/statstate.hpp | 8 ++++++- 12 files changed, 130 insertions(+), 8 deletions(-) create mode 100644 components/esm/creaturestats.cpp create mode 100644 components/esm/creaturestats.hpp diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 6af8373c55..81ca0ce2bf 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -766,8 +766,11 @@ namespace MWClass ensureCustomData (ptr); - dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mContainerStore-> - readState (state2.mInventory); + CustomData& customData = dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()); + + customData.mContainerStore->readState (state2.mInventory); + customData.mCreatureStats.readState (state2.mCreatureStats); + } void Creature::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) @@ -777,8 +780,10 @@ namespace MWClass ensureCustomData (ptr); - dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mContainerStore-> - writeState (state2.mInventory); + CustomData& customData = dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()); + + customData.mContainerStore->writeState (state2.mInventory); + customData.mCreatureStats.writeState (state2.mCreatureStats); } const ESM::GameSetting* Creature::fMinWalkSpeedCreature; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 7e67738d44..3a95f3c294 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1282,6 +1282,7 @@ namespace MWClass customData.mInventoryStore.readState (state2.mInventory); customData.mNpcStats.readState (state2.mNpcStats); + static_cast<MWMechanics::CreatureStats&> (customData.mNpcStats).readState (state2.mCreatureStats); } void Npc::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state) @@ -1295,6 +1296,7 @@ namespace MWClass customData.mInventoryStore.writeState (state2.mInventory); customData.mNpcStats.writeState (state2.mNpcStats); + static_cast<const MWMechanics::CreatureStats&> (customData.mNpcStats).writeState (state2.mCreatureStats); } const ESM::GameSetting *Npc::fMinWalkSpeed; diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index 8f890befba..d61b967390 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -2,6 +2,8 @@ #include <algorithm> +#include <components/esm/creaturestats.hpp> + #include "../mwworld/esmstore.hpp" #include "../mwbase/environment.hpp" @@ -457,4 +459,21 @@ namespace MWMechanics mAttackStrength = value; } + void CreatureStats::writeState (ESM::CreatureStats& state) const + { + for (int i=0; i<8; ++i) + mAttributes[i].writeState (state.mAttributes[i]); + + for (int i=0; i<3; ++i) + mDynamic[i].writeState (state.mDynamic[i]); + } + + void CreatureStats::readState (const ESM::CreatureStats& state) + { + for (int i=0; i<8; ++i) + mAttributes[i].readState (state.mAttributes[i]); + + for (int i=0; i<3; ++i) + mDynamic[i].readState (state.mDynamic[i]); + } } diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index bb95833015..94e506fc4f 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -12,6 +12,11 @@ #include "aisequence.hpp" #include "drawstate.hpp" +namespace ESM +{ + struct CreatureStats; +} + namespace MWMechanics { /// \brief Common creature stats @@ -212,6 +217,10 @@ namespace MWMechanics std::set<int> mBoundItems; // Same as above std::map<int, std::string> mSummonedCreatures; + + void writeState (ESM::CreatureStats& state) const; + + void readState (const ESM::CreatureStats& state); }; } diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index 786d35b9cb..eee27272aa 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -437,7 +437,6 @@ void MWMechanics::NpcStats::writeState (ESM::NpcStats& state) const { mSkill[i].writeState (state.mSkills[i].mRegular); mWerewolfSkill[i].writeState (state.mSkills[i].mWerewolf); - state.mSkills[i].mIncrease = mSkillIncreases[i]; } state.mBounty = mBounty; @@ -456,6 +455,9 @@ void MWMechanics::NpcStats::writeState (ESM::NpcStats& state) const state.mAttackStrength = mAttackStrength; state.mLevelProgress = mLevelProgress; + for (int i=0; i<8; ++i) + state.mSkillIncrease[i] = mSkillIncreases[i]; + std::copy (mUsedIds.begin(), mUsedIds.end(), std::back_inserter (state.mUsedIds)); state.mTimeToStartDrowning = mTimeToStartDrowning; @@ -484,7 +486,6 @@ void MWMechanics::NpcStats::readState (const ESM::NpcStats& state) { mSkill[i].readState (state.mSkills[i].mRegular); mWerewolfSkill[i].readState (state.mSkills[i].mWerewolf); - mSkillIncreases[i] = state.mSkills[i].mIncrease; } mBounty = state.mBounty; @@ -494,6 +495,9 @@ void MWMechanics::NpcStats::readState (const ESM::NpcStats& state) mAttackStrength = state.mAttackStrength; mLevelProgress = state.mLevelProgress; + for (int i=0; i<8; ++i) + mSkillIncreases[i] = state.mSkillIncrease[i]; + std::copy (state.mUsedIds.begin(), state.mUsedIds.end(), std::inserter (mUsedIds, mUsedIds.begin())); mTimeToStartDrowning = state.mTimeToStartDrowning; diff --git a/apps/openmw/mwmechanics/stat.hpp b/apps/openmw/mwmechanics/stat.hpp index 28005966a0..0fb4c57328 100644 --- a/apps/openmw/mwmechanics/stat.hpp +++ b/apps/openmw/mwmechanics/stat.hpp @@ -88,6 +88,18 @@ namespace MWMechanics { mModified = mBase + modifier; } + + void writeState (ESM::StatState<T>& state) const + { + state.mBase = mBase; + state.mMod = mModified; + } + + void readState (const ESM::StatState<T>& state) + { + mBase = state.mBase; + mModified = state.mMod; + } }; template<typename T> @@ -192,6 +204,18 @@ namespace MWMechanics mStatic.setModifier (modifier); setCurrent (getCurrent()+diff); } + + void writeState (ESM::StatState<T>& state) const + { + mStatic.writeState (state); + state.mCurrent = mCurrent; + } + + void readState (const ESM::StatState<T>& state) + { + mStatic.readState (state); + mCurrent = state.mCurrent; + } }; template<typename T> diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 8665938630..831b140575 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -45,7 +45,7 @@ add_component_dir (esm loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap lightstate inventorystate containerstate npcstate creaturestate dialoguestate statstate - npcstats + npcstats creaturestats ) add_component_dir (misc diff --git a/components/esm/creaturestate.cpp b/components/esm/creaturestate.cpp index 43cde30251..9e9b561026 100644 --- a/components/esm/creaturestate.cpp +++ b/components/esm/creaturestate.cpp @@ -6,6 +6,8 @@ void ESM::CreatureState::load (ESMReader &esm) ObjectState::load (esm); mInventory.load (esm); + + mCreatureStats.load (esm); } void ESM::CreatureState::save (ESMWriter &esm, bool inInventory) const @@ -13,4 +15,6 @@ void ESM::CreatureState::save (ESMWriter &esm, bool inInventory) const ObjectState::save (esm, inInventory); mInventory.save (esm); + + mCreatureStats.save (esm); } \ No newline at end of file diff --git a/components/esm/creaturestate.hpp b/components/esm/creaturestate.hpp index f7f9b80380..604c2f3a70 100644 --- a/components/esm/creaturestate.hpp +++ b/components/esm/creaturestate.hpp @@ -3,6 +3,7 @@ #include "objectstate.hpp" #include "inventorystate.hpp" +#include "creaturestats.hpp" namespace ESM { @@ -11,6 +12,7 @@ namespace ESM struct CreatureState : public ObjectState { InventoryState mInventory; + CreatureStats mCreatureStats; virtual void load (ESMReader &esm); virtual void save (ESMWriter &esm, bool inInventory = false) const; diff --git a/components/esm/creaturestats.cpp b/components/esm/creaturestats.cpp new file mode 100644 index 0000000000..fe250089aa --- /dev/null +++ b/components/esm/creaturestats.cpp @@ -0,0 +1,20 @@ + +#include "creaturestats.hpp" + +void ESM::CreatureStats::load (ESMReader &esm) +{ + for (int i=0; i<8; ++i) + mAttributes[i].load (esm); + + for (int i=0; i<3; ++i) + mDynamic[i].load (esm); +} + +void ESM::CreatureStats::save (ESMWriter &esm) const +{ + for (int i=0; i<8; ++i) + mAttributes[i].save (esm); + + for (int i=0; i<3; ++i) + mDynamic[i].save (esm); +} \ No newline at end of file diff --git a/components/esm/creaturestats.hpp b/components/esm/creaturestats.hpp new file mode 100644 index 0000000000..540044f389 --- /dev/null +++ b/components/esm/creaturestats.hpp @@ -0,0 +1,27 @@ +#ifndef OPENMW_ESM_CREATURESTATS_H +#define OPENMW_ESM_CREATURESTATS_H + +#include <string> +#include <vector> +#include <map> + +#include "statstate.hpp" + +namespace ESM +{ + class ESMReader; + class ESMWriter; + + // format 0, saved games only + + struct CreatureStats + { + StatState<int> mAttributes[8]; + StatState<float> mDynamic[3]; + + void load (ESMReader &esm); + void save (ESMWriter &esm) const; + }; +} + +#endif \ No newline at end of file diff --git a/components/esm/statstate.hpp b/components/esm/statstate.hpp index c8b0d6a4d9..4b4023bc22 100644 --- a/components/esm/statstate.hpp +++ b/components/esm/statstate.hpp @@ -13,6 +13,7 @@ namespace ESM { T mBase; T mMod; + T mCurrent; T mDamage; float mProgress; @@ -23,13 +24,15 @@ namespace ESM }; template<typename T> - StatState<T>::StatState() : mBase (0), mMod (0), mDamage (0), mProgress (0) {} + StatState<T>::StatState() : mBase (0), mMod (0), mCurrent (0), mDamage (0), mProgress (0) {} template<typename T> void StatState<T>::load (ESMReader &esm) { esm.getHNT (mBase, "STBA"); esm.getHNT (mMod, "STMO"); + mCurrent = 0; + esm.getHNOT (mCurrent, "STCU"); mDamage = 0; esm.getHNOT (mDamage, "STDA"); mProgress = 0; @@ -42,6 +45,9 @@ namespace ESM esm.writeHNT ("STBA", mBase); esm.writeHNT ("STMO", mMod); + if (mCurrent) + esm.writeHNT ("STCU", mCurrent); + if (mDamage) esm.writeHNT ("STDA", mDamage); From 4a6186852129332ad34dbb79118a10729d6e8b4f Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov <corrmage@gmail.com> Date: Sun, 16 Feb 2014 19:01:28 +0400 Subject: [PATCH 87/94] OS X: fixed Ogre plugin packaging --- CMakeLists.txt | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 024527ae55..a9d1f20172 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -668,11 +668,15 @@ if (APPLE) set(ABSOLUTE_PLUGINS ${PLUGIN_ABS} ${ABSOLUTE_PLUGINS}) endforeach () + install(CODE " + set(BU_CHMOD_BUNDLE_ITEMS ON) + include(BundleUtilities) + " COMPONENT Runtime) + # installs used plugins in bundle at given path (bundle_path must be relative to ${CMAKE_INSTALL_PREFIX}) # and returns list of install paths for all installed plugins function (install_plugins_for_bundle bundle_path plugins_var) set(RELATIVE_PLUGIN_INSTALL_BASE "${bundle_path}/Contents/Frameworks") - install(DIRECTORY ${ABSOLUTE_PLUGINS} DESTINATION ${RELATIVE_PLUGIN_INSTALL_BASE} COMPONENT Runtime) set(PLUGINS "") set(PLUGIN_INSTALL_BASE "\${CMAKE_INSTALL_PREFIX}/${RELATIVE_PLUGIN_INSTALL_BASE}") @@ -680,7 +684,13 @@ if (APPLE) foreach (PLUGIN ${ABSOLUTE_PLUGINS}) get_filename_component(PLUGIN_RELATIVE ${PLUGIN} NAME) get_filename_component(PLUGIN_RELATIVE_WE ${PLUGIN} NAME_WE) - set(PLUGINS ${PLUGINS} "${PLUGIN_INSTALL_BASE}/${PLUGIN_RELATIVE}/${PLUGIN_RELATIVE_WE}") + + set(PLUGIN_DYLIB_IN_BUNDLE "${PLUGIN_INSTALL_BASE}/${PLUGIN_RELATIVE}/${PLUGIN_RELATIVE_WE}") + set(PLUGINS ${PLUGINS} "${PLUGIN_DYLIB_IN_BUNDLE}") + + install(CODE " + copy_resolved_framework_into_bundle(\"${PLUGIN}/${PLUGIN_RELATIVE_WE}\" \"${PLUGIN_DYLIB_IN_BUNDLE}\") + " COMPONENT Runtime) endforeach () set(${plugins_var} ${PLUGINS} PARENT_SCOPE) @@ -700,6 +710,7 @@ if (APPLE) # Current limitations: # 1. Handles only frameworks, not simple libs INSTALL(CODE " + cmake_policy(SET CMP0009 OLD) set(CMAKE_FIND_LIBRARY_PREFIXES ${CMAKE_FIND_LIBRARY_PREFIXES}) set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) set(CMAKE_SYSTEM_FRAMEWORK_PATH ${CMAKE_SYSTEM_FRAMEWORK_PATH}) @@ -731,9 +742,6 @@ if (APPLE) endif() endfunction(gp_resolve_item_override) - cmake_policy(SET CMP0009 OLD) - set(BU_CHMOD_BUNDLE_ITEMS ON) - include(BundleUtilities) fixup_bundle(\"${OPENMW_APP}\" \"${PLUGINS}\" \"${DIRS}\") fixup_bundle(\"${OPENCS_APP}\" \"${OPENCS_PLUGINS}\" \"${DIRS}\") " COMPONENT Runtime) From c18c3e51ee81e50247fdfa5e8a945a3b0660dc90 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag <marc@zpages.de> Date: Sun, 16 Feb 2014 16:22:09 +0100 Subject: [PATCH 88/94] handle IDs that don't exist anymore after loading --- apps/openmw/mwmechanics/npcstats.cpp | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index eee27272aa..8918bfbe70 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -467,18 +467,21 @@ void MWMechanics::NpcStats::writeState (ESM::NpcStats& state) const void MWMechanics::NpcStats::readState (const ESM::NpcStats& state) { + const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + for (std::map<std::string, ESM::NpcStats::Faction>::const_iterator iter (state.mFactions.begin()); iter!=state.mFactions.end(); ++iter) - { - if (iter->second.mExpelled) - mExpelled.insert (iter->first); + if (store.get<ESM::Faction>().search (iter->first)) + { + if (iter->second.mExpelled) + mExpelled.insert (iter->first); - if (iter->second.mRank) - mFactionRank.insert (std::make_pair (iter->first, iter->second.mRank)); + if (iter->second.mRank) + mFactionRank.insert (std::make_pair (iter->first, iter->second.mRank)); - if (iter->second.mReputation) - mFactionReputation.insert (std::make_pair (iter->first, iter->second.mReputation)); - } + if (iter->second.mReputation) + mFactionReputation.insert (std::make_pair (iter->first, iter->second.mReputation)); + } mDisposition = state.mDisposition; @@ -498,7 +501,10 @@ void MWMechanics::NpcStats::readState (const ESM::NpcStats& state) for (int i=0; i<8; ++i) mSkillIncreases[i] = state.mSkillIncrease[i]; - std::copy (state.mUsedIds.begin(), state.mUsedIds.end(), std::inserter (mUsedIds, mUsedIds.begin())); + for (std::vector<std::string>::const_iterator iter (state.mUsedIds.begin()); + iter!=state.mUsedIds.end(); ++iter) + if (store.find (*iter)) + mUsedIds.insert (*iter); mTimeToStartDrowning = state.mTimeToStartDrowning; mLastDrowningHit = state.mLastDrowningHit; From 4e28fd85a39782f2c220e3d5804148b2ca072296 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov <corrmage@gmail.com> Date: Sun, 16 Feb 2014 20:22:46 +0400 Subject: [PATCH 89/94] Fixed build on OS X --- apps/opencs/view/world/table.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index c077d5f7fe..3ce90d3a78 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -7,7 +7,7 @@ #include <QMenu> #include <QContextMenuEvent> #include <QString> -#include <qt4/QtCore/qnamespace.h> +#include <QtCore/qnamespace.h> #include "../../model/world/data.hpp" #include "../../model/world/commands.hpp" From 5e8cb2e4667abe4dfded326897347b7a124623f6 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov <corrmage@gmail.com> Date: Mon, 17 Feb 2014 02:35:13 +0400 Subject: [PATCH 90/94] Another attempt to fix #1041. This time I'm sending real data from decoder once after playback started. --- apps/openmw/mwsound/openal_output.cpp | 33 +++++++++++++++++++-------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 9dc0b8c5db..7563ad0150 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -172,6 +172,7 @@ class OpenAL_SoundStream : public Sound DecoderPtr mDecoder; volatile bool mIsFinished; + volatile bool mIsInitialBatchEnqueued; void updateAll(bool local); @@ -264,7 +265,7 @@ private: OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder, float basevol, float pitch, int flags) : Sound(Ogre::Vector3(0.0f), 1.0f, basevol, pitch, 1.0f, 1000.0f, flags) - , mOutput(output), mSource(src), mSamplesQueued(0), mDecoder(decoder), mIsFinished(true) + , mOutput(output), mSource(src), mSamplesQueued(0), mDecoder(decoder), mIsFinished(true), mIsInitialBatchEnqueued(false) { throwALerror(); @@ -315,16 +316,8 @@ void OpenAL_SoundStream::play() alSourcei(mSource, AL_BUFFER, 0); throwALerror(); mSamplesQueued = 0; - - for(ALuint i = 0;i < sNumBuffers;i++) - alBufferData(mBuffers[i], mFormat, this, 0, mSampleRate); - throwALerror(); - - alSourceQueueBuffers(mSource, sNumBuffers, mBuffers); - alSourcePlay(mSource); - throwALerror(); - mIsFinished = false; + mIsInitialBatchEnqueued = false; mOutput.mStreamThread->add(this); } @@ -332,6 +325,7 @@ void OpenAL_SoundStream::stop() { mOutput.mStreamThread->remove(this); mIsFinished = true; + mIsInitialBatchEnqueued = false; alSourceStop(mSource); alSourcei(mSource, AL_BUFFER, 0); @@ -444,6 +438,24 @@ bool OpenAL_SoundStream::process() } while(processed > 0); throwALerror(); } + else if (!mIsInitialBatchEnqueued) { // nothing enqueued yet + std::vector<char> data(mBufferSize); + + for(ALuint i = 0;i < sNumBuffers && !finished;i++) + { + size_t got = mDecoder->read(&data[0], data.size()); + finished = (got < data.size()); + if(got > 0) + { + ALuint bufid = mBuffers[i]; + alBufferData(bufid, mFormat, &data[0], got, mSampleRate); + alSourceQueueBuffers(mSource, 1, &bufid); + throwALerror(); + mSamplesQueued += getBufferSampleCount(bufid); + } + } + mIsInitialBatchEnqueued = true; + } if(state != AL_PLAYING && state != AL_PAUSED) { @@ -461,6 +473,7 @@ bool OpenAL_SoundStream::process() std::cout<< "Error updating stream \""<<mDecoder->getName()<<"\"" <<std::endl; mSamplesQueued = 0; mIsFinished = true; + mIsInitialBatchEnqueued = false; } return !mIsFinished; } From 51fb9f65ea5086433fa0d1db12197b133a9b27fd Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov <corrmage@gmail.com> Date: Mon, 17 Feb 2014 02:59:23 +0400 Subject: [PATCH 91/94] #1041 in progress: decode first sample batch right in OpenAL_SoundStream::play() --- apps/openmw/mwsound/openal_output.cpp | 45 +++++++++++++-------------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 7563ad0150..58566225bd 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -172,7 +172,6 @@ class OpenAL_SoundStream : public Sound DecoderPtr mDecoder; volatile bool mIsFinished; - volatile bool mIsInitialBatchEnqueued; void updateAll(bool local); @@ -265,7 +264,7 @@ private: OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder, float basevol, float pitch, int flags) : Sound(Ogre::Vector3(0.0f), 1.0f, basevol, pitch, 1.0f, 1000.0f, flags) - , mOutput(output), mSource(src), mSamplesQueued(0), mDecoder(decoder), mIsFinished(true), mIsInitialBatchEnqueued(false) + , mOutput(output), mSource(src), mSamplesQueued(0), mDecoder(decoder), mIsFinished(true) { throwALerror(); @@ -316,8 +315,26 @@ void OpenAL_SoundStream::play() alSourcei(mSource, AL_BUFFER, 0); throwALerror(); mSamplesQueued = 0; - mIsFinished = false; - mIsInitialBatchEnqueued = false; + + std::vector<char> data(mBufferSize); + + bool finished = false; + for(ALuint i = 0;i < sNumBuffers && !finished;i++) + { + size_t got = mDecoder->read(&data[0], data.size()); + finished = (got < data.size()); + if(got > 0) + { + ALuint bufid = mBuffers[i]; + alBufferData(bufid, mFormat, &data[0], got, mSampleRate); + alSourceQueueBuffers(mSource, 1, &bufid); + throwALerror(); + mSamplesQueued += getBufferSampleCount(bufid); + } + } + + mIsFinished = finished; + alSourcePlay(mSource); mOutput.mStreamThread->add(this); } @@ -325,7 +342,6 @@ void OpenAL_SoundStream::stop() { mOutput.mStreamThread->remove(this); mIsFinished = true; - mIsInitialBatchEnqueued = false; alSourceStop(mSource); alSourcei(mSource, AL_BUFFER, 0); @@ -438,24 +454,6 @@ bool OpenAL_SoundStream::process() } while(processed > 0); throwALerror(); } - else if (!mIsInitialBatchEnqueued) { // nothing enqueued yet - std::vector<char> data(mBufferSize); - - for(ALuint i = 0;i < sNumBuffers && !finished;i++) - { - size_t got = mDecoder->read(&data[0], data.size()); - finished = (got < data.size()); - if(got > 0) - { - ALuint bufid = mBuffers[i]; - alBufferData(bufid, mFormat, &data[0], got, mSampleRate); - alSourceQueueBuffers(mSource, 1, &bufid); - throwALerror(); - mSamplesQueued += getBufferSampleCount(bufid); - } - } - mIsInitialBatchEnqueued = true; - } if(state != AL_PLAYING && state != AL_PAUSED) { @@ -473,7 +471,6 @@ bool OpenAL_SoundStream::process() std::cout<< "Error updating stream \""<<mDecoder->getName()<<"\"" <<std::endl; mSamplesQueued = 0; mIsFinished = true; - mIsInitialBatchEnqueued = false; } return !mIsFinished; } From e5b19cf3c696b5c4b392112c2b785799e2b9a66a Mon Sep 17 00:00:00 2001 From: gus <gus_512@hotmail.com> Date: Mon, 17 Feb 2014 10:37:11 +0100 Subject: [PATCH 92/94] clean up --- apps/openmw/mwclass/door.cpp | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index a846a84923..e9ac39f1d1 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -115,21 +115,11 @@ namespace MWClass if (ref->mRef.mTeleport) { - // teleport door - /// \todo remove this if clause once ActionTeleport can also support other actors - //if (MWBase::Environment::get().getWorld()->getPlayerPtr()==actor) - //{ - boost::shared_ptr<MWWorld::Action> action(new MWWorld::ActionTeleport (ref->mRef.mDestCell, ref->mRef.mDoorDest)); + boost::shared_ptr<MWWorld::Action> action(new MWWorld::ActionTeleport (ref->mRef.mDestCell, ref->mRef.mDoorDest)); - action->setSound(openSound); + action->setSound(openSound); - return action; - /*} - else - { - // another NPC or a creature is using the door - return boost::shared_ptr<MWWorld::Action> (new MWWorld::FailedAction); - }*/ + return action; } else { From 6e1425321bba487587d7c4ba7e6e90154e085b36 Mon Sep 17 00:00:00 2001 From: gus <gus_512@hotmail.com> Date: Mon, 17 Feb 2014 10:43:09 +0100 Subject: [PATCH 93/94] remove cout spam --- apps/openmw/mwmechanics/aiactivate.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwmechanics/aiactivate.cpp b/apps/openmw/mwmechanics/aiactivate.cpp index 667ebea889..a22c2b9ba7 100644 --- a/apps/openmw/mwmechanics/aiactivate.cpp +++ b/apps/openmw/mwmechanics/aiactivate.cpp @@ -86,7 +86,6 @@ bool MWMechanics::AiActivate::execute (const MWWorld::Ptr& actor,float duration) movement.mPosition[1] = 0; MWWorld::Ptr target = world->getPtr(mObjectId,false); MWWorld::Class::get(target).activate(target,actor).get()->execute(actor); - std::cout << "activated"; return true; } @@ -95,7 +94,6 @@ bool MWMechanics::AiActivate::execute (const MWWorld::Ptr& actor,float duration) movement.mPosition[1] = 0; MWWorld::Ptr target = world->getPtr(mObjectId,false); MWWorld::Class::get(target).activate(target,actor).get()->execute(actor); - std::cout << "activated"; return true; } From 84959eea288057e48374862b86452b70eab9e027 Mon Sep 17 00:00:00 2001 From: gus <gus_512@hotmail.com> Date: Mon, 17 Feb 2014 10:50:10 +0100 Subject: [PATCH 94/94] woops, thanks scrawl --- apps/openmw/mwmechanics/aiactivate.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/aiactivate.cpp b/apps/openmw/mwmechanics/aiactivate.cpp index a22c2b9ba7..1f3c585216 100644 --- a/apps/openmw/mwmechanics/aiactivate.cpp +++ b/apps/openmw/mwmechanics/aiactivate.cpp @@ -8,6 +8,8 @@ #include "../mwworld/class.hpp" #include "../mwworld/action.hpp" +#include "steering.hpp" + namespace { float sgn(float a) @@ -98,8 +100,8 @@ bool MWMechanics::AiActivate::execute (const MWWorld::Ptr& actor,float duration) } float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]); - // TODO: use movement settings instead of rotating directly - world->rotateObject(actor, 0, 0, zAngle, false); + zTurn(actor, Ogre::Degree(zAngle)); + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1; movement.mPosition[1] = 1; return false;