From 4e7a056e9e1d3e8c21e107ec3e4d97395144f205 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Sun, 27 Mar 2011 23:28:46 +0400 Subject: [PATCH 01/41] Now working mac app bundle generated during build (includes plugins & resources). Still need to copy frameworks before deployment. FindOGRE.cmake finds Ogre plugins dir on OS X. Default OS X data path set to the data subdir near .app. README_Mac updated. --- CMakeLists.txt | 55 ++++++++++++++---- README_Mac.md | 32 +++-------- cmake/FindOGRE.cmake | 21 ++++++- extern/caelum/CMakeLists.txt | 92 ++++++++++++++++--------------- extern/mygui_3.0.1/CMakeLists.txt | 6 +- files/plugins.cfg.mac | 2 +- 6 files changed, 125 insertions(+), 83 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 957fc1b8a..8f21728bb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,9 @@ project(OpenMW) +IF (APPLE) + set(APP_BUNDLE_DIR "${OpenMW_BINARY_DIR}/OpenMW.app") +ENDIF (APPLE) + # Sound source selection option(USE_AUDIERE "use Audiere for sound" OFF) option(USE_FFMPEG "use ffmpeg for sound" OFF) @@ -14,7 +18,7 @@ if(DPKG_PROGRAM) else() if (APPLE) # set path inside bundle - set(MORROWIND_DATA_FILES "Contents/Resources/data" CACHE PATH "location of Morrowind data files") + set(MORROWIND_DATA_FILES "../data" CACHE PATH "location of Morrowind data files") set(MORROWIND_RESOURCE_FILES "Contents/Resources/resources" CACHE PATH "location of Morrowind data files") else() set(MORROWIND_DATA_FILES "data" CACHE PATH "location of Morrowind data files") @@ -286,25 +290,47 @@ add_definitions(-DCAELUM_STATIC) # Specify build paths -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}") +if (APPLE) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${APP_BUNDLE_DIR}/Contents/MacOS") +else (APPLE) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}") +endif (APPLE) # Other files if (WIN32) -configure_file(${OpenMW_SOURCE_DIR}/files/plugins.cfg.win32 - "${OpenMW_BINARY_DIR}/plugins.cfg" COPYONLY) + configure_file(${OpenMW_SOURCE_DIR}/files/plugins.cfg.win32 + "${OpenMW_BINARY_DIR}/plugins.cfg" COPYONLY) endif (WIN32) if (LINUX) -configure_file(${OpenMW_SOURCE_DIR}/files/plugins.cfg.linux - "${OpenMW_BINARY_DIR}/plugins.cfg") + configure_file(${OpenMW_SOURCE_DIR}/files/plugins.cfg.linux + "${OpenMW_BINARY_DIR}/plugins.cfg") endif (LINUX) if (APPLE) -configure_file(${OpenMW_SOURCE_DIR}/files/plugins.cfg.mac - "${OpenMW_BINARY_DIR}/plugins.cfg") + configure_file(${OpenMW_SOURCE_DIR}/files/plugins.cfg.mac + "${APP_BUNDLE_DIR}/Contents/MacOS/plugins.cfg") + + configure_file(${OpenMW_SOURCE_DIR}/files/mac/Info.plist + "${APP_BUNDLE_DIR}/Contents/Info.plist" COPYONLY) + + configure_file(${OpenMW_SOURCE_DIR}/files/mac/openmw.icns + "${APP_BUNDLE_DIR}/Contents/Resources/OpenMW.icns" COPYONLY) + + + # prepare plugins + configure_file(${OGRE_PLUGIN_DIR}/RenderSystem_GL.dylib + "${APP_BUNDLE_DIR}/Contents/Plugins/RenderSystem_GL.dylib" COPYONLY) + + configure_file(${OGRE_PLUGIN_DIR}/Plugin_OctreeSceneManager.dylib + "${APP_BUNDLE_DIR}/Contents/Plugins/Plugin_OctreeSceneManager.dylib" COPYONLY) + + configure_file(${OGRE_PLUGIN_DIR}/Plugin_ParticleFX.dylib + "${APP_BUNDLE_DIR}/Contents/Plugins/Plugin_ParticleFX.dylib" COPYONLY) + endif (APPLE) configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg - "${OpenMW_BINARY_DIR}/openmw.cfg") + "${APP_BUNDLE_DIR}/Contents/MacOS/openmw.cfg") # Compiler settings if (CMAKE_COMPILER_IS_GNUCC) @@ -315,10 +341,15 @@ endif (CMAKE_COMPILER_IS_GNUCC) # Apple bundling if (APPLE) set(MISC_FILES - ${OpenMW_BINARY_DIR}/openmw.cfg - ${OpenMW_BINARY_DIR}/plugins.cfg) + ${APP_BUNDLE_DIR}/Contents/MacOS/openmw.cfg + ${APP_BUNDLE_DIR}/Contents/MacOS/plugins.cfg) + + set(OGRE_PLUGINS + ${APP_BUNDLE_DIR}/Contents/Plugins/*) + install(FILES ${MISC_FILES} DESTINATION ../MacOS) -install(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ../Resources) +install(DIRECTORY "${APP_BUNDLE_DIR}/Contents/Plugins" DESTINATION ..) +install(DIRECTORY "${APP_BUNDLE_DIR}/Contents/Resources/resources" DESTINATION ../Resources) set(CPACK_GENERATOR "Bundle") set(CPACK_BUNDLE_PLIST "${CMAKE_SOURCE_DIR}/files/mac/Info.plist") set(CPACK_BUNDLE_ICON "${CMAKE_SOURCE_DIR}/files/mac/openmw.icns") diff --git a/README_Mac.md b/README_Mac.md index ee5faca98..39382e0c9 100644 --- a/README_Mac.md +++ b/README_Mac.md @@ -49,8 +49,8 @@ Getting OpenMW Working --link-shared,static --prefix=$OMW_LIB_PREFIX install -5. Download [Ogre][] SDK (tested with 1.7.2) and move `lib/Release/Ogre.framework` into - `Library/Frameworks`. +5. Download [Ogre][] SDK (tested with 1.7.2), unpack it and move +`lib/Release/Ogre.framework` into `Library/Frameworks`. 6. Download [OIS][] and use the XCode project provided in `ois/Mac/XCode-2.2`. Be sure to set your build architecture to @@ -92,6 +92,7 @@ Getting OpenMW Working $ cd /path/to/open/build/dir $ cmake \ -D CMAKE_OSX_ARCHITECTURES=i386 \ + -D OGRESDK=/path/to/ogre/sdk \ -D BOOST_INCLUDEDIR=$OMW_LIB_PREFIX/include/boost-1_45 \ -D BOOST_LIBRARYDIR=$OMW_LIB_PREFIX/lib \ -D SNDFILE_INCLUDE_DIR=$OMW_LIB_PREFIX/include \ @@ -108,32 +109,17 @@ Getting OpenMW Working You can use -G"Xcode" if you prefer Xcode, or -G"Eclipse CDT4 - Unix Makefiles" if you prefer Eclipse. You also can specify -D CMAKE_BUILD_TYPE=Debug for debug build. - -11. In build directory create directory for game resources: - $ cd /path/to/openmw/build/dir - $ mkdir Contents - $ mkdir Contents/Resources - $ mkdir Contents/Plugins - Copy Ogre plugins from Ogre SDK to Plugins subdir: - $ cp /path/to/ogre/sdk/lib/*.dylib Contents/Plugins - Create symlink to resources subdirectory: - $ ln -s resources Contents/Resources/resources - Create symlinks for *.cfg files: - $ ln -s plugins.cfg Contents/MacOS/plugins.cfg - $ ln -s openmw.cfg Contents/MacOS/openmw.cfg -12. Move your Morrowind `Data Files` directory into the `Contents/Resources` +11. Copy your Morrowind `Data Files` directory into the OpenMW build dir with the name `data` or create symlink: - $ ln -s /path/to/morrowind/data/files Contents/Resources/data + $ ln -s /path/to/morrowind/data/files /path/to/openmw/build/dir/data -13. From your build directory run: - $ ./openmw +12. From your build directory run: + $ OpenMW.app/Contents/MacOS/openmw + or: + $ open OpenMW.app Enjoy! -14. Optionally you can create .app bundle: - $ make package - But for now you shold manually copy Contents directory from build directory to bundle - (because there is no plugins and resources in generated .app). [boost]: http://www.boost.org diff --git a/cmake/FindOGRE.cmake b/cmake/FindOGRE.cmake index eebb20338..ce3993805 100644 --- a/cmake/FindOGRE.cmake +++ b/cmake/FindOGRE.cmake @@ -12,9 +12,9 @@ # For details see the accompanying COPYING-CMAKE-SCRIPTS file. CMAKE_POLICY(PUSH) -IF (OGRE_LIBRARIES AND OGRE_INCLUDE_DIR) +IF (OGRE_LIBRARIES AND OGRE_INCLUDE_DIR AND OGRE_LIB_DIR AND OGRE_PLUGIN_DIR) SET(OGRE_FIND_QUIETLY TRUE) # Already in cache, be silent -ENDIF (OGRE_LIBRARIES AND OGRE_INCLUDE_DIR) +ENDIF (OGRE_LIBRARIES AND OGRE_INCLUDE_DIR AND OGRE_LIB_DIR AND OGRE_PLUGIN_DIR) IF (WIN32) #Windows MESSAGE(STATUS "Looking for OGRE") @@ -47,7 +47,16 @@ IF (UNIX AND NOT APPLE) PKG_CHECK_MODULES(OGRE OGRE) ENDIF (UNIX AND NOT APPLE) +# on OS X we need Ogre SDK because framework doesn't include all libs, just Ogre Main lib IF (APPLE) + IF (OGRESDK) + MESSAGE(STATUS "Using Ogre SDK") + SET(OGRE_LIB_DIR ${OGRESDK}/lib) + ELSE (OGRESDK) + MESSAGE(FATAL_ERROR "Path to Ogre SDK not specified. Specify OGRESDK.") + ENDIF (OGRESDK) + + FIND_PATH(OGRE_INCLUDE_DIR Ogre.h PATHS /Library/Frameworks @@ -71,7 +80,12 @@ SET(OGRE_LIB_DIR ${OGRE_LIB_DIR} CACHE PATH "") if(OGRE_LIB_DIR) CMAKE_POLICY(SET CMP0009 NEW) - FILE(GLOB_RECURSE OGRE_PLUGINS "${OGRE_LIB_DIR}/Plugin_*.so") + IF (NOT APPLE) + FILE(GLOB_RECURSE OGRE_PLUGINS "${OGRE_LIB_DIR}/Plugin_*.so") + ENDIF (NOT APPLE) + IF (APPLE) + FILE(GLOB_RECURSE OGRE_PLUGINS "${OGRE_LIB_DIR}/Plugin_*.dylib") + ENDIF (APPLE) FOREACH (OGRE_PLUGINS_FILE ${OGRE_PLUGINS}) STRING(REGEX REPLACE "/[^/]*$" "" OGRE_PLUGIN_DIR ${OGRE_PLUGINS_FILE}) ENDFOREACH(OGRE_PLUGINS_FILE) @@ -85,6 +99,7 @@ IF (OGRE_FOUND) IF (NOT OGRE_FIND_QUIETLY) MESSAGE(STATUS " libraries : ${OGRE_LIBRARIES} from ${OGRE_LIB_DIR}") MESSAGE(STATUS " includes : ${OGRE_INCLUDE_DIR}") + MESSAGE(STATUS " plugins : ${OGRE_PLUGIN_DIR}") ENDIF (NOT OGRE_FIND_QUIETLY) ELSE (OGRE_FOUND) IF (OGRE_FIND_REQUIRED) diff --git a/extern/caelum/CMakeLists.txt b/extern/caelum/CMakeLists.txt index c1854904c..88ed51fad 100755 --- a/extern/caelum/CMakeLists.txt +++ b/extern/caelum/CMakeLists.txt @@ -19,46 +19,52 @@ add_library(caelum STATIC ${SOURCES}) # # Resources # -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/AtmosphereDepth.png "${OpenMW_BINARY_DIR}/resources/caelum/AtmosphereDepth.png" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/CaelumGroundFog.cg "${OpenMW_BINARY_DIR}/resources/caelum/CaelumGroundFog.cg" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/CaelumLayeredClouds.cg "${OpenMW_BINARY_DIR}/resources/caelum/CaelumLayeredClouds.cg" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/CaelumPhaseMoon.cg "${OpenMW_BINARY_DIR}/resources/caelum/CaelumPhaseMoon.cg" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/CaelumPointStarfield.cg "${OpenMW_BINARY_DIR}/resources/caelum/CaelumPointStarfield.cg" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/CaelumSkyDome.cg "${OpenMW_BINARY_DIR}/resources/caelum/CaelumSkyDome.cg" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/CloudCoverLookup.png "${OpenMW_BINARY_DIR}/resources/caelum/CloudCoverLookup.png" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/DepthComposer.cg "${OpenMW_BINARY_DIR}/resources/caelum/DepthComposer.cg" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/DepthComposer.compositor "${OpenMW_BINARY_DIR}/resources/caelum/DepthComposer.compositor" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/DepthComposer.material "${OpenMW_BINARY_DIR}/resources/caelum/DepthComposer.material" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/DepthRender.program "${OpenMW_BINARY_DIR}/resources/caelum/DepthRender.program" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/EarthClearSky2.png "${OpenMW_BINARY_DIR}/resources/caelum/EarthClearSky2.png" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/GroundFog.material "${OpenMW_BINARY_DIR}/resources/caelum/GroundFog.material" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/GroundFog.program "${OpenMW_BINARY_DIR}/resources/caelum/GroundFog.program" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/Haze.program "${OpenMW_BINARY_DIR}/resources/caelum/Haze.program" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/LayeredClouds.material "${OpenMW_BINARY_DIR}/resources/caelum/LayeredClouds.material" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/MinimalCompositorVP.cg "${OpenMW_BINARY_DIR}/resources/caelum/MinimalCompositorVP.cg" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/MinimalCompositorVP.program "${OpenMW_BINARY_DIR}/resources/caelum/MinimalCompositorVP.program" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/moon.material "${OpenMW_BINARY_DIR}/resources/caelum/moon.material" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/moon_disc.dds "${OpenMW_BINARY_DIR}/resources/caelum/moon_disc.dds" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/noise1.dds "${OpenMW_BINARY_DIR}/resources/caelum/noise1.dds" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/noise2.dds "${OpenMW_BINARY_DIR}/resources/caelum/noise2.dds" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/noise3.dds "${OpenMW_BINARY_DIR}/resources/caelum/noise3.dds" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/noise4.dds "${OpenMW_BINARY_DIR}/resources/caelum/noise4.dds" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/PointStarfield.material "${OpenMW_BINARY_DIR}/resources/caelum/PointStarfield.material" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/Precipitation.cg "${OpenMW_BINARY_DIR}/resources/caelum/Precipitation.cg" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/Precipitation.compositor "${OpenMW_BINARY_DIR}/resources/caelum/Precipitation.compositor" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/Precipitation.material "${OpenMW_BINARY_DIR}/resources/caelum/Precipitation.material" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/precipitation_drizzle.png "${OpenMW_BINARY_DIR}/resources/caelum/precipitation_drizzle.png" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/precipitation_hail.png "${OpenMW_BINARY_DIR}/resources/caelum/precipitation_hail.png" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/precipitation_icecrystals.png "${OpenMW_BINARY_DIR}/resources/caelum/precipitation_icecrystals.png" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/precipitation_icepellets.png "${OpenMW_BINARY_DIR}/resources/caelum/precipitation_icepellets.png" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/precipitation_rain.png "${OpenMW_BINARY_DIR}/resources/caelum/precipitation_rain.png" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/precipitation_smallhail.png "${OpenMW_BINARY_DIR}/resources/caelum/precipitation_smallhail.png" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/precipitation_snow.png "${OpenMW_BINARY_DIR}/resources/caelum/precipitation_snow.png" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/precipitation_snowgrains.png "${OpenMW_BINARY_DIR}/resources/caelum/precipitation_snowgrains.png" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/SkyDome.material "${OpenMW_BINARY_DIR}/resources/caelum/SkyDome.material" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/sphere.mesh "${OpenMW_BINARY_DIR}/resources/caelum/sphere.mesh" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/Starfield.jpg "${OpenMW_BINARY_DIR}/resources/caelum/Starfield.jpg" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/Starfield.material "${OpenMW_BINARY_DIR}/resources/caelum/Starfield.material" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/Sun.material "${OpenMW_BINARY_DIR}/resources/caelum/Sun.material" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/SunGradient.png "${OpenMW_BINARY_DIR}/resources/caelum/SunGradient.png" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/sun_disc.png "${OpenMW_BINARY_DIR}/resources/caelum/sun_disc.png" COPYONLY) +if (APPLE) + SET(CAELUM_RES_DEST "${APP_BUNDLE_DIR}/Contents/Resources") +else (APPLE) + SET(CAELUM_RES_DEST "${OpenMW_BINARY_DIR}") +endif (APPLE) + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/AtmosphereDepth.png "${CAELUM_RES_DEST}/resources/caelum/AtmosphereDepth.png" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/CaelumGroundFog.cg "${CAELUM_RES_DEST}/resources/caelum/CaelumGroundFog.cg" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/CaelumLayeredClouds.cg "${CAELUM_RES_DEST}/resources/caelum/CaelumLayeredClouds.cg" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/CaelumPhaseMoon.cg "${CAELUM_RES_DEST}/resources/caelum/CaelumPhaseMoon.cg" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/CaelumPointStarfield.cg "${CAELUM_RES_DEST}/resources/caelum/CaelumPointStarfield.cg" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/CaelumSkyDome.cg "${CAELUM_RES_DEST}/resources/caelum/CaelumSkyDome.cg" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/CloudCoverLookup.png "${CAELUM_RES_DEST}/resources/caelum/CloudCoverLookup.png" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/DepthComposer.cg "${CAELUM_RES_DEST}/resources/caelum/DepthComposer.cg" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/DepthComposer.compositor "${CAELUM_RES_DEST}/resources/caelum/DepthComposer.compositor" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/DepthComposer.material "${CAELUM_RES_DEST}/resources/caelum/DepthComposer.material" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/DepthRender.program "${CAELUM_RES_DEST}/resources/caelum/DepthRender.program" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/EarthClearSky2.png "${CAELUM_RES_DEST}/resources/caelum/EarthClearSky2.png" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/GroundFog.material "${CAELUM_RES_DEST}/resources/caelum/GroundFog.material" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/GroundFog.program "${CAELUM_RES_DEST}/resources/caelum/GroundFog.program" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/Haze.program "${CAELUM_RES_DEST}/resources/caelum/Haze.program" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/LayeredClouds.material "${CAELUM_RES_DEST}/resources/caelum/LayeredClouds.material" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/MinimalCompositorVP.cg "${CAELUM_RES_DEST}/resources/caelum/MinimalCompositorVP.cg" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/MinimalCompositorVP.program "${CAELUM_RES_DEST}/resources/caelum/MinimalCompositorVP.program" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/moon.material "${CAELUM_RES_DEST}/resources/caelum/moon.material" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/moon_disc.dds "${CAELUM_RES_DEST}/resources/caelum/moon_disc.dds" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/noise1.dds "${CAELUM_RES_DEST}/resources/caelum/noise1.dds" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/noise2.dds "${CAELUM_RES_DEST}/resources/caelum/noise2.dds" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/noise3.dds "${CAELUM_RES_DEST}/resources/caelum/noise3.dds" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/noise4.dds "${CAELUM_RES_DEST}/resources/caelum/noise4.dds" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/PointStarfield.material "${CAELUM_RES_DEST}/resources/caelum/PointStarfield.material" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/Precipitation.cg "${CAELUM_RES_DEST}/resources/caelum/Precipitation.cg" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/Precipitation.compositor "${CAELUM_RES_DEST}/resources/caelum/Precipitation.compositor" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/Precipitation.material "${CAELUM_RES_DEST}/resources/caelum/Precipitation.material" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/precipitation_drizzle.png "${CAELUM_RES_DEST}/resources/caelum/precipitation_drizzle.png" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/precipitation_hail.png "${CAELUM_RES_DEST}/resources/caelum/precipitation_hail.png" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/precipitation_icecrystals.png "${CAELUM_RES_DEST}/resources/caelum/precipitation_icecrystals.png" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/precipitation_icepellets.png "${CAELUM_RES_DEST}/resources/caelum/precipitation_icepellets.png" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/precipitation_rain.png "${CAELUM_RES_DEST}/resources/caelum/precipitation_rain.png" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/precipitation_smallhail.png "${CAELUM_RES_DEST}/resources/caelum/precipitation_smallhail.png" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/precipitation_snow.png "${CAELUM_RES_DEST}/resources/caelum/precipitation_snow.png" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/precipitation_snowgrains.png "${CAELUM_RES_DEST}/resources/caelum/precipitation_snowgrains.png" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/SkyDome.material "${CAELUM_RES_DEST}/resources/caelum/SkyDome.material" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/sphere.mesh "${CAELUM_RES_DEST}/resources/caelum/sphere.mesh" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/Starfield.jpg "${CAELUM_RES_DEST}/resources/caelum/Starfield.jpg" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/Starfield.material "${CAELUM_RES_DEST}/resources/caelum/Starfield.material" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/Sun.material "${CAELUM_RES_DEST}/resources/caelum/Sun.material" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/SunGradient.png "${CAELUM_RES_DEST}/resources/caelum/SunGradient.png" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/resources/sun_disc.png "${CAELUM_RES_DEST}/resources/caelum/sun_disc.png" COPYONLY) diff --git a/extern/mygui_3.0.1/CMakeLists.txt b/extern/mygui_3.0.1/CMakeLists.txt index d7e0bd483..8101ad91a 100644 --- a/extern/mygui_3.0.1/CMakeLists.txt +++ b/extern/mygui_3.0.1/CMakeLists.txt @@ -22,7 +22,11 @@ add_subdirectory(OgrePlatform) # Copy resource files into the build directory set(SDIR ${CMAKE_CURRENT_SOURCE_DIR}/openmw_resources) -set(DDIR ${OpenMW_BINARY_DIR}/resources/mygui) +if (APPLE) + set(DDIR ${APP_BUNDLE_DIR}/Contents/Resources/resources/mygui) +else (APPLE) + set(DDIR ${OpenMW_BINARY_DIR}/resources/mygui) +endif (APPLE) configure_file("${SDIR}/bigbars.png" "${DDIR}/bigbars.png" COPYONLY) configure_file("${SDIR}/black.png" "${DDIR}/black.png" COPYONLY) diff --git a/files/plugins.cfg.mac b/files/plugins.cfg.mac index 9fe2798f7..baaca4479 100644 --- a/files/plugins.cfg.mac +++ b/files/plugins.cfg.mac @@ -1,7 +1,7 @@ # Defines plugins to load # Define plugin folder -PluginFolder=${OGRE_PLUGIN_DIR} +PluginFolder= # Define plugins Plugin=RenderSystem_GL.dylib From beb1422c774e433ed3a65b9172d9c58cb8e8a45c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 29 Mar 2011 13:57:56 +0200 Subject: [PATCH 02/41] allow multiple --master and --plugin command line arguments --- apps/openmw/main.cpp | 49 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 4d7e6595c..697b06e93 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -47,8 +47,14 @@ bool parseOptions (int argc, char**argv, OMW::Engine& engine) "set resources directory") ("start", bpo::value()->default_value ("Beshara"), "set initial cell") - ("master", bpo::value()->default_value ("Morrowind"), - "master file") + ("master", bpo::value >() + ->default_value (std::vector(), "") + ->multitoken(), + "master file(s)") + ("plugin", bpo::value >() + ->default_value (std::vector(), "") + ->multitoken(), + "plugin file(s)") ( "showfps", "show fps counter") ( "debug", "debug mode" ) ( "nosound", "disable all sound" ) @@ -83,26 +89,51 @@ bool parseOptions (int argc, char**argv, OMW::Engine& engine) return false; } + // directory settings engine.setDataDir (variables["data"].as()); engine.setResourceDir (variables["resources"].as()); - engine.setCell (variables["start"].as()); - engine.addMaster (variables["master"].as()); - if (variables.count ("showfps")) + // master and plugin + std::vector master = variables["master"].as >(); + if (master.empty()) + { + std::cout << "No master file given. Assuming Morrowind.esm" << std::endl; + master.push_back ("Morrowind"); + } + + if (master.size()>1) + { + std::cout + << "Ignoring all but the first master file (multiple master files not yet supported)." + << std::endl; + } + + engine.addMaster (master[0]); + + std::vector plugin = variables["plugin"].as >(); + + if (!plugin.empty()) + std::cout << "Ignoring plugin files (plugins not yet supported)." << std::endl; + + // startup-settings + engine.setCell (variables["start"].as()); + + if (variables.count ("new-game")) + engine.setNewGame(); + + // other settings + if (variables.count ("fps")) engine.showFPS(); if (variables.count ("debug")) engine.enableDebugMode(); - if (variables.count ("nosound")) + if (variables.count ("no-sound")) engine.disableSound(); if (variables.count ("script-verbose")) engine.enableVerboseScripts(); - if (variables.count ("new-game")) - engine.setNewGame(); - if (variables.count ("script-all")) engine.setCompileAll (true); From 190f77f6c9711582afa282a37983777b9dbd18da Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 4 Apr 2011 11:16:56 +0200 Subject: [PATCH 03/41] added journal class --- apps/openmw/CMakeLists.txt | 2 ++ apps/openmw/engine.cpp | 3 +++ apps/openmw/mwdialogue/journal.cpp | 10 ++++++++++ apps/openmw/mwdialogue/journal.hpp | 21 +++++++++++++++++++++ apps/openmw/mwworld/environment.hpp | 4 +++- 5 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 apps/openmw/mwdialogue/journal.cpp create mode 100644 apps/openmw/mwdialogue/journal.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 0fa027f0c..bdc018c10 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -70,9 +70,11 @@ source_group(apps\\openmw\\mwgui FILES ${GAMEGUI_HEADER} ${GAMEGUI}) set(GAMEDIALOGUE_HEADER mwdialogue/dialoguemanager.hpp + mwdialogue/journal.hpp ) set(GAMEDIALOGUE mwdialogue/dialoguemanager.cpp + mwdialogue/journal.cpp ) source_group(apps\\openmw\\mwdialogue FILES ${GAMEDIALOGUE_HEADER} ${GAMEDIALOGUE}) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 78ddffbe8..dd556ba49 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -36,6 +36,7 @@ #include "mwclass/classes.hpp" #include "mwdialogue/dialoguemanager.hpp" +#include "mwdialogue/journal.hpp" #include "mwmechanics/mechanicsmanager.hpp" @@ -228,6 +229,7 @@ OMW::Engine::~Engine() delete mEnvironment.mGlobalScripts; delete mEnvironment.mMechanicsManager; delete mEnvironment.mDialogueManager; + delete mEnvironment.mJournal; delete mScriptManager; delete mScriptContext; delete mPhysicEngine; @@ -396,6 +398,7 @@ void OMW::Engine::go() mEnvironment.mMechanicsManager = new MWMechanics::MechanicsManager (mEnvironment); // Create dialog system + mEnvironment.mJournal = new MWDialogue::Journal (mEnvironment); mEnvironment.mDialogueManager = new MWDialogue::DialogueManager (mEnvironment); // load cell diff --git a/apps/openmw/mwdialogue/journal.cpp b/apps/openmw/mwdialogue/journal.cpp new file mode 100644 index 000000000..3b674a53e --- /dev/null +++ b/apps/openmw/mwdialogue/journal.cpp @@ -0,0 +1,10 @@ + +#include "journal.hpp" + +namespace MWDialogue +{ + MWDialogue::Journal::Journal (MWWorld::Environment& environment) + : mEnvironment (environment) + {} + +} diff --git a/apps/openmw/mwdialogue/journal.hpp b/apps/openmw/mwdialogue/journal.hpp new file mode 100644 index 000000000..1988e230d --- /dev/null +++ b/apps/openmw/mwdialogue/journal.hpp @@ -0,0 +1,21 @@ +#ifndef GAME_MMDIALOG_JOURNAL_H +#define GAME_MWDIALOG_JOURNAL_H + +namespace MWWorld +{ + struct Environment; +} + +namespace MWDialogue +{ + class Journal + { + MWWorld::Environment& mEnvironment; + + public: + + Journal (MWWorld::Environment& environment); + }; +} + +#endif diff --git a/apps/openmw/mwworld/environment.hpp b/apps/openmw/mwworld/environment.hpp index c04dfcbf1..a403ee165 100644 --- a/apps/openmw/mwworld/environment.hpp +++ b/apps/openmw/mwworld/environment.hpp @@ -24,6 +24,7 @@ namespace MWMechanics namespace MWDialogue { class DialogueManager; + class Journal; } namespace MWInput @@ -41,7 +42,7 @@ namespace MWWorld public: Environment() : mWorld (0), mSoundManager (0), mGlobalScripts (0), mWindowManager (0), - mMechanicsManager (0), mDialogueManager (0), mFrameDuration (0), + mMechanicsManager (0), mDialogueManager (0), mJournal (0), mFrameDuration (0), mInputManager (0) {} @@ -51,6 +52,7 @@ namespace MWWorld MWGui::WindowManager *mWindowManager; MWMechanics::MechanicsManager *mMechanicsManager; MWDialogue::DialogueManager *mDialogueManager; + MWDialogue::Journal *mJournal; float mFrameDuration; // For setting GUI mode From b40117449a2bd282fe5210f0d1fd775021a989ca Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 4 Apr 2011 11:23:15 +0200 Subject: [PATCH 04/41] added journal script interface --- apps/openmw/mwdialogue/journal.cpp | 18 +++++++++++++++++- apps/openmw/mwdialogue/journal.hpp | 11 +++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwdialogue/journal.cpp b/apps/openmw/mwdialogue/journal.cpp index 3b674a53e..031917c1c 100644 --- a/apps/openmw/mwdialogue/journal.cpp +++ b/apps/openmw/mwdialogue/journal.cpp @@ -1,10 +1,26 @@ #include "journal.hpp" + +#include namespace MWDialogue { - MWDialogue::Journal::Journal (MWWorld::Environment& environment) + Journal::Journal (MWWorld::Environment& environment) : mEnvironment (environment) {} + void Journal::addEntry (const std::string& id, int index) + { + std::cout << "journal: " << id << " at " << index << std::endl; + } + + void Journal::setJournalIndex (const std::string& id, int index) + { + std::cout << "journal (no entry): " << id << " at " << index << std::endl; + } + + int Journal::getJournalIndex (const std::string& id) const + { + return 0; + } } diff --git a/apps/openmw/mwdialogue/journal.hpp b/apps/openmw/mwdialogue/journal.hpp index 1988e230d..cd4814255 100644 --- a/apps/openmw/mwdialogue/journal.hpp +++ b/apps/openmw/mwdialogue/journal.hpp @@ -1,6 +1,8 @@ #ifndef GAME_MMDIALOG_JOURNAL_H #define GAME_MWDIALOG_JOURNAL_H +#include + namespace MWWorld { struct Environment; @@ -15,6 +17,15 @@ namespace MWDialogue public: Journal (MWWorld::Environment& environment); + + void addEntry (const std::string& id, int index); + ///< Add a journal entry. + + void setJournalIndex (const std::string& id, int index); + ///< Set the journal index without adding an entry. + + int getJournalIndex (const std::string& id) const; + ///< Get the journal index. }; } From e4a0702bb49566225225bf25dbfbec1afe7111a5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 4 Apr 2011 14:49:26 +0200 Subject: [PATCH 05/41] added journal-related script instructions --- apps/openmw/CMakeLists.txt | 2 + apps/openmw/mwscript/dialogueextensions.cpp | 94 +++++++++++++++++++++ apps/openmw/mwscript/dialogueextensions.hpp | 25 ++++++ apps/openmw/mwscript/docs/vmformat.txt | 5 +- apps/openmw/mwscript/extensions.cpp | 3 + apps/openmw/mwscript/interpretercontext.cpp | 5 ++ apps/openmw/mwscript/interpretercontext.hpp | 4 + 7 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 apps/openmw/mwscript/dialogueextensions.cpp create mode 100644 apps/openmw/mwscript/dialogueextensions.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index bdc018c10..3cb08b5f7 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -93,6 +93,7 @@ set(GAMESCRIPT mwscript/controlextensions.cpp mwscript/extensions.cpp mwscript/globalscripts.cpp + mwscript/dialogueextensions.cpp ) set(GAMESCRIPT_HEADER mwscript/locals.hpp @@ -111,6 +112,7 @@ set(GAMESCRIPT_HEADER mwscript/extensions.hpp mwscript/globalscripts.hpp mwscript/ref.hpp + mwscript/dialogueextensions.hpp ) source_group(apps\\openmw\\mwscript FILES ${GAMESCRIPT} ${GAMESCRIPT_HEADER}) diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp new file mode 100644 index 000000000..c2ff9ed8b --- /dev/null +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -0,0 +1,94 @@ + +#include "dialogueextensions.hpp" + +#include + +#include +#include +#include + +#include "../mwdialogue/journal.hpp" + +#include "interpretercontext.hpp" + +namespace MWScript +{ + namespace Dialogue + { + class OpJournal : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + + std::string quest = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + Interpreter::Type_Integer index = runtime[0].mInteger; + runtime.pop(); + + context.getEnvironment().mJournal->addEntry (quest, index); + } + }; + + class OpSetJournalIndex : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + + std::string quest = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + Interpreter::Type_Integer index = runtime[0].mInteger; + runtime.pop(); + + context.getEnvironment().mJournal->setJournalIndex (quest, index); + } + }; + + class OpGetJournalIndex : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + + std::string quest = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + int index = context.getEnvironment().mJournal->getJournalIndex (quest); + + runtime.push (index); + + } + }; + + const int opcodeJournal = 0x2000133; + const int opcodeSetJournalIndex = 0x2000134; + const int opcodeGetJournalIndex = 0x2000135; + + void registerExtensions (Compiler::Extensions& extensions) + { + extensions.registerInstruction ("journal", "cl", opcodeJournal); + extensions.registerInstruction ("setjournalindex", "cl", opcodeSetJournalIndex); + extensions.registerFunction ("getjournalindex", 'l', "c", opcodeGetJournalIndex); + } + + void installOpcodes (Interpreter::Interpreter& interpreter) + { + interpreter.installSegment5 (opcodeJournal, new OpJournal); + interpreter.installSegment5 (opcodeSetJournalIndex, new OpSetJournalIndex); + interpreter.installSegment5 (opcodeGetJournalIndex, new OpGetJournalIndex); + } + } + +} diff --git a/apps/openmw/mwscript/dialogueextensions.hpp b/apps/openmw/mwscript/dialogueextensions.hpp new file mode 100644 index 000000000..ece7d62ce --- /dev/null +++ b/apps/openmw/mwscript/dialogueextensions.hpp @@ -0,0 +1,25 @@ +#ifndef GAME_SCRIPT_DIALOGUEEXTENSIONS_H +#define GAME_SCRIPT_DIALOGUEEXTENSIONS_H + +namespace Compiler +{ + class Extensions; +} + +namespace Interpreter +{ + class Interpreter; +} + +namespace MWScript +{ + /// \brief Dialogue/Journal-related script functionality + namespace Dialogue + { + void registerExtensions (Compiler::Extensions& extensions); + + void installOpcodes (Interpreter::Interpreter& interpreter); + } +} + +#endif diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index d803d0bac..90962f56b 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -104,4 +104,7 @@ op 0x2000115-0x200012f: ModSKill, explicit reference op 0x2000130: ToggleCollision op 0x2000131: GetInterior op 0x2000132: ToggleCollsionDebug -opcodes 0x2000133-0x3ffffff unused +op 0x2000133: Journal +op 0x2000134: SetJournalIndex +op 0x2000135: GetJournalIndex +opcodes 0x2000136-0x3ffffff unused diff --git a/apps/openmw/mwscript/extensions.cpp b/apps/openmw/mwscript/extensions.cpp index 15d482fc1..86161d2b1 100644 --- a/apps/openmw/mwscript/extensions.cpp +++ b/apps/openmw/mwscript/extensions.cpp @@ -13,6 +13,7 @@ #include "containerextensions.hpp" #include "aiextensions.hpp" #include "controlextensions.hpp" +#include "dialogueextensions.hpp" namespace MWScript { @@ -27,6 +28,7 @@ namespace MWScript Container::registerExtensions (extensions); Ai::registerExtensions (extensions); Control::registerExtensions (extensions); + Dialogue::registerExtensions (extensions); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -41,5 +43,6 @@ namespace MWScript Container::installOpcodes (interpreter); Ai::installOpcodes (interpreter); Control::installOpcodes (interpreter); + Dialogue::installOpcodes (interpreter); } } diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index f2f1e6e10..cb6ecb218 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -260,6 +260,11 @@ namespace MWScript mEnvironment.mWorld->disable (ref); } + MWWorld::Environment& InterpreterContext::getEnvironment() + { + return mEnvironment; + } + MWGui::WindowManager& InterpreterContext::getWindowManager() { return *mEnvironment.mWindowManager; diff --git a/apps/openmw/mwscript/interpretercontext.hpp b/apps/openmw/mwscript/interpretercontext.hpp index 031820d5d..aebfc620e 100644 --- a/apps/openmw/mwscript/interpretercontext.hpp +++ b/apps/openmw/mwscript/interpretercontext.hpp @@ -106,6 +106,10 @@ namespace MWScript virtual void disable (const std::string& id = ""); + MWWorld::Environment& getEnvironment(); + + /// \todo remove the following functions (extentions should use getEnvironment instead) + MWWorld::World& getWorld(); MWSound::SoundManager& getSoundManager(); From f321e549a4bb4af4bae0bf6a37e4b5a558156681 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 4 Apr 2011 15:10:37 +0200 Subject: [PATCH 06/41] added instruction GetPCCell --- apps/openmw/mwscript/cellextensions.cpp | 34 +++++++++++++++++++++++++ apps/openmw/mwscript/docs/vmformat.txt | 3 ++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/cellextensions.cpp b/apps/openmw/mwscript/cellextensions.cpp index 9c756e11f..bb5263203 100644 --- a/apps/openmw/mwscript/cellextensions.cpp +++ b/apps/openmw/mwscript/cellextensions.cpp @@ -102,10 +102,42 @@ namespace MWScript } }; + class OpGetPCCell : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + InterpreterContext& context + = static_cast (runtime.getContext()); + + std::string name = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + const ESM::Cell *cell = context.getWorld().getPlayer().getPlayer().getCell()->cell; + + std::string current = cell->name; + + if (!(cell->data.flags & ESM::Cell::Interior) && current.empty()) + { + const ESM::Region *region = + context.getWorld().getStore().regions.find (cell->region); + + current = region->name; + } + + bool match = current.length()>=name.length() && + current.substr (0, name.length())==name; + + runtime.push (match ? 1 : 0); + } + }; + const int opcodeCellChanged = 0x2000000; const int opcodeCOC = 0x2000026; const int opcodeCOE = 0x200008e; const int opcodeGetInterior = 0x2000131; + const int opcodeGetPCCell = 0x2000136; void registerExtensions (Compiler::Extensions& extensions) { @@ -115,6 +147,7 @@ namespace MWScript extensions.registerInstruction ("coe", "ll", opcodeCOE); extensions.registerInstruction ("centeronexterior", "ll", opcodeCOE); extensions.registerFunction ("getinterior", 'l', "", opcodeGetInterior); + extensions.registerFunction ("getpccell", 'l', "c", opcodeGetPCCell); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -123,6 +156,7 @@ namespace MWScript interpreter.installSegment5 (opcodeCOC, new OpCOC); interpreter.installSegment5 (opcodeCOE, new OpCOE); interpreter.installSegment5 (opcodeGetInterior, new OpGetInterior); + interpreter.installSegment5 (opcodeGetPCCell, new OpGetPCCell); } } } diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 90962f56b..fcebaae2b 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -107,4 +107,5 @@ op 0x2000132: ToggleCollsionDebug op 0x2000133: Journal op 0x2000134: SetJournalIndex op 0x2000135: GetJournalIndex -opcodes 0x2000136-0x3ffffff unused +op 0x2000136: GetPCCell +opcodes 0x2000137-0x3ffffff unused From 53e0e3886242511804dbf1454892b139342beee5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 6 Apr 2011 09:49:00 +0200 Subject: [PATCH 07/41] added missing TCL instruction --- apps/openmw/mwscript/controlextensions.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwscript/controlextensions.cpp b/apps/openmw/mwscript/controlextensions.cpp index f5a5c08a4..e687b1352 100644 --- a/apps/openmw/mwscript/controlextensions.cpp +++ b/apps/openmw/mwscript/controlextensions.cpp @@ -74,6 +74,7 @@ namespace MWScript } extensions.registerInstruction ("togglecollision", "", opcodeToggleCollision); + extensions.registerInstruction ("tcl", "", opcodeToggleCollision); } void installOpcodes (Interpreter::Interpreter& interpreter) From a2c42ab5a2b1dc2fda3399c657f1ad5b1af31cca Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Wed, 6 Apr 2011 20:11:08 +0400 Subject: [PATCH 08/41] components/esm header refactoring in progress. Refactored: esm_reader.hpp loadacti.hpp loadalch.hpp loadappa.hpp loadarmo.hpp loadbody.hpp loadbook.hpp loadbsgn.hpp loadcell.hpp loadclas.hpp loadclot.hpp loadland.hpp Updated code style in defs.hpp --- CMakeLists.txt | 13 ++ components/esm/defs.hpp | 85 ++++----- components/esm/esm_reader.cpp | 345 ++++++++++++++++++++++++++++++++++ components/esm/esm_reader.hpp | 345 ++++------------------------------ components/esm/loadacti.cpp | 11 ++ components/esm/loadacti.hpp | 12 +- components/esm/loadalch.cpp | 14 ++ components/esm/loadalch.hpp | 31 ++- components/esm/loadappa.cpp | 13 ++ components/esm/loadappa.hpp | 37 ++-- components/esm/loadarmo.cpp | 28 +++ components/esm/loadarmo.hpp | 135 ++++++------- components/esm/loadbody.cpp | 13 ++ components/esm/loadbody.hpp | 71 ++++--- components/esm/loadbook.cpp | 17 ++ components/esm/loadbook.hpp | 28 +-- components/esm/loadbsgn.cpp | 15 ++ components/esm/loadbsgn.hpp | 18 +- components/esm/loadcell.cpp | 113 +++++++++++ components/esm/loadcell.hpp | 102 +--------- components/esm/loadclas.cpp | 17 ++ components/esm/loadclas.hpp | 84 ++++----- components/esm/loadclot.cpp | 20 ++ components/esm/loadclot.hpp | 59 +++--- components/esm/loadland.cpp | 32 ++++ components/esm/loadland.hpp | 46 +---- 26 files changed, 942 insertions(+), 762 deletions(-) create mode 100644 components/esm/esm_reader.cpp create mode 100644 components/esm/loadacti.cpp create mode 100644 components/esm/loadalch.cpp create mode 100644 components/esm/loadappa.cpp create mode 100644 components/esm/loadarmo.cpp create mode 100644 components/esm/loadbody.cpp create mode 100644 components/esm/loadbook.cpp create mode 100644 components/esm/loadbsgn.cpp create mode 100644 components/esm/loadcell.cpp create mode 100644 components/esm/loadclas.cpp create mode 100644 components/esm/loadclot.cpp create mode 100644 components/esm/loadland.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f21728bb..9aac8e11f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -131,6 +131,19 @@ set(ESM ${COMP_DIR}/esm/skill.cpp ${COMP_DIR}/esm/attr.cpp ${COMP_DIR}/esm/class.cpp + ${COMP_DIR}/esm/esm_reader.cpp + ${COMP_DIR}/esm/loadland.cpp + ${COMP_DIR}/esm/loadacti.cpp + ${COMP_DIR}/esm/loadalch.cpp + ${COMP_DIR}/esm/loadappa.cpp + ${COMP_DIR}/esm/loadarmo.cpp + ${COMP_DIR}/esm/loadbody.cpp + ${COMP_DIR}/esm/loadbook.cpp + ${COMP_DIR}/esm/loadbsgn.cpp + ${COMP_DIR}/esm/loadcell.cpp + ${COMP_DIR}/esm/loadclas.cpp + ${COMP_DIR}/esm/loadclot.cpp + ) source_group(components\\esm FILES ${ESM_HEADER} ${ESM}) diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index 9a4cefa37..0fdbe45aa 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -3,13 +3,14 @@ #include "esm_reader.hpp" -namespace ESM { +namespace ESM +{ // Pixel color value. Standard four-byte rr,gg,bb,aa format. typedef int32_t Color; enum VarType - { +{ VT_Unknown, VT_None, VT_Short, @@ -18,79 +19,75 @@ enum VarType VT_Float, VT_String, VT_Ignored - }; +}; enum Specialization - { - SPC_Combat = 0, - SPC_Magic = 1, - SPC_Stealth = 2 - }; +{ + SPC_Combat = 0, SPC_Magic = 1, SPC_Stealth = 2 +}; enum RangeType - { - RT_Self = 0, - RT_Touch = 1, - RT_Target = 2 - }; +{ + RT_Self = 0, RT_Touch = 1, RT_Target = 2 +}; /** A list of references to spells and spell effects. This is shared - between the records BSGN, NPC and RACE. -*/ + between the records BSGN, NPC and RACE. + */ struct SpellList { - std::vector list; + std::vector list; - void load(ESMReader &esm) - { - while(esm.isNextSub("NPCS")) - list.push_back(esm.getHString()); - } + void load(ESMReader &esm) + { + while (esm.isNextSub("NPCS")) + list.push_back(esm.getHString()); + } }; /** Defines a spell effect. Shared between SPEL (Spells), ALCH - (Potions) and ENCH (Item enchantments) records -*/ + (Potions) and ENCH (Item enchantments) records + */ #pragma pack(push) #pragma pack(1) // Position and rotation struct Position { - float pos[3]; - float rot[3]; + float pos[3]; + float rot[3]; }; struct ENAMstruct { - // Magical effect, hard-coded ID - short effectID; + // Magical effect, hard-coded ID + short effectID; - // Which skills/attributes are affected (for restore/drain spells - // etc.) - signed char skill, attribute; // -1 if N/A + // Which skills/attributes are affected (for restore/drain spells + // etc.) + signed char skill, attribute; // -1 if N/A - // Other spell parameters - int range; // 0 - self, 1 - touch, 2 - target (RangeType enum) - int area, duration, magnMin, magnMax; + // Other spell parameters + int range; // 0 - self, 1 - touch, 2 - target (RangeType enum) + int area, duration, magnMin, magnMax; - // Struct size should be 24 bytes + // Struct size should be 24 bytes }; #pragma pack(pop) struct EffectList { - std::vector list; + std::vector list; - void load(ESMReader &esm) - { - ENAMstruct s; - while(esm.isNextSub("ENAM")) - { - esm.getHT(s, 24); - list.push_back(s); - } - } + void load(ESMReader &esm) + { + ENAMstruct s; + while (esm.isNextSub("ENAM")) + { + esm.getHT(s, 24); + list.push_back(s); + } + } }; } diff --git a/components/esm/esm_reader.cpp b/components/esm/esm_reader.cpp new file mode 100644 index 000000000..00a34e2df --- /dev/null +++ b/components/esm/esm_reader.cpp @@ -0,0 +1,345 @@ +#include "esm_reader.hpp" + +namespace ESM +{ + +ESM_Context ESMReader::getContext() +{ + // Update the file position before returning + mCtx.filePos = mEsm->tell(); + return mCtx; +} + +void ESMReader::restoreContext(const ESM_Context &rc) +{ + // Reopen the file if necessary + if (mCtx.filename != rc.filename) + openRaw(rc.filename); + + // Copy the data + mCtx = rc; + + // Make sure we seek to the right place + mEsm->seek(mCtx.filePos); +} + +void ESMReader::close() +{ + mEsm.reset(); + mCtx.filename.clear(); + mCtx.leftFile = 0; + mCtx.leftRec = 0; + mCtx.leftSub = 0; + mCtx.subCached = false; + mCtx.recName.val = 0; + mCtx.subName.val = 0; +} + +void ESMReader::openRaw(Mangle::Stream::StreamPtr _esm, const std::string &name) +{ + close(); + mEsm = _esm; + mCtx.filename = name; + mCtx.leftFile = mEsm->size(); + + // Flag certain files for special treatment, based on the file + // name. + const char *cstr = mCtx.filename.c_str(); + if (iends(cstr, "Morrowind.esm")) + mSpf = SF_Morrowind; + else if (iends(cstr, "Tribunal.esm")) + mSpf = SF_Tribunal; + else if (iends(cstr, "Bloodmoon.esm")) + mSpf = SF_Bloodmoon; + else + mSpf = SF_Other; +} + +void ESMReader::open(Mangle::Stream::StreamPtr _esm, const std::string &name) +{ + openRaw(_esm, name); + + if (getRecName() != "TES3") + fail("Not a valid Morrowind file"); + + getRecHeader(); + + // Get the header + getHNT(mCtx.header, "HEDR", 300); + + if (mCtx.header.version != VER_12 && mCtx.header.version != VER_13) + fail("Unsupported file format version"); + + while (isNextSub("MAST")) + { + MasterData m; + m.name = getHString(); + m.size = getHNLong("DATA"); + mMasters.push_back(m); + } + + if (mCtx.header.type == FT_ESS) + { + // Savegame-related data + + // Player position etc + getHNT(mSaveData, "GMDT", 124); + + /* Image properties, five ints. Is always: + Red-mask: 0xff0000 + Blue-mask: 0x00ff00 + Green-mask: 0x0000ff + Alpha-mask: 0x000000 + Bpp: 32 + */ + getSubNameIs("SCRD"); + skipHSubSize(20); + + /* Savegame screenshot: + 128x128 pixels * 4 bytes per pixel + */ + getSubNameIs("SCRS"); + skipHSubSize(65536); + } +} + +void ESMReader::open(const std::string &file) +{ + using namespace Mangle::Stream; + open(StreamPtr(new FileStream(file)), file); +} + +void ESMReader::openRaw(const std::string &file) +{ + using namespace Mangle::Stream; + openRaw(StreamPtr(new FileStream(file)), file); +} + +int64_t ESMReader::getHNLong(const char *name) +{ + int64_t val; + getHNT(val, name); + return val; +} + +std::string ESMReader::getHNOString(const char* name) +{ + if (isNextSub(name)) + return getHString(); + return ""; +} + +std::string ESMReader::getHNString(const char* name) +{ + getSubNameIs(name); + return getHString(); +} + +std::string ESMReader::getHString() +{ + getSubHeader(); + + // Hack to make MultiMark.esp load. Zero-length strings do not + // occur in any of the official mods, but MultiMark makes use of + // them. For some reason, they break the rules, and contain a byte + // (value 0) even if the header says there is no data. If + // Morrowind accepts it, so should we. + if (mCtx.leftSub == 0) + { + // Skip the following zero byte + mCtx.leftRec--; + char c; + mEsm->read(&c, 1); + return ""; + } + + return getString(mCtx.leftSub); +} + +void ESMReader::getHExact(void*p, int size) +{ + getSubHeader(); + if (size != static_cast (mCtx.leftSub)) + fail("getHExact() size mismatch"); + getExact(p, size); +} + +// Read the given number of bytes from a named subrecord +void ESMReader::getHNExact(void*p, int size, const char* name) +{ + getSubNameIs(name); + getHExact(p, size); +} + +// Get the next subrecord name and check if it matches the parameter +void ESMReader::getSubNameIs(const char* name) +{ + getSubName(); + if (mCtx.subName != name) + fail( + "Expected subrecord " + std::string(name) + " but got " + + mCtx.subName.toString()); +} + +bool ESMReader::isNextSub(const char* name) +{ + if (!mCtx.leftRec) + return false; + + getSubName(); + + // If the name didn't match, then mark the it as 'cached' so it's + // available for the next call to getSubName. + mCtx.subCached = (mCtx.subName != name); + + // If subCached is false, then subName == name. + return !mCtx.subCached; +} + +// Read subrecord name. This gets called a LOT, so I've optimized it +// slightly. +void ESMReader::getSubName() +{ + // If the name has already been read, do nothing + if (mCtx.subCached) + { + mCtx.subCached = false; + return; + } + + // reading the subrecord data anyway. + mEsm->read(mCtx.subName.name, 4); + mCtx.leftRec -= 4; +} + +bool ESMReader::isEmptyOrGetName() +{ + if (mCtx.leftRec) + { + mEsm->read(mCtx.subName.name, 4); + mCtx.leftRec -= 4; + return false; + } + return true; +} + +void ESMReader::skipHSub() +{ + getSubHeader(); + skip(mCtx.leftSub); +} + +void ESMReader::skipHSubSize(int size) +{ + skipHSub(); + if (static_cast (mCtx.leftSub) != size) + fail("skipHSubSize() mismatch"); +} + +void ESMReader::getSubHeader() +{ + if (mCtx.leftRec < 4) + fail("End of record while reading sub-record header"); + + // Get subrecord size + getT(mCtx.leftSub); + + // Adjust number of record bytes left + mCtx.leftRec -= mCtx.leftSub + 4; +} + +void ESMReader::getSubHeaderIs(int size) +{ + getSubHeader(); + if (size != static_cast (mCtx.leftSub)) + fail("getSubHeaderIs(): Sub header mismatch"); +} + +NAME ESMReader::getRecName() +{ + if (!hasMoreRecs()) + fail("No more records, getRecName() failed"); + getName(mCtx.recName); + mCtx.leftFile -= 4; + + // Make sure we don't carry over any old cached subrecord + // names. This can happen in some cases when we skip parts of a + // record. + mCtx.subCached = false; + + return mCtx.recName; +} + +void ESMReader::skipRecord() +{ + skip(mCtx.leftRec); + mCtx.leftRec = 0; +} + +void ESMReader::skipHRecord() +{ + if (!mCtx.leftFile) + return; + getRecHeader(); + skipRecord(); +} + +void ESMReader::getRecHeader(uint32_t &flags) +{ + // General error checking + if (mCtx.leftFile < 12) + fail("End of file while reading record header"); + if (mCtx.leftRec) + fail("Previous record contains unread bytes"); + + getUint(mCtx.leftRec); + getUint(flags);// This header entry is always zero + getUint(flags); + mCtx.leftFile -= 12; + + // Check that sizes add up + if (mCtx.leftFile < mCtx.leftRec) + fail("Record size is larger than rest of file"); + + // Adjust number of bytes mCtx.left in file + mCtx.leftFile -= mCtx.leftRec; +} + +/************************************************************************* + * + * Lowest level data reading and misc methods + * + *************************************************************************/ + +void ESMReader::getExact(void*x, int size) +{ + int t = mEsm->read(x, size); + if (t != size) + fail("Read error"); +} + +std::string ESMReader::getString(int size) +{ + char *ptr = ToUTF8::getBuffer(size); + mEsm->read(ptr, size); + + // Convert to UTF8 and return + return ToUTF8::getUtf8(ToUTF8::WINDOWS_1252); +} + +void ESMReader::fail(const std::string &msg) +{ + using namespace std; + + stringstream ss; + + ss << "ESM Error: " << msg; + ss << "\n File: " << mCtx.filename; + ss << "\n Record: " << mCtx.recName.toString(); + ss << "\n Subrecord: " << mCtx.subName.toString(); + if (mEsm != NULL) + ss << "\n Offset: 0x" << hex << mEsm->tell(); + throw std::runtime_error(ss.str()); +} + +} diff --git a/components/esm/esm_reader.hpp b/components/esm/esm_reader.hpp index 8f4fafd88..dea1980e2 100644 --- a/components/esm/esm_reader.hpp +++ b/components/esm/esm_reader.hpp @@ -171,122 +171,27 @@ public: /** Save the current file position and information in a ESM_Context struct */ - ESM_Context getContext() - { - // Update the file position before returning - mCtx.filePos = mEsm->tell(); - return mCtx; - } + ESM_Context getContext(); /** Restore a previously saved context */ - void restoreContext(const ESM_Context &rc) - { - // Reopen the file if necessary - if(mCtx.filename != rc.filename) - openRaw(rc.filename); - - // Copy the data - mCtx = rc; - - // Make sure we seek to the right place - mEsm->seek(mCtx.filePos); - } + void restoreContext(const ESM_Context &rc); /** Close the file, resets all information. After calling close() the structure may be reused to load a new file. */ - void close() - { - mEsm.reset(); - mCtx.filename.clear(); - mCtx.leftFile = 0; - mCtx.leftRec = 0; - mCtx.leftSub = 0; - mCtx.subCached = false; - mCtx.recName.val = 0; - mCtx.subName.val = 0; - } + void close(); /// Raw opening. Opens the file and sets everything up but doesn't /// parse the header. - void openRaw(Mangle::Stream::StreamPtr _esm, const std::string &name) - { - close(); - mEsm = _esm; - mCtx.filename = name; - mCtx.leftFile = mEsm->size(); - - // Flag certain files for special treatment, based on the file - // name. - const char *cstr = mCtx.filename.c_str(); - if(iends(cstr, "Morrowind.esm")) mSpf = SF_Morrowind; - else if(iends(cstr, "Tribunal.esm")) mSpf = SF_Tribunal; - else if(iends(cstr, "Bloodmoon.esm")) mSpf = SF_Bloodmoon; - else mSpf = SF_Other; - } + void openRaw(Mangle::Stream::StreamPtr _esm, const std::string &name); /// Load ES file from a new stream, parses the header. Closes the /// currently open file first, if any. - void open(Mangle::Stream::StreamPtr _esm, const std::string &name) - { - openRaw(_esm, name); + void open(Mangle::Stream::StreamPtr _esm, const std::string &name); - if(getRecName() != "TES3") - fail("Not a valid Morrowind file"); + void open(const std::string &file); - getRecHeader(); - - // Get the header - getHNT(mCtx.header, "HEDR", 300); - - if(mCtx.header.version != VER_12 && - mCtx.header.version != VER_13) - fail("Unsupported file format version"); - - while(isNextSub("MAST")) - { - MasterData m; - m.name = getHString(); - m.size = getHNLong("DATA"); - mMasters.push_back(m); - } - - if(mCtx.header.type == FT_ESS) - { - // Savegame-related data - - // Player position etc - getHNT(mSaveData, "GMDT", 124); - - /* Image properties, five ints. Is always: - Red-mask: 0xff0000 - Blue-mask: 0x00ff00 - Green-mask: 0x0000ff - Alpha-mask: 0x000000 - Bpp: 32 - */ - getSubNameIs("SCRD"); - skipHSubSize(20); - - /* Savegame screenshot: - 128x128 pixels * 4 bytes per pixel - */ - getSubNameIs("SCRS"); - skipHSubSize(65536); - } - } - - void open(const std::string &file) - { - using namespace Mangle::Stream; - open(StreamPtr(new FileStream(file)), file); - } - - void openRaw(const std::string &file) - { - using namespace Mangle::Stream; - openRaw(StreamPtr(new FileStream(file)), file); - } + void openRaw(const std::string &file); /************************************************************************* * @@ -306,8 +211,8 @@ public: template void getHNOT(X &x, const char* name) { - if(isNextSub(name)) - getHT(x); + if(isNextSub(name)) + getHT(x); } // Version with extra size checking, to make sure the compiler @@ -315,26 +220,21 @@ public: template void getHNT(X &x, const char* name, int size) { - assert(sizeof(X) == size); - getSubNameIs(name); - getHT(x); + assert(sizeof(X) == size); + getSubNameIs(name); + getHT(x); } - int64_t getHNLong(const char *name) - { - int64_t val; - getHNT(val, name); - return val; - } + int64_t getHNLong(const char *name); // Get data of a given type/size, including subrecord header template void getHT(X &x) { - getSubHeader(); - if(mCtx.leftSub != sizeof(X)) - fail("getHT(): subrecord size mismatch"); - getT(x); + getSubHeader(); + if (mCtx.leftSub != sizeof(X)) + fail("getHT(): subrecord size mismatch"); + getT(x); } // Version with extra size checking, to make sure the compiler @@ -342,62 +242,24 @@ public: template void getHT(X &x, int size) { - assert(sizeof(X) == size); - getHT(x); + assert(sizeof(X) == size); + getHT(x); } // Read a string by the given name if it is the next record. - std::string getHNOString(const char* name) - { - if(isNextSub(name)) - return getHString(); - return ""; - } + std::string getHNOString(const char* name); // Read a string with the given sub-record name - std::string getHNString(const char* name) - { - getSubNameIs(name); - return getHString(); - } + std::string getHNString(const char* name); // Read a string, including the sub-record header (but not the name) - std::string getHString() - { - getSubHeader(); - - // Hack to make MultiMark.esp load. Zero-length strings do not - // occur in any of the official mods, but MultiMark makes use of - // them. For some reason, they break the rules, and contain a byte - // (value 0) even if the header says there is no data. If - // Morrowind accepts it, so should we. - if(mCtx.leftSub == 0) - { - // Skip the following zero byte - mCtx.leftRec--; - char c; - mEsm->read(&c,1); - return ""; - } - - return getString(mCtx.leftSub); - } + std::string getHString(); // Read the given number of bytes from a subrecord - void getHExact(void*p, int size) - { - getSubHeader(); - if(size !=static_cast (mCtx.leftSub)) - fail("getHExact() size mismatch"); - getExact(p,size); - } + void getHExact(void*p, int size); // Read the given number of bytes from a named subrecord - void getHNExact(void*p, int size, const char* name) - { - getSubNameIs(name); - getHExact(p,size); - } + void getHNExact(void*p, int size, const char* name); /************************************************************************* * @@ -406,100 +268,37 @@ public: *************************************************************************/ // Get the next subrecord name and check if it matches the parameter - void getSubNameIs(const char* name) - { - getSubName(); - if(mCtx.subName != name) - fail("Expected subrecord " + std::string(name) + " but got " + mCtx.subName.toString()); - } + void getSubNameIs(const char* name); /** Checks if the next sub record name matches the parameter. If it does, it is read into 'subName' just as if getSubName() was called. If not, the read name will still be available for future calls to getSubName(), isNextSub() and getSubNameIs(). */ - bool isNextSub(const char* name) - { - if(!mCtx.leftRec) return false; - - getSubName(); - - // If the name didn't match, then mark the it as 'cached' so it's - // available for the next call to getSubName. - mCtx.subCached = (mCtx.subName != name); - - // If subCached is false, then subName == name. - return !mCtx.subCached; - } + bool isNextSub(const char* name); // Read subrecord name. This gets called a LOT, so I've optimized it // slightly. - void getSubName() - { - // If the name has already been read, do nothing - if(mCtx.subCached) - { - mCtx.subCached = false; - return; - } - - // Don't bother with error checking, we will catch an EOF upon - // reading the subrecord data anyway. - mEsm->read(mCtx.subName.name, 4); - mCtx.leftRec -= 4; - } + void getSubName(); // This is specially optimized for LoadINFO. - bool isEmptyOrGetName() - { - if(mCtx.leftRec) - { - mEsm->read(mCtx.subName.name, 4); - mCtx.leftRec -= 4; - return false; - } - return true; - } + bool isEmptyOrGetName(); // Skip current sub record, including header (but not including // name.) - void skipHSub() - { - getSubHeader(); - skip(mCtx.leftSub); - } + void skipHSub(); // Skip sub record and check its size - void skipHSubSize(int size) - { - skipHSub(); - if(static_cast (mCtx.leftSub) != size) - fail("skipHSubSize() mismatch"); - } + void skipHSubSize(int size); /* Sub-record header. This updates leftRec beyond the current sub-record as well. leftSub contains size of current sub-record. */ - void getSubHeader() - { - if(mCtx.leftRec < 4) - fail("End of record while reading sub-record header"); - - // Get subrecord size - getT(mCtx.leftSub); - - // Adjust number of record bytes left - mCtx.leftRec -= mCtx.leftSub + 4; - } + void getSubHeader(); /** Get sub header and check the size */ - void getSubHeaderIs(int size) - { - getSubHeader(); - if(size != static_cast (mCtx.leftSub)) - fail("getSubHeaderIs(): Sub header mismatch"); - } + void getSubHeaderIs(int size); /************************************************************************* * @@ -508,62 +307,21 @@ public: *************************************************************************/ // Get the next record name - NAME getRecName() - { - if(!hasMoreRecs()) - fail("No more records, getRecName() failed"); - getName(mCtx.recName); - mCtx.leftFile -= 4; - - // Make sure we don't carry over any old cached subrecord - // names. This can happen in some cases when we skip parts of a - // record. - mCtx.subCached = false; - - return mCtx.recName; - } + NAME getRecName(); // Skip the rest of this record. Assumes the name and header have // already been read - void skipRecord() - { - skip(mCtx.leftRec); - mCtx.leftRec = 0; - } + void skipRecord(); // Skip an entire record, including the header (but not the name) - void skipHRecord() - { - if(!mCtx.leftFile) return; - getRecHeader(); - skipRecord(); - } + void skipHRecord(); /* Read record header. This updatesleftFile BEYOND the data that follows the header, ie beyond the entire record. You should use leftRec to orient yourself inside the record itself. */ void getRecHeader() { uint32_t u; getRecHeader(u); } - void getRecHeader(uint32_t &flags) - { - // General error checking - if(mCtx.leftFile < 12) - fail("End of file while reading record header"); - if(mCtx.leftRec) - fail("Previous record contains unread bytes"); - - getUint(mCtx.leftRec); - getUint(flags);// This header entry is always zero - getUint(flags); - mCtx.leftFile -= 12; - - // Check that sizes add up - if(mCtx.leftFile < mCtx.leftRec) - fail("Record size is larger than rest of file"); - - // Adjust number of bytes mCtx.left in file - mCtx.leftFile -= mCtx.leftRec; - } + void getRecHeader(uint32_t &flags); bool hasMoreRecs() { return mCtx.leftFile > 0; } bool hasMoreSubs() { return mCtx.leftRec > 0; } @@ -578,44 +336,19 @@ public: template void getT(X &x) { getExact(&x, sizeof(X)); } - void getExact(void*x, int size) - { - int t = mEsm->read(x, size); - if(t != size) - fail("Read error"); - } + void getExact(void*x, int size); void getName(NAME &name) { getT(name); } void getUint(uint32_t &u) { getT(u); } // Read the next 'size' bytes and return them as a string. Converts // them from native encoding to UTF8 in the process. - std::string getString(int size) - { - char *ptr = ToUTF8::getBuffer(size); - mEsm->read(ptr,size); - - // Convert to UTF8 and return - return ToUTF8::getUtf8(ToUTF8::WINDOWS_1252); - } + std::string getString(int size); void skip(int bytes) { mEsm->seek(mEsm->tell()+bytes); } uint64_t getOffset() { return mEsm->tell(); } /// Used for error handling - void fail(const std::string &msg) - { - using namespace std; - - stringstream ss; - - ss << "ESM Error: " << msg; - ss << "\n File: " << mCtx.filename; - ss << "\n Record: " << mCtx.recName.toString(); - ss << "\n Subrecord: " << mCtx.subName.toString(); - if(mEsm != NULL) - ss << "\n Offset: 0x" << hex << mEsm->tell(); - throw std::runtime_error(ss.str()); - } + void fail(const std::string &msg); private: Mangle::Stream::StreamPtr mEsm; diff --git a/components/esm/loadacti.cpp b/components/esm/loadacti.cpp new file mode 100644 index 000000000..40c9b635c --- /dev/null +++ b/components/esm/loadacti.cpp @@ -0,0 +1,11 @@ +#include "loadacti.hpp" + +namespace ESM +{ +void Activator::load(ESMReader &esm) +{ + model = esm.getHNString("MODL"); + name = esm.getHNString("FNAM"); + script = esm.getHNOString("SCRI"); +} +} diff --git a/components/esm/loadacti.hpp b/components/esm/loadacti.hpp index a50a58f6d..783559e11 100644 --- a/components/esm/loadacti.hpp +++ b/components/esm/loadacti.hpp @@ -3,18 +3,14 @@ #include "esm_reader.hpp" -namespace ESM { +namespace ESM +{ struct Activator { - std::string name, script, model; + std::string name, script, model; - void load(ESMReader &esm) - { - model = esm.getHNString("MODL"); - name = esm.getHNString("FNAM"); - script = esm.getHNOString("SCRI"); - } + void load(ESMReader &esm); }; } #endif diff --git a/components/esm/loadalch.cpp b/components/esm/loadalch.cpp new file mode 100644 index 000000000..d3bc36a77 --- /dev/null +++ b/components/esm/loadalch.cpp @@ -0,0 +1,14 @@ +#include "loadalch.hpp" + +namespace ESM +{ +void Potion::load(ESMReader &esm) +{ + model = esm.getHNString("MODL"); + icon = esm.getHNOString("TEXT"); // not ITEX here for some reason + script = esm.getHNOString("SCRI"); + name = esm.getHNOString("FNAM"); + esm.getHNT(data, "ALDT", 12); + effects.load(esm); +} +} diff --git a/components/esm/loadalch.hpp b/components/esm/loadalch.hpp index a556350b0..c21e5dea0 100644 --- a/components/esm/loadalch.hpp +++ b/components/esm/loadalch.hpp @@ -4,7 +4,8 @@ #include "esm_reader.hpp" #include "defs.hpp" -namespace ESM { +namespace ESM +{ /* * Alchemy item (potions) @@ -12,26 +13,18 @@ namespace ESM { struct Potion { - struct ALDTstruct - { - float weight; - int value; - int autoCalc; - }; - ALDTstruct data; + struct ALDTstruct + { + float weight; + int value; + int autoCalc; + }; + ALDTstruct data; - std::string name, model, icon, script; - EffectList effects; + std::string name, model, icon, script; + EffectList effects; - void load(ESMReader &esm) - { - model = esm.getHNString("MODL"); - icon = esm.getHNOString("TEXT"); // not ITEX here for some reason - script = esm.getHNOString("SCRI"); - name = esm.getHNOString("FNAM"); - esm.getHNT(data, "ALDT", 12); - effects.load(esm); - } + void load(ESMReader &esm); }; } #endif diff --git a/components/esm/loadappa.cpp b/components/esm/loadappa.cpp new file mode 100644 index 000000000..c76ad5350 --- /dev/null +++ b/components/esm/loadappa.cpp @@ -0,0 +1,13 @@ +#include "loadappa.hpp" + +namespace ESM +{ +void Apparatus::load(ESMReader &esm) +{ + model = esm.getHNString("MODL"); + name = esm.getHNString("FNAM"); + esm.getHNT(data, "AADT", 16); + script = esm.getHNOString("SCRI"); + icon = esm.getHNString("ITEX"); +} +} diff --git a/components/esm/loadappa.hpp b/components/esm/loadappa.hpp index 6fd1d00d8..bbb4aefde 100644 --- a/components/esm/loadappa.hpp +++ b/components/esm/loadappa.hpp @@ -3,7 +3,8 @@ #include "esm_reader.hpp" -namespace ESM { +namespace ESM +{ /* * Alchemist apparatus @@ -11,33 +12,23 @@ namespace ESM { struct Apparatus { - enum AppaType + enum AppaType { - MortarPestle = 0, - Albemic = 1, - Calcinator = 2, - Retort = 3 + MortarPestle = 0, Albemic = 1, Calcinator = 2, Retort = 3 }; - struct AADTstruct - { - int type; - float quality; - float weight; - int value; - }; + struct AADTstruct + { + int type; + float quality; + float weight; + int value; + }; - AADTstruct data; - std::string model, icon, script, name; + AADTstruct data; + std::string model, icon, script, name; - void load(ESMReader &esm) - { - model = esm.getHNString("MODL"); - name = esm.getHNString("FNAM"); - esm.getHNT(data, "AADT", 16); - script = esm.getHNOString("SCRI"); - icon = esm.getHNString("ITEX"); - } + void load(ESMReader &esm); }; } #endif diff --git a/components/esm/loadarmo.cpp b/components/esm/loadarmo.cpp new file mode 100644 index 000000000..ddc25e176 --- /dev/null +++ b/components/esm/loadarmo.cpp @@ -0,0 +1,28 @@ +#include "loadarmo.hpp" + +namespace ESM +{ + +void PartReferenceList::load(ESMReader &esm) +{ + while (esm.isNextSub("INDX")) + { + PartReference pr; + esm.getHT(pr.part); // The INDX byte + pr.male = esm.getHNOString("BNAM"); + pr.female = esm.getHNOString("CNAM"); + } +} + +void Armor::load(ESMReader &esm) +{ + model = esm.getHNString("MODL"); + name = esm.getHNString("FNAM"); + script = esm.getHNOString("SCRI"); + esm.getHNT(data, "AODT", 24); + icon = esm.getHNOString("ITEX"); + parts.load(esm); + enchant = esm.getHNOString("ENAM"); +} + +} diff --git a/components/esm/loadarmo.hpp b/components/esm/loadarmo.hpp index c10287869..16b6b1d3a 100644 --- a/components/esm/loadarmo.hpp +++ b/components/esm/loadarmo.hpp @@ -3,102 +3,85 @@ #include "esm_reader.hpp" -namespace ESM { +namespace ESM +{ enum PartReferenceType - { - PRT_Head = 0, - PRT_Hair = 1, - PRT_Neck = 2, - PRT_Cuirass = 3, - PRT_Groin = 4, - PRT_Skirt = 5, - PRT_RHand = 6, - PRT_LHand = 7, - PRT_RWrist = 8, - PRT_LWrist = 9, - PRT_Shield = 10, - PRT_RForearm = 11, - PRT_LForearm = 12, - PRT_RUpperarm = 13, - PRT_LUpperarm = 14, - PRT_RFoot = 15, - PRT_LFoot = 16, - PRT_RAnkle = 17, - PRT_LAnkle = 18, - PRT_RKnee = 19, - PRT_LKnee = 20, - PRT_RLeg = 21, - PRT_LLeg = 22, - PRT_RPauldron = 23, - PRT_LPauldron = 24, - PRT_Weapon = 25, - PRT_Tail = 26 - }; +{ + PRT_Head = 0, + PRT_Hair = 1, + PRT_Neck = 2, + PRT_Cuirass = 3, + PRT_Groin = 4, + PRT_Skirt = 5, + PRT_RHand = 6, + PRT_LHand = 7, + PRT_RWrist = 8, + PRT_LWrist = 9, + PRT_Shield = 10, + PRT_RForearm = 11, + PRT_LForearm = 12, + PRT_RUpperarm = 13, + PRT_LUpperarm = 14, + PRT_RFoot = 15, + PRT_LFoot = 16, + PRT_RAnkle = 17, + PRT_LAnkle = 18, + PRT_RKnee = 19, + PRT_LKnee = 20, + PRT_RLeg = 21, + PRT_LLeg = 22, + PRT_RPauldron = 23, + PRT_LPauldron = 24, + PRT_Weapon = 25, + PRT_Tail = 26 +}; // Reference to body parts struct PartReference { - char part; - std::string male, female; + char part; + std::string male, female; }; // A list of references to body parts struct PartReferenceList { - std::vector parts; + std::vector parts; - void load(ESMReader &esm) - { - while(esm.isNextSub("INDX")) - { - PartReference pr; - esm.getHT(pr.part); // The INDX byte - pr.male = esm.getHNOString("BNAM"); - pr.female = esm.getHNOString("CNAM"); - } - } + void load(ESMReader &esm); }; struct Armor { - enum Type - { - Helmet = 0, - Cuirass = 1, - LPauldron = 2, - RPauldron = 3, - Greaves = 4, - Boots = 5, - LGauntlet = 6, - RGauntlet = 7, - Shield = 8, - LBracer = 9, - RBracer = 10 - }; + enum Type + { + Helmet = 0, + Cuirass = 1, + LPauldron = 2, + RPauldron = 3, + Greaves = 4, + Boots = 5, + LGauntlet = 6, + RGauntlet = 7, + Shield = 8, + LBracer = 9, + RBracer = 10 + }; - struct AODTstruct - { - int type; - float weight; - int value, health, enchant, armor; - }; + struct AODTstruct + { + int type; + float weight; + int value, health, enchant, armor; + }; - AODTstruct data; - PartReferenceList parts; + AODTstruct data; + PartReferenceList parts; - std::string name, model, icon, script, enchant; + std::string name, model, icon, script, enchant; - void load(ESMReader &esm) - { - model = esm.getHNString("MODL"); - name = esm.getHNString("FNAM"); - script = esm.getHNOString("SCRI"); - esm.getHNT(data, "AODT", 24); - icon = esm.getHNOString("ITEX"); - parts.load(esm); - enchant = esm.getHNOString("ENAM"); - } + void load(ESMReader &esm); }; } #endif diff --git a/components/esm/loadbody.cpp b/components/esm/loadbody.cpp new file mode 100644 index 000000000..1c72b0fe0 --- /dev/null +++ b/components/esm/loadbody.cpp @@ -0,0 +1,13 @@ +#include "loadbody.hpp" + +namespace ESM +{ + +void BodyPart::load(ESMReader &esm) +{ + model = esm.getHNString("MODL"); + name = esm.getHNString("FNAM"); + esm.getHNT(data, "BYDT", 4); +} + +} diff --git a/components/esm/loadbody.hpp b/components/esm/loadbody.hpp index 5da0e6acb..14e28f59c 100644 --- a/components/esm/loadbody.hpp +++ b/components/esm/loadbody.hpp @@ -3,59 +3,52 @@ #include "esm_reader.hpp" -namespace ESM { +namespace ESM +{ struct BodyPart { - enum MeshPart + enum MeshPart { - MP_Head = 0, - MP_Hair = 1, - MP_Neck = 2, - MP_Chest = 3, - MP_Groin = 4, - MP_Hand = 5, - MP_Wrist = 6, - MP_Forearm = 7, - MP_Upperarm = 8, - MP_Foot = 9, - MP_Ankle = 10, - MP_Knee = 11, - MP_Upperleg = 12, - MP_Clavicle = 13, - MP_Tail = 14 + MP_Head = 0, + MP_Hair = 1, + MP_Neck = 2, + MP_Chest = 3, + MP_Groin = 4, + MP_Hand = 5, + MP_Wrist = 6, + MP_Forearm = 7, + MP_Upperarm = 8, + MP_Foot = 9, + MP_Ankle = 10, + MP_Knee = 11, + MP_Upperleg = 12, + MP_Clavicle = 13, + MP_Tail = 14 }; - enum Flags + enum Flags { - BPF_Female = 1, - BPF_Playable = 2 + BPF_Female = 1, BPF_Playable = 2 }; - enum MeshType + enum MeshType { - MT_Skin = 0, - MT_Clothing = 1, - MT_Armor = 2 + MT_Skin = 0, MT_Clothing = 1, MT_Armor = 2 }; - struct BYDTstruct - { - char part; - char vampire; - char flags; - char type; - }; + struct BYDTstruct + { + char part; + char vampire; + char flags; + char type; + }; - BYDTstruct data; - std::string model, name; + BYDTstruct data; + std::string model, name; - void load(ESMReader &esm) - { - model = esm.getHNString("MODL"); - name = esm.getHNString("FNAM"); - esm.getHNT(data, "BYDT", 4); - } + void load(ESMReader &esm); }; } #endif diff --git a/components/esm/loadbook.cpp b/components/esm/loadbook.cpp new file mode 100644 index 000000000..ffa958e14 --- /dev/null +++ b/components/esm/loadbook.cpp @@ -0,0 +1,17 @@ +#include "loadbook.hpp" + +namespace ESM +{ + +void Book::load(ESMReader &esm) +{ + model = esm.getHNString("MODL"); + name = esm.getHNOString("FNAM"); + esm.getHNT(data, "BKDT", 20); + script = esm.getHNOString("SCRI"); + icon = esm.getHNOString("ITEX"); + text = esm.getHNOString("TEXT"); + enchant = esm.getHNOString("ENAM"); +} + +} diff --git a/components/esm/loadbook.hpp b/components/esm/loadbook.hpp index 8e9da0d51..3a4ab441e 100644 --- a/components/esm/loadbook.hpp +++ b/components/esm/loadbook.hpp @@ -3,7 +3,8 @@ #include "esm_reader.hpp" -namespace ESM { +namespace ESM +{ /* * Books, magic scrolls, notes and so on @@ -11,25 +12,16 @@ namespace ESM { struct Book { - struct BKDTstruct - { - float weight; - int value, isScroll, skillID, enchant; - }; + struct BKDTstruct + { + float weight; + int value, isScroll, skillID, enchant; + }; - BKDTstruct data; - std::string name, model, icon, script, enchant, text; + BKDTstruct data; + std::string name, model, icon, script, enchant, text; - void load(ESMReader &esm) - { - model = esm.getHNString("MODL"); - name = esm.getHNOString("FNAM"); - esm.getHNT(data, "BKDT", 20); - script = esm.getHNOString("SCRI"); - icon = esm.getHNOString("ITEX"); - text = esm.getHNOString("TEXT"); - enchant = esm.getHNOString("ENAM"); - } + void load(ESMReader &esm); }; } #endif diff --git a/components/esm/loadbsgn.cpp b/components/esm/loadbsgn.cpp new file mode 100644 index 000000000..976cb7d20 --- /dev/null +++ b/components/esm/loadbsgn.cpp @@ -0,0 +1,15 @@ +#include "loadbsgn.hpp" + +namespace ESM +{ + +void BirthSign::load(ESMReader &esm) +{ + name = esm.getHNString("FNAM"); + texture = esm.getHNOString("TNAM"); + description = esm.getHNOString("DESC"); + + powers.load(esm); +} + +} diff --git a/components/esm/loadbsgn.hpp b/components/esm/loadbsgn.hpp index 8c713e5ef..53964b02c 100644 --- a/components/esm/loadbsgn.hpp +++ b/components/esm/loadbsgn.hpp @@ -4,23 +4,17 @@ #include "defs.hpp" #include "esm_reader.hpp" -namespace ESM { +namespace ESM +{ struct BirthSign { - std::string name, description, texture; + std::string name, description, texture; - // List of powers and abilities that come with this birth sign. - SpellList powers; + // List of powers and abilities that come with this birth sign. + SpellList powers; - void load(ESMReader &esm) - { - name = esm.getHNString("FNAM"); - texture = esm.getHNOString("TNAM"); - description = esm.getHNOString("DESC"); - - powers.load(esm); - }; + void load(ESMReader &esm); }; } #endif diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp new file mode 100644 index 000000000..2d1085260 --- /dev/null +++ b/components/esm/loadcell.cpp @@ -0,0 +1,113 @@ +#include "loadcell.hpp" + +namespace ESM +{ + +void Cell::load(ESMReader &esm) +{ + // Ignore this for now, it might mean we should delete the entire + // cell? + if (esm.isNextSub("DELE")) + esm.skipHSub(); + + esm.getHNT(data, "DATA", 12); + + // Water level + water = 0; + + if (data.flags & Interior) + { + // Interior cells + + if (esm.isNextSub("INTV") || esm.isNextSub("WHGT")) + esm.getHT(water); + + // Quasi-exterior cells have a region (which determines the + // weather), pure interior cells have ambient lighting + // instead. + if (data.flags & QuasiEx) + region = esm.getHNOString("RGNN"); + else + esm.getHNT(ambi, "AMBI", 16); + } + else + { + // Exterior cells + region = esm.getHNOString("RGNN"); + esm.getHNOT(mapColor, "NAM5"); + } + + // Save position of the cell references and move on + context = esm.getContext(); + esm.skipRecord(); +} + +void Cell::restore(ESMReader &esm) const +{ + esm.restoreContext(context); +} + +bool Cell::getNextRef(ESMReader &esm, CellRef &ref) +{ + if (!esm.hasMoreSubs()) + return false; + + // Number of references in the cell? Maximum once in each cell, + // but not always at the beginning, and not always right. In other + // words, completely useless. + { + int i; + esm.getHNOT(i, "NAM0"); + } + + esm.getHNT(ref.refnum, "FRMR"); + ref.refID = esm.getHNString("NAME"); + + // getHNOT will not change the existing value if the subrecord is + // missing + ref.scale = 1.0; + esm.getHNOT(ref.scale, "XSCL"); + + ref.owner = esm.getHNOString("ANAM"); + ref.glob = esm.getHNOString("BNAM"); + ref.soul = esm.getHNOString("XSOL"); + + ref.faction = esm.getHNOString("CNAM"); + ref.factIndex = -1; + esm.getHNOT(ref.factIndex, "INDX"); + + ref.charge = -1.0; + esm.getHNOT(ref.charge, "XCHG"); + + ref.intv = 0; + ref.nam9 = 0; + esm.getHNOT(ref.intv, "INTV"); + esm.getHNOT(ref.nam9, "NAM9"); + + // Present for doors that teleport you to another cell. + if (esm.isNextSub("DODT")) + { + ref.teleport = true; + esm.getHT(ref.doorDest); + ref.destCell = esm.getHNOString("DNAM"); + } + else + ref.teleport = false; + + // Integer, despite the name suggesting otherwise + ref.lockLevel = 0; + esm.getHNOT(ref.lockLevel, "FLTV"); + ref.key = esm.getHNOString("KNAM"); + ref.trap = esm.getHNOString("TNAM"); + + ref.unam = 0; + ref.fltv = 0; + esm.getHNOT(ref.unam, "UNAM"); + esm.getHNOT(ref.fltv, "FLTV"); + + esm.getHNT(ref.pos, "DATA", 24); + + return true; +} + +} diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index 3f2a6b5a2..bf3ec6f73 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -117,51 +117,14 @@ struct Cell int water; // Water level int mapColor; - void load(ESMReader &esm) - { - // Ignore this for now, it might mean we should delete the entire - // cell? - if(esm.isNextSub("DELE")) esm.skipHSub(); - - esm.getHNT(data, "DATA", 12); - - // Water level - water = 0; - - if(data.flags & Interior) - { - // Interior cells - - if(esm.isNextSub("INTV") || esm.isNextSub("WHGT")) - esm.getHT(water); - - // Quasi-exterior cells have a region (which determines the - // weather), pure interior cells have ambient lighting - // instead. - if(data.flags & QuasiEx) - region = esm.getHNOString("RGNN"); - else - esm.getHNT(ambi, "AMBI", 16); - } - else - { - // Exterior cells - region = esm.getHNOString("RGNN"); - esm.getHNOT(mapColor, "NAM5"); - } - - // Save position of the cell references and move on - context = esm.getContext(); - esm.skipRecord(); - } + void load(ESMReader &esm); // Restore the given reader to the stored position. Will try to open // the file matching the stored file name. If you want to read from // somewhere other than the file system, you need to pre-open the // ESMReader, and the filename must match the stored filename // exactly. - void restore(ESMReader &esm) const - { esm.restoreContext(context); } + void restore(ESMReader &esm) const; /* Get the next reference in this cell, if any. Returns false when there are no more references in the cell. @@ -169,66 +132,7 @@ struct Cell All fields of the CellRef struct are overwritten. You can safely reuse one memory location without blanking it between calls. */ - static bool getNextRef(ESMReader &esm, CellRef &ref) - { - if(!esm.hasMoreSubs()) return false; - - // Number of references in the cell? Maximum once in each cell, - // but not always at the beginning, and not always right. In other - // words, completely useless. - { - int i; - esm.getHNOT(i, "NAM0"); - } - - esm.getHNT(ref.refnum, "FRMR"); - ref.refID = esm.getHNString("NAME"); - - // getHNOT will not change the existing value if the subrecord is - // missing - ref.scale = 1.0; - esm.getHNOT(ref.scale, "XSCL"); - - ref.owner = esm.getHNOString("ANAM"); - ref.glob = esm.getHNOString("BNAM"); - ref.soul = esm.getHNOString("XSOL"); - - ref.faction = esm.getHNOString("CNAM"); - ref.factIndex = -1; - esm.getHNOT(ref.factIndex, "INDX"); - - ref.charge = -1.0; - esm.getHNOT(ref.charge, "XCHG"); - - ref.intv = 0; - ref.nam9 = 0; - esm.getHNOT(ref.intv, "INTV"); - esm.getHNOT(ref.nam9, "NAM9"); - - // Present for doors that teleport you to another cell. - if(esm.isNextSub("DODT")) - { - ref.teleport = true; - esm.getHT(ref.doorDest); - ref.destCell = esm.getHNOString("DNAM"); - } - else ref.teleport = false; - - // Integer, despite the name suggesting otherwise - ref.lockLevel = 0; - esm.getHNOT(ref.lockLevel, "FLTV"); - ref.key = esm.getHNOString("KNAM"); - ref.trap = esm.getHNOString("TNAM"); - - ref.unam = 0; - ref.fltv = 0; - esm.getHNOT(ref.unam, "UNAM"); - esm.getHNOT(ref.fltv, "FLTV"); - - esm.getHNT(ref.pos, "DATA", 24); - - return true; - } + static bool getNextRef(ESMReader &esm, CellRef &ref); }; } #endif diff --git a/components/esm/loadclas.cpp b/components/esm/loadclas.cpp new file mode 100644 index 000000000..9a0b847ab --- /dev/null +++ b/components/esm/loadclas.cpp @@ -0,0 +1,17 @@ +#include "loadclas.hpp" + +namespace ESM +{ + +void Class::load(ESMReader &esm) +{ + name = esm.getHNString("FNAM"); + esm.getHNT(data, "CLDT", 60); + + if (data.isPlayable > 1) + esm.fail("Unknown bool value"); + + description = esm.getHNOString("DESC"); +} + +} diff --git a/components/esm/loadclas.hpp b/components/esm/loadclas.hpp index 999fdfffd..5fc44abe5 100644 --- a/components/esm/loadclas.hpp +++ b/components/esm/loadclas.hpp @@ -3,7 +3,8 @@ #include "esm_reader.hpp" -namespace ESM { +namespace ESM +{ /* * Character class definitions @@ -13,62 +14,51 @@ namespace ESM { // class struct Class { - enum AutoCalc + enum AutoCalc { - Weapon = 0x00001, - Armor = 0x00002, - Clothing = 0x00004, - Books = 0x00008, - Ingredient = 0x00010, - Lockpick = 0x00020, - Probe = 0x00040, - Lights = 0x00080, - Apparatus = 0x00100, - Repair = 0x00200, - Misc = 0x00400, - Spells = 0x00800, - MagicItems = 0x01000, - Potions = 0x02000, - Training = 0x04000, - Spellmaking = 0x08000, - Enchanting = 0x10000, - RepairItem = 0x20000 + Weapon = 0x00001, + Armor = 0x00002, + Clothing = 0x00004, + Books = 0x00008, + Ingredient = 0x00010, + Lockpick = 0x00020, + Probe = 0x00040, + Lights = 0x00080, + Apparatus = 0x00100, + Repair = 0x00200, + Misc = 0x00400, + Spells = 0x00800, + MagicItems = 0x01000, + Potions = 0x02000, + Training = 0x04000, + Spellmaking = 0x08000, + Enchanting = 0x10000, + RepairItem = 0x20000 }; - enum Specialization + enum Specialization { - Combat = 0, - Magic = 1, - Stealth = 2 + Combat = 0, Magic = 1, Stealth = 2 }; - static const Specialization specializationIds[3]; - static const char *gmstSpecializationIds[3]; + static const Specialization specializationIds[3]; + static const char *gmstSpecializationIds[3]; - struct CLDTstruct - { - int attribute[2]; // Attributes that get class bonus - int specialization; // 0 = Combat, 1 = Magic, 2 = Stealth - int skills[5][2]; // Minor and major skills. - int isPlayable; // 0x0001 - Playable class - - // I have no idea how to autocalculate these items... - int calc; - }; // 60 bytes - - std::string name, description; - CLDTstruct data; - - void load(ESMReader &esm) + struct CLDTstruct { - name = esm.getHNString("FNAM"); - esm.getHNT(data, "CLDT", 60); + int attribute[2]; // Attributes that get class bonus + int specialization; // 0 = Combat, 1 = Magic, 2 = Stealth + int skills[5][2]; // Minor and major skills. + int isPlayable; // 0x0001 - Playable class - if(data.isPlayable > 1) - esm.fail("Unknown bool value"); + // I have no idea how to autocalculate these items... + int calc; + }; // 60 bytes - description = esm.getHNOString("DESC"); - } + std::string name, description; + CLDTstruct data; + + void load(ESMReader &esm); }; } #endif diff --git a/components/esm/loadclot.cpp b/components/esm/loadclot.cpp new file mode 100644 index 000000000..1d6c9d4a1 --- /dev/null +++ b/components/esm/loadclot.cpp @@ -0,0 +1,20 @@ +#include "loadclot.hpp" + +namespace ESM +{ + +void Clothing::load(ESMReader &esm) +{ + model = esm.getHNString("MODL"); + name = esm.getHNOString("FNAM"); + esm.getHNT(data, "CTDT", 12); + + script = esm.getHNOString("SCRI"); + icon = esm.getHNOString("ITEX"); + + parts.load(esm); + + enchant = esm.getHNOString("ENAM"); +} + +} diff --git a/components/esm/loadclot.hpp b/components/esm/loadclot.hpp index 47b24ddb1..8fa06e7e4 100644 --- a/components/esm/loadclot.hpp +++ b/components/esm/loadclot.hpp @@ -4,7 +4,8 @@ #include "esm_reader.hpp" #include "loadarmo.hpp" -namespace ESM { +namespace ESM +{ /* * Clothing @@ -12,46 +13,34 @@ namespace ESM { struct Clothing { - enum Type + enum Type { - Pants = 0, - Shoes = 1, - Shirt = 2, - Belt = 3, - Robe = 4, - RGlove = 5, - LGlove = 6, - Skirt = 7, - Ring = 8, - Amulet = 9 + Pants = 0, + Shoes = 1, + Shirt = 2, + Belt = 3, + Robe = 4, + RGlove = 5, + LGlove = 6, + Skirt = 7, + Ring = 8, + Amulet = 9 }; - struct CTDTstruct - { - int type; - float weight; - short value; - short enchant; - }; - CTDTstruct data; + struct CTDTstruct + { + int type; + float weight; + short value; + short enchant; + }; + CTDTstruct data; - PartReferenceList parts; + PartReferenceList parts; - std::string name, model, icon, enchant, script; + std::string name, model, icon, enchant, script; - void load(ESMReader &esm) - { - model = esm.getHNString("MODL"); - name = esm.getHNOString("FNAM"); - esm.getHNT(data, "CTDT", 12); - - script = esm.getHNOString("SCRI"); - icon = esm.getHNOString("ITEX"); - - parts.load(esm); - - enchant = esm.getHNOString("ENAM"); - } + void load(ESMReader &esm); }; } #endif diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp new file mode 100644 index 000000000..740d15a40 --- /dev/null +++ b/components/esm/loadland.cpp @@ -0,0 +1,32 @@ +#include "loadland.hpp" + +namespace ESM +{ +void Land::load(ESMReader &esm) +{ + // Get the grid location + esm.getSubNameIs("INTV"); + esm.getSubHeaderIs(8); + esm.getT(X); + esm.getT(Y); + + esm.getHNT(flags, "DATA"); + + // Store the file position + context = esm.getContext(); + + hasData = false; + int cnt = 0; + + // Skip these here. Load the actual data when the cell is loaded. + if(esm.isNextSub("VNML")) {esm.skipHSubSize(12675);cnt++;} + if(esm.isNextSub("VHGT")) {esm.skipHSubSize(4232);cnt++;} + if(esm.isNextSub("WNAM")) esm.skipHSubSize(81); + if(esm.isNextSub("VCLR")) esm.skipHSubSize(12675); + if(esm.isNextSub("VTEX")) {esm.skipHSubSize(512);cnt++;} + + // We need all three of VNML, VHGT and VTEX in order to use the + // landscape. + hasData = (cnt == 3); +} +} diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index d1a9e4068..af91850ac 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -3,51 +3,25 @@ #include "esm_reader.hpp" -namespace ESM { - +namespace ESM +{ /* * Landscape data. */ struct Land { - int flags; // Only first four bits seem to be used, don't know what - // they mean. - int X, Y; // Map coordinates. + int flags; // Only first four bits seem to be used, don't know what + // they mean. + int X, Y; // Map coordinates. - // File context. This allows the ESM reader to be 'reset' to this - // location later when we are ready to load the full data set. - ESM_Context context; + // File context. This allows the ESM reader to be 'reset' to this + // location later when we are ready to load the full data set. + ESM_Context context; - bool hasData; + bool hasData; - void load(ESMReader &esm) - { - // Get the grid location - esm.getSubNameIs("INTV"); - esm.getSubHeaderIs(8); - esm.getT(X); - esm.getT(Y); - - esm.getHNT(flags, "DATA"); - - // Store the file position - context = esm.getContext(); - - hasData = false; - int cnt = 0; - - // Skip these here. Load the actual data when the cell is loaded. - if(esm.isNextSub("VNML")) {esm.skipHSubSize(12675);cnt++;} - if(esm.isNextSub("VHGT")) {esm.skipHSubSize(4232);cnt++;} - if(esm.isNextSub("WNAM")) esm.skipHSubSize(81); - if(esm.isNextSub("VCLR")) esm.skipHSubSize(12675); - if(esm.isNextSub("VTEX")) {esm.skipHSubSize(512);cnt++;} - - // We need all three of VNML, VHGT and VTEX in order to use the - // landscape. - hasData = (cnt == 3); - } + void load(ESMReader &esm); }; } #endif From 1e5768170f9a5458310b673b45db3a4c84479096 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Fri, 8 Apr 2011 17:58:21 +0400 Subject: [PATCH 09/41] Refactored remaining headers in components/esm except defs.hpp. Removed obsolete *.cpp files. --- CMakeLists.txt | 31 +++- components/esm/class.cpp | 15 -- components/esm/load_impl.cpp | 175 --------------------- components/esm/loadclas.cpp | 12 ++ components/esm/loadcont.cpp | 33 ++++ components/esm/loadcont.hpp | 50 ++---- components/esm/loadcrea.cpp | 40 +++++ components/esm/loadcrea.hpp | 109 +++++-------- components/esm/loaddial.cpp | 25 +++ components/esm/loaddial.hpp | 39 ++--- components/esm/loaddoor.cpp | 15 ++ components/esm/loaddoor.hpp | 14 +- components/esm/loadench.cpp | 12 ++ components/esm/loadench.hpp | 40 +++-- components/esm/loadfact.cpp | 31 ++++ components/esm/loadfact.hpp | 76 ++++----- components/esm/loadglob.cpp | 24 +++ components/esm/loadglob.hpp | 22 +-- components/esm/loadgmst.cpp | 172 ++++++++++++++++++++ components/esm/loadgmst.hpp | 278 +++++++-------------------------- components/esm/loadinfo.cpp | 133 ++++++++++++++++ components/esm/loadinfo.hpp | 149 +++++++++--------- components/esm/loadingr.cpp | 15 ++ components/esm/loadingr.hpp | 32 ++-- components/esm/loadlevlist.cpp | 34 ++++ components/esm/loadlevlist.hpp | 90 +++++------ components/esm/loadligh.cpp | 17 ++ components/esm/loadligh.hpp | 56 +++---- components/esm/loadlocks.cpp | 30 ++++ components/esm/loadlocks.hpp | 53 ++----- components/esm/loadltex.cpp | 12 ++ components/esm/loadltex.hpp | 13 +- components/esm/loadmgef.cpp | 27 ++++ components/esm/loadmgef.hpp | 85 ++++------ components/esm/loadmisc.cpp | 15 ++ components/esm/loadmisc.hpp | 32 ++-- components/esm/loadnpc.cpp | 48 ++++++ components/esm/loadpgrd.cpp | 35 +++++ components/esm/loadpgrd.hpp | 54 ++----- components/esm/loadrace.cpp | 14 ++ components/esm/loadrace.hpp | 81 +++++----- components/esm/loadregn.cpp | 29 ++++ components/esm/loadregn.hpp | 66 +++----- components/esm/loadscpt.cpp | 42 +++++ components/esm/loadscpt.hpp | 98 ++++-------- components/esm/loadskil.cpp | 93 +++++++---- components/esm/loadskil.hpp | 7 +- components/esm/loadsndg.cpp | 14 ++ components/esm/loadsndg.hpp | 8 +- components/esm/loadsoun.cpp | 18 +++ components/esm/loadsoun.hpp | 12 +- components/esm/loadspel.cpp | 13 ++ components/esm/loadspel.hpp | 51 +++--- components/esm/loadsscr.cpp | 13 ++ components/esm/loadsscr.hpp | 24 ++- components/esm/loadstat.cpp | 11 ++ components/esm/loadstat.hpp | 5 +- components/esm/loadweap.cpp | 16 ++ components/esm/loadweap.hpp | 75 ++++----- components/esm/skill.cpp | 63 -------- 60 files changed, 1571 insertions(+), 1325 deletions(-) delete mode 100644 components/esm/class.cpp delete mode 100644 components/esm/load_impl.cpp create mode 100644 components/esm/loadcont.cpp create mode 100644 components/esm/loadcrea.cpp create mode 100644 components/esm/loaddial.cpp create mode 100644 components/esm/loaddoor.cpp create mode 100644 components/esm/loadench.cpp create mode 100644 components/esm/loadfact.cpp create mode 100644 components/esm/loadglob.cpp create mode 100644 components/esm/loadgmst.cpp create mode 100644 components/esm/loadinfo.cpp create mode 100644 components/esm/loadingr.cpp create mode 100644 components/esm/loadlevlist.cpp create mode 100644 components/esm/loadligh.cpp create mode 100644 components/esm/loadlocks.cpp create mode 100644 components/esm/loadltex.cpp create mode 100644 components/esm/loadmgef.cpp create mode 100644 components/esm/loadmisc.cpp create mode 100644 components/esm/loadnpc.cpp create mode 100644 components/esm/loadpgrd.cpp create mode 100644 components/esm/loadrace.cpp create mode 100644 components/esm/loadregn.cpp create mode 100644 components/esm/loadscpt.cpp create mode 100644 components/esm/loadsndg.cpp create mode 100644 components/esm/loadsoun.cpp create mode 100644 components/esm/loadspel.cpp create mode 100644 components/esm/loadsscr.cpp create mode 100644 components/esm/loadstat.cpp create mode 100644 components/esm/loadweap.cpp delete mode 100644 components/esm/skill.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 9aac8e11f..4f937f01d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -127,10 +127,7 @@ source_group(components\\esm_store FILES ${ESM_STORE} ${ESM_STORE_HEADER}) file(GLOB ESM_HEADER ${COMP_DIR}/esm/*.hpp) set(ESM - ${COMP_DIR}/esm/load_impl.cpp - ${COMP_DIR}/esm/skill.cpp ${COMP_DIR}/esm/attr.cpp - ${COMP_DIR}/esm/class.cpp ${COMP_DIR}/esm/esm_reader.cpp ${COMP_DIR}/esm/loadland.cpp ${COMP_DIR}/esm/loadacti.cpp @@ -143,6 +140,34 @@ set(ESM ${COMP_DIR}/esm/loadcell.cpp ${COMP_DIR}/esm/loadclas.cpp ${COMP_DIR}/esm/loadclot.cpp + ${COMP_DIR}/esm/loadcont.cpp + ${COMP_DIR}/esm/loadcrea.cpp + ${COMP_DIR}/esm/loaddial.cpp + ${COMP_DIR}/esm/loaddoor.cpp + ${COMP_DIR}/esm/loadench.cpp + ${COMP_DIR}/esm/loadfact.cpp + ${COMP_DIR}/esm/loadglob.cpp + ${COMP_DIR}/esm/loadgmst.cpp + ${COMP_DIR}/esm/loadinfo.cpp + ${COMP_DIR}/esm/loadingr.cpp + ${COMP_DIR}/esm/loadlevlist.cpp + ${COMP_DIR}/esm/loadligh.cpp + ${COMP_DIR}/esm/loadlocks.cpp + ${COMP_DIR}/esm/loadltex.cpp + ${COMP_DIR}/esm/loadmgef.cpp + ${COMP_DIR}/esm/loadmisc.cpp + ${COMP_DIR}/esm/loadnpc.cpp + ${COMP_DIR}/esm/loadpgrd.cpp + ${COMP_DIR}/esm/loadrace.cpp + ${COMP_DIR}/esm/loadregn.cpp + ${COMP_DIR}/esm/loadscpt.cpp + ${COMP_DIR}/esm/loadskil.cpp + ${COMP_DIR}/esm/loadsndg.cpp + ${COMP_DIR}/esm/loadsoun.cpp + ${COMP_DIR}/esm/loadspel.cpp + ${COMP_DIR}/esm/loadsscr.cpp + ${COMP_DIR}/esm/loadstat.cpp + ${COMP_DIR}/esm/loadweap.cpp ) source_group(components\\esm FILES ${ESM_HEADER} ${ESM}) diff --git a/components/esm/class.cpp b/components/esm/class.cpp deleted file mode 100644 index 5866205fa..000000000 --- a/components/esm/class.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "loadclas.hpp" - -using namespace ESM; - -const Class::Specialization Class::specializationIds[3] = { - Class::Combat, - Class::Magic, - Class::Stealth -}; - -const char *Class::gmstSpecializationIds[3] = { - "sSpecializationCombat", - "sSpecializationMagic", - "sSpecializationStealth" -}; diff --git a/components/esm/load_impl.cpp b/components/esm/load_impl.cpp deleted file mode 100644 index 28edbbe58..000000000 --- a/components/esm/load_impl.cpp +++ /dev/null @@ -1,175 +0,0 @@ -#include "records.hpp" - -/** Implementation for some of the load() functions. Most are found in - the header files themselves, but this is a bit irritating to - compile if you're changing the functions often, as virtually the - entire engine depends on these headers. - */ - -/* -#include -using namespace std; -*/ - -namespace ESM -{ - void NPC::load(ESMReader &esm, const std::string& id) - { - mId = id; - - npdt52.gold = -10; - - model = esm.getHNOString("MODL"); - name = esm.getHNOString("FNAM"); - - race = esm.getHNString("RNAM"); - cls = esm.getHNString("CNAM"); - faction = esm.getHNString("ANAM"); - head = esm.getHNString("BNAM"); - hair = esm.getHNString("KNAM"); - - script = esm.getHNOString("SCRI"); - - esm.getSubNameIs("NPDT"); - esm.getSubHeader(); - if(esm.getSubSize() == 52) esm.getExact(&npdt52, 52); - else if(esm.getSubSize() == 12) esm.getExact(&npdt12, 12); - else esm.fail("NPC_NPDT must be 12 or 52 bytes long"); - - esm.getHNT(flags, "FLAG"); - - inventory.load(esm); - spells.load(esm); - - if(esm.isNextSub("AIDT")) - { - esm.getHExact(&AI, sizeof(AI)); - hasAI = true; - } - else hasAI = false; - - esm.skipRecord(); - } - - void DialInfo::load(ESMReader &esm) - { - id = esm.getHNString("INAM"); - prev = esm.getHNString("PNAM"); - next = esm.getHNString("NNAM"); - - // Not present if deleted - if(esm.isNextSub("DATA")) - esm.getHT(data, 12); - - // What follows is somewhat spaghetti-ish, but it's worth if for - // an extra speedup. INFO is by far the most common record type. - - // subName is a reference to the original, so it changes whenever - // a new sub name is read. esm.isEmptyOrGetName() will get the - // next name for us, or return true if there are no more records. - esm.getSubName(); - const NAME &subName = esm.retSubName(); - - if(subName.val == REC_ONAM) - { - actor = esm.getHString(); - if(esm.isEmptyOrGetName()) return; - } - if(subName.val == REC_RNAM) - { - race = esm.getHString(); - if(esm.isEmptyOrGetName()) return; - } - if(subName.val == REC_CNAM) - { - clas = esm.getHString(); - if(esm.isEmptyOrGetName()) return; - } - - factionLess = false; - if(subName.val == REC_FNAM) - { - npcFaction = esm.getHString(); - if(npcFaction == "FFFF") factionLess = true; - if(esm.isEmptyOrGetName()) return; - } - if(subName.val == REC_ANAM) - { - cell = esm.getHString(); - if(esm.isEmptyOrGetName()) return; - } - if(subName.val == REC_DNAM) - { - pcFaction = esm.getHString(); - if(esm.isEmptyOrGetName()) return; - } - if(subName.val == REC_SNAM) - { - sound = esm.getHString(); - if(esm.isEmptyOrGetName()) return; - } - if(subName.val == REC_NAME) - { - response = esm.getHString(); - if(esm.isEmptyOrGetName()) return; - } - - while(subName.val == REC_SCVR) - { - SelectStruct ss; - - ss.selectRule = esm.getHString(); - esm.isEmptyOrGetName(); - - if(subName.val == REC_INTV) - { - ss.type = VT_Int; - esm.getHT(ss.i); - } - else if(subName.val == REC_FLTV) - { - ss.type = VT_Float; - esm.getHT(ss.f); - } - else - esm.fail("INFO.SCVR must precede INTV or FLTV, not " - + subName.toString()); - - selects.push_back(ss); - - if(esm.isEmptyOrGetName()) return; - } - - if(subName.val == REC_BNAM) - { - resultScript = esm.getHString(); - if(esm.isEmptyOrGetName()) return; - } - - questStatus = QS_None; - - if (subName.val == REC_QSTN) questStatus = QS_Name; - else if(subName.val == REC_QSTF) questStatus = QS_Finished; - else if(subName.val == REC_QSTR) questStatus = QS_Restart; - else if(subName.val == REC_DELE) questStatus = QS_Deleted; - else - esm.fail("Don't know what to do with " + subName.toString() + " in INFO " + id); - - if(questStatus != QS_None) - // Skip rest of record - esm.skipRecord(); - } - - void Sound::load(ESMReader &esm) - { - sound = esm.getHNString("FNAM"); - esm.getHNT(data, "DATA", 3); - /* - cout << "vol=" << (int)data.volume - << " min=" << (int)data.minRange - << " max=" << (int)data.maxRange - << endl; - */ - } - -} diff --git a/components/esm/loadclas.cpp b/components/esm/loadclas.cpp index 9a0b847ab..b15852cc2 100644 --- a/components/esm/loadclas.cpp +++ b/components/esm/loadclas.cpp @@ -3,6 +3,18 @@ namespace ESM { +const Class::Specialization Class::specializationIds[3] = { + Class::Combat, + Class::Magic, + Class::Stealth +}; + +const char *Class::gmstSpecializationIds[3] = { + "sSpecializationCombat", + "sSpecializationMagic", + "sSpecializationStealth" +}; + void Class::load(ESMReader &esm) { name = esm.getHNString("FNAM"); diff --git a/components/esm/loadcont.cpp b/components/esm/loadcont.cpp new file mode 100644 index 000000000..14699ccc5 --- /dev/null +++ b/components/esm/loadcont.cpp @@ -0,0 +1,33 @@ +#include "loadcont.hpp" + +namespace ESM +{ + +void InventoryList::load(ESMReader &esm) +{ + ContItem ci; + while (esm.isNextSub("NPCO")) + { + esm.getHT(ci, 36); + list.push_back(ci); + } +} + +void Container::load(ESMReader &esm) +{ + model = esm.getHNString("MODL"); + name = esm.getHNOString("FNAM"); + esm.getHNT(weight, "CNDT", 4); + esm.getHNT(flags, "FLAG", 4); + + if (flags & 0xf4) + esm.fail("Unknown flags"); + if (!(flags & 0x8)) + esm.fail("Flag 8 not set"); + + script = esm.getHNOString("SCRI"); + + inventory.load(esm); +} + +} diff --git a/components/esm/loadcont.hpp b/components/esm/loadcont.hpp index 3c7ed8598..4614c4230 100644 --- a/components/esm/loadcont.hpp +++ b/components/esm/loadcont.hpp @@ -3,7 +3,8 @@ #include "esm_reader.hpp" -namespace ESM { +namespace ESM +{ /* * Container definition @@ -11,54 +12,33 @@ namespace ESM { struct ContItem { - int count; - NAME32 item; + int count; + NAME32 item; }; struct InventoryList { - std::vector list; + std::vector list; - void load(ESMReader &esm) - { - ContItem ci; - while(esm.isNextSub("NPCO")) - { - esm.getHT(ci, 36); - list.push_back(ci); - } - } + void load(ESMReader &esm); }; struct Container { - enum Flags + enum Flags { - Organic = 1, // Objects cannot be placed in this container - Respawn = 2, // Respawns after 4 months - Unknown = 8 + Organic = 1, // Objects cannot be placed in this container + Respawn = 2, // Respawns after 4 months + Unknown = 8 }; - std::string name, model, script; + std::string name, model, script; - float weight; // Not sure, might be max total weight allowed? - int flags; - InventoryList inventory; + float weight; // Not sure, might be max total weight allowed? + int flags; + InventoryList inventory; - void load(ESMReader &esm) - { - model = esm.getHNString("MODL"); - name = esm.getHNOString("FNAM"); - esm.getHNT(weight, "CNDT", 4); - esm.getHNT(flags, "FLAG", 4); - - if(flags & 0xf4) esm.fail("Unknown flags"); - if(!(flags & 0x8)) esm.fail("Flag 8 not set"); - - script = esm.getHNOString("SCRI"); - - inventory.load(esm); - } + void load(ESMReader &esm); }; } #endif diff --git a/components/esm/loadcrea.cpp b/components/esm/loadcrea.cpp new file mode 100644 index 000000000..651d9a318 --- /dev/null +++ b/components/esm/loadcrea.cpp @@ -0,0 +1,40 @@ +#include "loadcrea.hpp" + +namespace ESM { + +void Creature::load(ESMReader &esm, const std::string& id) +{ + mId = id; + + model = esm.getHNString("MODL"); + original = esm.getHNOString("CNAM"); + name = esm.getHNOString("FNAM"); + script = esm.getHNOString("SCRI"); + + esm.getHNT(data, "NPDT", 96); + + esm.getHNT(flags, "FLAG"); + scale = 1.0; + esm.getHNOT(scale, "XSCL"); + + inventory.load(esm); + + // More subrecords: + + // AIDT - data (12 bytes, unknown) + // AI_W - wander (14 bytes, i don't understand it) + // short distance + // byte duration + // byte timeOfDay + // byte idle[10] + // + // Rest is optional: + // AI_T - travel? + // AI_F - follow? + // AI_E - escort? + // AI_A - activate? + + esm.skipRecord(); +} + +} diff --git a/components/esm/loadcrea.hpp b/components/esm/loadcrea.hpp index df8578866..40c929213 100644 --- a/components/esm/loadcrea.hpp +++ b/components/esm/loadcrea.hpp @@ -4,7 +4,8 @@ #include "esm_reader.hpp" #include "loadcont.hpp" -namespace ESM { +namespace ESM +{ /* * Creature definition @@ -13,91 +14,53 @@ namespace ESM { struct Creature { - // Default is 0x48? - enum Flags + // Default is 0x48? + enum Flags { - Biped = 0x001, - Respawn = 0x002, - Weapon = 0x004, // Has weapon and shield - None = 0x008, // ?? - Swims = 0x010, - Flies = 0x020, // Don't know what happens if several - Walks = 0x040, // of these are set - Essential = 0x080, - Skeleton = 0x400, // Does not have normal blood - Metal = 0x800 // Has 'golden' blood + Biped = 0x001, Respawn = 0x002, Weapon = 0x004, // Has weapon and shield + None = 0x008, // ?? + Swims = 0x010, + Flies = 0x020, // Don't know what happens if several + Walks = 0x040, // of these are set + Essential = 0x080, + Skeleton = 0x400, // Does not have normal blood + Metal = 0x800 + // Has 'golden' blood }; - enum Type + enum Type { - Creatures = 0, - Deadra = 1, - Undead = 2, - Humanoid = 3 + Creatures = 0, Deadra = 1, Undead = 2, Humanoid = 3 }; - struct NPDTstruct - { - int type; - // For creatures we obviously have to use ints, not shorts and - // bytes like we use for NPCs.... this file format just makes so - // much sense! (Still, _much_ easier to decode than the NIFs.) - int level; - int strength, intelligence, willpower, agility, speed, endurance, - personality, luck, health, mana, fatigue; // Stats - int soul; // The creatures soul value (used with soul gems.) - int combat, magic, stealth; // Don't know yet. - int attack[6]; // AttackMin1, AttackMax1, ditto2, ditto3 - int gold; - }; // 96 bytes + struct NPDTstruct + { + int type; + // For creatures we obviously have to use ints, not shorts and + // bytes like we use for NPCs.... this file format just makes so + // much sense! (Still, _much_ easier to decode than the NIFs.) + int level; + int strength, intelligence, willpower, agility, speed, endurance, + personality, luck, health, mana, fatigue; // Stats + int soul; // The creatures soul value (used with soul gems.) + int combat, magic, stealth; // Don't know yet. + int attack[6]; // AttackMin1, AttackMax1, ditto2, ditto3 + int gold; + }; // 96 bytes - NPDTstruct data; + NPDTstruct data; - int flags; - float scale; + int flags; + float scale; - std::string model, name, script, - original; // Base creature that this is a modification of + std::string model, name, script, original; // Base creature that this is a modification of - // Defined in loadcont.hpp - InventoryList inventory; + // Defined in loadcont.hpp + InventoryList inventory; std::string mId; - void load(ESMReader &esm, const std::string& id) - { - mId = id; - - model = esm.getHNString("MODL"); - original = esm.getHNOString("CNAM"); - name = esm.getHNOString("FNAM"); - script = esm.getHNOString("SCRI"); - - esm.getHNT(data, "NPDT", 96); - - esm.getHNT(flags, "FLAG"); - scale = 1.0; - esm.getHNOT(scale, "XSCL"); - - inventory.load(esm); - - // More subrecords: - - // AIDT - data (12 bytes, unknown) - // AI_W - wander (14 bytes, i don't understand it) - // short distance - // byte duration - // byte timeOfDay - // byte idle[10] - // - // Rest is optional: - // AI_T - travel? - // AI_F - follow? - // AI_E - escort? - // AI_A - activate? - - esm.skipRecord(); - } + void load(ESMReader &esm, const std::string& id); }; } #endif diff --git a/components/esm/loaddial.cpp b/components/esm/loaddial.cpp new file mode 100644 index 000000000..d2283d351 --- /dev/null +++ b/components/esm/loaddial.cpp @@ -0,0 +1,25 @@ +#include "loaddial.hpp" + +namespace ESM +{ + +void Dialogue::load(ESMReader &esm) +{ + esm.getSubNameIs("DATA"); + esm.getSubHeader(); + int si = esm.getSubSize(); + if (si == 1) + esm.getT(type); + else if (si == 4) + { + // These are just markers, their values are not used. + int i; + esm.getT(i); + esm.getHNT(i, "DELE"); + type = Deleted; + } + else + esm.fail("Unknown sub record size"); +} + +} diff --git a/components/esm/loaddial.hpp b/components/esm/loaddial.hpp index 0cfba36eb..1f18a49d0 100644 --- a/components/esm/loaddial.hpp +++ b/components/esm/loaddial.hpp @@ -6,7 +6,8 @@ #include "esm_reader.hpp" #include "loadinfo.hpp" -namespace ESM { +namespace ESM +{ /* * Dialogue topic and journal entries. The actual data is contained in @@ -15,36 +16,20 @@ namespace ESM { struct Dialogue { - enum Type + enum Type { - Topic = 0, - Voice = 1, - Greeting = 2, - Persuasion = 3, - Journal = 4, - Deleted = -1 + Topic = 0, + Voice = 1, + Greeting = 2, + Persuasion = 3, + Journal = 4, + Deleted = -1 }; - char type; - std::vector mInfo; + char type; + std::vector mInfo; - void load(ESMReader &esm) - { - esm.getSubNameIs("DATA"); - esm.getSubHeader(); - int si = esm.getSubSize(); - if(si == 1) - esm.getT(type); - else if(si == 4) - { - // These are just markers, their values are not used. - int i; - esm.getT(i); - esm.getHNT(i,"DELE"); - type = Deleted; - } - else esm.fail("Unknown sub record size"); - } + void load(ESMReader &esm); }; } #endif diff --git a/components/esm/loaddoor.cpp b/components/esm/loaddoor.cpp new file mode 100644 index 000000000..d3cc69bd4 --- /dev/null +++ b/components/esm/loaddoor.cpp @@ -0,0 +1,15 @@ +#include "loaddoor.hpp" + +namespace ESM +{ + +void Door::load(ESMReader &esm) +{ + model = esm.getHNString("MODL"); + name = esm.getHNOString("FNAM"); + script = esm.getHNOString("SCRI"); + openSound = esm.getHNOString("SNAM"); + closeSound = esm.getHNOString("ANAM"); +} + +} diff --git a/components/esm/loaddoor.hpp b/components/esm/loaddoor.hpp index 7d76f20c8..2c0db4064 100644 --- a/components/esm/loaddoor.hpp +++ b/components/esm/loaddoor.hpp @@ -3,20 +3,14 @@ #include "esm_reader.hpp" -namespace ESM { +namespace ESM +{ struct Door { - std::string name, model, script, openSound, closeSound; + std::string name, model, script, openSound, closeSound; - void load(ESMReader &esm) - { - model = esm.getHNString("MODL"); - name = esm.getHNOString("FNAM"); - script = esm.getHNOString("SCRI"); - openSound = esm.getHNOString("SNAM"); - closeSound = esm.getHNOString("ANAM"); - } + void load(ESMReader &esm); }; } #endif diff --git a/components/esm/loadench.cpp b/components/esm/loadench.cpp new file mode 100644 index 000000000..b2787492d --- /dev/null +++ b/components/esm/loadench.cpp @@ -0,0 +1,12 @@ +#include "loadench.hpp" + +namespace ESM +{ + +void Enchantment::load(ESMReader &esm) +{ + esm.getHNT(data, "ENDT", 16); + effects.load(esm); +} + +} diff --git a/components/esm/loadench.hpp b/components/esm/loadench.hpp index 15830c70c..449589e25 100644 --- a/components/esm/loadench.hpp +++ b/components/esm/loadench.hpp @@ -2,8 +2,10 @@ #define _ESM_ENCH_H #include "esm_reader.hpp" +#include "defs.hpp" -namespace ESM { +namespace ESM +{ /* * Enchantments @@ -11,31 +13,27 @@ namespace ESM { struct Enchantment { - enum Type + enum Type { - CastOnce = 0, - WhenStrikes = 1, - WhenUsed = 2, - ConstantEffect = 3 + CastOnce = 0, + WhenStrikes = 1, + WhenUsed = 2, + ConstantEffect = 3 }; - struct ENDTstruct - { - int type; - int cost; - int charge; - int autocalc; // Guessing this is 1 if we are supposed to auto - // calculate - }; + struct ENDTstruct + { + int type; + int cost; + int charge; + int autocalc; // Guessing this is 1 if we are supposed to auto + // calculate + }; - ENDTstruct data; - EffectList effects; + ENDTstruct data; + EffectList effects; - void load(ESMReader &esm) - { - esm.getHNT(data, "ENDT", 16); - effects.load(esm); - } + void load(ESMReader &esm); }; } #endif diff --git a/components/esm/loadfact.cpp b/components/esm/loadfact.cpp new file mode 100644 index 000000000..346ad2a2e --- /dev/null +++ b/components/esm/loadfact.cpp @@ -0,0 +1,31 @@ +#include "loadfact.hpp" + +namespace ESM +{ + +void Faction::load(ESMReader &esm) +{ + name = esm.getHNString("FNAM"); + + // Read rank names. These are optional. + int i = 0; + while (esm.isNextSub("RNAM") && i < 10) + ranks[i++] = esm.getHString(); + + // Main data struct + esm.getHNT(data, "FADT", 240); + + if (data.isHidden > 1) + esm.fail("Unknown flag!"); + + // Read faction response values + while (esm.hasMoreSubs()) + { + Reaction r; + r.faction = esm.getHNString("ANAM"); + esm.getHNT(r.reaction, "INTV"); + reactions.push_back(r); + } +} + +} diff --git a/components/esm/loadfact.hpp b/components/esm/loadfact.hpp index c938d912a..85874aa78 100644 --- a/components/esm/loadfact.hpp +++ b/components/esm/loadfact.hpp @@ -3,7 +3,8 @@ #include "esm_reader.hpp" -namespace ESM { +namespace ESM +{ /* * Faction definitions @@ -12,67 +13,46 @@ namespace ESM { // Requirements for each rank struct RankData { - int attribute1, attribute2; // Attribute level + int attribute1, attribute2; // Attribute level - int skill1, skill2; // Skill level (faction skills given in - // skillID below.) You need one skill at - // level 'skill1' and two skills at level - // 'skill2' to advance to this rank. + int skill1, skill2; // Skill level (faction skills given in + // skillID below.) You need one skill at + // level 'skill1' and two skills at level + // 'skill2' to advance to this rank. - int factReaction; // Reaction from faction members + int factReaction; // Reaction from faction members }; struct Faction { - std::string id, name; + std::string id, name; - struct FADTstruct - { - // Which attributes we like - int attribute1, attribute2; + struct FADTstruct + { + // Which attributes we like + int attribute1, attribute2; - RankData rankData[10]; + RankData rankData[10]; - int skillID[6]; // IDs of skills this faction require - int unknown; // Always -1? - int isHidden; // 1 - hidden from player - }; // 240 bytes + int skillID[6]; // IDs of skills this faction require + int unknown; // Always -1? + int isHidden; // 1 - hidden from player + }; // 240 bytes - FADTstruct data; + FADTstruct data; - struct Reaction - { - std::string faction; - int reaction; - }; + struct Reaction + { + std::string faction; + int reaction; + }; - std::vector reactions; + std::vector reactions; - // Name of faction ranks (may be empty for NPC factions) - std::string ranks[10]; + // Name of faction ranks (may be empty for NPC factions) + std::string ranks[10]; - void load(ESMReader &esm) - { - name = esm.getHNString("FNAM"); - - // Read rank names. These are optional. - int i = 0; - while(esm.isNextSub("RNAM") && i<10) ranks[i++] = esm.getHString(); - - // Main data struct - esm.getHNT(data, "FADT", 240); - - if(data.isHidden > 1) esm.fail("Unknown flag!"); - - // Read faction response values - while(esm.hasMoreSubs()) - { - Reaction r; - r.faction = esm.getHNString("ANAM"); - esm.getHNT(r.reaction, "INTV"); - reactions.push_back(r); - } - } + void load(ESMReader &esm); }; } #endif diff --git a/components/esm/loadglob.cpp b/components/esm/loadglob.cpp new file mode 100644 index 000000000..c946b3fa0 --- /dev/null +++ b/components/esm/loadglob.cpp @@ -0,0 +1,24 @@ +#include "loadglob.hpp" + +namespace ESM +{ + +void Global::load(ESMReader &esm) +{ + VarType t; + std::string tmp = esm.getHNString("FNAM"); + if (tmp == "s") + t = VT_Short; + else if (tmp == "l") + t = VT_Int; + else if (tmp == "f") + t = VT_Float; + else + esm.fail("Illegal global variable type " + tmp); + type = t; + + // Note: Both floats and longs are represented as floats. + esm.getHNT(value, "FLTV"); +} + +} diff --git a/components/esm/loadglob.hpp b/components/esm/loadglob.hpp index 9de3e1a46..5028679dd 100644 --- a/components/esm/loadglob.hpp +++ b/components/esm/loadglob.hpp @@ -2,8 +2,10 @@ #define _ESM_GLOB_H #include "esm_reader.hpp" +#include "defs.hpp" -namespace ESM { +namespace ESM +{ /* * Global script variables @@ -11,22 +13,10 @@ namespace ESM { struct Global { - unsigned value; - VarType type; + unsigned value; + VarType type; - void load(ESMReader &esm) - { - VarType t; - std::string tmp = esm.getHNString("FNAM"); - if(tmp == "s") t = VT_Short; - else if(tmp == "l") t = VT_Int; - else if(tmp == "f") t = VT_Float; - else esm.fail("Illegal global variable type " + tmp); - type = t; - - // Note: Both floats and longs are represented as floats. - esm.getHNT(value, "FLTV"); - } + void load(ESMReader &esm); }; } #endif diff --git a/components/esm/loadgmst.cpp b/components/esm/loadgmst.cpp new file mode 100644 index 000000000..677642e31 --- /dev/null +++ b/components/esm/loadgmst.cpp @@ -0,0 +1,172 @@ +#include "loadgmst.hpp" + +namespace ESM +{ + +// Some handy macros +#define cI(s,x) { if(id == (s)) return (i == (x)); } +#define cF(s,x) { if(id == (s)) return (f == (x)); } +#define cS(s,x) { if(id == (s)) return (str == (x)); } + +bool GameSetting::isDirtyTribunal() +{ + /* + Here, id contains the game setting name, and we check the + setting for certain values. If it matches, this is a "dirty" + entry. The correct entry (as defined in Tribunal and Bloodmoon + esms) are given in the comments. Many of the values are correct, + and are marked as 'same'. We still ignore them though, as they + are still in the wrong file and might override custom values + from other mods. + */ + + // Strings + cS("sProfitValue", "Profit Value"); // 'Profit:' + cS("sEditNote", "Edit Note"); // same + cS("sDeleteNote", "Delete Note?"); // same + cS("sMaxSale", "Max Sale"); // 'Seller Max' + cS("sMagicFabricantID", "Fabricant"); // 'Fabricant_summon' + cS("sTeleportDisabled", + "Teleportation magic does not work here.");// same + cS("sLevitateDisabled", + "Levitation magic does not work here."); // same + cS("sCompanionShare", "Companion Share"); // 'Share' + cS("sCompanionWarningButtonOne", + "Let the mercenary quit."); // same + cS("sCompanionWarningButtonTwo", + "Return to Companion Share display."); // same + cS("sCompanionWarningMessage", + "Your mercenary is poorer now than when he contracted with you. Your mercenary will quit if you do not give him gold or goods to bring his Profit Value to a positive value."); + // 'Your mercenary is poorer now than when he contracted with + // you. Your mercenary will quit if you do not give him gold + // or goods to bring his Profit to a positive value.' + // [The difference here is "Profit Value" -> "Profit"] + + // Strings that matches the id + cS("sEffectSummonFabricant", id);// 'Summon Fabricant' + return false; +} + +// Bloodmoon variant +bool GameSetting::isDirtyBloodmoon() +{ + // Strings + cS("sWerewolfPopup", "Werewolf"); // same + cS("sWerewolfRestMessage", + "You cannot rest in werewolf form."); // same + cS("sWerewolfRefusal", + "You cannot do this as a werewolf."); // same + cS("sWerewolfAlarmMessage", + "You have been detected changing from a werewolf state."); + // 'You have been detected as a known werewolf.' + + // Strings that matches the id + cS("sMagicCreature01ID", id); // 'BM_wolf_grey_summon' + cS("sMagicCreature02ID", id); // 'BM_bear_black_summon' + cS("sMagicCreature03ID", id); // 'BM_wolf_bone_summon' + cS("sMagicCreature04ID", id); // same + cS("sMagicCreature05ID", id); // same + cS("sEffectSummonCreature01", id); // 'Calf Wolf' + cS("sEffectSummonCreature02", id); // 'Calf Bear' + cS("sEffectSummonCreature03", id); // 'Summon Bonewolf' + cS("sEffectSummonCreature04", id); // same + cS("sEffectSummonCreature05", id); // same + + // Integers + cI("iWereWolfBounty", 10000); // 1000 + cI("iWereWolfFightMod", 100); // same + cI("iWereWolfFleeMod", 100); // same + cI("iWereWolfLevelToAttack", 20); // same + + // Floats + cF("fFleeDistance", 3000); // same + cF("fCombatDistanceWerewolfMod", 0.3); // same + cF("fWereWolfFatigue", 400); // same + cF("fWereWolfEnchant", 1); // 0 + cF("fWereWolfArmorer", 1); // 0 + cF("fWereWolfBlock", 1); // 0 + cF("fWereWolfSneak", 1); // 95 + cF("fWereWolfDestruction", 1); // 0 + cF("fWereWolfEndurance", 150); // same + cF("fWereWolfConjuration", 1); // 0 + cF("fWereWolfRestoration", 1); // 0 + cF("fWereWolfAthletics", 150); // 50 + cF("fWereWolfLuck", 1); // 25 + cF("fWereWolfSilverWeaponDamageMult", 1.5); // 2 + cF("fWereWolfMediumArmor", 1); // 0 + cF("fWereWolfShortBlade", 1); // 0 + cF("fWereWolfAcrobatics", 150); // 80 + cF("fWereWolfSpeechcraft", 1); // 0 + cF("fWereWolfAlteration", 1); // 0 + cF("fWereWolfIllusion", 1); // 0 + cF("fWereWolfLongBlade", 1); // 0 + cF("fWereWolfMarksman", 1); // 0 + cF("fWereWolfHandtoHand", 100); // same + cF("fWereWolfIntellegence", 1); // 0 + cF("fWereWolfAlchemy", 1); // 0 + cF("fWereWolfUnarmored", 100); // same + cF("fWereWolfAxe", 1); // 0 + cF("fWereWolfRunMult", 1.5); // 1.3 + cF("fWereWolfMagicka", 100); // same + cF("fWereWolfAgility", 150); // same + cF("fWereWolfBluntWeapon", 1); // 0 + cF("fWereWolfSecurity", 1); // 0 + cF("fWereWolfPersonality", 1); // 0 + cF("fWereWolfMerchantile", 1); // 0 + cF("fWereWolfHeavyArmor", 1); // 0 + cF("fWereWolfSpear", 1); // 0 + cF("fWereWolfStrength", 150); // same + cF("fWereWolfHealth", 2); // same + cF("fWereWolfMysticism", 1); // 0 + cF("fWereWolfLightArmor", 1); // 0 + cF("fWereWolfWillPower", 1); // 0 + cF("fWereWolfSpeed", 150); // 90 + return false; +} + +void GameSetting::load(ESMReader &esm) +{ + assert(id != ""); + + dirty = false; + + // We are apparently allowed to be empty + if (!esm.hasMoreSubs()) + { + type = VT_None; + return; + } + + // Load some data + esm.getSubName(); + NAME n = esm.retSubName(); + if (n == "STRV") + { + str = esm.getHString(); + type = VT_String; + } + else if (n == "INTV") + { + esm.getHT(i); + type = VT_Int; + } + else if (n == "FLTV") + { + esm.getHT(f); + type = VT_Float; + } + else + esm.fail("Unwanted subrecord type"); + + int spf = esm.getSpecial(); + + // Check if this is one of the dirty values mentioned above. If it + // is, we set the dirty flag. This will ONLY work if you've set + // the 'id' string correctly before calling load(). + + if ((spf != SF_Tribunal && isDirtyTribunal()) || (spf != SF_Bloodmoon + && isDirtyBloodmoon())) + dirty = true; +} + +} diff --git a/components/esm/loadgmst.hpp b/components/esm/loadgmst.hpp index 2e112ecb6..01fbc3067 100644 --- a/components/esm/loadgmst.hpp +++ b/components/esm/loadgmst.hpp @@ -4,7 +4,8 @@ #include "esm_reader.hpp" #include "defs.hpp" -namespace ESM { +namespace ESM +{ /* * Game setting, with automatic cleaning of "dirty" entries. @@ -13,238 +14,75 @@ namespace ESM { struct GameSetting { - std::string id; + std::string id; - // One of these is used depending on the variable type - std::string str; - int i; - float f; - VarType type; + // One of these is used depending on the variable type + std::string str; + int i; + float f; + VarType type; - // Set to true if this is a 'dirty' entry which should be ignored - bool dirty; + // Set to true if this is a 'dirty' entry which should be ignored + bool dirty; - /* - These functions check if this game setting is one of the "dirty" - GMST records found in many mods. These are due to a serious bug in - the official TES3 editor. It only occurs in the newer editor - versions that came with Tribunal and Bloodmoon, and only if a - modder tries to make a mod without loading the corresponding - expansion master file. For example, if you have Tribunal installed - and try to make a mod without loading Tribunal.esm, the editor - will insert these GMST records as a replacement for the entries it - cannot find in the ESMs. - - The values of these "dirty" records differ in general from their - values as defined in Tribunal.esm and Bloodmoon.esm, and are - always set to the same "default" values. Most of these values are - nonsensical, ie. changing the "Seller Max" string to "Max Sale", - or change the stats of werewolves to useless values like 1. Some - of them break certain spell effects. - - It is most likely that these values are just leftover values from - an early stage of development that are inserted as default values - by the editor code. They are supposed to be overridden when the - correct esm file is loaded. When it isn't loaded however, you get - stuck with the initial value, and this gets written to every mod - by the editor, for some reason. - - Bethesda themselves have fallen for this bug. If you install both - Tribunal and Bloodmoon, the updated Tribunal.esm will contain the - dirty GMST settings from Bloodmoon, and Bloodmoon.esm will contain - some of the dirty settings from Tribunal. In other words, this bug - affects the game EVEN IF YOU DO NOT USE ANY MODS! - - The guys at Bethesda are well aware of this bug (and many others), - as the mod community and fan base complained about them for a long - time. But unfortunately it was never fixed. - - There are several tools available to help modders remove these - records from their files, but not all modders use them, and they - really shouldn't have to. In this file we choose instead to reject - all the corrupt values at load time. - - These functions checks if the current game setting is one of the - "dirty" ones as described above. TODO: I have not checked this - against other sources yet, do that later. Currently recognizes 22 - values for tribunal and 50 for bloodmoon. Legitimate GMSTs in mods - (setting values other than the default "dirty" ones) are not - affected and will work correctly. - */ - - // Some handy macros -#define cI(s,x) { if(id == (s)) return (i == (x)); } -#define cF(s,x) { if(id == (s)) return (f == (x)); } -#define cS(s,x) { if(id == (s)) return (str == (x)); } - - /* - Checks for dirty tribunal values. These will be ignored if found - in any file except when they are found in "Tribunal.esm". - */ - bool isDirtyTribunal() - { /* - Here, id contains the game setting name, and we check the - setting for certain values. If it matches, this is a "dirty" - entry. The correct entry (as defined in Tribunal and Bloodmoon - esms) are given in the comments. Many of the values are correct, - and are marked as 'same'. We still ignore them though, as they - are still in the wrong file and might override custom values - from other mods. - */ + These functions check if this game setting is one of the "dirty" + GMST records found in many mods. These are due to a serious bug in + the official TES3 editor. It only occurs in the newer editor + versions that came with Tribunal and Bloodmoon, and only if a + modder tries to make a mod without loading the corresponding + expansion master file. For example, if you have Tribunal installed + and try to make a mod without loading Tribunal.esm, the editor + will insert these GMST records as a replacement for the entries it + cannot find in the ESMs. - // Strings - cS("sProfitValue", "Profit Value"); // 'Profit:' - cS("sEditNote", "Edit Note"); // same - cS("sDeleteNote", "Delete Note?"); // same - cS("sMaxSale", "Max Sale"); // 'Seller Max' - cS("sMagicFabricantID", "Fabricant"); // 'Fabricant_summon' - cS("sTeleportDisabled", - "Teleportation magic does not work here.");// same - cS("sLevitateDisabled", - "Levitation magic does not work here."); // same - cS("sCompanionShare", "Companion Share"); // 'Share' - cS("sCompanionWarningButtonOne", - "Let the mercenary quit."); // same - cS("sCompanionWarningButtonTwo", - "Return to Companion Share display."); // same - cS("sCompanionWarningMessage", - "Your mercenary is poorer now than when he contracted with you. Your mercenary will quit if you do not give him gold or goods to bring his Profit Value to a positive value."); - // 'Your mercenary is poorer now than when he contracted with - // you. Your mercenary will quit if you do not give him gold - // or goods to bring his Profit to a positive value.' - // [The difference here is "Profit Value" -> "Profit"] + The values of these "dirty" records differ in general from their + values as defined in Tribunal.esm and Bloodmoon.esm, and are + always set to the same "default" values. Most of these values are + nonsensical, ie. changing the "Seller Max" string to "Max Sale", + or change the stats of werewolves to useless values like 1. Some + of them break certain spell effects. - // Strings that matches the id - cS("sEffectSummonFabricant", id);// 'Summon Fabricant' - return false; - } + It is most likely that these values are just leftover values from + an early stage of development that are inserted as default values + by the editor code. They are supposed to be overridden when the + correct esm file is loaded. When it isn't loaded however, you get + stuck with the initial value, and this gets written to every mod + by the editor, for some reason. - // Bloodmoon variant - bool isDirtyBloodmoon() - { - // Strings - cS("sWerewolfPopup", "Werewolf"); // same - cS("sWerewolfRestMessage", - "You cannot rest in werewolf form."); // same - cS("sWerewolfRefusal", - "You cannot do this as a werewolf."); // same - cS("sWerewolfAlarmMessage", - "You have been detected changing from a werewolf state."); - // 'You have been detected as a known werewolf.' + Bethesda themselves have fallen for this bug. If you install both + Tribunal and Bloodmoon, the updated Tribunal.esm will contain the + dirty GMST settings from Bloodmoon, and Bloodmoon.esm will contain + some of the dirty settings from Tribunal. In other words, this bug + affects the game EVEN IF YOU DO NOT USE ANY MODS! - // Strings that matches the id - cS("sMagicCreature01ID", id); // 'BM_wolf_grey_summon' - cS("sMagicCreature02ID", id); // 'BM_bear_black_summon' - cS("sMagicCreature03ID", id); // 'BM_wolf_bone_summon' - cS("sMagicCreature04ID", id); // same - cS("sMagicCreature05ID", id); // same - cS("sEffectSummonCreature01", id); // 'Calf Wolf' - cS("sEffectSummonCreature02", id); // 'Calf Bear' - cS("sEffectSummonCreature03", id); // 'Summon Bonewolf' - cS("sEffectSummonCreature04", id); // same - cS("sEffectSummonCreature05", id); // same + The guys at Bethesda are well aware of this bug (and many others), + as the mod community and fan base complained about them for a long + time. But unfortunately it was never fixed. - // Integers - cI("iWereWolfBounty", 10000); // 1000 - cI("iWereWolfFightMod", 100); // same - cI("iWereWolfFleeMod", 100); // same - cI("iWereWolfLevelToAttack", 20); // same + There are several tools available to help modders remove these + records from their files, but not all modders use them, and they + really shouldn't have to. In this file we choose instead to reject + all the corrupt values at load time. - // Floats - cF("fFleeDistance", 3000); // same - cF("fCombatDistanceWerewolfMod", 0.3); // same - cF("fWereWolfFatigue", 400); // same - cF("fWereWolfEnchant", 1); // 0 - cF("fWereWolfArmorer", 1); // 0 - cF("fWereWolfBlock", 1); // 0 - cF("fWereWolfSneak", 1); // 95 - cF("fWereWolfDestruction", 1); // 0 - cF("fWereWolfEndurance", 150); // same - cF("fWereWolfConjuration", 1); // 0 - cF("fWereWolfRestoration", 1); // 0 - cF("fWereWolfAthletics", 150); // 50 - cF("fWereWolfLuck", 1); // 25 - cF("fWereWolfSilverWeaponDamageMult", 1.5); // 2 - cF("fWereWolfMediumArmor", 1); // 0 - cF("fWereWolfShortBlade", 1); // 0 - cF("fWereWolfAcrobatics", 150); // 80 - cF("fWereWolfSpeechcraft", 1); // 0 - cF("fWereWolfAlteration", 1); // 0 - cF("fWereWolfIllusion", 1); // 0 - cF("fWereWolfLongBlade", 1); // 0 - cF("fWereWolfMarksman", 1); // 0 - cF("fWereWolfHandtoHand", 100); // same - cF("fWereWolfIntellegence", 1); // 0 - cF("fWereWolfAlchemy", 1); // 0 - cF("fWereWolfUnarmored", 100); // same - cF("fWereWolfAxe", 1); // 0 - cF("fWereWolfRunMult", 1.5); // 1.3 - cF("fWereWolfMagicka", 100); // same - cF("fWereWolfAgility", 150); // same - cF("fWereWolfBluntWeapon", 1); // 0 - cF("fWereWolfSecurity", 1); // 0 - cF("fWereWolfPersonality", 1); // 0 - cF("fWereWolfMerchantile", 1); // 0 - cF("fWereWolfHeavyArmor", 1); // 0 - cF("fWereWolfSpear", 1); // 0 - cF("fWereWolfStrength", 150); // same - cF("fWereWolfHealth", 2); // same - cF("fWereWolfMysticism", 1); // 0 - cF("fWereWolfLightArmor", 1); // 0 - cF("fWereWolfWillPower", 1); // 0 - cF("fWereWolfSpeed", 150); // 90 - return false; - } + These functions checks if the current game setting is one of the + "dirty" ones as described above. TODO: I have not checked this + against other sources yet, do that later. Currently recognizes 22 + values for tribunal and 50 for bloodmoon. Legitimate GMSTs in mods + (setting values other than the default "dirty" ones) are not + affected and will work correctly. + */ -#undef cI -#undef cF -#undef cS + /* + Checks for dirty tribunal values. These will be ignored if found + in any file except when they are found in "Tribunal.esm". + */ + bool isDirtyTribunal(); - void load(ESMReader &esm) - { - assert(id != ""); + // Bloodmoon variant + bool isDirtyBloodmoon(); - dirty = false; - - // We are apparently allowed to be empty - if(!esm.hasMoreSubs()) - { - type = VT_None; - return; - } - - // Load some data - esm.getSubName(); - NAME n = esm.retSubName(); - if(n == "STRV") - { - str = esm.getHString(); - type = VT_String; - } - else if(n == "INTV") - { - esm.getHT(i); - type = VT_Int; - } - else if(n == "FLTV") - { - esm.getHT(f); - type = VT_Float; - } - else - esm.fail("Unwanted subrecord type"); - - int spf = esm.getSpecial(); - - // Check if this is one of the dirty values mentioned above. If it - // is, we set the dirty flag. This will ONLY work if you've set - // the 'id' string correctly before calling load(). - - if( ( spf != SF_Tribunal && isDirtyTribunal() ) || - ( spf != SF_Bloodmoon && isDirtyBloodmoon() ) ) - dirty = true; - } + void load(ESMReader &esm); }; } #endif diff --git a/components/esm/loadinfo.cpp b/components/esm/loadinfo.cpp new file mode 100644 index 000000000..0f08b3c8a --- /dev/null +++ b/components/esm/loadinfo.cpp @@ -0,0 +1,133 @@ +#include "loadinfo.hpp" + +namespace ESM +{ + +void DialInfo::load(ESMReader &esm) +{ + id = esm.getHNString("INAM"); + prev = esm.getHNString("PNAM"); + next = esm.getHNString("NNAM"); + + // Not present if deleted + if (esm.isNextSub("DATA")) + esm.getHT(data, 12); + + // What follows is somewhat spaghetti-ish, but it's worth if for + // an extra speedup. INFO is by far the most common record type. + + // subName is a reference to the original, so it changes whenever + // a new sub name is read. esm.isEmptyOrGetName() will get the + // next name for us, or return true if there are no more records. + esm.getSubName(); + const NAME &subName = esm.retSubName(); + + if (subName.val == REC_ONAM) + { + actor = esm.getHString(); + if (esm.isEmptyOrGetName()) + return; + } + if (subName.val == REC_RNAM) + { + race = esm.getHString(); + if (esm.isEmptyOrGetName()) + return; + } + if (subName.val == REC_CNAM) + { + clas = esm.getHString(); + if (esm.isEmptyOrGetName()) + return; + } + + factionLess = false; + if (subName.val == REC_FNAM) + { + npcFaction = esm.getHString(); + if (npcFaction == "FFFF") + factionLess = true; + if (esm.isEmptyOrGetName()) + return; + } + if (subName.val == REC_ANAM) + { + cell = esm.getHString(); + if (esm.isEmptyOrGetName()) + return; + } + if (subName.val == REC_DNAM) + { + pcFaction = esm.getHString(); + if (esm.isEmptyOrGetName()) + return; + } + if (subName.val == REC_SNAM) + { + sound = esm.getHString(); + if (esm.isEmptyOrGetName()) + return; + } + if (subName.val == REC_NAME) + { + response = esm.getHString(); + if (esm.isEmptyOrGetName()) + return; + } + + while (subName.val == REC_SCVR) + { + SelectStruct ss; + + ss.selectRule = esm.getHString(); + esm.isEmptyOrGetName(); + + if (subName.val == REC_INTV) + { + ss.type = VT_Int; + esm.getHT(ss.i); + } + else if (subName.val == REC_FLTV) + { + ss.type = VT_Float; + esm.getHT(ss.f); + } + else + esm.fail( + "INFO.SCVR must precede INTV or FLTV, not " + + subName.toString()); + + selects.push_back(ss); + + if (esm.isEmptyOrGetName()) + return; + } + + if (subName.val == REC_BNAM) + { + resultScript = esm.getHString(); + if (esm.isEmptyOrGetName()) + return; + } + + questStatus = QS_None; + + if (subName.val == REC_QSTN) + questStatus = QS_Name; + else if (subName.val == REC_QSTF) + questStatus = QS_Finished; + else if (subName.val == REC_QSTR) + questStatus = QS_Restart; + else if (subName.val == REC_DELE) + questStatus = QS_Deleted; + else + esm.fail( + "Don't know what to do with " + subName.toString() + + " in INFO " + id); + + if (questStatus != QS_None) + // Skip rest of record + esm.skipRecord(); +} + +} diff --git a/components/esm/loadinfo.hpp b/components/esm/loadinfo.hpp index 480deda73..c47af341e 100644 --- a/components/esm/loadinfo.hpp +++ b/components/esm/loadinfo.hpp @@ -4,7 +4,8 @@ #include "esm_reader.hpp" #include "defs.hpp" -namespace ESM { +namespace ESM +{ // NOT DONE @@ -15,88 +16,88 @@ namespace ESM { struct DialInfo { - enum Gender + enum Gender { - Male = 0, - Female = 1, - NA = -1 + Male = 0, + Female = 1, + NA = -1 }; - struct DATAstruct - { - int unknown1; - int disposition; - char rank; // Rank of NPC - char gender; // See Gender enum - char PCrank; // Player rank - char unknown2; - }; // 12 bytes - DATAstruct data; - - // The rules for whether or not we will select this dialog item. - struct SelectStruct - { - std::string selectRule; // This has a complicated format - float f; // Only one of 'f' or 'i' is used - int i; - VarType type; - }; - - // Journal quest indices (introduced with the quest system in Tribunal) - enum QuestStatus + struct DATAstruct { - QS_None, - QS_Name, - QS_Finished, - QS_Restart, - QS_Deleted + int unknown1; + int disposition; + char rank; // Rank of NPC + char gender; // See Gender enum + char PCrank; // Player rank + char unknown2; + }; // 12 bytes + DATAstruct data; + + // The rules for whether or not we will select this dialog item. + struct SelectStruct + { + std::string selectRule; // This has a complicated format + float f; // Only one of 'f' or 'i' is used + int i; + VarType type; }; - // Rules for when to include this item in the final list of options - // visible to the player. - std::vector selects; - - // Id of this, previous and next INFO items - std::string id, prev, next, - - // Various references used in determining when to select this item. - actor, race, clas, npcFaction, pcFaction, cell, - - // Sound and text associated with this item - sound, response, - - // Result script (uncomiled) to run whenever this dialog item is - // selected - resultScript; - - // ONLY include this item the NPC is not part of any faction. - bool factionLess; - - // Status of this quest item - QuestStatus questStatus; - - // Hexadecimal versions of the various subrecord names. - enum SubNames + // Journal quest indices (introduced with the quest system in Tribunal) + enum QuestStatus { - REC_ONAM = 0x4d414e4f, - REC_RNAM = 0x4d414e52, - REC_CNAM = 0x4d414e43, - REC_FNAM = 0x4d414e46, - REC_ANAM = 0x4d414e41, - REC_DNAM = 0x4d414e44, - REC_SNAM = 0x4d414e53, - REC_NAME = 0x454d414e, - REC_SCVR = 0x52564353, - REC_INTV = 0x56544e49, - REC_FLTV = 0x56544c46, - REC_BNAM = 0x4d414e42, - REC_QSTN = 0x4e545351, - REC_QSTF = 0x46545351, - REC_QSTR = 0x52545351, - REC_DELE = 0x454c4544 + QS_None, + QS_Name, + QS_Finished, + QS_Restart, + QS_Deleted }; - void load(ESMReader &esm); + // Rules for when to include this item in the final list of options + // visible to the player. + std::vector selects; + + // Id of this, previous and next INFO items + std::string id, prev, next, + + // Various references used in determining when to select this item. + actor, race, clas, npcFaction, pcFaction, cell, + + // Sound and text associated with this item + sound, response, + + // Result script (uncomiled) to run whenever this dialog item is + // selected + resultScript; + + // ONLY include this item the NPC is not part of any faction. + bool factionLess; + + // Status of this quest item + QuestStatus questStatus; + + // Hexadecimal versions of the various subrecord names. + enum SubNames + { + REC_ONAM = 0x4d414e4f, + REC_RNAM = 0x4d414e52, + REC_CNAM = 0x4d414e43, + REC_FNAM = 0x4d414e46, + REC_ANAM = 0x4d414e41, + REC_DNAM = 0x4d414e44, + REC_SNAM = 0x4d414e53, + REC_NAME = 0x454d414e, + REC_SCVR = 0x52564353, + REC_INTV = 0x56544e49, + REC_FLTV = 0x56544c46, + REC_BNAM = 0x4d414e42, + REC_QSTN = 0x4e545351, + REC_QSTF = 0x46545351, + REC_QSTR = 0x52545351, + REC_DELE = 0x454c4544 + }; + + void load(ESMReader &esm); }; /* diff --git a/components/esm/loadingr.cpp b/components/esm/loadingr.cpp new file mode 100644 index 000000000..471f71780 --- /dev/null +++ b/components/esm/loadingr.cpp @@ -0,0 +1,15 @@ +#include "loadingr.hpp" + +namespace ESM +{ + +void Ingredient::load(ESMReader &esm) +{ + model = esm.getHNString("MODL"); + name = esm.getHNString("FNAM"); + esm.getHNT(data, "IRDT", 56); + script = esm.getHNOString("SCRI"); + icon = esm.getHNOString("ITEX"); +} + +} diff --git a/components/esm/loadingr.hpp b/components/esm/loadingr.hpp index 5845cb570..af9599ed0 100644 --- a/components/esm/loadingr.hpp +++ b/components/esm/loadingr.hpp @@ -3,7 +3,8 @@ #include "esm_reader.hpp" -namespace ESM { +namespace ESM +{ /* * Alchemy ingredient @@ -11,26 +12,19 @@ namespace ESM { struct Ingredient { - struct IRDTstruct - { - float weight; - int value; - int effectID[4]; // Effect, 0 or -1 means none - int skills[4]; // SkillEnum related to effect - int attributes[4]; // Attribute related to effect - }; + struct IRDTstruct + { + float weight; + int value; + int effectID[4]; // Effect, 0 or -1 means none + int skills[4]; // SkillEnum related to effect + int attributes[4]; // Attribute related to effect + }; - IRDTstruct data; - std::string name, model, icon, script; + IRDTstruct data; + std::string name, model, icon, script; - void load(ESMReader &esm) - { - model = esm.getHNString("MODL"); - name = esm.getHNString("FNAM"); - esm.getHNT(data, "IRDT", 56); - script = esm.getHNOString("SCRI"); - icon = esm.getHNOString("ITEX"); - } + void load(ESMReader &esm); }; } #endif diff --git a/components/esm/loadlevlist.cpp b/components/esm/loadlevlist.cpp new file mode 100644 index 000000000..d1bff7972 --- /dev/null +++ b/components/esm/loadlevlist.cpp @@ -0,0 +1,34 @@ +#include "loadlevlist.hpp" + +namespace ESM +{ + +void LeveledListBase::load(ESMReader &esm) +{ + esm.getHNT(flags, "DATA"); + esm.getHNT(chanceNone, "NNAM"); + + if (esm.isNextSub("INDX")) + { + int len; + esm.getHT(len); + list.resize(len); + } + else + return; + + // TODO: Merge with an existing lists here. This can be done + // simply by adding the lists together, making sure that they are + // sorted by level. A better way might be to exclude repeated + // items. Also, some times we don't want to merge lists, just + // overwrite. Figure out a way to give the user this option. + + for (size_t i = 0; i < list.size(); i++) + { + LevelItem &li = list[i]; + li.id = esm.getHNString(recName); + esm.getHNT(li.level, "INTV"); + } +} + +} diff --git a/components/esm/loadlevlist.hpp b/components/esm/loadlevlist.hpp index 8b0ae45b2..4affce539 100644 --- a/components/esm/loadlevlist.hpp +++ b/components/esm/loadlevlist.hpp @@ -3,7 +3,8 @@ #include "esm_reader.hpp" -namespace ESM { +namespace ESM +{ /* * Leveled lists. Since these have identical layout, I only bothered @@ -15,65 +16,50 @@ namespace ESM { struct LeveledListBase { - enum Flags + enum Flags { - AllLevels = 0x01, // Calculate from all levels <= player - // level, not just the closest below - // player. - Each = 0x02 // Select a new item each time this - // list is instantiated, instead of - // giving several identical items - }; // (used when a container has more - // than one instance of one leveled - // list.) - int flags; - unsigned char chanceNone; // Chance that none are selected (0-255?) + AllLevels = 0x01, // Calculate from all levels <= player + // level, not just the closest below + // player. + Each = 0x02 // Select a new item each time this + // list is instantiated, instead of + // giving several identical items + }; // (used when a container has more + // than one instance of one leveled + // list.) + int flags; + unsigned char chanceNone; // Chance that none are selected (0-255?) - // Record name used to read references. Must be set before load() is - // called. - const char *recName; + // Record name used to read references. Must be set before load() is + // called. + const char *recName; - struct LevelItem - { - std::string id; - short level; - }; + struct LevelItem + { + std::string id; + short level; + }; - std::vector list; + std::vector list; - void load(ESMReader &esm) - { - esm.getHNT(flags, "DATA"); - esm.getHNT(chanceNone, "NNAM"); - - if(esm.isNextSub("INDX")) - { - int len; - esm.getHT(len); - list.resize(len); - } - else return; - - // TODO: Merge with an existing lists here. This can be done - // simply by adding the lists together, making sure that they are - // sorted by level. A better way might be to exclude repeated - // items. Also, some times we don't want to merge lists, just - // overwrite. Figure out a way to give the user this option. - - for(size_t i=0; i soundList; + std::vector soundList; - void load(ESMReader &esm) - { - name = esm.getHNString("FNAM"); - - if(esm.getVer() == VER_12) - esm.getHNExact(&data, sizeof(data)-2, "WEAT"); - else if(esm.getVer() == VER_13) - esm.getHNExact(&data, sizeof(data), "WEAT"); - else esm.fail("Don't know what to do in this version"); - - sleepList = esm.getHNOString("BNAM"); - - esm.getHNT(mapColor, "CNAM"); - - while(esm.hasMoreSubs()) - { - SoundRef sr; - esm.getHNT(sr, "SNAM", 33); - soundList.push_back(sr); - } - } + void load(ESMReader &esm); }; } #endif diff --git a/components/esm/loadscpt.cpp b/components/esm/loadscpt.cpp new file mode 100644 index 000000000..9c0176725 --- /dev/null +++ b/components/esm/loadscpt.cpp @@ -0,0 +1,42 @@ +#include "loadscpt.hpp" + +namespace ESM +{ + +void Script::load(ESMReader &esm) +{ + esm.getHNT(data, "SCHD", 52); + + // List of local variables + if (esm.isNextSub("SCVR")) + { + int s = data.stringTableSize; + char* tmp = new char[s]; + esm.getHExact(tmp, s); + + // Set up the list of variable names + varNames.resize(data.numShorts + data.numLongs + data.numFloats); + + // The tmp buffer is a null-byte separated string list, we + // just have to pick out one string at a time. + char* str = tmp; + for (size_t i = 0; i < varNames.size(); i++) + { + varNames[i] = std::string(str); + str += varNames[i].size() + 1; + + if (str - tmp > s) + esm.fail("String table overflow"); + } + delete[] tmp; + } + + // Script data + scriptData.resize(data.scriptDataSize); + esm.getHNExact(&scriptData[0], scriptData.size(), "SCDT"); + + // Script text + scriptText = esm.getHNOString("SCTX"); +} + +} diff --git a/components/esm/loadscpt.hpp b/components/esm/loadscpt.hpp index aa189c888..3ce3d9636 100644 --- a/components/esm/loadscpt.hpp +++ b/components/esm/loadscpt.hpp @@ -3,7 +3,8 @@ #include "esm_reader.hpp" -namespace ESM { +namespace ESM +{ /* * Script definitions @@ -12,80 +13,43 @@ namespace ESM { class Script { public: - struct SCHDstruct - { - /* Script name. + struct SCHDstruct + { + /* Script name. - NOTE: You should handle the name "Main" (case insensitive) with - care. With tribunal, modders got the ability to add 'start - scripts' to their mods, which is a script that is run at - startup and which runs throughout the game (I think.) + NOTE: You should handle the name "Main" (case insensitive) with + care. With tribunal, modders got the ability to add 'start + scripts' to their mods, which is a script that is run at + startup and which runs throughout the game (I think.) - However, before Tribunal, there was only one startup script, - called "Main". If mods wanted to make their own start scripts, - they had to overwrite Main. This is obviously problem if - multiple mods to this at the same time. + However, before Tribunal, there was only one startup script, + called "Main". If mods wanted to make their own start scripts, + they had to overwrite Main. This is obviously problem if + multiple mods to this at the same time. - Although most mods have switched to using Trib-style startup - scripts, some legacy mods might still overwrite Main, and this - can cause problems if several mods do it. I think the best - course of action is to NEVER overwrite main, but instead add - each with a separate unique name and add them to the start - script list. But there might be other problems with this - approach though. - */ + Although most mods have switched to using Trib-style startup + scripts, some legacy mods might still overwrite Main, and this + can cause problems if several mods do it. I think the best + course of action is to NEVER overwrite main, but instead add + each with a separate unique name and add them to the start + script list. But there might be other problems with this + approach though. + */ - NAME32 name; + NAME32 name; - // These describe the sizes we need to allocate for the script - // data. - int numShorts, numLongs, numFloats, - scriptDataSize, stringTableSize; - }; // 52 bytes + // These describe the sizes we need to allocate for the script + // data. + int numShorts, numLongs, numFloats, scriptDataSize, stringTableSize; + }; // 52 bytes - SCHDstruct data; + SCHDstruct data; - std::vector varNames; // Variable names - std::vector scriptData; // Compiled bytecode - std::string scriptText; // Uncompiled script + std::vector varNames; // Variable names + std::vector scriptData; // Compiled bytecode + std::string scriptText; // Uncompiled script - void load(ESMReader &esm) - { - esm.getHNT(data, "SCHD", 52); - - // List of local variables - if(esm.isNextSub("SCVR")) - { - int s = data.stringTableSize; - char* tmp = new char[s]; - esm.getHExact(tmp, s); - - // Set up the list of variable names - varNames.resize(data.numShorts + - data.numLongs + - data.numFloats); - - // The tmp buffer is a null-byte separated string list, we - // just have to pick out one string at a time. - char* str = tmp; - for(size_t i=0; i< varNames.size(); i++) - { - varNames[i] = std::string(str); - str += varNames[i].size()+1; - - if(str - tmp > s) - esm.fail("String table overflow"); - } - delete[] tmp; - } - - // Script data - scriptData.resize(data.scriptDataSize); - esm.getHNExact(&scriptData[0], scriptData.size(), "SCDT"); - - // Script text - scriptText = esm.getHNOString("SCTX"); - } + void load(ESMReader &esm); }; } #endif diff --git a/components/esm/loadskil.cpp b/components/esm/loadskil.cpp index 77ce2d368..aa7103efc 100644 --- a/components/esm/loadskil.cpp +++ b/components/esm/loadskil.cpp @@ -1,33 +1,70 @@ #include "loadskil.hpp" -namespace ESMS +namespace ESM { - const std::string Skill::sSkillNames[Length] = { - "Block", - "Armorer", - "Medium Armor", - "Heavy Armor", - "Blunt Weapon", - "Long Blade", - "Axe", - "Spear", - "Athletics", - "Enchant", - "Destruction", - "Alteration", - "Illusion", - "Conjuration", - "Mysticism", - "Restoration", - "Alchemy", - "Unarmored", - "Security", - "Sneak", - "Acrobatics", - "Light Armor", - "Short Blade", - "Marksman", - "Speechcraft", - "Hand To Hand", + const std::string Skill::sSkillNameIds[Length] = { + "sSkillBlock", + "sSkillArmorer", + "sSkillMediumarmor", + "sSkillHeavyarmor", + "sSkillBluntweapon", + "sSkillLongblade", + "sSkillAxe", + "sSkillSpear", + "sSkillAthletics", + "sSkillEnchant", + "sSkillDestruction", + "sSkillAlteration", + "sSkillIllusion", + "sSkillConjuration", + "sSkillMysticism", + "sSkillRestoration", + "sSkillAlchemy", + "sSkillUnarmored", + "sSkillSecurity", + "sSkillSneak", + "sSkillAcrobatics", + "sSkillLightarmor", + "sSkillShortblade", + "sSkillMarksman", + "sSkillMercantile", + "sSkillSpeechcraft", + "sSkillHandtohand", }; + const boost::array Skill::skillIds = {{ + Block, + Armorer, + MediumArmor, + HeavyArmor, + BluntWeapon, + LongBlade, + Axe, + Spear, + Athletics, + Enchant, + Destruction, + Alteration, + Illusion, + Conjuration, + Mysticism, + Restoration, + Alchemy, + Unarmored, + Security, + Sneak, + Acrobatics, + LightArmor, + ShortBlade, + Marksman, + Mercantile, + Speechcraft, + HandToHand + }}; + +void Skill::load(ESMReader &esm) +{ + esm.getHNT(index, "INDX"); + esm.getHNT(data, "SKDT", 24); + description = esm.getHNOString("DESC"); +} } diff --git a/components/esm/loadskil.hpp b/components/esm/loadskil.hpp index ffcbcbb31..836f70205 100644 --- a/components/esm/loadskil.hpp +++ b/components/esm/loadskil.hpp @@ -66,12 +66,7 @@ struct Skill static const std::string sSkillNameIds[Length]; static const boost::array skillIds; - void load(ESMReader &esm) - { - esm.getHNT(index, "INDX"); - esm.getHNT(data, "SKDT", 24); - description = esm.getHNOString("DESC"); - } + void load(ESMReader &esm); }; } #endif diff --git a/components/esm/loadsndg.cpp b/components/esm/loadsndg.cpp new file mode 100644 index 000000000..b7b568132 --- /dev/null +++ b/components/esm/loadsndg.cpp @@ -0,0 +1,14 @@ +#include "loadsndg.hpp" + +namespace ESM +{ + +void SoundGenerator::load(ESMReader &esm) +{ + esm.getHNT(type, "DATA", 4); + + creature = esm.getHNOString("CNAM"); + sound = esm.getHNOString("SNAM"); +} + +} diff --git a/components/esm/loadsndg.hpp b/components/esm/loadsndg.hpp index 372b75085..f8803f8c0 100644 --- a/components/esm/loadsndg.hpp +++ b/components/esm/loadsndg.hpp @@ -28,13 +28,7 @@ struct SoundGenerator std::string creature, sound; - void load(ESMReader &esm) - { - esm.getHNT(type, "DATA", 4); - - creature = esm.getHNOString("CNAM"); - sound = esm.getHNOString("SNAM"); - } + void load(ESMReader &esm); }; } #endif diff --git a/components/esm/loadsoun.cpp b/components/esm/loadsoun.cpp new file mode 100644 index 000000000..cd47f0f17 --- /dev/null +++ b/components/esm/loadsoun.cpp @@ -0,0 +1,18 @@ +#include "loadsoun.hpp" + +namespace ESM +{ + +void Sound::load(ESMReader &esm) +{ + sound = esm.getHNString("FNAM"); + esm.getHNT(data, "DATA", 3); + /* + cout << "vol=" << (int)data.volume + << " min=" << (int)data.minRange + << " max=" << (int)data.maxRange + << endl; + */ +} + +} diff --git a/components/esm/loadsoun.hpp b/components/esm/loadsoun.hpp index 597c91491..775a664be 100644 --- a/components/esm/loadsoun.hpp +++ b/components/esm/loadsoun.hpp @@ -3,20 +3,20 @@ #include "esm_reader.hpp" -namespace ESM { +namespace ESM +{ struct SOUNstruct { - unsigned char volume, minRange, maxRange; + unsigned char volume, minRange, maxRange; }; struct Sound { - SOUNstruct data; - std::string sound; + SOUNstruct data; + std::string sound; - // Body moved to load_impl.cpp - void load(ESMReader &esm); + void load(ESMReader &esm); }; } #endif diff --git a/components/esm/loadspel.cpp b/components/esm/loadspel.cpp new file mode 100644 index 000000000..c3c928ce6 --- /dev/null +++ b/components/esm/loadspel.cpp @@ -0,0 +1,13 @@ +#include "loadspel.hpp" + +namespace ESM +{ + +void Spell::load(ESMReader &esm) +{ + name = esm.getHNOString("FNAM"); + esm.getHNT(data, "SPDT", 12); + effects.load(esm); +} + +} diff --git a/components/esm/loadspel.hpp b/components/esm/loadspel.hpp index a141e7dc1..c97d037cd 100644 --- a/components/esm/loadspel.hpp +++ b/components/esm/loadspel.hpp @@ -2,45 +2,42 @@ #define _ESM_SPEL_H #include "esm_reader.hpp" +#include "defs.hpp" -namespace ESM { +namespace ESM +{ struct Spell { - enum SpellType + enum SpellType { - ST_Spell = 0, // Normal spell, must be cast and costs mana - ST_Ability = 1, // Inert ability, always in effect - ST_Blight = 2, // Blight disease - ST_Disease = 3, // Common disease - ST_Curse = 4, // Curse (?) - ST_Power = 5 // Power, can use once a day + ST_Spell = 0, // Normal spell, must be cast and costs mana + ST_Ability = 1, // Inert ability, always in effect + ST_Blight = 2, // Blight disease + ST_Disease = 3, // Common disease + ST_Curse = 4, // Curse (?) + ST_Power = 5 // Power, can use once a day }; - enum Flags + enum Flags { - F_Autocalc = 1, - F_PCStart = 2, - F_Always = 4 // Casting always succeeds + F_Autocalc = 1, + F_PCStart = 2, + F_Always = 4 // Casting always succeeds }; - struct SPDTstruct - { - int type; // SpellType - int cost; // Mana cost - int flags; // Flags - }; + struct SPDTstruct + { + int type; // SpellType + int cost; // Mana cost + int flags; // Flags + }; - SPDTstruct data; - std::string name; - EffectList effects; + SPDTstruct data; + std::string name; + EffectList effects; - void load(ESMReader &esm) - { - name = esm.getHNOString("FNAM"); - esm.getHNT(data, "SPDT", 12); - effects.load(esm); - } + void load(ESMReader &esm); }; } #endif diff --git a/components/esm/loadsscr.cpp b/components/esm/loadsscr.cpp new file mode 100644 index 000000000..f4e79271c --- /dev/null +++ b/components/esm/loadsscr.cpp @@ -0,0 +1,13 @@ +#include "loadsscr.hpp" + +namespace ESM +{ + +void StartScript::load(ESMReader &esm) +{ + esm.getSubNameIs("DATA"); + esm.skipHSub(); + script = esm.getHNString("NAME"); +} + +} diff --git a/components/esm/loadsscr.hpp b/components/esm/loadsscr.hpp index e06fd6c70..d18bde101 100644 --- a/components/esm/loadsscr.hpp +++ b/components/esm/loadsscr.hpp @@ -3,27 +3,23 @@ #include "esm_reader.hpp" -namespace ESM { +namespace ESM +{ /* - Startup script. I think this is simply a 'main' script that is run - from the begining. The SSCR records contain a DATA identifier which - is totally useless (TODO: don't remember what it contains exactly, - document it below later.), and a NAME which is simply a script - reference. + Startup script. I think this is simply a 'main' script that is run + from the begining. The SSCR records contain a DATA identifier which + is totally useless (TODO: don't remember what it contains exactly, + document it below later.), and a NAME which is simply a script + reference. */ struct StartScript { - std::string script; + std::string script; - // Load a record and add it to the list - void load(ESMReader &esm) - { - esm.getSubNameIs("DATA"); - esm.skipHSub(); - script = esm.getHNString("NAME"); - } + // Load a record and add it to the list + void load(ESMReader &esm); }; } diff --git a/components/esm/loadstat.cpp b/components/esm/loadstat.cpp new file mode 100644 index 000000000..654bf290a --- /dev/null +++ b/components/esm/loadstat.cpp @@ -0,0 +1,11 @@ +#include "loadstat.hpp" + +namespace ESM +{ + +void Static::load(ESMReader &esm) +{ + model = esm.getHNString("MODL"); +} + +} diff --git a/components/esm/loadstat.hpp b/components/esm/loadstat.hpp index 7b00df406..4f3121d18 100644 --- a/components/esm/loadstat.hpp +++ b/components/esm/loadstat.hpp @@ -21,10 +21,7 @@ struct Static { std::string model; - void load(ESMReader &esm) - { - model = esm.getHNString("MODL"); - } + void load(ESMReader &esm); }; } #endif diff --git a/components/esm/loadweap.cpp b/components/esm/loadweap.cpp new file mode 100644 index 000000000..1910631bc --- /dev/null +++ b/components/esm/loadweap.cpp @@ -0,0 +1,16 @@ +#include "loadweap.hpp" + +namespace ESM +{ + +void Weapon::load(ESMReader &esm) +{ + model = esm.getHNString("MODL"); + name = esm.getHNOString("FNAM"); + esm.getHNT(data, "WPDT", 32); + script = esm.getHNOString("SCRI"); + icon = esm.getHNOString("ITEX"); + enchant = esm.getHNOString("ENAM"); +} + +} diff --git a/components/esm/loadweap.hpp b/components/esm/loadweap.hpp index e6a848a59..8bd3b147c 100644 --- a/components/esm/loadweap.hpp +++ b/components/esm/loadweap.hpp @@ -3,7 +3,8 @@ #include "esm_reader.hpp" -namespace ESM { +namespace ESM +{ /* * Weapon definition @@ -11,58 +12,50 @@ namespace ESM { struct Weapon { - enum Type + enum Type { - ShortBladeOneHand = 0, - LongBladeOneHand = 1, - LongBladeTwoHand = 2, - BluntOneHand = 3, - BluntTwoClose = 4, - BluntTwoWide = 5, - SpearTwoWide = 6, - AxeOneHand = 7, - AxeTwoHand = 8, - MarksmanBow = 9, - MarksmanCrossbow = 10, - MarksmanThrown = 11, - Arrow = 12, - Bolt = 13 + ShortBladeOneHand = 0, + LongBladeOneHand = 1, + LongBladeTwoHand = 2, + BluntOneHand = 3, + BluntTwoClose = 4, + BluntTwoWide = 5, + SpearTwoWide = 6, + AxeOneHand = 7, + AxeTwoHand = 8, + MarksmanBow = 9, + MarksmanCrossbow = 10, + MarksmanThrown = 11, + Arrow = 12, + Bolt = 13 }; - enum Flags + enum Flags { - Magical = 0x01, - Silver = 0x02 + Magical = 0x01, + Silver = 0x02 }; #pragma pack(push) #pragma pack(1) - struct WPDTstruct - { - float weight; - int value; - short type; - short health; - float speed, reach; - short enchant; // Enchantment points - unsigned char chop[2], slash[2], thrust[2]; // Min and max - int flags; - }; // 32 bytes + struct WPDTstruct + { + float weight; + int value; + short type; + short health; + float speed, reach; + short enchant; // Enchantment points + unsigned char chop[2], slash[2], thrust[2]; // Min and max + int flags; + }; // 32 bytes #pragma pack(pop) - WPDTstruct data; + WPDTstruct data; - std::string name, model, icon, enchant, script; + std::string name, model, icon, enchant, script; - void load(ESMReader &esm) - { - model = esm.getHNString("MODL"); - name = esm.getHNOString("FNAM"); - esm.getHNT(data, "WPDT", 32); - script = esm.getHNOString("SCRI"); - icon = esm.getHNOString("ITEX"); - enchant = esm.getHNOString("ENAM"); - } + void load(ESMReader &esm); }; } #endif diff --git a/components/esm/skill.cpp b/components/esm/skill.cpp deleted file mode 100644 index 05c8c103a..000000000 --- a/components/esm/skill.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "loadskil.hpp" - -namespace ESM -{ - const std::string Skill::sSkillNameIds[Length] = { - "sSkillBlock", - "sSkillArmorer", - "sSkillMediumarmor", - "sSkillHeavyarmor", - "sSkillBluntweapon", - "sSkillLongblade", - "sSkillAxe", - "sSkillSpear", - "sSkillAthletics", - "sSkillEnchant", - "sSkillDestruction", - "sSkillAlteration", - "sSkillIllusion", - "sSkillConjuration", - "sSkillMysticism", - "sSkillRestoration", - "sSkillAlchemy", - "sSkillUnarmored", - "sSkillSecurity", - "sSkillSneak", - "sSkillAcrobatics", - "sSkillLightarmor", - "sSkillShortblade", - "sSkillMarksman", - "sSkillMercantile", - "sSkillSpeechcraft", - "sSkillHandtohand", - }; - const boost::array Skill::skillIds = {{ - Block, - Armorer, - MediumArmor, - HeavyArmor, - BluntWeapon, - LongBlade, - Axe, - Spear, - Athletics, - Enchant, - Destruction, - Alteration, - Illusion, - Conjuration, - Mysticism, - Restoration, - Alchemy, - Unarmored, - Security, - Sneak, - Acrobatics, - LightArmor, - ShortBlade, - Marksman, - Mercantile, - Speechcraft, - HandToHand - }}; -} From 79911b16d0d71cd2cae36cb93e18755785215f8a Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Fri, 8 Apr 2011 22:26:27 +0400 Subject: [PATCH 10/41] Fixed enum formatting in components/esm headers --- components/esm/defs.hpp | 8 ++++++-- components/esm/loadappa.hpp | 5 ++++- components/esm/loadbody.hpp | 7 +++++-- components/esm/loadclas.hpp | 4 +++- components/esm/loadcrea.hpp | 5 ++++- components/esm/loadsndg.hpp | 29 +++++++++++++++-------------- 6 files changed, 37 insertions(+), 21 deletions(-) diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index 0fdbe45aa..917c1031f 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -23,12 +23,16 @@ enum VarType enum Specialization { - SPC_Combat = 0, SPC_Magic = 1, SPC_Stealth = 2 + SPC_Combat = 0, + SPC_Magic = 1, + SPC_Stealth = 2 }; enum RangeType { - RT_Self = 0, RT_Touch = 1, RT_Target = 2 + RT_Self = 0, + RT_Touch = 1, + RT_Target = 2 }; /** A list of references to spells and spell effects. This is shared diff --git a/components/esm/loadappa.hpp b/components/esm/loadappa.hpp index bbb4aefde..2caca32b3 100644 --- a/components/esm/loadappa.hpp +++ b/components/esm/loadappa.hpp @@ -14,7 +14,10 @@ struct Apparatus { enum AppaType { - MortarPestle = 0, Albemic = 1, Calcinator = 2, Retort = 3 + MortarPestle = 0, + Albemic = 1, + Calcinator = 2, + Retort = 3 }; struct AADTstruct diff --git a/components/esm/loadbody.hpp b/components/esm/loadbody.hpp index 14e28f59c..de3db40fc 100644 --- a/components/esm/loadbody.hpp +++ b/components/esm/loadbody.hpp @@ -29,12 +29,15 @@ struct BodyPart enum Flags { - BPF_Female = 1, BPF_Playable = 2 + BPF_Female = 1, + BPF_Playable = 2 }; enum MeshType { - MT_Skin = 0, MT_Clothing = 1, MT_Armor = 2 + MT_Skin = 0, + MT_Clothing = 1, + MT_Armor = 2 }; struct BYDTstruct diff --git a/components/esm/loadclas.hpp b/components/esm/loadclas.hpp index 5fc44abe5..08412c838 100644 --- a/components/esm/loadclas.hpp +++ b/components/esm/loadclas.hpp @@ -38,7 +38,9 @@ struct Class enum Specialization { - Combat = 0, Magic = 1, Stealth = 2 + Combat = 0, + Magic = 1, + Stealth = 2 }; static const Specialization specializationIds[3]; diff --git a/components/esm/loadcrea.hpp b/components/esm/loadcrea.hpp index 40c929213..3c334ebbd 100644 --- a/components/esm/loadcrea.hpp +++ b/components/esm/loadcrea.hpp @@ -30,7 +30,10 @@ struct Creature enum Type { - Creatures = 0, Deadra = 1, Undead = 2, Humanoid = 3 + Creatures = 0, + Deadra = 1, + Undead = 2, + Humanoid = 3 }; struct NPDTstruct diff --git a/components/esm/loadsndg.hpp b/components/esm/loadsndg.hpp index f8803f8c0..2953369c4 100644 --- a/components/esm/loadsndg.hpp +++ b/components/esm/loadsndg.hpp @@ -3,7 +3,8 @@ #include "esm_reader.hpp" -namespace ESM { +namespace ESM +{ /* * Sound generator. This describes the sounds a creature make. @@ -11,24 +12,24 @@ namespace ESM { struct SoundGenerator { - enum Type + enum Type { - LeftFoot = 0, - RightFoot = 1, - SwimLeft = 2, - SwimRight = 3, - Moan = 4, - Roar = 5, - Scream = 6, - Land = 7 + LeftFoot = 0, + RightFoot = 1, + SwimLeft = 2, + SwimRight = 3, + Moan = 4, + Roar = 5, + Scream = 6, + Land = 7 }; - // Type - int type; + // Type + int type; - std::string creature, sound; + std::string creature, sound; - void load(ESMReader &esm); + void load(ESMReader &esm); }; } #endif From f2faa34bd941ba5805ebd1b33df504b86bb368ed Mon Sep 17 00:00:00 2001 From: Jan-Peter Nilsson Date: Sun, 3 Apr 2011 19:37:53 +0200 Subject: [PATCH 11/41] If there is an openmw.cfg in the current path, use it as global config --- apps/openmw/main.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 4d7e6595c..64450157d 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -59,7 +59,13 @@ bool parseOptions (int argc, char**argv, OMW::Engine& engine) bpo::variables_map variables; - std::string cfgFile = OMW::Path::getPath(OMW::Path::GLOBAL_CFG_PATH, "openmw", "openmw.cfg"); + //If there is an openmw.cfg in the current path use that as global config + //Otherwise try getPath + std::string cfgFile = "openmw.cfg"; + if(!isFile(cfgFile.c_str())) + { + cfgFile = OMW::Path::getPath(OMW::Path::GLOBAL_CFG_PATH, "openmw", "openmw.cfg"); + } std::cout << "Using global config file: " << cfgFile << std::endl; std::ifstream globalConfigFile(cfgFile.c_str()); From 5851e0a28c6d9c24530a24f3bbb6cc87f683ee45 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 19 Apr 2011 10:54:11 +0200 Subject: [PATCH 12/41] added journal entry struct --- apps/openmw/CMakeLists.txt | 2 ++ apps/openmw/mwdialogue/journalentry.cpp | 27 +++++++++++++++++++++++ apps/openmw/mwdialogue/journalentry.hpp | 29 +++++++++++++++++++++++++ 3 files changed, 58 insertions(+) create mode 100644 apps/openmw/mwdialogue/journalentry.cpp create mode 100644 apps/openmw/mwdialogue/journalentry.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 3cb08b5f7..63add2fce 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -71,10 +71,12 @@ source_group(apps\\openmw\\mwgui FILES ${GAMEGUI_HEADER} ${GAMEGUI}) set(GAMEDIALOGUE_HEADER mwdialogue/dialoguemanager.hpp mwdialogue/journal.hpp + mwdialogue/journalentry.hpp ) set(GAMEDIALOGUE mwdialogue/dialoguemanager.cpp mwdialogue/journal.cpp + mwdialogue/journalentry.cpp ) source_group(apps\\openmw\\mwdialogue FILES ${GAMEDIALOGUE_HEADER} ${GAMEDIALOGUE}) diff --git a/apps/openmw/mwdialogue/journalentry.cpp b/apps/openmw/mwdialogue/journalentry.cpp new file mode 100644 index 000000000..8e3aeb93b --- /dev/null +++ b/apps/openmw/mwdialogue/journalentry.cpp @@ -0,0 +1,27 @@ + +#include "journalentry.hpp" + +#include + +#include + +namespace MWDialogue +{ + JournalEntry::JournalEntry() {} + + JournalEntry::JournalEntry (int day, const std::string& topic, const std::string& infoId) + : mDay (day), mTopic (topic), mInfoId (infoId) + {} + + std::string JournalEntry::getText (const ESMS::ESMStore& store) const + { + const ESM::Dialogue *dialogue = store.dialogs.find (mTopic); + + for (std::vector::const_iterator iter (dialogue->mInfo.begin()); + iter!=dialogue->mInfo.end(); ++iter) + if (iter->id==mInfoId) + return iter->response; + + throw std::runtime_error ("unknown info ID " + mInfoId + " for topic " + mTopic); + } +} diff --git a/apps/openmw/mwdialogue/journalentry.hpp b/apps/openmw/mwdialogue/journalentry.hpp new file mode 100644 index 000000000..8506b9dbc --- /dev/null +++ b/apps/openmw/mwdialogue/journalentry.hpp @@ -0,0 +1,29 @@ +#ifndef GAME_MMDIALOGUE_JOURNALENTRY_H +#define GAME_MWDIALOGUE_JOURNALENTRY_H + +#include + +namespace ESMS +{ + struct ESMStore; +} + +namespace MWDialogue +{ + /// \brief a quest or dialogue entry with a timestamp + struct JournalEntry + { + int mDay; + std::string mTopic; + std::string mInfoId; + + JournalEntry(); + + JournalEntry (int day, const std::string& topic, const std::string& infoId); + + std::string getText (const ESMS::ESMStore& store) const; + }; + +} + +#endif From 23464e403581e48f6d2200b64a2532796de8ee0a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 19 Apr 2011 11:02:22 +0200 Subject: [PATCH 13/41] added interface and container for main journal --- apps/openmw/mwdialogue/journal.cpp | 10 ++++++++++ apps/openmw/mwdialogue/journal.hpp | 19 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/apps/openmw/mwdialogue/journal.cpp b/apps/openmw/mwdialogue/journal.cpp index 031917c1c..545e2f3ee 100644 --- a/apps/openmw/mwdialogue/journal.cpp +++ b/apps/openmw/mwdialogue/journal.cpp @@ -23,4 +23,14 @@ namespace MWDialogue { return 0; } + + Journal::TEntryIter Journal::begin() const + { + return mJournal.begin(); + } + + Journal::TEntryIter Journal::end() const + { + return mJournal.end(); + } } diff --git a/apps/openmw/mwdialogue/journal.hpp b/apps/openmw/mwdialogue/journal.hpp index cd4814255..07090ef4a 100644 --- a/apps/openmw/mwdialogue/journal.hpp +++ b/apps/openmw/mwdialogue/journal.hpp @@ -2,6 +2,9 @@ #define GAME_MWDIALOG_JOURNAL_H #include +#include + +#include "journalentry.hpp" namespace MWWorld { @@ -12,7 +15,15 @@ namespace MWDialogue { class Journal { + public: + + typedef std::deque TEntryContainer; + typedef TEntryContainer::const_iterator TEntryIter; + + private: + MWWorld::Environment& mEnvironment; + std::deque mJournal; public: @@ -26,6 +37,14 @@ namespace MWDialogue int getJournalIndex (const std::string& id) const; ///< Get the journal index. + + TEntryIter begin() const; + ///< Iterator pointing to the begin of the main journal. + /// + /// \note Iterators to main journal entries will never become invalid. + + TEntryIter end() const; + ///< Iterator pointing past the end of the main journal. }; } From 717b5e1784106dc70f949d829ce65a40af8ba49c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 21 Apr 2011 10:49:45 +0200 Subject: [PATCH 14/41] fixed a constness problem --- apps/openmw/mwgui/birth.cpp | 6 +++--- apps/openmw/mwgui/class.cpp | 18 +++++++++--------- apps/openmw/mwgui/race.cpp | 8 ++++---- apps/openmw/mwgui/stats_window.cpp | 2 +- apps/openmw/mwgui/widgets.cpp | 6 +++--- apps/openmw/mwgui/window_manager.cpp | 2 +- apps/openmw/mwgui/window_manager.hpp | 2 +- apps/openmw/mwworld/world.cpp | 2 +- apps/openmw/mwworld/world.hpp | 2 +- 9 files changed, 24 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index 7db93a508..93dde9f1b 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -119,8 +119,8 @@ void BirthDialog::updateBirths() { birthList->removeAllItems(); - ESMS::ESMStore &store = mWindowManager.getStore(); - + const ESMS::ESMStore &store = mWindowManager.getStore(); + ESMS::RecListT::MapType::const_iterator it = store.birthSigns.list.begin(); ESMS::RecListT::MapType::const_iterator end = store.birthSigns.list.end(); int index = 0; @@ -149,7 +149,7 @@ void BirthDialog::updateSpells() const int lineHeight = 18; MyGUI::IntCoord coord(0, 0, spellArea->getWidth(), 18); - ESMS::ESMStore &store = mWindowManager.getStore(); + const ESMS::ESMStore &store = mWindowManager.getStore(); const ESM::BirthSign *birth = store.birthSigns.find(currentBirthId); std::string texturePath = std::string("textures\\") + birth->texture; diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 01516cfe2..ad94f30b1 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -50,7 +50,7 @@ void GenerateClassResultDialog::setClassId(const std::string &classId) { currentClassId = classId; classImage->setImageTexture(std::string("textures\\levelup\\") + currentClassId + ".dds"); - ESMS::ESMStore &store = mWindowManager.getStore(); + const ESMS::ESMStore &store = mWindowManager.getStore(); className->setCaption(store.classes.find(currentClassId)->name); } @@ -196,8 +196,8 @@ void PickClassDialog::updateClasses() { classList->removeAllItems(); - ESMS::ESMStore &store = mWindowManager.getStore(); - + const ESMS::ESMStore &store = mWindowManager.getStore(); + ESMS::RecListT::MapType::const_iterator it = store.classes.list.begin(); ESMS::RecListT::MapType::const_iterator end = store.classes.list.end(); int index = 0; @@ -220,7 +220,7 @@ void PickClassDialog::updateStats() { if (currentClassId.empty()) return; - ESMS::ESMStore &store = mWindowManager.getStore(); + const ESMS::ESMStore &store = mWindowManager.getStore(); const ESM::Class *klass = store.classes.search(currentClassId); if (!klass) return; @@ -767,7 +767,7 @@ SelectSkillDialog::SelectSkillDialog(WindowManager& parWindowManager) { char theIndex = '0'+i; getWidget(combatSkill[i], std::string("CombatSkill").append(1, theIndex)); - getWidget(magicSkill[i], std::string("MagicSkill").append(1, theIndex)); + getWidget(magicSkill[i], std::string("MagicSkill").append(1, theIndex)); getWidget(stealthSkill[i], std::string("StealthSkill").append(1, theIndex)); } @@ -782,8 +782,8 @@ SelectSkillDialog::SelectSkillDialog(WindowManager& parWindowManager) {combatSkill[6], ESM::Skill::Axe}, {combatSkill[7], ESM::Skill::Spear}, {combatSkill[8], ESM::Skill::Athletics} - }, - { + }, + { {magicSkill[0], ESM::Skill::Enchant}, {magicSkill[1], ESM::Skill::Destruction}, {magicSkill[2], ESM::Skill::Alteration}, @@ -793,8 +793,8 @@ SelectSkillDialog::SelectSkillDialog(WindowManager& parWindowManager) {magicSkill[6], ESM::Skill::Restoration}, {magicSkill[7], ESM::Skill::Alchemy}, {magicSkill[8], ESM::Skill::Unarmored} - }, - { + }, + { {stealthSkill[0], ESM::Skill::Security}, {stealthSkill[1], ESM::Skill::Sneak}, {stealthSkill[2], ESM::Skill::Acrobatics}, diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 65e6afd2e..037f97fc3 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -212,8 +212,8 @@ void RaceDialog::updateRaces() { raceList->removeAllItems(); - ESMS::ESMStore &store = mWindowManager.getStore(); - + const ESMS::ESMStore &store = mWindowManager.getStore(); + ESMS::RecListT::MapType::const_iterator it = store.races.list.begin(); ESMS::RecListT::MapType::const_iterator end = store.races.list.end(); int index = 0; @@ -246,7 +246,7 @@ void RaceDialog::updateSkills() const int lineHeight = 18; MyGUI::IntCoord coord1(0, 0, skillList->getWidth(), 18); - ESMS::ESMStore &store = mWindowManager.getStore(); + const ESMS::ESMStore &store = mWindowManager.getStore(); const ESM::Race *race = store.races.find(currentRaceId); int count = sizeof(race->data.bonus)/sizeof(race->data.bonus[0]); // TODO: Find a portable macro for this ARRAYSIZE? for (int i = 0; i < count; ++i) @@ -282,7 +282,7 @@ void RaceDialog::updateSpellPowers() const int lineHeight = 18; MyGUI::IntCoord coord(0, 0, spellPowerList->getWidth(), 18); - ESMS::ESMStore &store = mWindowManager.getStore(); + const ESMS::ESMStore &store = mWindowManager.getStore(); const ESM::Race *race = store.races.find(currentRaceId); std::vector::const_iterator it = race->powers.list.begin(); diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index d08e6384d..30a4015e3 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -323,7 +323,7 @@ void StatsWindow::updateSkillArea() if (!miscSkills.empty()) addSkills(miscSkills, "sSkillClassMisc", "Misc Skills", coord1, coord2); - ESMS::ESMStore &store = mWindowManager.getStore(); + const ESMS::ESMStore &store = mWindowManager.getStore(); if (!factions.empty()) { diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 861939b7e..f62da2bab 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -278,7 +278,7 @@ void MWSpell::setSpellId(const std::string &spellId) void MWSpell::createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord) { - ESMS::ESMStore &store = mWindowManager->getStore(); + const ESMS::ESMStore &store = mWindowManager->getStore(); const ESM::Spell *spell = store.spells.search(id); MYGUI_ASSERT(spell, "spell with id '" << id << "' not found"); @@ -298,7 +298,7 @@ void MWSpell::updateWidgets() { if (spellNameWidget && mWindowManager) { - ESMS::ESMStore &store = mWindowManager->getStore(); + const ESMS::ESMStore &store = mWindowManager->getStore(); const ESM::Spell *spell = store.spells.search(id); if (spell) spellNameWidget->setCaption(spell->name); @@ -363,7 +363,7 @@ void MWSpellEffect::updateWidgets() if (!mWindowManager) return; - ESMS::ESMStore &store = mWindowManager->getStore(); + const ESMS::ESMStore &store = mWindowManager->getStore(); const ESM::MagicEffect *magicEffect = store.magicEffects.search(effect.effectID); if (textWidget) { diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index f0c409cbe..2d7f70ef8 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -940,7 +940,7 @@ void WindowManager::onReviewActivateDialog(int parDialog) }; } -ESMS::ESMStore& WindowManager::getStore() +const ESMS::ESMStore& WindowManager::getStore() const { return environment.mWorld->getStore(); } diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index 1bf620496..d3fbf3ea3 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -257,7 +257,7 @@ namespace MWGui */ const std::string &getGameSettingString(const std::string &id, const std::string &default_); - ESMS::ESMStore& getStore(); + const ESMS::ESMStore& getStore() const; private: diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index 63019349c..dde3ff711 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -460,7 +460,7 @@ namespace MWWorld return *mPlayer; } - ESMS::ESMStore& World::getStore() + const ESMS::ESMStore& World::getStore() const { return mStore; } diff --git a/apps/openmw/mwworld/world.hpp b/apps/openmw/mwworld/world.hpp index 6965aebc6..76d6bd922 100644 --- a/apps/openmw/mwworld/world.hpp +++ b/apps/openmw/mwworld/world.hpp @@ -115,7 +115,7 @@ namespace MWWorld MWWorld::Player& getPlayer(); - ESMS::ESMStore& getStore(); + const ESMS::ESMStore& getStore() const; const ScriptList& getLocalScripts() const; ///< Names and local variable state of all local scripts in active cells. From 792de880cf738530bdb11dc3b378c834e941585c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 21 Apr 2011 11:00:00 +0200 Subject: [PATCH 15/41] another constness fix --- apps/openmw/mwworld/world.cpp | 5 +++++ apps/openmw/mwworld/world.hpp | 2 ++ 2 files changed, 7 insertions(+) diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index dde3ff711..f10bbfc9a 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -480,6 +480,11 @@ namespace MWWorld return (*mGlobalVariables)[name]; } + Globals::Data World::getGlobalVariable (const std::string& name) const + { + return (*mGlobalVariables)[name]; + } + char World::getGlobalVariableType (const std::string& name) const { return mGlobalVariables->getType (name); diff --git a/apps/openmw/mwworld/world.hpp b/apps/openmw/mwworld/world.hpp index 76d6bd922..f7e5bd3f7 100644 --- a/apps/openmw/mwworld/world.hpp +++ b/apps/openmw/mwworld/world.hpp @@ -125,6 +125,8 @@ namespace MWWorld Globals::Data& getGlobalVariable (const std::string& name); + Globals::Data getGlobalVariable (const std::string& name) const; + char getGlobalVariableType (const std::string& name) const; ///< Return ' ', if there is no global variable with this name. From f3fecdc627d366f2a146a9f2961d989574c5529e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 21 Apr 2011 11:05:49 +0200 Subject: [PATCH 16/41] quest entries are added to main journal now --- apps/openmw/mwdialogue/journal.cpp | 2 ++ apps/openmw/mwdialogue/journalentry.cpp | 18 ++++++++++++++++++ apps/openmw/mwdialogue/journalentry.hpp | 8 ++++++++ 3 files changed, 28 insertions(+) diff --git a/apps/openmw/mwdialogue/journal.cpp b/apps/openmw/mwdialogue/journal.cpp index 545e2f3ee..8f84edabc 100644 --- a/apps/openmw/mwdialogue/journal.cpp +++ b/apps/openmw/mwdialogue/journal.cpp @@ -1,6 +1,7 @@ #include "journal.hpp" +#include "../mwworld/environment.hpp" #include namespace MWDialogue @@ -11,6 +12,7 @@ namespace MWDialogue void Journal::addEntry (const std::string& id, int index) { + mJournal.push_back (JournalEntry::makeFromQuest (id, index, *mEnvironment.mWorld)); std::cout << "journal: " << id << " at " << index << std::endl; } diff --git a/apps/openmw/mwdialogue/journalentry.cpp b/apps/openmw/mwdialogue/journalentry.cpp index 8e3aeb93b..6cfee7cf4 100644 --- a/apps/openmw/mwdialogue/journalentry.cpp +++ b/apps/openmw/mwdialogue/journalentry.cpp @@ -5,6 +5,8 @@ #include +#include "../mwworld/world.hpp" + namespace MWDialogue { JournalEntry::JournalEntry() {} @@ -24,4 +26,20 @@ namespace MWDialogue throw std::runtime_error ("unknown info ID " + mInfoId + " for topic " + mTopic); } + + JournalEntry JournalEntry::makeFromQuest (const std::string& topic, int index, + const MWWorld::World& world) + { + const ESM::Dialogue *dialogue = world.getStore().dialogs.find (topic); + + for (std::vector::const_iterator iter (dialogue->mInfo.begin()); + iter!=dialogue->mInfo.end(); ++iter) + if (iter->data.disposition==index) /// \todo cleanup info structure + { + int day = world.getGlobalVariable ("dayspassed").mLong; + return JournalEntry (day, topic, iter->id); + } + + throw std::runtime_error ("unknown journal index for topic " + topic); + } } diff --git a/apps/openmw/mwdialogue/journalentry.hpp b/apps/openmw/mwdialogue/journalentry.hpp index 8506b9dbc..f19e9c52c 100644 --- a/apps/openmw/mwdialogue/journalentry.hpp +++ b/apps/openmw/mwdialogue/journalentry.hpp @@ -8,6 +8,11 @@ namespace ESMS struct ESMStore; } +namespace MWWorld +{ + class World; +} + namespace MWDialogue { /// \brief a quest or dialogue entry with a timestamp @@ -22,6 +27,9 @@ namespace MWDialogue JournalEntry (int day, const std::string& topic, const std::string& infoId); std::string getText (const ESMS::ESMStore& store) const; + + static JournalEntry makeFromQuest (const std::string& topic, int index, + const MWWorld::World& world); }; } From 8915e8a751c26ee7205daedf4aa513de62c32bcc Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 21 Apr 2011 18:10:35 +0200 Subject: [PATCH 17/41] change in multi_es branch broke fps switch; fixed now --- apps/openmw/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 697b06e93..059bf39f7 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -55,7 +55,7 @@ bool parseOptions (int argc, char**argv, OMW::Engine& engine) ->default_value (std::vector(), "") ->multitoken(), "plugin file(s)") - ( "showfps", "show fps counter") + ( "fps", "show fps counter") ( "debug", "debug mode" ) ( "nosound", "disable all sound" ) ( "script-verbose", "verbose script output" ) From f4f12e885f43cf1382340d3288958d2fba114dea Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 21 Apr 2011 18:23:46 +0200 Subject: [PATCH 18/41] all program options (except help) can now be used from a cfg file --- apps/openmw/main.cpp | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 059bf39f7..f6f023592 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -55,12 +55,20 @@ bool parseOptions (int argc, char**argv, OMW::Engine& engine) ->default_value (std::vector(), "") ->multitoken(), "plugin file(s)") - ( "fps", "show fps counter") - ( "debug", "debug mode" ) - ( "nosound", "disable all sound" ) - ( "script-verbose", "verbose script output" ) - ( "new-game", "activate char gen/new game mechanics" ) - ( "script-all", "compile all scripts (excluding dialogue scripts) at startup") + ( "fps", boost::program_options::value()-> + implicit_value (true)->default_value (false), "show fps counter") + ( "debug", boost::program_options::value()-> + implicit_value (true)->default_value (false), "debug mode" ) + ( "nosound", boost::program_options::value()-> + implicit_value (true)->default_value (false), "disable all sound" ) + ( "script-verbose", boost::program_options::value()-> + implicit_value (true)->default_value (false), "verbose script output" ) + ( "new-game", boost::program_options::value()-> + implicit_value (true)->default_value (false), + "activate char gen/new game mechanics" ) + ( "script-all", boost::program_options::value()-> + implicit_value (true)->default_value (false), + "compile all scripts (excluding dialogue scripts) at startup") ; bpo::variables_map variables; @@ -118,23 +126,23 @@ bool parseOptions (int argc, char**argv, OMW::Engine& engine) // startup-settings engine.setCell (variables["start"].as()); - if (variables.count ("new-game")) + if (variables["new-game"].as()==true) engine.setNewGame(); // other settings - if (variables.count ("fps")) + if (variables["fps"].as()==true) engine.showFPS(); - if (variables.count ("debug")) + if (variables["debug"].as()==true) engine.enableDebugMode(); - if (variables.count ("no-sound")) + if (variables["nosound"].as()==true) engine.disableSound(); - if (variables.count ("script-verbose")) + if (variables["script-verbose"].as()==true) engine.enableVerboseScripts(); - if (variables.count ("script-all")) + if (variables["script-all"].as()==true) engine.setCompileAll (true); return true; From 65e43c448a9a31bfdbcc5d7aa5ef6c2da28f2515 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 22 Apr 2011 11:16:39 +0200 Subject: [PATCH 19/41] splitted StampedJournalEntry class off from JournalEntry --- apps/openmw/mwdialogue/journal.cpp | 2 +- apps/openmw/mwdialogue/journal.hpp | 4 ++-- apps/openmw/mwdialogue/journalentry.cpp | 32 +++++++++++++++++++++---- apps/openmw/mwdialogue/journalentry.hpp | 23 +++++++++++++++--- 4 files changed, 51 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwdialogue/journal.cpp b/apps/openmw/mwdialogue/journal.cpp index 8f84edabc..570d32d36 100644 --- a/apps/openmw/mwdialogue/journal.cpp +++ b/apps/openmw/mwdialogue/journal.cpp @@ -12,7 +12,7 @@ namespace MWDialogue void Journal::addEntry (const std::string& id, int index) { - mJournal.push_back (JournalEntry::makeFromQuest (id, index, *mEnvironment.mWorld)); + mJournal.push_back (StampedJournalEntry::makeFromQuest (id, index, *mEnvironment.mWorld)); std::cout << "journal: " << id << " at " << index << std::endl; } diff --git a/apps/openmw/mwdialogue/journal.hpp b/apps/openmw/mwdialogue/journal.hpp index 07090ef4a..6b2b12cac 100644 --- a/apps/openmw/mwdialogue/journal.hpp +++ b/apps/openmw/mwdialogue/journal.hpp @@ -17,13 +17,13 @@ namespace MWDialogue { public: - typedef std::deque TEntryContainer; + typedef std::deque TEntryContainer; typedef TEntryContainer::const_iterator TEntryIter; private: MWWorld::Environment& mEnvironment; - std::deque mJournal; + TEntryContainer mJournal; public: diff --git a/apps/openmw/mwdialogue/journalentry.cpp b/apps/openmw/mwdialogue/journalentry.cpp index 6cfee7cf4..5e9dfa674 100644 --- a/apps/openmw/mwdialogue/journalentry.cpp +++ b/apps/openmw/mwdialogue/journalentry.cpp @@ -11,8 +11,8 @@ namespace MWDialogue { JournalEntry::JournalEntry() {} - JournalEntry::JournalEntry (int day, const std::string& topic, const std::string& infoId) - : mDay (day), mTopic (topic), mInfoId (infoId) + JournalEntry::JournalEntry (const std::string& topic, const std::string& infoId) + : mTopic (topic), mInfoId (infoId) {} std::string JournalEntry::getText (const ESMS::ESMStore& store) const @@ -29,6 +29,12 @@ namespace MWDialogue JournalEntry JournalEntry::makeFromQuest (const std::string& topic, int index, const MWWorld::World& world) + { + return JournalEntry (topic, idFromIndex (topic, index, world)); + } + + std::string JournalEntry::idFromIndex (const std::string& topic, int index, + const MWWorld::World& world) { const ESM::Dialogue *dialogue = world.getStore().dialogs.find (topic); @@ -36,10 +42,28 @@ namespace MWDialogue iter!=dialogue->mInfo.end(); ++iter) if (iter->data.disposition==index) /// \todo cleanup info structure { - int day = world.getGlobalVariable ("dayspassed").mLong; - return JournalEntry (day, topic, iter->id); + iter->id; } throw std::runtime_error ("unknown journal index for topic " + topic); } + + StampedJournalEntry::StampedJournalEntry() + : mDay (0), mMonth (0), mDayOfMonth (0) + {} + + StampedJournalEntry::StampedJournalEntry (const std::string& topic, const std::string& infoId, + int day, int month, int dayOfMonth) + : JournalEntry (topic, infoId), mDay (day), mMonth (month), mDayOfMonth (dayOfMonth) + {} + + StampedJournalEntry StampedJournalEntry::makeFromQuest (const std::string& topic, int index, + const MWWorld::World& world) + { + int day = world.getGlobalVariable ("dayspassed").mLong; + int month = world.getGlobalVariable ("day").mLong; + int dayOfMonth = world.getGlobalVariable ("month").mLong; + + return StampedJournalEntry (topic, idFromIndex (topic, index, world), day, month, dayOfMonth); + } } diff --git a/apps/openmw/mwdialogue/journalentry.hpp b/apps/openmw/mwdialogue/journalentry.hpp index f19e9c52c..058843008 100644 --- a/apps/openmw/mwdialogue/journalentry.hpp +++ b/apps/openmw/mwdialogue/journalentry.hpp @@ -15,23 +15,40 @@ namespace MWWorld namespace MWDialogue { - /// \brief a quest or dialogue entry with a timestamp + /// \brief A quest or dialogue entry struct JournalEntry { - int mDay; std::string mTopic; std::string mInfoId; JournalEntry(); - JournalEntry (int day, const std::string& topic, const std::string& infoId); + JournalEntry (const std::string& topic, const std::string& infoId); std::string getText (const ESMS::ESMStore& store) const; static JournalEntry makeFromQuest (const std::string& topic, int index, const MWWorld::World& world); + + static std::string idFromIndex (const std::string& topic, int index, + const MWWorld::World& world); }; + /// \biref A quest entry with a timestamp. + struct StampedJournalEntry : public JournalEntry + { + int mDay; + int mMonth; + int mDayOfMonth; + + StampedJournalEntry(); + + StampedJournalEntry (const std::string& topic, const std::string& infoId, + int day, int month, int dayOfMonth); + + static StampedJournalEntry makeFromQuest (const std::string& topic, int index, + const MWWorld::World& world); + }; } #endif From 0c4e9d92070c606ce0906572d6783973f286a55a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 24 Apr 2011 12:39:50 +0200 Subject: [PATCH 20/41] create local openmw.cfg file for uninstalled version --- CMakeLists.txt | 6 +++++- files/openmw.cfg.local | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 files/openmw.cfg.local diff --git a/CMakeLists.txt b/CMakeLists.txt index 22ba839b2..3273ccef8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -336,6 +336,10 @@ endif (APPLE) # Other files +configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg.local + "${OpenMW_BINARY_DIR}/openmw.cfg" COPYONLY) + + if (WIN32) configure_file(${OpenMW_SOURCE_DIR}/files/plugins.cfg.win32 "${OpenMW_BINARY_DIR}/plugins.cfg" COPYONLY) @@ -424,7 +428,7 @@ if(DPKG_PROGRAM) endif() #Install global configuration files - INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg" DESTINATION "../etc/openmw/" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") + INSTALL(FILES "${OpenMW_SOURCE_DIR}/openmw.cfg" DESTINATION "../etc/openmw/" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") INSTALL(FILES "${OpenMW_BINARY_DIR}/plugins.cfg" DESTINATION "../etc/openmw/" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") #Install resources diff --git a/files/openmw.cfg.local b/files/openmw.cfg.local new file mode 100644 index 000000000..dd116e108 --- /dev/null +++ b/files/openmw.cfg.local @@ -0,0 +1,2 @@ +data=./data +resources=./resources From 573090a07fb747f7a7399c0c305b3fabcb9aa3a4 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 24 Apr 2011 12:41:55 +0200 Subject: [PATCH 21/41] improved description of openmw.cfg related cmake-variable --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3273ccef8..8de24f57f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,15 +14,15 @@ find_program(DPKG_PROGRAM dpkg DOC "dpkg program of Debian-based systems") # Location of morrowind data files if(DPKG_PROGRAM) set(MORROWIND_DATA_FILES "/usr/share/games/openmw/data/" CACHE PATH "location of Morrowind data files") - set(MORROWIND_RESOURCE_FILES "/usr/share/games/openmw/resources/" CACHE PATH "location of Morrowind data files") + set(MORROWIND_RESOURCE_FILES "/usr/share/games/openmw/resources/" CACHE PATH "location of OpenMW resources files") else() if (APPLE) # set path inside bundle set(MORROWIND_DATA_FILES "../data" CACHE PATH "location of Morrowind data files") - set(MORROWIND_RESOURCE_FILES "Contents/Resources/resources" CACHE PATH "location of Morrowind data files") + set(MORROWIND_RESOURCE_FILES "Contents/Resources/resources" CACHE PATH "location of OpenMW resources files") else() set(MORROWIND_DATA_FILES "data" CACHE PATH "location of Morrowind data files") - set(MORROWIND_RESOURCE_FILES "resources" CACHE PATH "location of Morrowind data files") + set(MORROWIND_RESOURCE_FILES "resources" CACHE PATH "location of OpenMW resources files") endif(APPLE) endif(DPKG_PROGRAM) From 944291d34fa06706de59adf95eb1d812ecf85802 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 26 Apr 2011 20:08:37 +0200 Subject: [PATCH 22/41] added quest tracking to the journal --- apps/openmw/CMakeLists.txt | 2 + apps/openmw/mwdialogue/journal.cpp | 40 +++++++++-- apps/openmw/mwdialogue/journal.hpp | 14 ++++ apps/openmw/mwdialogue/journalentry.hpp | 2 +- apps/openmw/mwdialogue/quest.cpp | 96 +++++++++++++++++++++++++ apps/openmw/mwdialogue/quest.hpp | 60 ++++++++++++++++ 6 files changed, 209 insertions(+), 5 deletions(-) create mode 100644 apps/openmw/mwdialogue/quest.cpp create mode 100644 apps/openmw/mwdialogue/quest.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 63add2fce..8fa6d6591 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -72,11 +72,13 @@ set(GAMEDIALOGUE_HEADER mwdialogue/dialoguemanager.hpp mwdialogue/journal.hpp mwdialogue/journalentry.hpp + mwdialogue/quest.hpp ) set(GAMEDIALOGUE mwdialogue/dialoguemanager.cpp mwdialogue/journal.cpp mwdialogue/journalentry.cpp + mwdialogue/quest.cpp ) source_group(apps\\openmw\\mwdialogue FILES ${GAMEDIALOGUE_HEADER} ${GAMEDIALOGUE}) diff --git a/apps/openmw/mwdialogue/journal.cpp b/apps/openmw/mwdialogue/journal.cpp index 570d32d36..b1d85f729 100644 --- a/apps/openmw/mwdialogue/journal.cpp +++ b/apps/openmw/mwdialogue/journal.cpp @@ -3,22 +3,44 @@ #include "../mwworld/environment.hpp" -#include namespace MWDialogue { + Quest& Journal::getQuest (const std::string& id) + { + TQuestContainer::iterator iter = mQuests.find (id); + + if (iter==mQuests.end()) + { + std::pair result = + mQuests.insert (std::make_pair (id, Quest (id))); + + iter = result.first; + } + + return iter->second; + } + Journal::Journal (MWWorld::Environment& environment) : mEnvironment (environment) {} void Journal::addEntry (const std::string& id, int index) { - mJournal.push_back (StampedJournalEntry::makeFromQuest (id, index, *mEnvironment.mWorld)); - std::cout << "journal: " << id << " at " << index << std::endl; + StampedJournalEntry entry = + StampedJournalEntry::makeFromQuest (id, index, *mEnvironment.mWorld); + + mJournal.push_back (entry); + + Quest& quest = getQuest (id); + + quest.addEntry (entry, *mEnvironment.mWorld); // we are doing slicing on purpose here } void Journal::setJournalIndex (const std::string& id, int index) { - std::cout << "journal (no entry): " << id << " at " << index << std::endl; + Quest& quest = getQuest (id); + + quest.setIndex (index, *mEnvironment.mWorld); } int Journal::getJournalIndex (const std::string& id) const @@ -35,4 +57,14 @@ namespace MWDialogue { return mJournal.end(); } + + Journal::TQuestIter Journal::questBegin() const + { + return mQuests.begin(); + } + + Journal::TQuestIter Journal::questEnd() const + { + return mQuests.end(); + } } diff --git a/apps/openmw/mwdialogue/journal.hpp b/apps/openmw/mwdialogue/journal.hpp index 6b2b12cac..5477ae5a5 100644 --- a/apps/openmw/mwdialogue/journal.hpp +++ b/apps/openmw/mwdialogue/journal.hpp @@ -3,8 +3,10 @@ #include #include +#include #include "journalentry.hpp" +#include "quest.hpp" namespace MWWorld { @@ -13,17 +15,23 @@ namespace MWWorld namespace MWDialogue { + /// \brief The player's journal class Journal { public: typedef std::deque TEntryContainer; typedef TEntryContainer::const_iterator TEntryIter; + typedef std::map TQuestContainer; // topc, quest + typedef TQuestContainer::const_iterator TQuestIter; private: MWWorld::Environment& mEnvironment; TEntryContainer mJournal; + TQuestContainer mQuests; + + Quest& getQuest (const std::string& id); public: @@ -45,6 +53,12 @@ namespace MWDialogue TEntryIter end() const; ///< Iterator pointing past the end of the main journal. + + TQuestIter questBegin() const; + ///< Iterator pointing to the first quest (sorted by topic ID) + + TQuestIter questEnd() const; + ///< Iterator pointing past the last quest. }; } diff --git a/apps/openmw/mwdialogue/journalentry.hpp b/apps/openmw/mwdialogue/journalentry.hpp index 058843008..11b715630 100644 --- a/apps/openmw/mwdialogue/journalentry.hpp +++ b/apps/openmw/mwdialogue/journalentry.hpp @@ -1,5 +1,5 @@ #ifndef GAME_MMDIALOGUE_JOURNALENTRY_H -#define GAME_MWDIALOGUE_JOURNALENTRY_H +#define GAME_MMDIALOGUE_JOURNALENTRY_H #include diff --git a/apps/openmw/mwdialogue/quest.cpp b/apps/openmw/mwdialogue/quest.cpp new file mode 100644 index 000000000..13e432762 --- /dev/null +++ b/apps/openmw/mwdialogue/quest.cpp @@ -0,0 +1,96 @@ + +#include "quest.hpp" + +#include + +#include "../mwworld/world.hpp" + +namespace MWDialogue +{ + Quest::Quest() + : mIndex (0), mFinished (false) + {} + + Quest::Quest (const std::string& topic) + : mTopic (topic), mIndex (0), mFinished (false) + {} + + const std::string Quest::getName (const MWWorld::World& world) const + { + const ESM::Dialogue *dialogue = world.getStore().dialogs.find (mTopic); + + for (std::vector::const_iterator iter (dialogue->mInfo.begin()); + iter!=dialogue->mInfo.end(); ++iter) + if (iter->questStatus==ESM::DialInfo::QS_Name) + return iter->response; + + return ""; + } + + int Quest::getIndex() const + { + return mIndex; + } + + void Quest::setIndex (int index, const MWWorld::World& world) + { + const ESM::Dialogue *dialogue = world.getStore().dialogs.find (mTopic); + + for (std::vector::const_iterator iter (dialogue->mInfo.begin()); + iter!=dialogue->mInfo.end(); ++iter) + if (iter->data.disposition==index && iter->questStatus!=ESM::DialInfo::QS_Name) + { + mIndex = index; + + if (iter->questStatus==ESM::DialInfo::QS_Finished) + mFinished = true; + else if (iter->questStatus==ESM::DialInfo::QS_Restart) + mFinished = false; + + return; + } + + throw std::runtime_error ("unknown journal index for topic " + mTopic); + } + + bool Quest::isFinished() const + { + return mFinished; + } + + void Quest::addEntry (const JournalEntry& entry, const MWWorld::World& world) + { + int index = -1; + + const ESM::Dialogue *dialogue = world.getStore().dialogs.find (entry.mTopic); + + for (std::vector::const_iterator iter (dialogue->mInfo.begin()); + iter!=dialogue->mInfo.end(); ++iter) + if (iter->id==entry.mInfoId) + { + index = iter->data.disposition; /// \todo cleanup info structure + break; + } + + if (index==-1) + throw std::runtime_error ("unknown journal entry for topic " + mTopic); + + setIndex (index, world); + + for (TEntryIter iter (mEntries.begin()); iter!=mEntries.end(); ++iter) + if (iter->mInfoId==entry.mInfoId) + return; + + mEntries.push_back (entry); + } + + Quest::TEntryIter Quest::begin() + { + return mEntries.begin(); + } + + Quest::TEntryIter Quest::end() + { + return mEntries.end(); + } +} diff --git a/apps/openmw/mwdialogue/quest.hpp b/apps/openmw/mwdialogue/quest.hpp new file mode 100644 index 000000000..f484dfaf7 --- /dev/null +++ b/apps/openmw/mwdialogue/quest.hpp @@ -0,0 +1,60 @@ +#ifndef GAME_MMDIALOG_QUEST_H +#define GAME_MWDIALOG_QUEST_H + +#include +#include + +#include "journalentry.hpp" + +namespace MWWorld +{ + class World; +} + +namespace MWDialogue +{ + /// \brief A quest in progress or a compelted quest + class Quest + { + public: + + typedef std::vector TEntryContainer; + typedef TEntryContainer::const_iterator TEntryIter; + + private: + + std::string mTopic; + int mIndex; + std::vector mEntries; + bool mFinished; + + public: + + Quest(); + + Quest (const std::string& topic); + + const std::string getName (const MWWorld::World& world) const; + ///< May be an empty string + + int getIndex() const; + + void setIndex (int index, const MWWorld::World& world); + ///< Calling this function with a non-existant index while throw an exception. + + bool isFinished() const; + + void addEntry (const JournalEntry& entry, const MWWorld::World& world); + ///< Add entry and adjust index accordingly. + /// + /// \note Redundant entries are ignored, but the index is still adjusted. + + TEntryIter begin(); + ///< Iterator pointing to the begin of the journal for this quest. + + TEntryIter end(); + ///< Iterator pointing past the end of the journal for this quest. + }; +} + +#endif From 3406d2fa89234cddd542a8ef97ddd1f107664a22 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 26 Apr 2011 20:22:50 +0200 Subject: [PATCH 23/41] removed redundant data from quest class --- apps/openmw/mwdialogue/quest.cpp | 9 +++++++-- apps/openmw/mwdialogue/quest.hpp | 6 ++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwdialogue/quest.cpp b/apps/openmw/mwdialogue/quest.cpp index 13e432762..d47c78c6e 100644 --- a/apps/openmw/mwdialogue/quest.cpp +++ b/apps/openmw/mwdialogue/quest.cpp @@ -78,10 +78,10 @@ namespace MWDialogue setIndex (index, world); for (TEntryIter iter (mEntries.begin()); iter!=mEntries.end(); ++iter) - if (iter->mInfoId==entry.mInfoId) + if (*iter==entry.mInfoId) return; - mEntries.push_back (entry); + mEntries.push_back (entry.mInfoId); } Quest::TEntryIter Quest::begin() @@ -93,4 +93,9 @@ namespace MWDialogue { return mEntries.end(); } + + JournalEntry Quest::getEntry (const std::string& infoId) + { + return JournalEntry (mTopic, infoId); + } } diff --git a/apps/openmw/mwdialogue/quest.hpp b/apps/openmw/mwdialogue/quest.hpp index f484dfaf7..9f173f6d3 100644 --- a/apps/openmw/mwdialogue/quest.hpp +++ b/apps/openmw/mwdialogue/quest.hpp @@ -18,14 +18,14 @@ namespace MWDialogue { public: - typedef std::vector TEntryContainer; + typedef std::vector TEntryContainer; typedef TEntryContainer::const_iterator TEntryIter; private: std::string mTopic; int mIndex; - std::vector mEntries; + TEntryContainer mEntries; // info-IDs bool mFinished; public: @@ -54,6 +54,8 @@ namespace MWDialogue TEntryIter end(); ///< Iterator pointing past the end of the journal for this quest. + + JournalEntry getEntry (const std::string& infoId); }; } From 7a1b215b6abdf00d36d5bba9341a9c0b9ac7a6e5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 26 Apr 2011 20:39:59 +0200 Subject: [PATCH 24/41] splitting of topic class from quest class --- apps/openmw/CMakeLists.txt | 2 ++ apps/openmw/mwdialogue/quest.cpp | 19 ++---------- apps/openmw/mwdialogue/quest.hpp | 31 ++----------------- apps/openmw/mwdialogue/topic.cpp | 46 ++++++++++++++++++++++++++++ apps/openmw/mwdialogue/topic.hpp | 52 ++++++++++++++++++++++++++++++++ 5 files changed, 105 insertions(+), 45 deletions(-) create mode 100644 apps/openmw/mwdialogue/topic.cpp create mode 100644 apps/openmw/mwdialogue/topic.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 8fa6d6591..3145082ed 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -73,12 +73,14 @@ set(GAMEDIALOGUE_HEADER mwdialogue/journal.hpp mwdialogue/journalentry.hpp mwdialogue/quest.hpp + mwdialogue/topic.hpp ) set(GAMEDIALOGUE mwdialogue/dialoguemanager.cpp mwdialogue/journal.cpp mwdialogue/journalentry.cpp mwdialogue/quest.cpp + mwdialogue/topic.cpp ) source_group(apps\\openmw\\mwdialogue FILES ${GAMEDIALOGUE_HEADER} ${GAMEDIALOGUE}) diff --git a/apps/openmw/mwdialogue/quest.cpp b/apps/openmw/mwdialogue/quest.cpp index d47c78c6e..1f387e862 100644 --- a/apps/openmw/mwdialogue/quest.cpp +++ b/apps/openmw/mwdialogue/quest.cpp @@ -8,11 +8,11 @@ namespace MWDialogue { Quest::Quest() - : mIndex (0), mFinished (false) + : Topic(), mIndex (0), mFinished (false) {} Quest::Quest (const std::string& topic) - : mTopic (topic), mIndex (0), mFinished (false) + : Topic (topic), mIndex (0), mFinished (false) {} const std::string Quest::getName (const MWWorld::World& world) const @@ -83,19 +83,4 @@ namespace MWDialogue mEntries.push_back (entry.mInfoId); } - - Quest::TEntryIter Quest::begin() - { - return mEntries.begin(); - } - - Quest::TEntryIter Quest::end() - { - return mEntries.end(); - } - - JournalEntry Quest::getEntry (const std::string& infoId) - { - return JournalEntry (mTopic, infoId); - } } diff --git a/apps/openmw/mwdialogue/quest.hpp b/apps/openmw/mwdialogue/quest.hpp index 9f173f6d3..c162c03f4 100644 --- a/apps/openmw/mwdialogue/quest.hpp +++ b/apps/openmw/mwdialogue/quest.hpp @@ -1,31 +1,14 @@ #ifndef GAME_MMDIALOG_QUEST_H #define GAME_MWDIALOG_QUEST_H -#include -#include - -#include "journalentry.hpp" - -namespace MWWorld -{ - class World; -} +#include "topic.hpp" namespace MWDialogue { /// \brief A quest in progress or a compelted quest - class Quest + class Quest : public Topic { - public: - - typedef std::vector TEntryContainer; - typedef TEntryContainer::const_iterator TEntryIter; - - private: - - std::string mTopic; int mIndex; - TEntryContainer mEntries; // info-IDs bool mFinished; public: @@ -44,18 +27,10 @@ namespace MWDialogue bool isFinished() const; - void addEntry (const JournalEntry& entry, const MWWorld::World& world); + virtual void addEntry (const JournalEntry& entry, const MWWorld::World& world); ///< Add entry and adjust index accordingly. /// /// \note Redundant entries are ignored, but the index is still adjusted. - - TEntryIter begin(); - ///< Iterator pointing to the begin of the journal for this quest. - - TEntryIter end(); - ///< Iterator pointing past the end of the journal for this quest. - - JournalEntry getEntry (const std::string& infoId); }; } diff --git a/apps/openmw/mwdialogue/topic.cpp b/apps/openmw/mwdialogue/topic.cpp new file mode 100644 index 000000000..8f165d3c8 --- /dev/null +++ b/apps/openmw/mwdialogue/topic.cpp @@ -0,0 +1,46 @@ + +#include "topic.hpp" + +#include + +#include "../mwworld/world.hpp" + +namespace MWDialogue +{ + Topic::Topic() + {} + + Topic::Topic (const std::string& topic) + : mTopic (topic) + {} + + Topic::~Topic() + {} + + void Topic::addEntry (const JournalEntry& entry, const MWWorld::World& world) + { + if (entry.mTopic!=mTopic) + throw std::runtime_error ("topic does not match: " + mTopic); + + for (TEntryIter iter = begin(); iter!=end(); ++iter) + if (*iter==entry.mInfoId) + return; + + mEntries.push_back (entry.mInfoId); + } + + Topic::TEntryIter Topic::begin() + { + return mEntries.begin(); + } + + Topic::TEntryIter Topic::end() + { + return mEntries.end(); + } + + JournalEntry Topic::getEntry (const std::string& infoId) + { + return JournalEntry (mTopic, infoId); + } +} diff --git a/apps/openmw/mwdialogue/topic.hpp b/apps/openmw/mwdialogue/topic.hpp new file mode 100644 index 000000000..c085f1ed9 --- /dev/null +++ b/apps/openmw/mwdialogue/topic.hpp @@ -0,0 +1,52 @@ +#ifndef GAME_MMDIALOG_TOPIC_H +#define GAME_MWDIALOG_TOPIC_H + +#include +#include + +#include "journalentry.hpp" + +namespace MWWorld +{ + class World; +} + +namespace MWDialogue +{ + /// \brief Collection of seen responses for a topic + class Topic + { + public: + + typedef std::vector TEntryContainer; + typedef TEntryContainer::const_iterator TEntryIter; + + protected: + + std::string mTopic; + TEntryContainer mEntries; // info-IDs + + public: + + Topic(); + + Topic (const std::string& topic); + + virtual ~Topic(); + + virtual void addEntry (const JournalEntry& entry, const MWWorld::World& world); + ///< Add entry + /// + /// \note Redundant entries are ignored. + + TEntryIter begin(); + ///< Iterator pointing to the begin of the journal for this topic. + + TEntryIter end(); + ///< Iterator pointing past the end of the journal for this topic. + + JournalEntry getEntry (const std::string& infoId); + }; +} + +#endif From e18dde45711c99be9954e69aa348096b652ae2a3 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 26 Apr 2011 20:48:36 +0200 Subject: [PATCH 25/41] added topic tracking --- apps/openmw/mwdialogue/journal.cpp | 25 +++++++++++++++++++++++++ apps/openmw/mwdialogue/journal.hpp | 13 +++++++++++++ 2 files changed, 38 insertions(+) diff --git a/apps/openmw/mwdialogue/journal.cpp b/apps/openmw/mwdialogue/journal.cpp index b1d85f729..42cce5cf5 100644 --- a/apps/openmw/mwdialogue/journal.cpp +++ b/apps/openmw/mwdialogue/journal.cpp @@ -43,6 +43,21 @@ namespace MWDialogue quest.setIndex (index, *mEnvironment.mWorld); } + void Journal::addTopic (const std::string& topicId, const std::string& infoId) + { + TTopicContainer::iterator iter = mTopics.find (topicId); + + if (iter==mTopics.end()) + { + std::pair result + = mTopics.insert (std::make_pair (topicId, Topic (topicId))); + + iter = result.first; + } + + iter->second.addEntry (JournalEntry (topicId, infoId), *mEnvironment.mWorld); + } + int Journal::getJournalIndex (const std::string& id) const { return 0; @@ -67,4 +82,14 @@ namespace MWDialogue { return mQuests.end(); } + + Journal::TTopicIter Journal::topicBegin() const + { + return mTopics.begin(); + } + + Journal::TTopicIter Journal::topicEnd() const + { + return mTopics.end(); + } } diff --git a/apps/openmw/mwdialogue/journal.hpp b/apps/openmw/mwdialogue/journal.hpp index 5477ae5a5..ff1343945 100644 --- a/apps/openmw/mwdialogue/journal.hpp +++ b/apps/openmw/mwdialogue/journal.hpp @@ -24,12 +24,15 @@ namespace MWDialogue typedef TEntryContainer::const_iterator TEntryIter; typedef std::map TQuestContainer; // topc, quest typedef TQuestContainer::const_iterator TQuestIter; + typedef std::map TTopicContainer; // topic-id, topic-content + typedef TTopicContainer::const_iterator TTopicIter; private: MWWorld::Environment& mEnvironment; TEntryContainer mJournal; TQuestContainer mQuests; + TTopicContainer mTopics; Quest& getQuest (const std::string& id); @@ -46,6 +49,8 @@ namespace MWDialogue int getJournalIndex (const std::string& id) const; ///< Get the journal index. + void addTopic (const std::string& topicId, const std::string& infoId); + TEntryIter begin() const; ///< Iterator pointing to the begin of the main journal. /// @@ -59,6 +64,14 @@ namespace MWDialogue TQuestIter questEnd() const; ///< Iterator pointing past the last quest. + + TTopicIter topicBegin() const; + ///< Iterator pointing to the first topic (sorted by topic ID) + /// + /// \note The topic ID is identical with the user-visible topic string. + + TTopicIter topicEnd() const; + ///< Iterator pointing past the last topic. }; } From f52e6bd5ef9dad530134a39ba1446b64caab6755 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 26 Apr 2011 21:38:21 +0200 Subject: [PATCH 26/41] made toggle-type script instructions more verbose --- apps/openmw/mwrender/mwscene.cpp | 13 +++-- apps/openmw/mwrender/mwscene.hpp | 6 ++- apps/openmw/mwscript/controlextensions.cpp | 4 +- apps/openmw/mwscript/miscextensions.cpp | 6 ++- apps/openmw/mwscript/skyextensions.cpp | 55 +++++++++++----------- apps/openmw/mwworld/world.cpp | 12 +++-- apps/openmw/mwworld/world.hpp | 9 ++-- 7 files changed, 63 insertions(+), 42 deletions(-) diff --git a/apps/openmw/mwrender/mwscene.cpp b/apps/openmw/mwrender/mwscene.cpp index 890bf2cd6..e4d449bf2 100644 --- a/apps/openmw/mwrender/mwscene.cpp +++ b/apps/openmw/mwrender/mwscene.cpp @@ -191,7 +191,7 @@ void MWScene::scaleObject (const std::string& handle, float scale) } -void MWScene::toggleCollisionMode() +bool MWScene::toggleCollisionMode() { for(std::map::iterator it = eng->PhysicActorMap.begin(); it != eng->PhysicActorMap.end();it++) { @@ -203,6 +203,7 @@ void MWScene::toggleCollisionMode() act->setGravity(0.); act->setVerticalVelocity(0); mFreeFly = true; + return false; } else { @@ -210,11 +211,15 @@ void MWScene::toggleCollisionMode() act->enableCollisions(true); act->setGravity(4.); act->setVerticalVelocity(0); + return true; } } + + return false; // This should never happen, but it shall not bother us now, since + // this part of the code needs a rewrite anyway. } -void MWScene::toggleRenderMode (int mode) +bool MWScene::toggleRenderMode (int mode) { switch (mode) { @@ -223,6 +228,8 @@ void MWScene::toggleRenderMode (int mode) // TODO use a proper function instead of accessing the member variable // directly. eng->setDebugRenderingMode (!eng->isDebugCreated); - break; + return eng->isDebugCreated; } + + return false; } diff --git a/apps/openmw/mwrender/mwscene.hpp b/apps/openmw/mwrender/mwscene.hpp index fd14fcce0..7429ff21e 100644 --- a/apps/openmw/mwrender/mwscene.hpp +++ b/apps/openmw/mwrender/mwscene.hpp @@ -91,12 +91,14 @@ namespace MWRender /// Toggle collision mode for player. If disabled player object should ignore /// collisions and gravity. - void toggleCollisionMode(); + /// \return Resulting mode + bool toggleCollisionMode(); /// Toggle render mode /// \todo Using an int instead of a enum here to avoid cyclic includes. Will be fixed /// when the mw*-refactoring is done. - void toggleRenderMode (int mode); + /// \return Resulting mode + bool toggleRenderMode (int mode); }; } diff --git a/apps/openmw/mwscript/controlextensions.cpp b/apps/openmw/mwscript/controlextensions.cpp index e687b1352..3d65c5705 100644 --- a/apps/openmw/mwscript/controlextensions.cpp +++ b/apps/openmw/mwscript/controlextensions.cpp @@ -46,7 +46,9 @@ namespace MWScript InterpreterContext& context = static_cast (runtime.getContext()); - context.getWorld().toggleCollisionMode(); + bool enabled = context.getWorld().toggleCollisionMode(); + + context.messageBox (enabled ? "Collsion -> On" : "Collision -> Off"); } }; diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 9bfb8774d..e1c9eae3b 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -99,7 +99,11 @@ namespace MWScript InterpreterContext& context = static_cast (runtime.getContext()); - context.getWorld().toggleRenderMode (MWWorld::World::Render_CollisionDebug); + bool enabled = + context.getWorld().toggleRenderMode (MWWorld::World::Render_CollisionDebug); + + context.messageBox (enabled ? + "Collsion Mesh Rendering -> On" : "Collision Mesh Rendering -> Off"); } }; diff --git a/apps/openmw/mwscript/skyextensions.cpp b/apps/openmw/mwscript/skyextensions.cpp index f53168240..1a761e3bb 100644 --- a/apps/openmw/mwscript/skyextensions.cpp +++ b/apps/openmw/mwscript/skyextensions.cpp @@ -16,68 +16,70 @@ namespace MWScript class OpToggleSky : public Interpreter::Opcode0 { public: - + virtual void execute (Interpreter::Runtime& runtime) { InterpreterContext& context = static_cast (runtime.getContext()); - - context.getWorld().toggleSky(); - } - }; - + + bool enabled = context.getWorld().toggleSky(); + + context.messageBox (enabled ? "Sky -> On" : "Sky -> Off"); + } + }; + class OpTurnMoonWhite : public Interpreter::Opcode0 { public: - + virtual void execute (Interpreter::Runtime& runtime) { InterpreterContext& context = static_cast (runtime.getContext()); - + context.getWorld().setMoonColour (false); - } - }; + } + }; class OpTurnMoonRed : public Interpreter::Opcode0 { public: - + virtual void execute (Interpreter::Runtime& runtime) { InterpreterContext& context = static_cast (runtime.getContext()); - + context.getWorld().setMoonColour (true); - } - }; - + } + }; + class OpGetMasserPhase : public Interpreter::Opcode0 { public: - + virtual void execute (Interpreter::Runtime& runtime) { InterpreterContext& context = static_cast (runtime.getContext()); - + runtime.push (context.getWorld().getMasserPhase()); - } - }; + } + }; class OpGetSecundaPhase : public Interpreter::Opcode0 { public: - + virtual void execute (Interpreter::Runtime& runtime) { InterpreterContext& context = static_cast (runtime.getContext()); - + runtime.push (context.getWorld().getSecundaPhase()); - } - }; - + } + }; + const int opcodeToggleSky = 0x2000021; const int opcodeTurnMoonWhite = 0x2000022; const int opcodeTurnMoonRed = 0x2000023; @@ -93,7 +95,7 @@ namespace MWScript extensions.registerFunction ("getmasserphase", 'l', "", opcodeGetMasserPhase); extensions.registerFunction ("getsecundaphase", 'l', "", opcodeGetSecundaPhase); } - + void installOpcodes (Interpreter::Interpreter& interpreter) { interpreter.installSegment5 (opcodeToggleSky, new OpToggleSky); @@ -101,7 +103,6 @@ namespace MWScript interpreter.installSegment5 (opcodeTurnMoonRed, new OpTurnMoonRed); interpreter.installSegment5 (opcodeGetMasserPhase, new OpGetMasserPhase); interpreter.installSegment5 (opcodeGetSecundaPhase, new OpGetSecundaPhase); - } + } } } - diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index 63019349c..a4001169d 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -645,12 +645,13 @@ namespace MWWorld mSkyManager->setDate (mGlobalVariables->getInt ("day"), month); } - void World::toggleSky() + bool World::toggleSky() { if (mSky) { mSky = false; mSkyManager->disable(); + return false; } else { @@ -660,6 +661,7 @@ namespace MWWorld mSkyManager->setDate (mGlobalVariables->getInt ("day"), mGlobalVariables->getInt ("month")); mSkyManager->enable(); + return true; } } @@ -853,13 +855,13 @@ namespace MWWorld mScene.doPhysics (duration, *this, actors); } - void World::toggleCollisionMode() + bool World::toggleCollisionMode() { - mScene.toggleCollisionMode(); + return mScene.toggleCollisionMode(); } - void World::toggleRenderMode (RenderMode mode) + bool World::toggleRenderMode (RenderMode mode) { - mScene.toggleRenderMode (mode); + return mScene.toggleRenderMode (mode); } } diff --git a/apps/openmw/mwworld/world.hpp b/apps/openmw/mwworld/world.hpp index 6965aebc6..739353394 100644 --- a/apps/openmw/mwworld/world.hpp +++ b/apps/openmw/mwworld/world.hpp @@ -147,7 +147,8 @@ namespace MWWorld void setDay (int day); - void toggleSky(); + bool toggleSky(); + ///< \return Resulting mode int getMasserPhase() const; @@ -185,12 +186,14 @@ namespace MWWorld float duration); ///< Run physics simulation and modify \a world accordingly. - void toggleCollisionMode(); + bool toggleCollisionMode(); ///< Toggle collision mode for player. If disabled player object should ignore /// collisions and gravity. + ///< \return Resulting mode - void toggleRenderMode (RenderMode mode); + bool toggleRenderMode (RenderMode mode); ///< Toggle a render mode. + ///< \return Resulting mode }; } From 125319c441559378993437059756236c78236a8a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 26 Apr 2011 21:48:13 +0200 Subject: [PATCH 27/41] splitting off console output from messageBox channel --- apps/openmw/mwgui/console.cpp | 7 ++++ apps/openmw/mwscript/controlextensions.cpp | 2 +- apps/openmw/mwscript/interpretercontext.cpp | 5 +++ apps/openmw/mwscript/interpretercontext.hpp | 4 ++ apps/openmw/mwscript/miscextensions.cpp | 2 +- apps/openmw/mwscript/skyextensions.cpp | 2 +- components/interpreter/context.hpp | 42 ++++++++++----------- 7 files changed, 40 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index 836a0f0db..0421dc370 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -17,6 +17,8 @@ namespace MWGui ConsoleInterpreterContext (Console& console, MWWorld::Environment& environment, MWWorld::Ptr reference); + + virtual void report (const std::string& message); }; ConsoleInterpreterContext::ConsoleInterpreterContext (Console& console, @@ -26,6 +28,11 @@ namespace MWGui mConsole (console) {} + void ConsoleInterpreterContext::report (const std::string& message) + { + mConsole.printOK (message); + } + bool Console::compile (const std::string& cmd, Compiler::Output& output) { try diff --git a/apps/openmw/mwscript/controlextensions.cpp b/apps/openmw/mwscript/controlextensions.cpp index 3d65c5705..893af259f 100644 --- a/apps/openmw/mwscript/controlextensions.cpp +++ b/apps/openmw/mwscript/controlextensions.cpp @@ -48,7 +48,7 @@ namespace MWScript bool enabled = context.getWorld().toggleCollisionMode(); - context.messageBox (enabled ? "Collsion -> On" : "Collision -> Off"); + context.report (enabled ? "Collsion -> On" : "Collision -> Off"); } }; diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index cb6ecb218..77a71a1d4 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -110,6 +110,11 @@ namespace MWScript mEnvironment.mWindowManager->messageBox (message, buttons); } + void InterpreterContext::report (const std::string& message) + { + messageBox (message); + } + bool InterpreterContext::menuMode() { return mEnvironment.mWindowManager->isGuiMode(); diff --git a/apps/openmw/mwscript/interpretercontext.hpp b/apps/openmw/mwscript/interpretercontext.hpp index aebfc620e..35b4a169d 100644 --- a/apps/openmw/mwscript/interpretercontext.hpp +++ b/apps/openmw/mwscript/interpretercontext.hpp @@ -57,9 +57,13 @@ namespace MWScript virtual void setLocalFloat (int index, float value); using Interpreter::Context::messageBox; + virtual void messageBox (const std::string& message, const std::vector& buttons); + virtual void report (const std::string& message); + ///< By default echo via messageBox. + virtual bool menuMode(); virtual int getGlobalShort (const std::string& name) const; diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index e1c9eae3b..d8dfbdde4 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -102,7 +102,7 @@ namespace MWScript bool enabled = context.getWorld().toggleRenderMode (MWWorld::World::Render_CollisionDebug); - context.messageBox (enabled ? + context.report (enabled ? "Collsion Mesh Rendering -> On" : "Collision Mesh Rendering -> Off"); } }; diff --git a/apps/openmw/mwscript/skyextensions.cpp b/apps/openmw/mwscript/skyextensions.cpp index 1a761e3bb..caa07c095 100644 --- a/apps/openmw/mwscript/skyextensions.cpp +++ b/apps/openmw/mwscript/skyextensions.cpp @@ -24,7 +24,7 @@ namespace MWScript bool enabled = context.getWorld().toggleSky(); - context.messageBox (enabled ? "Sky -> On" : "Sky -> Off"); + context.report (enabled ? "Sky -> On" : "Sky -> Off"); } }; diff --git a/components/interpreter/context.hpp b/components/interpreter/context.hpp index 0d77903f4..973b22d35 100644 --- a/components/interpreter/context.hpp +++ b/components/interpreter/context.hpp @@ -18,21 +18,23 @@ namespace Interpreter virtual float getLocalFloat (int index) const = 0; - virtual void setLocalShort (int index, int value) = 0; + virtual void setLocalShort (int index, int value) = 0; - virtual void setLocalLong (int index, int value) = 0; + virtual void setLocalLong (int index, int value) = 0; virtual void setLocalFloat (int index, float value) = 0; - + virtual void messageBox (const std::string& message, - const std::vector& buttons) = 0; - + const std::vector& buttons) = 0; + void messageBox (const std::string& message) { std::vector empty; messageBox (message, empty); } - + + virtual void report (const std::string& message) = 0; + virtual bool menuMode() = 0; virtual int getGlobalShort (const std::string& name) const = 0; @@ -41,31 +43,29 @@ namespace Interpreter virtual float getGlobalFloat (const std::string& name) const = 0; - virtual void setGlobalShort (const std::string& name, int value) = 0; + virtual void setGlobalShort (const std::string& name, int value) = 0; - virtual void setGlobalLong (const std::string& name, int value) = 0; + virtual void setGlobalLong (const std::string& name, int value) = 0; + + virtual void setGlobalFloat (const std::string& name, float value) = 0; - virtual void setGlobalFloat (const std::string& name, float value) = 0; - virtual bool isScriptRunning (const std::string& name) const = 0; - + virtual void startScript (const std::string& name) = 0; - + virtual void stopScript (const std::string& name) = 0; - + virtual float getDistance (const std::string& name, const std::string& id = "") const - = 0; - + = 0; + virtual float getSecondsPassed() const = 0; - + virtual bool isDisabled (const std::string& id = "") const = 0; - + virtual void enable (const std::string& id = "") = 0; - - virtual void disable (const std::string& id = "") = 0; + + virtual void disable (const std::string& id = "") = 0; }; } #endif - - From 861dc6a16e7f52d44e8877c11f581929b1ad43bb Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 26 Apr 2011 22:07:27 +0200 Subject: [PATCH 28/41] redirecting output of expression evalutation to new report channel --- components/compiler/generator.cpp | 13 +++ components/compiler/generator.hpp | 2 + components/compiler/lineparser.cpp | 4 +- components/interpreter/docs/vmformat.txt | 6 +- components/interpreter/installopcodes.cpp | 2 +- components/interpreter/miscopcodes.hpp | 135 +++++++++++++--------- 6 files changed, 103 insertions(+), 59 deletions(-) diff --git a/components/compiler/generator.cpp b/components/compiler/generator.cpp index 3d3b21d65..ee9876a14 100644 --- a/components/compiler/generator.cpp +++ b/components/compiler/generator.cpp @@ -125,6 +125,11 @@ namespace code.push_back (Compiler::Generator::segment3 (0, buttons)); } + void opReport (Compiler::Generator::CodeContainer& code) + { + code.push_back (Compiler::Generator::segment5 (58)); + } + void opFetchLocalShort (Compiler::Generator::CodeContainer& code) { code.push_back (Compiler::Generator::segment5 (21)); @@ -516,6 +521,14 @@ namespace Compiler opMessageBox (code, buttons); } + void report (CodeContainer& code, Literals& literals, const std::string& message) + { + int index = literals.addString (message); + + opPushInt (code, index); + opReport (code); + } + void fetchLocal (CodeContainer& code, char localType, int localIndex) { opPushInt (code, localIndex); diff --git a/components/compiler/generator.hpp b/components/compiler/generator.hpp index 5671949f2..fd1f954ca 100644 --- a/components/compiler/generator.hpp +++ b/components/compiler/generator.hpp @@ -81,6 +81,8 @@ namespace Compiler void message (CodeContainer& code, Literals& literals, const std::string& message, int buttons); + void report (CodeContainer& code, Literals& literals, const std::string& message); + void fetchLocal (CodeContainer& code, char localType, int localIndex); void jump (CodeContainer& code, int offset); diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 5462f7788..834cd27b4 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -30,12 +30,12 @@ namespace Compiler { case 'l': - Generator::message (mCode, mLiterals, "%g", 0); + Generator::report (mCode, mLiterals, "%g"); break; case 'f': - Generator::message (mCode, mLiterals, "%f", 0); + Generator::report (mCode, mLiterals, "%f"); break; default: diff --git a/components/interpreter/docs/vmformat.txt b/components/interpreter/docs/vmformat.txt index 6619fc30a..3e513aa44 100644 --- a/components/interpreter/docs/vmformat.txt +++ b/components/interpreter/docs/vmformat.txt @@ -117,5 +117,9 @@ op 55: explicit reference = stack[0]; pop; disable explicit reference op 56: explicit reference = stack[0]; pop; push 1, if explicit reference is disabled, 0 else op 57: explicit reference = stack[0]; pop; replace stack[0] with distance between explicit reference and a reference of ID stack[0] -opcodes 58-33554431 unused +op 58: report string literal index in stack[0]; + additional arguments (if any) in stack[n]..stack[1]; + n is determined according to the message string + all arguments are removed from stack +opcodes 59-33554431 unused opcodes 33554432-67108863 reserved for extensions diff --git a/components/interpreter/installopcodes.cpp b/components/interpreter/installopcodes.cpp index f383ff47c..556477af2 100644 --- a/components/interpreter/installopcodes.cpp +++ b/components/interpreter/installopcodes.cpp @@ -95,6 +95,7 @@ namespace Interpreter interpreter.installSegment5 (54, new OpEnableExplicit); interpreter.installSegment5 (55, new OpDisableExplicit); interpreter.installSegment5 (56, new OpGetDisabledExplicit); + interpreter.installSegment5 (58, new OpReport); // script control interpreter.installSegment5 (46, new OpScriptRunning); @@ -106,4 +107,3 @@ namespace Interpreter interpreter.installSegment5 (57, new OpGetDistanceExplicit); } } - diff --git a/components/interpreter/miscopcodes.hpp b/components/interpreter/miscopcodes.hpp index fbee0aa26..37c38fc30 100644 --- a/components/interpreter/miscopcodes.hpp +++ b/components/interpreter/miscopcodes.hpp @@ -13,6 +13,66 @@ namespace Interpreter { + inline std::string formatMessage (const std::string& message, Runtime& runtime) + { + std::string formattedMessage; + + for (std::size_t i=0; i Date: Thu, 28 Apr 2011 09:30:45 +0200 Subject: [PATCH 29/41] fixed the openmw.cfg install problem (I hope) --- CMakeLists.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8de24f57f..949a6e522 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -337,8 +337,9 @@ endif (APPLE) # Other files configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg.local - "${OpenMW_BINARY_DIR}/openmw.cfg" COPYONLY) - + "${OpenMW_BINARY_DIR}/openmw.cfg") +configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg + "${OpenMW_BINARY_DIR}/openmw.cfg.install") if (WIN32) configure_file(${OpenMW_SOURCE_DIR}/files/plugins.cfg.win32 @@ -428,7 +429,7 @@ if(DPKG_PROGRAM) endif() #Install global configuration files - INSTALL(FILES "${OpenMW_SOURCE_DIR}/openmw.cfg" DESTINATION "../etc/openmw/" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") + INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "../etc/openmw/" RENAME "openmw.cfg" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") INSTALL(FILES "${OpenMW_BINARY_DIR}/plugins.cfg" DESTINATION "../etc/openmw/" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") #Install resources From 7131c08ca499d9718bfb916c9f4a72582c4073e2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 28 Apr 2011 09:39:40 +0200 Subject: [PATCH 30/41] moved path.hpp/path.cpp to a new component --- CMakeLists.txt | 12 ++++++++++-- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/engine.cpp | 3 ++- apps/openmw/main.cpp | 3 ++- {apps/openmw => components/files}/path.cpp | 0 {apps/openmw => components/files}/path.hpp | 0 6 files changed, 15 insertions(+), 5 deletions(-) rename {apps/openmw => components/files}/path.cpp (100%) rename {apps/openmw => components/files}/path.hpp (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 949a6e522..7d02e50f4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -181,6 +181,14 @@ set(MISC_HEADER ${COMP_DIR}/misc/stringops.hpp) source_group(components\\misc FILES ${MISC} ${MISC_HEADER}) +set(FILES + ${COMP_DIR}/files/path.cpp + ) +set(FILES_HEADER + ${COMP_DIR}/files/path.hpp + ) +source_group(components\\files FILES ${FILES} ${FILES_HEADER}) + file(GLOB COMPILER ${COMP_DIR}/compiler/*.cpp) file(GLOB COMPILER_HEADER ${COMP_DIR}/compiler/*.hpp) source_group(components\\compiler FILES ${COMPILER} ${COMPILER_HEADER}) @@ -190,10 +198,10 @@ file(GLOB INTERPRETER_HEADER ${COMP_DIR}/interpreter/*.hpp) source_group(components\\interpreter FILES ${INTERPRETER} ${INTERPRETER_HEADER}) set(COMPONENTS ${BSA} ${NIF} ${NIFOGRE} ${ESM_STORE} ${MISC} ${TO_UTF8} - ${COMPILER} ${INTERPRETER} ${ESM} ${FILE_FINDER} ${NIFBULLET}) + ${COMPILER} ${INTERPRETER} ${ESM} ${FILE_FINDER} ${NIFBULLET} ${FILES}) set(COMPONENTS_HEADER ${BSA_HEADER} ${NIF_HEADER} ${NIFOGRE_HEADER} ${ESM_STORE_HEADER} ${ESM_HEADER} ${MISC_HEADER} ${COMPILER_HEADER} ${TO_UTF8_HEADER} - ${INTERPRETER_HEADER} ${FILE_FINDER_HEADER} ${NIFBULLET_HEADER}) + ${INTERPRETER_HEADER} ${FILE_FINDER_HEADER} ${NIFBULLET_HEADER} ${FILES_HEADER}) # source directory: libs diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 0fa027f0c..9bc27b16d 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -5,7 +5,7 @@ project(OpenMW) set(GAME main.cpp engine.cpp - path.cpp) + ) set(GAME_HEADER engine.hpp) source_group(game FILES ${GAME} ${GAME_HEADER}) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 78ddffbe8..39ab43008 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -14,6 +14,8 @@ #include #include #include +#include + #include #include "mwgui/window_manager.hpp" @@ -47,7 +49,6 @@ #include #include "mwgui/class.hpp" -#include "path.hpp" #include "components/nifbullet/bullet_nif_loader.hpp" diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 7ba3fb4d6..754627602 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -6,8 +6,9 @@ #include #include +#include + #include "engine.hpp" -#include "path.hpp" #if defined(_WIN32) && !defined(_CONSOLE) #include diff --git a/apps/openmw/path.cpp b/components/files/path.cpp similarity index 100% rename from apps/openmw/path.cpp rename to components/files/path.cpp diff --git a/apps/openmw/path.hpp b/components/files/path.hpp similarity index 100% rename from apps/openmw/path.hpp rename to components/files/path.hpp From bdfd28f44d052905b05492262303c619c3c3b0cf Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 28 Apr 2011 09:56:50 +0200 Subject: [PATCH 31/41] adjusted components/files namespace; some related cleanup --- apps/openmw/engine.cpp | 6 ++---- apps/openmw/main.cpp | 4 ++-- components/files/path.cpp | 15 ++++++++++----- components/files/path.hpp | 26 +++++++++----------------- 4 files changed, 23 insertions(+), 28 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 39ab43008..c6b57efc0 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -323,12 +323,10 @@ void OMW::Engine::go() test.name = ""; total = 0; - - std::cout << "Data directory: " << mDataDir << "\n"; - std::string cfgDir = OMW::Path::getPath(OMW::Path::GLOBAL_CFG_PATH, "openmw", ""); - std::string cfgUserDir = OMW::Path::getPath(OMW::Path::USER_CFG_PATH, "openmw", ""); + std::string cfgDir = Files::getPath (Files::Path_ConfigUser, "openmw", ""); + std::string cfgUserDir = Files::getPath (Files::Path_ConfigGlobal, "openmw", ""); std::string plugCfg = "plugins.cfg"; std::string ogreCfg = "ogre.cfg"; ogreCfg.insert(0, cfgUserDir); diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 754627602..c5f53d7b5 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -79,12 +79,12 @@ bool parseOptions (int argc, char**argv, OMW::Engine& engine) std::string cfgFile = "openmw.cfg"; if(!isFile(cfgFile.c_str())) { - cfgFile = OMW::Path::getPath(OMW::Path::GLOBAL_CFG_PATH, "openmw", "openmw.cfg"); + cfgFile = Files::getPath (Files::Path_ConfigGlobal, "openmw", "openmw.cfg"); } std::cout << "Using global config file: " << cfgFile << std::endl; std::ifstream globalConfigFile(cfgFile.c_str()); - cfgFile = OMW::Path::getPath(OMW::Path::USER_CFG_PATH, "openmw", "openmw.cfg"); + cfgFile = Files::getPath (Files::Path_ConfigUser, "openmw", "openmw.cfg"); std::cout << "Using user config file: " << cfgFile << std::endl; std::ifstream userConfigFile(cfgFile.c_str()); diff --git a/components/files/path.cpp b/components/files/path.cpp index e7dbc0471..a7b66822f 100644 --- a/components/files/path.cpp +++ b/components/files/path.cpp @@ -2,15 +2,21 @@ #include +#include +#include + +#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE +#include +#endif + #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX #include //getenv #endif - -std::string OMW::Path::getPath(PathTypeEnum parType, const std::string parApp, const std::string parFile) +std::string Files::getPath (PathTypeEnum parType, const std::string parApp, const std::string parFile) { std::string theBasePath; - if(parType == GLOBAL_CFG_PATH) + if (parType==Path_ConfigGlobal) { #if OGRE_PLATFORM == OGRE_PLATFORM_APPLE theBasePath = Ogre::macBundlePath() + "/Contents/MacOS/"; //FIXME do we have global/local with OSX? @@ -21,7 +27,7 @@ std::string OMW::Path::getPath(PathTypeEnum parType, const std::string parApp, c #endif } - else + else if (parType==Path_ConfigUser) { #if OGRE_PLATFORM == OGRE_PLATFORM_APPLE theBasePath = Ogre::macBundlePath() + "/Contents/MacOS/"; //FIXME do we have global/local with OSX? @@ -53,4 +59,3 @@ std::string OMW::Path::getPath(PathTypeEnum parType, const std::string parApp, c theBasePath.append(parFile); return theBasePath; } - diff --git a/components/files/path.hpp b/components/files/path.hpp index 84ff9ecab..a42646404 100644 --- a/components/files/path.hpp +++ b/components/files/path.hpp @@ -1,25 +1,17 @@ -#ifndef PATH__HPP -#define PATH__HPP +#ifndef COMPONENTS_FILES_PATH_HPP +#define COMPONENTS_FILES_PATH_HPP -#include #include -#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE -#include -#endif - -namespace OMW +namespace Files { - class Path + enum PathTypeEnum { - public: - enum PathTypeEnum - { - USER_CFG_PATH, - GLOBAL_CFG_PATH - }; - - static std::string getPath(PathTypeEnum parType, const std::string parApp, const std::string parFile); + Path_ConfigUser, + Path_ConfigGlobal }; + + std::string getPath (PathTypeEnum parType, const std::string parApp, const std::string parFile); } + #endif From 8b9ee30924663155c2e87290bd80a4df102cebc7 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 28 Apr 2011 10:15:04 +0200 Subject: [PATCH 32/41] user/global mixup --- apps/openmw/engine.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index c6b57efc0..047bc3751 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -325,8 +325,8 @@ void OMW::Engine::go() std::cout << "Data directory: " << mDataDir << "\n"; - std::string cfgDir = Files::getPath (Files::Path_ConfigUser, "openmw", ""); - std::string cfgUserDir = Files::getPath (Files::Path_ConfigGlobal, "openmw", ""); + std::string cfgDir = Files::getPath (Files::Path_ConfigGlobal, "openmw", ""); + std::string cfgUserDir = Files::getPath (Files::Path_ConfigUser, "openmw", ""); std::string plugCfg = "plugins.cfg"; std::string ogreCfg = "ogre.cfg"; ogreCfg.insert(0, cfgUserDir); From d260e5c1bd39a07209eba69f9a291bd9f871bbe3 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 5 May 2011 19:00:00 +0200 Subject: [PATCH 33/41] added file collection class --- CMakeLists.txt | 4 + components/files/collections.cpp | 25 ++++++ components/files/collections.hpp | 26 ++++++ components/files/multidircollection.cpp | 102 ++++++++++++++++++++++++ components/files/multidircollection.hpp | 78 ++++++++++++++++++ 5 files changed, 235 insertions(+) create mode 100644 components/files/collections.cpp create mode 100644 components/files/collections.hpp create mode 100644 components/files/multidircollection.cpp create mode 100644 components/files/multidircollection.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d02e50f4..c5001a894 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -183,9 +183,13 @@ source_group(components\\misc FILES ${MISC} ${MISC_HEADER}) set(FILES ${COMP_DIR}/files/path.cpp + ${COMP_DIR}/files/multidircollection.cpp + ${COMP_DIR}/files/collections.cpp ) set(FILES_HEADER ${COMP_DIR}/files/path.hpp + ${COMP_DIR}/files/multidircollection.hpp + ${COMP_DIR}/files/collections.hpp ) source_group(components\\files FILES ${FILES} ${FILES_HEADER}) diff --git a/components/files/collections.cpp b/components/files/collections.cpp new file mode 100644 index 000000000..6d1c00ab1 --- /dev/null +++ b/components/files/collections.cpp @@ -0,0 +1,25 @@ + +#include "collections.hpp" + +namespace Files +{ + Collections::Collections (const std::vector& directories, bool foldCase) + : mDirectories (directories), mFoldCase (foldCase) + {} + + const MultiDirCollection& Collections::getCollection (const std::string& extension) const + { + std::map::iterator iter = mCollections.find (extension); + + if (iter==mCollections.end()) + { + std::pair::iterator, bool> result = + mCollections.insert (std::make_pair (extension, + MultiDirCollection (mDirectories, extension, mFoldCase))); + + iter = result.first; + } + + return iter->second; + } +} diff --git a/components/files/collections.hpp b/components/files/collections.hpp new file mode 100644 index 000000000..9e23892af --- /dev/null +++ b/components/files/collections.hpp @@ -0,0 +1,26 @@ +#ifndef COMPONENTS_FILES_COLLECTION_HPP +#define COMPONENTS_FILES_COLLECTION_HPP + +#include "multidircollection.hpp" + +namespace Files +{ + class Collections + { + std::vector mDirectories; + bool mFoldCase; + mutable std::map mCollections; + + public: + + Collections (const std::vector& directories, bool foldCase); + ///< Directories are listed with increasing priority. + + const MultiDirCollection& getCollection (const std::string& extension) const; + ///< Return a file collection for the given extension. Extension must contain the + /// leading dot and must be all lower-case. + + }; +} + +#endif diff --git a/components/files/multidircollection.cpp b/components/files/multidircollection.cpp new file mode 100644 index 000000000..0543312e0 --- /dev/null +++ b/components/files/multidircollection.cpp @@ -0,0 +1,102 @@ + +#include "multidircollection.hpp" + +#include + +#include +#include + +#include + +namespace Files +{ + struct NameEqual + { + bool mStrict; + + NameEqual (bool strict) : mStrict (strict) {} + + bool operator() (const std::string& left, const std::string& right) const + { + if (mStrict) + return left==right; + + std::size_t len = left.length(); + + if (len!=right.length()) + return false; + + for (std::size_t i=0; i& directories, + const std::string& extension, bool foldCase) + : mFiles (NameLess (foldCase)) + { + NameEqual equal (foldCase); + + for (std::vector::const_iterator iter = directories.begin(); + iter!=directories.end(); ++iter) + { + boost::filesystem::path dataDirectory = *iter; + + for (boost::filesystem::directory_iterator iter (dataDirectory); + iter!=boost::filesystem::directory_iterator(); ++iter) + { + boost::filesystem::path path = *iter; + + if (!equal (extension, path.extension())) + continue; + + std::string filename = path.filename(); + + TIter result = mFiles.find (filename); + + if (result==mFiles.end()) + { + mFiles.insert (std::make_pair (filename, path)); + } + else if (result->first==filename) + { + mFiles[filename] = path; + } + else + { + // handle case folding + mFiles.erase (result->first); + mFiles.insert (std::make_pair (filename, path)); + } + } + } + } + + boost::filesystem::path MultiDirCollection::getPath (const std::string& file) const + { + TIter iter = mFiles.find (file); + + if (iter==mFiles.end()) + throw std::runtime_error ("file " + file + " not found"); + + return iter->second; + } + + MultiDirCollection::TIter MultiDirCollection::begin() const + { + return mFiles.begin(); + } + + MultiDirCollection::TIter MultiDirCollection::end() const + { + return mFiles.end(); + } +} diff --git a/components/files/multidircollection.hpp b/components/files/multidircollection.hpp new file mode 100644 index 000000000..36270dfd1 --- /dev/null +++ b/components/files/multidircollection.hpp @@ -0,0 +1,78 @@ +#ifndef COMPONENTS_FILES_MULTIDIRSOLLECTION_HPP +#define COMPONENTS_FILES_MULTIDIRSOLLECTION_HPP + +#include +#include +#include + +#include + +namespace Files +{ + struct NameLess + { + bool mStrict; + + NameLess (bool strict) : mStrict (strict) {} + + bool operator() (const std::string& left, const std::string& right) const + { + if (mStrict) + return left=r) + return false; + } + + return left.length() TContainer; + typedef TContainer::const_iterator TIter; + + private: + + TContainer mFiles; + + public: + + MultiDirCollection (const std::vector& directories, + const std::string& extension, bool foldCase); + ///< Directories are listed with increasing priority. + /// \param extension The extension that should be listed in this collection. Must + /// contain the leading dot. + /// \param foldCase Ignore filename case + + boost::filesystem::path getPath (const std::string& file) const; + ///< Return full path (including filename) of \æ file. + /// + /// If the file does not exist, an exception is thrown. \a file must include + /// the extension. + + TIter begin() const; + ///< Return iterator pointing to the first file. + + TIter end() const; + ///< Return iterator pointing past the last file. + + }; +} + +#endif From 6e880cffb24ba19dd8622ae3477a42622e78b023 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 5 May 2011 19:32:42 +0200 Subject: [PATCH 34/41] changed engine class to support multiple data directories for esm files --- apps/openmw/engine.cpp | 26 ++++++++++++-------------- apps/openmw/engine.hpp | 9 +++++---- apps/openmw/main.cpp | 4 +++- apps/openmw/mwworld/world.cpp | 8 +++++--- apps/openmw/mwworld/world.hpp | 8 +++++++- components/files/collections.cpp | 2 ++ components/files/collections.hpp | 2 ++ 7 files changed, 36 insertions(+), 23 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 1ca5c68b4..fbba304b9 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -240,15 +240,12 @@ OMW::Engine::~Engine() void OMW::Engine::loadBSA() { - boost::filesystem::directory_iterator end; + const Files::MultiDirCollection& bsa = mFileCollections.getCollection (".bsa"); - for (boost::filesystem::directory_iterator iter (mDataDir); iter!=end; ++iter) + for (Files::MultiDirCollection::TIter iter (bsa.begin()); iter!=bsa.end(); ++iter) { - if (boost::filesystem::extension (iter->path())==".bsa") - { - std::cout << "Adding " << iter->path().string() << std::endl; - addBSA(iter->path().string()); - } + std::cout << "Adding " << iter->second.string() << std::endl; + addBSA (iter->second.string()); } } @@ -263,9 +260,13 @@ void OMW::Engine::addResourcesDirectory (const boost::filesystem::path& path) // Set data dir -void OMW::Engine::setDataDir (const boost::filesystem::path& dataDir) +void OMW::Engine::setDataDirs (const std::vector& dataDirs) { - mDataDir = boost::filesystem::system_complete (dataDir); + /// \todo remove mDataDir, once resources system can handle multiple directories + assert (!dataDirs.empty()); + mDataDir = dataDirs[0]; + + mFileCollections = Files::Collections (dataDirs, true); } // Set resource dir @@ -318,15 +319,12 @@ void OMW::Engine::setNewGame() void OMW::Engine::go() { assert (!mEnvironment.mWorld); - assert (!mDataDir.empty()); assert (!mCellName.empty()); assert (!mMaster.empty()); test.name = ""; total = 0; - std::cout << "Data directory: " << mDataDir << "\n"; - std::string cfgDir = Files::getPath (Files::Path_ConfigGlobal, "openmw", ""); std::string cfgUserDir = Files::getPath (Files::Path_ConfigUser, "openmw", ""); std::string plugCfg = "plugins.cfg"; @@ -358,8 +356,8 @@ void OMW::Engine::go() mPhysicEngine = new OEngine::Physic::PhysicEngine(shapeLoader); // Create the world - mEnvironment.mWorld = new MWWorld::World (mOgre, mPhysicEngine, mDataDir, mMaster, mResDir, mNewGame, mEnvironment); - + mEnvironment.mWorld = new MWWorld::World (mOgre, mPhysicEngine, mFileCollections, mMaster, + mResDir, mNewGame, mEnvironment); // Set up the GUI system mGuiManager = new OEngine::GUI::MyGUIManager(mOgre.getWindow(), mOgre.getScene(), false, cfgDir); diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 2f8a5b1d2..4631f60a7 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include "mwworld/environment.hpp" #include "mwworld/ptr.hpp" @@ -55,8 +56,6 @@ namespace OMW class Engine : private Ogre::FrameListener { - - //int nFiles; boost::filesystem::path mDataDir; boost::filesystem::path mResDir; OEngine::Render::OgreRenderer mOgre; @@ -84,6 +83,8 @@ namespace OMW MWWorld::Ptr mIgnoreLocalPtr; + Files::Collections mFileCollections; + // not implemented Engine (const Engine&); Engine& operator= (const Engine&); @@ -108,8 +109,8 @@ namespace OMW ~Engine(); - /// Set data dir - void setDataDir (const boost::filesystem::path& dataDir); + /// Set data dirs + void setDataDirs (const std::vector& dataDirs); /// Set resource dir void setResourceDir (const boost::filesystem::path& parResDir); diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index c5f53d7b5..7eba8c303 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -105,7 +105,9 @@ bool parseOptions (int argc, char**argv, OMW::Engine& engine) } // directory settings - engine.setDataDir (variables["data"].as()); + std::vector dataDirs; + dataDirs.push_back (variables["data"].as()); + engine.setDataDirs (dataDirs); engine.setResourceDir (variables["resources"].as()); // master and plugin diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index 81151ccdc..68e3a745d 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -5,6 +5,7 @@ #include #include +#include #include "../mwrender/sky.hpp" #include "../mwrender/interior.hpp" @@ -406,15 +407,16 @@ namespace MWWorld mCellChanged = true; } - World::World (OEngine::Render::OgreRenderer& renderer, OEngine::Physic::PhysicEngine* physEng, const boost::filesystem::path& dataDir, + World::World (OEngine::Render::OgreRenderer& renderer, OEngine::Physic::PhysicEngine* physEng, + const Files::Collections& fileCollections, const std::string& master, const boost::filesystem::path& resDir, bool newGame, Environment& environment) : mSkyManager (0), mScene (renderer,physEng), mPlayer (0), mCurrentCell (0), mGlobalVariables (0), mSky (false), mCellChanged (false), mEnvironment (environment) { mPhysEngine = physEng; - boost::filesystem::path masterPath (dataDir); - masterPath /= master; + + boost::filesystem::path masterPath (fileCollections.getCollection (".esm").getPath (master)); std::cout << "Loading ESM " << masterPath.string() << "\n"; diff --git a/apps/openmw/mwworld/world.hpp b/apps/openmw/mwworld/world.hpp index d722eb166..160c20314 100644 --- a/apps/openmw/mwworld/world.hpp +++ b/apps/openmw/mwworld/world.hpp @@ -26,6 +26,11 @@ namespace ESM struct Position; } +namespace Files +{ + class Collections; +} + namespace Render { class OgreRenderer; @@ -107,7 +112,8 @@ namespace MWWorld /// interior cell. public: - World (OEngine::Render::OgreRenderer& renderer, OEngine::Physic::PhysicEngine* physEng, const boost::filesystem::path& dataDir, + World (OEngine::Render::OgreRenderer& renderer, OEngine::Physic::PhysicEngine* physEng, + const Files::Collections& fileCollections, const std::string& master, const boost::filesystem::path& resDir, bool newGame, Environment& environment); diff --git a/components/files/collections.cpp b/components/files/collections.cpp index 6d1c00ab1..8cd4865b3 100644 --- a/components/files/collections.cpp +++ b/components/files/collections.cpp @@ -3,6 +3,8 @@ namespace Files { + Collections::Collections() : mFoldCase (false) {} + Collections::Collections (const std::vector& directories, bool foldCase) : mDirectories (directories), mFoldCase (foldCase) {} diff --git a/components/files/collections.hpp b/components/files/collections.hpp index 9e23892af..6eaf0303e 100644 --- a/components/files/collections.hpp +++ b/components/files/collections.hpp @@ -13,6 +13,8 @@ namespace Files public: + Collections(); + Collections (const std::vector& directories, bool foldCase); ///< Directories are listed with increasing priority. From e60f0e3b38c38004aa550dabbc616834c4da6875 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 5 May 2011 19:39:11 +0200 Subject: [PATCH 35/41] --data switch accepts multiple directories now --- apps/openmw/main.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 7eba8c303..0545e5a98 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -42,8 +42,10 @@ bool parseOptions (int argc, char**argv, OMW::Engine& engine) desc.add_options() ("help", "print help message") - ("data", bpo::value()->default_value ("data"), - "set data directory") + ("data", bpo::value >() + ->default_value (std::vector(), "data") + ->multitoken(), + "set data directories (later directories have higher priority)") ("resources", bpo::value()->default_value ("resources"), "set resources directory") ("start", bpo::value()->default_value ("Beshara"), @@ -105,9 +107,10 @@ bool parseOptions (int argc, char**argv, OMW::Engine& engine) } // directory settings - std::vector dataDirs; - dataDirs.push_back (variables["data"].as()); - engine.setDataDirs (dataDirs); + std::vector dataDirs = variables["data"].as >(); + std::vector dataDirs2 (dataDirs.begin(), dataDirs.end()); + engine.setDataDirs (dataDirs2); + engine.setResourceDir (variables["resources"].as()); // master and plugin From ef1e986a877d65c7db4065c9d846c95325bc50da Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 5 May 2011 19:50:28 +0200 Subject: [PATCH 36/41] added --data-local switch --- apps/openmw/main.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 0545e5a98..8dff52024 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -46,6 +46,8 @@ bool parseOptions (int argc, char**argv, OMW::Engine& engine) ->default_value (std::vector(), "data") ->multitoken(), "set data directories (later directories have higher priority)") + ("data-local", bpo::value()->default_value (""), + "set local data directory (highest priority)") ("resources", bpo::value()->default_value ("resources"), "set resources directory") ("start", bpo::value()->default_value ("Beshara"), @@ -109,6 +111,11 @@ bool parseOptions (int argc, char**argv, OMW::Engine& engine) // directory settings std::vector dataDirs = variables["data"].as >(); std::vector dataDirs2 (dataDirs.begin(), dataDirs.end()); + + std::string local = variables["data-local"].as(); + if (!local.empty()) + dataDirs.push_back (local); + engine.setDataDirs (dataDirs2); engine.setResourceDir (variables["resources"].as()); From 8829398bfc24ff1085020f58bf967f720681d80a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 5 May 2011 19:56:16 +0200 Subject: [PATCH 37/41] added --fs-strict switch --- apps/openmw/engine.cpp | 8 +++++++- apps/openmw/engine.hpp | 7 +++++++ apps/openmw/main.cpp | 6 ++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index fbba304b9..e1ce97bfa 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -218,6 +218,7 @@ OMW::Engine::Engine() , mScriptManager (0) , mScriptContext (0) , mGuiManager (0) + , mFSStrict (false) { MWClass::registerClasses(); } @@ -258,6 +259,11 @@ void OMW::Engine::addResourcesDirectory (const boost::filesystem::path& path) Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true); } +void OMW::Engine::enableFSStrict() +{ + mFSStrict = true; +} + // Set data dir void OMW::Engine::setDataDirs (const std::vector& dataDirs) @@ -266,7 +272,7 @@ void OMW::Engine::setDataDirs (const std::vector& dataD assert (!dataDirs.empty()); mDataDir = dataDirs[0]; - mFileCollections = Files::Collections (dataDirs, true); + mFileCollections = Files::Collections (dataDirs, !mFSStrict); } // Set resource dir diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 4631f60a7..e49ddfc06 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -84,6 +84,7 @@ namespace OMW MWWorld::Ptr mIgnoreLocalPtr; Files::Collections mFileCollections; + bool mFSStrict; // not implemented Engine (const Engine&); @@ -109,6 +110,12 @@ namespace OMW ~Engine(); + /// Enable strict filesystem mode (do not fold case) + /// + /// \attention The strict mode must be specified before any path-related settings + /// are given to the engine. + void enableFSStrict(); + /// Set data dirs void setDataDirs (const std::vector& dataDirs); diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 8dff52024..e117a0688 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -74,6 +74,9 @@ bool parseOptions (int argc, char**argv, OMW::Engine& engine) ( "script-all", boost::program_options::value()-> implicit_value (true)->default_value (false), "compile all scripts (excluding dialogue scripts) at startup") + ( "fs-strict", boost::program_options::value()-> + implicit_value (true)->default_value (false), + "strict file system handling (no case folding)") ; bpo::variables_map variables; @@ -109,6 +112,9 @@ bool parseOptions (int argc, char**argv, OMW::Engine& engine) } // directory settings + if (variables["fs-strict"].as()==true) + engine.enableFSStrict(); + std::vector dataDirs = variables["data"].as >(); std::vector dataDirs2 (dataDirs.begin(), dataDirs.end()); From d9f1b642134692805452e9788ba8c2188f4cc61f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 5 May 2011 21:39:52 +0200 Subject: [PATCH 38/41] some file collection bug fixing --- components/files/multidircollection.cpp | 4 ++-- components/files/multidircollection.hpp | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/components/files/multidircollection.cpp b/components/files/multidircollection.cpp index 0543312e0..4428b364e 100644 --- a/components/files/multidircollection.cpp +++ b/components/files/multidircollection.cpp @@ -41,9 +41,9 @@ namespace Files MultiDirCollection::MultiDirCollection (const std::vector& directories, const std::string& extension, bool foldCase) - : mFiles (NameLess (foldCase)) + : mFiles (NameLess (!foldCase)) { - NameEqual equal (foldCase); + NameEqual equal (!foldCase); for (std::vector::const_iterator iter = directories.begin(); iter!=directories.end(); ++iter) diff --git a/components/files/multidircollection.hpp b/components/files/multidircollection.hpp index 36270dfd1..bd0304e40 100644 --- a/components/files/multidircollection.hpp +++ b/components/files/multidircollection.hpp @@ -27,7 +27,9 @@ namespace Files char l = std::tolower (left[i]); char r = std::tolower (right[i]); - if (l>=r) + if (lr) return false; } From a133920eb0fc6913993552006bce9eb60eccdcb8 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 10 May 2011 09:32:47 +0200 Subject: [PATCH 39/41] boost filesystem fix --- components/files/multidircollection.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/files/multidircollection.cpp b/components/files/multidircollection.cpp index 4428b364e..9a0d31c42 100644 --- a/components/files/multidircollection.cpp +++ b/components/files/multidircollection.cpp @@ -55,10 +55,10 @@ namespace Files { boost::filesystem::path path = *iter; - if (!equal (extension, path.extension())) + if (!equal (extension, boost::filesystem::path (path.extension()).string())) continue; - std::string filename = path.filename(); + std::string filename = boost::filesystem::path (path.filename()).string(); TIter result = mFiles.find (filename); From 80691250ecffb239505a82e703a2398314c9b6b8 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 18 May 2011 16:01:19 +0200 Subject: [PATCH 40/41] don't create a new virtual machine for each script and frame --- apps/openmw/mwgui/console.cpp | 4 +- apps/openmw/mwscript/scriptmanager.cpp | 15 ++++--- apps/openmw/mwscript/scriptmanager.hpp | 3 ++ components/interpreter/interpreter.cpp | 7 ++-- components/interpreter/interpreter.hpp | 23 +++++----- components/interpreter/runtime.cpp | 58 +++++++++++++------------- components/interpreter/runtime.hpp | 38 ++++++++--------- 7 files changed, 77 insertions(+), 71 deletions(-) diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index 0421dc370..baa1309af 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -223,11 +223,11 @@ namespace MWGui try { ConsoleInterpreterContext interpreterContext (*this, mEnvironment, MWWorld::Ptr()); - Interpreter::Interpreter interpreter (interpreterContext); + Interpreter::Interpreter interpreter; MWScript::installOpcodes (interpreter); std::vector code; output.getCode (code); - interpreter.run (&code[0], code.size()); + interpreter.run (&code[0], code.size(), interpreterContext); } catch (const std::exception& error) { diff --git a/apps/openmw/mwscript/scriptmanager.cpp b/apps/openmw/mwscript/scriptmanager.cpp index 727297a98..07fa93454 100644 --- a/apps/openmw/mwscript/scriptmanager.cpp +++ b/apps/openmw/mwscript/scriptmanager.cpp @@ -12,8 +12,6 @@ #include #include -#include - #include "extensions.hpp" namespace MWScript @@ -21,7 +19,8 @@ namespace MWScript ScriptManager::ScriptManager (const ESMS::ESMStore& store, bool verbose, Compiler::Context& compilerContext) : mErrorHandler (std::cerr), mStore (store), mVerbose (verbose), - mCompilerContext (compilerContext), mParser (mErrorHandler, mCompilerContext) + mCompilerContext (compilerContext), mParser (mErrorHandler, mCompilerContext), + mOpcodesInstalled (false) {} bool ScriptManager::compile (const std::string& name) @@ -99,9 +98,13 @@ namespace MWScript if (!iter->second.empty()) try { - Interpreter::Interpreter interpreter (interpreterContext); - installOpcodes (interpreter); - interpreter.run (&iter->second[0], iter->second.size()); + if (!mOpcodesInstalled) + { + installOpcodes (mInterpreter); + mOpcodesInstalled = true; + } + + mInterpreter.run (&iter->second[0], iter->second.size(), interpreterContext); } catch (const std::exception& e) { diff --git a/apps/openmw/mwscript/scriptmanager.hpp b/apps/openmw/mwscript/scriptmanager.hpp index 639fc59bf..eab9bdcc0 100644 --- a/apps/openmw/mwscript/scriptmanager.hpp +++ b/apps/openmw/mwscript/scriptmanager.hpp @@ -8,6 +8,7 @@ #include #include +#include #include namespace ESMS @@ -35,6 +36,8 @@ namespace MWScript bool mVerbose; Compiler::Context& mCompilerContext; Compiler::FileParser mParser; + Interpreter::Interpreter mInterpreter; + bool mOpcodesInstalled; std::map > mScripts; diff --git a/components/interpreter/interpreter.cpp b/components/interpreter/interpreter.cpp index 44f626aad..10937e6bc 100644 --- a/components/interpreter/interpreter.cpp +++ b/components/interpreter/interpreter.cpp @@ -134,8 +134,7 @@ namespace Interpreter throw std::runtime_error (error.str()); } - Interpreter::Interpreter (Context& context) - : mRuntime (context) + Interpreter::Interpreter() {} Interpreter::~Interpreter() @@ -195,11 +194,11 @@ namespace Interpreter mSegment5.insert (std::make_pair (code, opcode)); } - void Interpreter::run (const Type_Code *code, int codeSize) + void Interpreter::run (const Type_Code *code, int codeSize, Context& context) { assert (codeSize>=4); - mRuntime.configure (code, codeSize); + mRuntime.configure (code, codeSize, context); int opcodes = static_cast (code[0]); diff --git a/components/interpreter/interpreter.hpp b/components/interpreter/interpreter.hpp index c67273707..e1016235a 100644 --- a/components/interpreter/interpreter.hpp +++ b/components/interpreter/interpreter.hpp @@ -21,23 +21,23 @@ namespace Interpreter std::map mSegment3; std::map mSegment4; std::map mSegment5; - + // not implemented Interpreter (const Interpreter&); Interpreter& operator= (const Interpreter&); - + void execute (Type_Code code); - + void abortUnknownCode (int segment, int opcode); - + void abortUnknownSegment (Type_Code code); - + public: - - Interpreter (Context& context); - + + Interpreter(); + ~Interpreter(); - + void installSegment0 (int code, Opcode1 *opcode); ///< ownership of \a opcode is transferred to *this. @@ -55,10 +55,9 @@ namespace Interpreter void installSegment5 (int code, Opcode0 *opcode); ///< ownership of \a opcode is transferred to *this. - - void run (const Type_Code *code, int codeSize); + + void run (const Type_Code *code, int codeSize, Context& context); }; } #endif - diff --git a/components/interpreter/runtime.cpp b/components/interpreter/runtime.cpp index f3a3a905d..dcf17d255 100644 --- a/components/interpreter/runtime.cpp +++ b/components/interpreter/runtime.cpp @@ -7,50 +7,51 @@ namespace Interpreter { - Runtime::Runtime (Context& context) : mContext (context), mCode (0), mPC (0) {} - + Runtime::Runtime() : mContext (0), mCode (0), mPC (0) {} + int Runtime::getPC() const { return mPC; } - + int Runtime::getIntegerLiteral (int index) const { assert (index>=0 && index (mCode[1])); - + const Type_Code *literalBlock = mCode + 4 + mCode[0]; - + return *reinterpret_cast (&literalBlock[index]); } - + float Runtime::getFloatLiteral (int index) const { assert (index>=0 && index (mCode[2])); - + const Type_Code *literalBlock = mCode + 4 + mCode[0] + mCode[1]; - + return *reinterpret_cast (&literalBlock[index]); } - + std::string Runtime::getStringLiteral (int index) const { assert (index>=0 && index (mCode[3])); - + const char *literalBlock = reinterpret_cast (mCode + 4 + mCode[0] + mCode[1] + mCode[2]); - + for (; index; --index) { literalBlock += std::strlen (literalBlock) + 1; } - + return literalBlock; } - - void Runtime::configure (const Interpreter::Type_Code *code, int codeSize) - { + + void Runtime::configure (const Interpreter::Type_Code *code, int codeSize, Context& context) + { clear(); - + + mContext = &context; mCode = code; mCodeSize = codeSize; mPC = 0; @@ -58,54 +59,55 @@ namespace Interpreter void Runtime::clear() { + mContext = 0; mCode = 0; mCodeSize = 0; mStack.clear(); } - + void Runtime::setPC (int PC) { mPC = PC; - } - + } + void Runtime::push (const Data& data) { mStack.push_back (data); } - + void Runtime::push (Type_Integer value) { Data data; data.mInteger = value; push (data); } - + void Runtime::push (Type_Float value) { Data data; data.mFloat = value; push (data); } - + void Runtime::pop() { if (mStack.empty()) throw std::runtime_error ("stack underflow"); - + mStack.resize (mStack.size()-1); } - + Data& Runtime::operator[] (int Index) { if (Index<0 || Index>=static_cast (mStack.size())) throw std::runtime_error ("stack index out of range"); - + return mStack[mStack.size()-Index-1]; } - + Context& Runtime::getContext() { - return mContext; + assert (mContext); + return *mContext; } } - diff --git a/components/interpreter/runtime.hpp b/components/interpreter/runtime.hpp index e9ba01041..2811ab0f0 100644 --- a/components/interpreter/runtime.hpp +++ b/components/interpreter/runtime.hpp @@ -11,52 +11,52 @@ namespace Interpreter class Context; /// Runtime data and engine interface - + class Runtime { - Context& mContext; + Context *mContext; const Type_Code *mCode; int mCodeSize; int mPC; std::vector mStack; - + public: - - Runtime (Context& context); - + + Runtime (); + int getPC() const; ///< return program counter. - + int getIntegerLiteral (int index) const; - + float getFloatLiteral (int index) const; - + std::string getStringLiteral (int index) const; - - void configure (const Type_Code *code, int codeSize); + + void configure (const Type_Code *code, int codeSize, Context& context); ///< \a context and \a code must exist as least until either configure, clear or /// the destructor is called. \a codeSize is given in 32-bit words. - + void clear(); - + void setPC (int PC); ///< set program counter. - + void push (const Data& data); ///< push data on stack - + void push (Type_Integer value); ///< push integer data on stack. - + void push (Type_Float value); ///< push float data on stack. - + void pop(); ///< pop stack - + Data& operator[] (int Index); ///< Access stack member, counted from the top. - + Context& getContext(); }; } From 64d6ee26bd67a317536e6c475171c3f0b8612ef2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 18 May 2011 16:37:09 +0200 Subject: [PATCH 41/41] changed OGRE framelistener function from frameStarted to frameRenderingQueued --- apps/openmw/engine.cpp | 2 +- apps/openmw/engine.hpp | 2 +- apps/openmw/mwinput/inputmanager.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index e1ce97bfa..b2ed0a767 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -76,7 +76,7 @@ void OMW::Engine::executeLocalScripts() } -bool OMW::Engine::frameStarted(const Ogre::FrameEvent& evt) +bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) { if(mShowFPS) { diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index e49ddfc06..4c70d7f35 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -100,7 +100,7 @@ namespace OMW void executeLocalScripts(); - virtual bool frameStarted(const Ogre::FrameEvent& evt); + virtual bool frameRenderingQueued (const Ogre::FrameEvent& evt); /// Process pending commands diff --git a/apps/openmw/mwinput/inputmanager.cpp b/apps/openmw/mwinput/inputmanager.cpp index dc21680af..eb6c59963 100644 --- a/apps/openmw/mwinput/inputmanager.cpp +++ b/apps/openmw/mwinput/inputmanager.cpp @@ -258,7 +258,7 @@ namespace MWInput } //NOTE: Used to check for movement keys - bool frameStarted(const Ogre::FrameEvent &evt) + bool frameRenderingQueued (const Ogre::FrameEvent &evt) { // Tell OIS to handle all input events input.capture();