Merge remote-tracking branch 'upstream/master' into HEAD

Conflicts:
	CMakeLists.txt
	components/CMakeLists.txt
	components/config/gamesettings.cpp
loadfix
pvdk 11 years ago
commit c54217d008

4
.gitignore vendored

@ -3,7 +3,6 @@ CMakeFiles
*/CMakeFiles */CMakeFiles
CMakeCache.txt CMakeCache.txt
cmake_install.cmake cmake_install.cmake
CMakeLists.txt.user
Makefile Makefile
makefile makefile
build build
@ -22,6 +21,8 @@ Doxygen
.project .project
.settings .settings
.directory .directory
## qt-creator
CMakeLists.txt.user*
## resources ## resources
data data
@ -39,6 +40,7 @@ resources
## generated objects ## generated objects
apps/openmw/config.hpp apps/openmw/config.hpp
components/version/version.hpp
Docs/mainpage.hpp Docs/mainpage.hpp
moc_*.cxx moc_*.cxx
*.cxx_parameters *.cxx_parameters

@ -4,18 +4,18 @@ compiler:
branches: branches:
only: only:
- master - master
- next - /openmw-.*$/
before_install: before_install:
- pwd - pwd
- git submodule update --init --recursive - git fetch --tags
- echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse" - echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse"
- echo "yes" | sudo apt-add-repository ppa:openmw/openmw - echo "yes" | sudo apt-add-repository ppa:openmw/openmw
- sudo apt-get update -qq - sudo apt-get update -qq
- sudo apt-get install -qq libboost-all-dev libgtest-dev google-mock libzzip-dev uuid-dev - sudo apt-get install -qq libboost-all-dev libgtest-dev google-mock
- sudo apt-get install -qq libqt4-dev libxaw7-dev libxrandr-dev libfreeimage-dev libpng-dev - sudo apt-get install -qq libqt4-dev
- sudo apt-get install -qq libopenal-dev libmpg123-dev libsndfile1-dev - sudo apt-get install -qq libopenal-dev
- sudo apt-get install -qq libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev libpostproc-dev - sudo apt-get install -qq libavcodec-dev libavformat-dev libavutil-dev libswscale-dev
- sudo apt-get install -qq libbullet-dev libogre-1.8-dev libmygui-dev libsdl2-dev libunshield-dev - sudo apt-get install -qq libbullet-dev libogre-1.9-dev libmygui-dev libsdl2-dev libunshield-dev
- sudo mkdir /usr/src/gtest/build - sudo mkdir /usr/src/gtest/build
- cd /usr/src/gtest/build - cd /usr/src/gtest/build
- sudo cmake .. -DBUILD_SHARED_LIBS=1 - sudo cmake .. -DBUILD_SHARED_LIBS=1
@ -37,3 +37,9 @@ notifications:
email: email:
on_success: change on_success: change
on_failure: always on_failure: always
irc:
channels:
- "chat.freenode.net#openmw"
on_success: change
on_failure: always

@ -4,25 +4,36 @@ if (APPLE)
set(APP_BUNDLE_NAME "${CMAKE_PROJECT_NAME}.app") set(APP_BUNDLE_NAME "${CMAKE_PROJECT_NAME}.app")
set(APP_BUNDLE_DIR "${OpenMW_BINARY_DIR}/${APP_BUNDLE_NAME}") set(APP_BUNDLE_DIR "${OpenMW_BINARY_DIR}/${APP_BUNDLE_NAME}")
set(CMAKE_EXE_LINKER_FLAGS "-F /Library/Frameworks")
set(CMAKE_SHARED_LINKER_FLAGS "-F /Library/Frameworks")
set(CMAKE_MODULE_LINKER_FLAGS "-F /Library/Frameworks")
endif (APPLE) endif (APPLE)
# Macros # Macros
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/) set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/)
include (OpenMWMacros) include(OpenMWMacros)
# Version # Version
set (OPENMW_VERSION_MAJOR 0) include(GetGitRevisionDescription)
set (OPENMW_VERSION_MINOR 27)
set (OPENMW_VERSION_RELEASE 0) get_git_tag_revision(TAGHASH --tags --max-count=1 "HEAD...")
get_git_head_revision(REFSPEC COMMITHASH)
git_describe(VERSION --tags ${TAGHASH})
string(REGEX MATCH "^openmw-[^0-9]*[0-9]+\\.[0-9]+\\.[0-9]+.*" MATCH "${VERSION}")
if (MATCH)
string(REGEX REPLACE "^openmw-([0-9]+)\\..*" "\\1" OPENMW_VERSION_MAJOR "${VERSION}")
string(REGEX REPLACE "^openmw-[0-9]+\\.([0-9]+).*" "\\1" OPENMW_VERSION_MINOR "${VERSION}")
string(REGEX REPLACE "^openmw-[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" OPENMW_VERSION_RELEASE "${VERSION}")
set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}") set(OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}")
set(OPENMW_VERSION_COMMITHASH "${COMMITHASH}")
set(OPENMW_VERSION_TAGHASH "${TAGHASH}")
message(STATUS "Configuring OpenMW ${OPENMW_VERSION}...")
else (MATCH)
message(FATAL_ERROR "Failed to get valid version information from Git")
endif (MATCH)
# doxygen main page # doxygen main page
@ -94,14 +105,10 @@ set(OENGINE_GUI
) )
set(OENGINE_BULLET set(OENGINE_BULLET
${LIBDIR}/openengine/bullet/btKinematicCharacterController.cpp
${LIBDIR}/openengine/bullet/btKinematicCharacterController.h
${LIBDIR}/openengine/bullet/BtOgre.cpp ${LIBDIR}/openengine/bullet/BtOgre.cpp
${LIBDIR}/openengine/bullet/BtOgreExtras.h ${LIBDIR}/openengine/bullet/BtOgreExtras.h
${LIBDIR}/openengine/bullet/BtOgreGP.h ${LIBDIR}/openengine/bullet/BtOgreGP.h
${LIBDIR}/openengine/bullet/BtOgrePG.h ${LIBDIR}/openengine/bullet/BtOgrePG.h
${LIBDIR}/openengine/bullet/CMotionState.cpp
${LIBDIR}/openengine/bullet/CMotionState.h
${LIBDIR}/openengine/bullet/physic.cpp ${LIBDIR}/openengine/bullet/physic.cpp
${LIBDIR}/openengine/bullet/physic.hpp ${LIBDIR}/openengine/bullet/physic.hpp
${LIBDIR}/openengine/bullet/BulletShapeLoader.cpp ${LIBDIR}/openengine/bullet/BulletShapeLoader.cpp
@ -186,19 +193,16 @@ if (WIN32)
set(Boost_USE_STATIC_LIBS ON) set(Boost_USE_STATIC_LIBS ON)
set(PLATFORM_INCLUDE_DIR "platform") set(PLATFORM_INCLUDE_DIR "platform")
add_definitions(-DBOOST_ALL_NO_LIB) add_definitions(-DBOOST_ALL_NO_LIB)
# Suppress WinMain(), provided by SDL
add_definitions(-DSDL_MAIN_HANDLED)
else (WIN32) else (WIN32)
set(PLATFORM_INCLUDE_DIR "") set(PLATFORM_INCLUDE_DIR "")
find_path (UUID_INCLUDE_DIR uuid/uuid.h)
include_directories(${UUID_INCLUDE_DIR})
endif (WIN32) endif (WIN32)
if (MSVC10) if (MSVC10)
set(PLATFORM_INCLUDE_DIR "") set(PLATFORM_INCLUDE_DIR "")
endif() endif()
if (APPLE)
set(Boost_USE_STATIC_LIBS ON)
endif (APPLE)
# Dependencies # Dependencies
# Fix for not visible pthreads functions for linker with glibc 2.15 # Fix for not visible pthreads functions for linker with glibc 2.15
@ -213,7 +217,7 @@ if (HAVE_UNORDERED_MAP)
endif () endif ()
set(BOOST_COMPONENTS system filesystem program_options thread date_time wave) set(BOOST_COMPONENTS system filesystem program_options)
IF(BOOST_STATIC) IF(BOOST_STATIC)
set(Boost_USE_STATIC_LIBS ON) set(Boost_USE_STATIC_LIBS ON)
@ -241,7 +245,6 @@ include_directories("."
${MYGUI_INCLUDE_DIRS} ${MYGUI_INCLUDE_DIRS}
${MYGUI_PLATFORM_INCLUDE_DIRS} ${MYGUI_PLATFORM_INCLUDE_DIRS}
${OPENAL_INCLUDE_DIR} ${OPENAL_INCLUDE_DIR}
${UUID_INCLUDE_DIR}
${LIBDIR} ${LIBDIR}
) )
@ -250,10 +253,15 @@ link_directories(${SDL2_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR} ${MY
if (APPLE) if (APPLE)
# List used Ogre plugins # List used Ogre plugins
SET(USED_OGRE_PLUGINS ${OGRE_RenderSystem_GL_LIBRARY_REL} SET(USED_OGRE_PLUGINS ${OGRE_RenderSystem_GL_LIBRARY_REL}
${OGRE_Plugin_OctreeSceneManager_LIBRARY_REL}
${OGRE_Plugin_CgProgramManager_LIBRARY_REL}
${OGRE_Plugin_ParticleFX_LIBRARY_REL}) ${OGRE_Plugin_ParticleFX_LIBRARY_REL})
# Actually we must use OGRE_Plugin_CgProgramManager_FOUND but it's
# not reliable and equals TRUE even if there's no Ogre Cg plugin
if (Cg_FOUND)
set(USED_OGRE_PLUGINS ${USED_OGRE_PLUGINS}
${OGRE_Plugin_CgProgramManager_LIBRARY_REL})
endif ()
if (${OGRE_PLUGIN_DIR_REL}}) if (${OGRE_PLUGIN_DIR_REL}})
set(OGRE_PLUGINS_REL_FOUND TRUE) set(OGRE_PLUGINS_REL_FOUND TRUE)
endif () endif ()
@ -268,8 +276,6 @@ if (APPLE)
set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_DBG}) set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_DBG})
endif () endif ()
#set(OGRE_PLUGIN_DIR "${OGRE_PLUGIN_DIR}/")
configure_file(${OpenMW_SOURCE_DIR}/files/mac/Info.plist configure_file(${OpenMW_SOURCE_DIR}/files/mac/Info.plist
"${APP_BUNDLE_DIR}/Contents/Info.plist") "${APP_BUNDLE_DIR}/Contents/Info.plist")
@ -291,7 +297,8 @@ endif()
add_definitions(-DOGRE_PLUGIN_DIR_REL="${OGRE_PLUGIN_DIR_REL}") add_definitions(-DOGRE_PLUGIN_DIR_REL="${OGRE_PLUGIN_DIR_REL}")
add_definitions(-DOGRE_PLUGIN_DIR_DBG="${OGRE_PLUGIN_DIR_DBG}") add_definitions(-DOGRE_PLUGIN_DIR_DBG="${OGRE_PLUGIN_DIR_DBG}")
if (APPLE AND OPENMW_OSX_DEPLOYMENT) if (APPLE AND OPENMW_OSX_DEPLOYMENT)
add_definitions(-DOGRE_PLUGIN_DIR="${APP_BUNDLE_NAME}/Contents/Plugins") # make it empty so plugin loading code can check this and try to find plugins inside app bundle
add_definitions(-DOGRE_PLUGIN_DIR="")
else() else()
add_definitions(-DOGRE_PLUGIN_DIR="${OGRE_PLUGIN_DIR}") add_definitions(-DOGRE_PLUGIN_DIR="${OGRE_PLUGIN_DIR}")
endif() endif()
@ -324,7 +331,7 @@ configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg
configure_file(${OpenMW_SOURCE_DIR}/files/opencs.cfg configure_file(${OpenMW_SOURCE_DIR}/files/opencs.cfg
"${OpenMW_BINARY_DIR}/opencs.cfg") "${OpenMW_BINARY_DIR}/opencs.cfg")
configure_file(${OpenMW_SOURCE_DIR}/files/opencs/defaultfilters configure_file(${OpenMW_SOURCE_DIR}/files/opencs/defaultfilters
"${OpenMW_BINARY_DIR}/resources/defaultfilters" COPYONLY) "${OpenMW_BINARY_DIR}/resources/defaultfilters" COPYONLY)
@ -415,46 +422,6 @@ IF(NOT WIN32 AND NOT APPLE)
# Install resources # Install resources
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${DATADIR}" FILE_PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT "Resources") INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${DATADIR}" FILE_PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT "Resources")
INSTALL(DIRECTORY DESTINATION "${DATADIR}/data" COMPONENT "Resources") INSTALL(DIRECTORY DESTINATION "${DATADIR}/data" COMPONENT "Resources")
IF (DPKG_PROGRAM)
## Debian Specific
IF(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/.git")
EXEC_PROGRAM("git" ${CMAKE_CURRENT_SOURCE_DIR} ARGS "describe" OUTPUT_VARIABLE GIT_VERSION )
STRING(REGEX REPLACE "openmw-" "" VERSION_STRING "${GIT_VERSION}")
EXEC_PROGRAM("git" ARGS "config --get user.name" OUTPUT_VARIABLE GIT_NAME )
EXEC_PROGRAM("git" ARGS "config --get user.email" OUTPUT_VARIABLE GIT_EMAIL)
SET(PACKAGE_MAINTAINER "${GIT_NAME} <${GIT_EMAIL}>")
ELSE()
SET(VERSION_STRING "${OPENMW_VERSION}")
SET(PACKAGE_MAINTAINER "unknown")
ENDIF()
SET(CPACK_GENERATOR "DEB")
SET(CPACK_PACKAGE_NAME "openmw")
SET(CPACK_DEBIAN_PACKAGE_HOMEPAGE "http://openmw.org")
SET(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
SET(CPACK_DEBIAN_PACKAGE_MAINTAINER "${PACKAGE_MAINTAINER}")
SET(CPACK_DEBIAN_PACKAGE_DESCRIPTION "A reimplementation of The Elder Scrolls III: Morrowind
OpenMW is a reimplementation of the Bethesda Game Studios game The Elder Scrolls III: Morrowind.
Data files from the original game is required to run it.")
SET(CPACK_DEBIAN_PACKAGE_NAME "openmw")
SET(CPACK_DEBIAN_PACKAGE_VERSION "${VERSION_STRING}")
SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW opencs;OpenCS bsatool;Bsatool esmtool;Esmtool omwlauncher;OMWLauncher mwiniimporter;MWiniImporter openmw-wizard;OpenMW Wizard")
SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.11.2), libfreetype6 (>= 2.2.1), libgcc1 (>= 1:4.1.1), libmpg123-0 (>= 1.12.1), libopenal1 (>= 1:1.12.854), libsndfile1 (>= 1.0.23), libstdc++6 (>= 4.4.5), libuuid1 (>= 2.17.2), libqtgui4 (>= 4.7.0)")
SET(CPACK_DEBIAN_PACKAGE_SECTION "Games")
STRING(TOLOWER "${CPACK_PACKAGE_NAME}" CPACK_PACKAGE_NAME_LOWERCASE)
EXECUTE_PROCESS(
COMMAND ${DPKG_PROGRAM} --print-architecture
OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE
OUTPUT_STRIP_TRAILING_WHITESPACE
)
SET(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME_LOWERCASE}_${CPACK_DEBIAN_PACKAGE_VERSION}_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}")
INCLUDE(CPack)
ENDIF(DPKG_PROGRAM)
ENDIF(NOT WIN32 AND NOT APPLE) ENDIF(NOT WIN32 AND NOT APPLE)
if(WIN32) if(WIN32)
@ -705,14 +672,14 @@ if (APPLE)
set(CPACK_GENERATOR "DragNDrop") set(CPACK_GENERATOR "DragNDrop")
set(CPACK_PACKAGE_VERSION ${OPENMW_VERSION}) set(CPACK_PACKAGE_VERSION ${OPENMW_VERSION})
set(CPACK_PACKAGE_VERSION_MAJOR ${OPENMW_VERSION_MAJOR}) set(CPACK_PACKAGE_VERSION_MAJOR ${OPENMW_VERSION_MAJOR})
set(CPACK_PACKAGE_VERSION_MINOR ${OPENMW_VERSION_MINO}) set(CPACK_PACKAGE_VERSION_MINOR ${OPENMW_VERSION_MINOR})
set(CPACK_PACKAGE_VERSION_PATCH ${OPENMW_VERSION_RELEASE}) set(CPACK_PACKAGE_VERSION_PATCH ${OPENMW_VERSION_RELEASE})
set(OPENMW_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}") set(OPENMW_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}")
set(OPENCS_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/OpenCS.app") set(OPENCS_BUNDLE_NAME "OpenCS.app")
set(OPENCS_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}")
set(PLUGINS "")
set(ABSOLUTE_PLUGINS "") set(ABSOLUTE_PLUGINS "")
foreach (PLUGIN ${USED_OGRE_PLUGINS}) foreach (PLUGIN ${USED_OGRE_PLUGINS})
@ -720,12 +687,36 @@ if (APPLE)
set(ABSOLUTE_PLUGINS ${PLUGIN_ABS} ${ABSOLUTE_PLUGINS}) set(ABSOLUTE_PLUGINS ${PLUGIN_ABS} ${ABSOLUTE_PLUGINS})
endforeach () endforeach ()
set(PLUGIN_INSTALL_BASE "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}/Contents/Plugins") install(CODE "
install(FILES ${ABSOLUTE_PLUGINS} DESTINATION "${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}/Contents/Plugins" COMPONENT Runtime) set(BU_CHMOD_BUNDLE_ITEMS ON)
foreach (PLUGIN ${ABSOLUTE_PLUGINS}) include(BundleUtilities)
get_filename_component(PLUGIN_RELATIVE ${PLUGIN} NAME) " COMPONENT Runtime)
set(PLUGINS ${PLUGINS} "${PLUGIN_INSTALL_BASE}/${PLUGIN_RELATIVE}")
endforeach () # installs used plugins in bundle at given path (bundle_path must be relative to ${CMAKE_INSTALL_PREFIX})
# and returns list of install paths for all installed plugins
function (install_plugins_for_bundle bundle_path plugins_var)
set(RELATIVE_PLUGIN_INSTALL_BASE "${bundle_path}/Contents/Frameworks")
set(PLUGINS "")
set(PLUGIN_INSTALL_BASE "\${CMAKE_INSTALL_PREFIX}/${RELATIVE_PLUGIN_INSTALL_BASE}")
foreach (PLUGIN ${ABSOLUTE_PLUGINS})
get_filename_component(PLUGIN_RELATIVE ${PLUGIN} NAME)
get_filename_component(PLUGIN_RELATIVE_WE ${PLUGIN} NAME_WE)
set(PLUGIN_DYLIB_IN_BUNDLE "${PLUGIN_INSTALL_BASE}/${PLUGIN_RELATIVE}/${PLUGIN_RELATIVE_WE}")
set(PLUGINS ${PLUGINS} "${PLUGIN_DYLIB_IN_BUNDLE}")
install(CODE "
copy_resolved_framework_into_bundle(\"${PLUGIN}/${PLUGIN_RELATIVE_WE}\" \"${PLUGIN_DYLIB_IN_BUNDLE}\")
" COMPONENT Runtime)
endforeach ()
set(${plugins_var} ${PLUGINS} PARENT_SCOPE)
endfunction (install_plugins_for_bundle)
install_plugins_for_bundle("${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}" PLUGINS)
install_plugins_for_bundle("${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}" OPENCS_PLUGINS)
#For now, search unresolved dependencies only in default system paths, so if you put unresolveable (i.e. with @executable_path in id name) lib or framework somewhere else, it would fail #For now, search unresolved dependencies only in default system paths, so if you put unresolveable (i.e. with @executable_path in id name) lib or framework somewhere else, it would fail
set(DIRS "") set(DIRS "")
@ -738,6 +729,7 @@ if (APPLE)
# Current limitations: # Current limitations:
# 1. Handles only frameworks, not simple libs # 1. Handles only frameworks, not simple libs
INSTALL(CODE " INSTALL(CODE "
cmake_policy(SET CMP0009 OLD)
set(CMAKE_FIND_LIBRARY_PREFIXES ${CMAKE_FIND_LIBRARY_PREFIXES}) set(CMAKE_FIND_LIBRARY_PREFIXES ${CMAKE_FIND_LIBRARY_PREFIXES})
set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
set(CMAKE_SYSTEM_FRAMEWORK_PATH ${CMAKE_SYSTEM_FRAMEWORK_PATH}) set(CMAKE_SYSTEM_FRAMEWORK_PATH ${CMAKE_SYSTEM_FRAMEWORK_PATH})
@ -769,11 +761,8 @@ if (APPLE)
endif() endif()
endfunction(gp_resolve_item_override) endfunction(gp_resolve_item_override)
cmake_policy(SET CMP0009 OLD)
set(BU_CHMOD_BUNDLE_ITEMS ON)
include(BundleUtilities)
fixup_bundle(\"${OPENMW_APP}\" \"${PLUGINS}\" \"${DIRS}\") fixup_bundle(\"${OPENMW_APP}\" \"${PLUGINS}\" \"${DIRS}\")
fixup_bundle(\"${OPENCS_APP}\" \"\" \"${DIRS}\") fixup_bundle(\"${OPENCS_APP}\" \"${OPENCS_PLUGINS}\" \"${DIRS}\")
" COMPONENT Runtime) " COMPONENT Runtime)
include(CPack) include(CPack)
endif (APPLE) endif (APPLE)

@ -236,7 +236,9 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info)
// Loop through all the references // Loop through all the references
ESM::CellRef ref; ESM::CellRef ref;
if(!quiet) std::cout << " References:\n"; if(!quiet) std::cout << " References:\n";
while(cell.getNextRef(esm, ref))
bool deleted = false;
while(cell.getNextRef(esm, ref, deleted))
{ {
if (save) { if (save) {
info.data.mCellRefs[&cell].push_back(ref); info.data.mCellRefs[&cell].push_back(ref);
@ -244,13 +246,14 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info)
if(quiet) continue; if(quiet) continue;
std::cout << " Refnum: " << ref.mRefnum << std::endl; std::cout << " Refnum: " << ref.mRefNum.mIndex << std::endl;
std::cout << " ID: '" << ref.mRefID << "'\n"; std::cout << " ID: '" << ref.mRefID << "'\n";
std::cout << " Owner: '" << ref.mOwner << "'\n"; std::cout << " Owner: '" << ref.mOwner << "'\n";
std::cout << " Enchantment charge: '" << ref.mEnchantmentCharge << "'\n"; std::cout << " Enchantment charge: '" << ref.mEnchantmentCharge << "'\n";
std::cout << " Uses/health: '" << ref.mCharge << "'\n"; std::cout << " Uses/health: '" << ref.mCharge << "'\n";
std::cout << " Gold value: '" << ref.mGoldValue << "'\n"; std::cout << " Gold value: '" << ref.mGoldValue << "'\n";
std::cout << " Blocked: '" << static_cast<int>(ref.mReferenceBlocked) << "'" << std::endl; std::cout << " Blocked: '" << static_cast<int>(ref.mReferenceBlocked) << "'" << std::endl;
std::cout << " Deleted: " << deleted << std::endl;
} }
} }

@ -680,7 +680,7 @@ std::string creatureFlags(int flags)
if (flags & ESM::Creature::Walks) properties += "Walks "; if (flags & ESM::Creature::Walks) properties += "Walks ";
if (flags & ESM::Creature::Swims) properties += "Swims "; if (flags & ESM::Creature::Swims) properties += "Swims ";
if (flags & ESM::Creature::Flies) properties += "Flies "; if (flags & ESM::Creature::Flies) properties += "Flies ";
if (flags & ESM::Creature::Biped) properties += "Biped "; if (flags & ESM::Creature::Bipedal) properties += "Bipedal ";
if (flags & ESM::Creature::Respawn) properties += "Respawn "; if (flags & ESM::Creature::Respawn) properties += "Respawn ";
if (flags & ESM::Creature::Weapon) properties += "Weapon "; if (flags & ESM::Creature::Weapon) properties += "Weapon ";
if (flags & ESM::Creature::Skeleton) properties += "Skeleton "; if (flags & ESM::Creature::Skeleton) properties += "Skeleton ";
@ -691,7 +691,7 @@ std::string creatureFlags(int flags)
ESM::Creature::Walks| ESM::Creature::Walks|
ESM::Creature::Swims| ESM::Creature::Swims|
ESM::Creature::Flies| ESM::Creature::Flies|
ESM::Creature::Biped| ESM::Creature::Bipedal|
ESM::Creature::Respawn| ESM::Creature::Respawn|
ESM::Creature::Weapon| ESM::Creature::Weapon|
ESM::Creature::Skeleton| ESM::Creature::Skeleton|
@ -717,16 +717,26 @@ std::string landFlags(int flags)
return properties; return properties;
} }
std::string leveledListFlags(int flags) std::string itemListFlags(int flags)
{ {
std::string properties = ""; std::string properties = "";
if (flags == 0) properties += "[None] "; if (flags == 0) properties += "[None] ";
if (flags & ESM::LeveledListBase::AllLevels) properties += "AllLevels "; if (flags & ESM::ItemLevList::AllLevels) properties += "AllLevels ";
// This flag apparently not present on creature lists... if (flags & ESM::ItemLevList::Each) properties += "Each ";
if (flags & ESM::LeveledListBase::Each) properties += "Each ";
int unused = (0xFFFFFFFF ^ int unused = (0xFFFFFFFF ^
(ESM::LeveledListBase::AllLevels| (ESM::ItemLevList::AllLevels|
ESM::LeveledListBase::Each)); ESM::ItemLevList::Each));
if (flags & unused) properties += "Invalid ";
properties += str(boost::format("(0x%08X)") % flags);
return properties;
}
std::string creatureListFlags(int flags)
{
std::string properties = "";
if (flags == 0) properties += "[None] ";
if (flags & ESM::CreatureLevList::AllLevels) properties += "AllLevels ";
int unused = (0xFFFFFFFF ^ ESM::CreatureLevList::AllLevels);
if (flags & unused) properties += "Invalid "; if (flags & unused) properties += "Invalid ";
properties += str(boost::format("(0x%08X)") % flags); properties += str(boost::format("(0x%08X)") % flags);
return properties; return properties;
@ -764,34 +774,19 @@ std::string magicEffectFlags(int flags)
{ {
std::string properties = ""; std::string properties = "";
if (flags == 0) properties += "[None] "; if (flags == 0) properties += "[None] ";
// Enchanting & SpellMaking occur on the same list of effects. if (flags & ESM::MagicEffect::TargetAttribute) properties += "TargetAttribute ";
// "EXTRA SPELL" appears in the construction set under both the if (flags & ESM::MagicEffect::TargetSkill) properties += "TargetSkill ";
// spell making and enchanting tabs as an allowed effect. Since
// most of the effects without this flags are defective in various
// ways, it's still very unclear what these flag bits are.
if (flags & ESM::MagicEffect::SpellMaking) properties += "SpellMaking ";
if (flags & ESM::MagicEffect::Enchanting) properties += "Enchanting ";
if (flags & 0x00000040) properties += "RangeNoSelf ";
if (flags & 0x00000080) properties += "RangeTouch ";
if (flags & 0x00000100) properties += "RangeTarget ";
if (flags & 0x00001000) properties += "Unknown2 ";
if (flags & 0x00000001) properties += "AffectSkill ";
if (flags & 0x00000002) properties += "AffectAttribute ";
if (flags & ESM::MagicEffect::NoDuration) properties += "NoDuration "; if (flags & ESM::MagicEffect::NoDuration) properties += "NoDuration ";
if (flags & 0x00000008) properties += "NoMagnitude "; if (flags & ESM::MagicEffect::NoMagnitude) properties += "NoMagnitude ";
if (flags & 0x00000010) properties += "Negative "; if (flags & ESM::MagicEffect::Harmful) properties += "Harmful ";
if (flags & 0x00000020) properties += "Unknown1 "; if (flags & ESM::MagicEffect::ContinuousVfx) properties += "ContinuousVFX ";
// ESM componet says 0x800 is negative, but none of the magic if (flags & ESM::MagicEffect::CastSelf) properties += "CastSelf ";
// effects have this flags set. if (flags & ESM::MagicEffect::CastTouch) properties += "CastTouch ";
if (flags & ESM::MagicEffect::Negative) properties += "Unused "; if (flags & ESM::MagicEffect::CastTarget) properties += "CastTarget ";
// Since only Chameleon has this flag it could be anything if (flags & ESM::MagicEffect::UncappedDamage) properties += "UncappedDamage ";
// that uniquely distinguishes Chameleon. if (flags & ESM::MagicEffect::NonRecastable) properties += "NonRecastable ";
if (flags & 0x00002000) properties += "Chameleon "; if (flags & ESM::MagicEffect::Unreflectable) properties += "Unreflectable ";
if (flags & 0x00004000) properties += "Bound "; if (flags & ESM::MagicEffect::CasterLinked) properties += "CasterLinked ";
if (flags & 0x00008000) properties += "Summon ";
// Calm, Demoralize, Frenzy, Lock, Open, Rally, Soultrap, Turn Unded
if (flags & 0x00010000) properties += "Unknown3 ";
if (flags & 0x00020000) properties += "Absorb ";
if (flags & 0xFFFC0000) properties += "Invalid "; if (flags & 0xFFFC0000) properties += "Invalid ";
properties += str(boost::format("(0x%08X)") % flags); properties += str(boost::format("(0x%08X)") % flags);
return properties; return properties;

@ -50,7 +50,8 @@ std::string cellFlags(int flags);
std::string containerFlags(int flags); std::string containerFlags(int flags);
std::string creatureFlags(int flags); std::string creatureFlags(int flags);
std::string landFlags(int flags); std::string landFlags(int flags);
std::string leveledListFlags(int flags); std::string creatureListFlags(int flags);
std::string itemListFlags(int flags);
std::string lightFlags(int flags); std::string lightFlags(int flags);
std::string magicEffectFlags(int flags); std::string magicEffectFlags(int flags);
std::string npcFlags(int flags); std::string npcFlags(int flags);

@ -13,8 +13,8 @@ void printAIPackage(ESM::AIPackage p)
std::cout << " Distance: " << p.mWander.mDistance << std::endl; std::cout << " Distance: " << p.mWander.mDistance << std::endl;
std::cout << " Duration: " << p.mWander.mDuration << std::endl; std::cout << " Duration: " << p.mWander.mDuration << std::endl;
std::cout << " Time of Day: " << (int)p.mWander.mTimeOfDay << std::endl; std::cout << " Time of Day: " << (int)p.mWander.mTimeOfDay << std::endl;
if (p.mWander.mUnk != 1) if (p.mWander.mShouldRepeat != 1)
std::cout << " Unknown: " << (int)p.mWander.mUnk << std::endl; std::cout << " Should repeat: " << (bool)p.mWander.mShouldRepeat << std::endl;
std::cout << " Idle: "; std::cout << " Idle: ";
for (int i = 0; i != 8; i++) for (int i = 0; i != 8; i++)
@ -834,7 +834,7 @@ template<>
void Record<ESM::CreatureLevList>::print() void Record<ESM::CreatureLevList>::print()
{ {
std::cout << " Chance for None: " << (int)mData.mChanceNone << std::endl; std::cout << " Chance for None: " << (int)mData.mChanceNone << std::endl;
std::cout << " Flags: " << leveledListFlags(mData.mFlags) << std::endl; std::cout << " Flags: " << creatureListFlags(mData.mFlags) << std::endl;
std::cout << " Number of items: " << mData.mList.size() << std::endl; std::cout << " Number of items: " << mData.mList.size() << std::endl;
std::vector<ESM::LeveledListBase::LevelItem>::iterator iit; std::vector<ESM::LeveledListBase::LevelItem>::iterator iit;
for (iit = mData.mList.begin(); iit != mData.mList.end(); iit++) for (iit = mData.mList.begin(); iit != mData.mList.end(); iit++)
@ -846,11 +846,11 @@ template<>
void Record<ESM::ItemLevList>::print() void Record<ESM::ItemLevList>::print()
{ {
std::cout << " Chance for None: " << (int)mData.mChanceNone << std::endl; std::cout << " Chance for None: " << (int)mData.mChanceNone << std::endl;
std::cout << " Flags: " << leveledListFlags(mData.mFlags) << std::endl; std::cout << " Flags: " << itemListFlags(mData.mFlags) << std::endl;
std::cout << " Number of items: " << mData.mList.size() << std::endl; std::cout << " Number of items: " << mData.mList.size() << std::endl;
std::vector<ESM::LeveledListBase::LevelItem>::iterator iit; std::vector<ESM::LeveledListBase::LevelItem>::iterator iit;
for (iit = mData.mList.begin(); iit != mData.mList.end(); iit++) for (iit = mData.mList.begin(); iit != mData.mList.end(); iit++)
std::cout << " Inventory: Count: " << iit->mLevel std::cout << " Inventory: Level: " << iit->mLevel
<< " Item: " << iit->mId << std::endl; << " Item: " << iit->mId << std::endl;
} }
@ -958,7 +958,7 @@ void Record<ESM::MagicEffect>::print()
std::cout << " RGB Color: " << "(" std::cout << " RGB Color: " << "("
<< mData.mData.mRed << "," << mData.mData.mRed << ","
<< mData.mData.mGreen << "," << mData.mData.mGreen << ","
<< mData.mData.mGreen << ")" << std::endl; << mData.mData.mBlue << ")" << std::endl;
} }
template<> template<>
@ -989,8 +989,7 @@ void Record<ESM::NPC>::print()
std::cout << " Faction: " << mData.mFaction << std::endl; std::cout << " Faction: " << mData.mFaction << std::endl;
std::cout << " Flags: " << npcFlags(mData.mFlags) << std::endl; std::cout << " Flags: " << npcFlags(mData.mFlags) << std::endl;
// Seriously? if (mData.mNpdtType == ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS)
if (mData.mNpdt52.mGold == -10)
{ {
std::cout << " Level: " << mData.mNpdt12.mLevel << std::endl; std::cout << " Level: " << mData.mNpdt12.mLevel << std::endl;
std::cout << " Reputation: " << (int)mData.mNpdt12.mReputation << std::endl; std::cout << " Reputation: " << (int)mData.mNpdt12.mReputation << std::endl;
@ -1022,7 +1021,7 @@ void Record<ESM::NPC>::print()
std::cout << " Luck: " << (int)mData.mNpdt52.mLuck << std::endl; std::cout << " Luck: " << (int)mData.mNpdt52.mLuck << std::endl;
std::cout << " Skills:" << std::endl; std::cout << " Skills:" << std::endl;
for (int i = 0; i != 27; i++) for (int i = 0; i != ESM::Skill::Length; i++)
std::cout << " " << skillLabel(i) << ": " std::cout << " " << skillLabel(i) << ": "
<< (int)((unsigned char)mData.mNpdt52.mSkills[i]) << std::endl; << (int)((unsigned char)mData.mNpdt52.mSkills[i]) << std::endl;

@ -132,8 +132,3 @@ if (BUILD_WITH_CODE_COVERAGE)
target_link_libraries(omwlauncher gcov) target_link_libraries(omwlauncher gcov)
endif() endif()
# Workaround for binutil => 2.23 problem when linking, should be fixed eventually upstream
if (UNIX AND NOT APPLE)
target_link_libraries(omwlauncher dl Xt)
endif()

@ -16,6 +16,7 @@
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software"); SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software");
SDL_SetMainReady();
if (SDL_Init(SDL_INIT_VIDEO) != 0) if (SDL_Init(SDL_INIT_VIDEO) != 0)
{ {
qDebug() << "SDL_Init failed: " << QString::fromStdString(SDL_GetError()); qDebug() << "SDL_Init failed: " << QString::fromStdString(SDL_GetError());

@ -1,5 +1,10 @@
#include "maindialog.hpp" #include "maindialog.hpp"
#include <components/version/version.hpp>
#include <QLabel>
#include <QDate>
#include <QTime>
#include <QPushButton> #include <QPushButton>
#include <QFontDatabase> #include <QFontDatabase>
#include <QInputDialog> #include <QInputDialog>
@ -67,6 +72,22 @@ Launcher::MainDialog::MainDialog(QWidget *parent)
// Remove what's this? button // Remove what's this? button
setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint); setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint);
// Add version information to bottom of the window
QString revision(OPENMW_VERSION_COMMITHASH);
QString tag(OPENMW_VERSION_TAGHASH);
if (revision == tag) {
versionLabel->setText(tr("OpenMW %0 release").arg(OPENMW_VERSION));
} else {
versionLabel->setText(tr("OpenMW development (%0)").arg(revision.left(10)));
}
// Add the compile date and time
versionLabel->setToolTip(tr("Compiled on %0 %1").arg(QLocale(QLocale::C).toDate(QString(__DATE__).simplified(),
QLatin1String("MMM d yyyy")).toString(Qt::SystemLocaleLongDate),
QLocale(QLocale::C).toTime(QString(__TIME__).simplified(),
QLatin1String("hh:mm:ss")).toString(Qt::SystemLocaleShortDate)));
createIcons(); createIcons();
} }
@ -219,7 +240,7 @@ bool Launcher::MainDialog::showFirstRunDialog()
} }
// Create the file if it doesn't already exist, else the importer will fail // Create the file if it doesn't already exist, else the importer will fail
QString path = QString::fromStdString(mCfgMgr.getUserPath().string()) + QString("openmw.cfg"); QString path = QString::fromStdString(mCfgMgr.getUserConfigPath().string()) + QString("openmw.cfg");
QFile file(path); QFile file(path);
if (!file.exists()) { if (!file.exists()) {
@ -334,7 +355,7 @@ bool Launcher::MainDialog::setupLauncherSettings()
{ {
mLauncherSettings.setMultiValueEnabled(true); mLauncherSettings.setMultiValueEnabled(true);
QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string()); QString userPath = QString::fromStdString(mCfgMgr.getUserConfigPath().string());
QStringList paths; QStringList paths;
paths.append(QString("launcher.cfg")); paths.append(QString("launcher.cfg"));
@ -440,9 +461,35 @@ bool Launcher::expansions(Launcher::UnshieldThread& cd)
bool Launcher::MainDialog::setupGameSettings() bool Launcher::MainDialog::setupGameSettings()
{ {
QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string()); QString userPath = QString::fromStdString(mCfgMgr.getUserConfigPath().string());
QString globalPath = QString::fromStdString(mCfgMgr.getGlobalPath().string()); QString globalPath = QString::fromStdString(mCfgMgr.getGlobalPath().string());
// Load the user config file first, separately
// So we can write it properly, uncontaminated
QString path = userPath + QLatin1String("openmw.cfg");
QFile file(path);
qDebug() << "Loading config file:" << qPrintable(path);
if (file.exists()) {
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
QMessageBox msgBox;
msgBox.setWindowTitle(tr("Error opening OpenMW configuration file"));
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(QObject::tr("<br><b>Could not open %0 for reading</b><br><br> \
Please make sure you have the right permissions \
and try again.<br>").arg(file.fileName()));
msgBox.exec();
return false;
}
QTextStream stream(&file);
stream.setCodec(QTextCodec::codecForName("UTF-8"));
mGameSettings.readUserFile(stream);
}
// Now the rest
QStringList paths; QStringList paths;
paths.append(userPath + QString("openmw.cfg")); paths.append(userPath + QString("openmw.cfg"));
paths.append(QString("openmw.cfg")); paths.append(QString("openmw.cfg"));
@ -565,7 +612,7 @@ bool Launcher::MainDialog::setupGraphicsSettings()
{ {
mGraphicsSettings.setMultiValueEnabled(false); mGraphicsSettings.setMultiValueEnabled(false);
QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string()); QString userPath = QString::fromStdString(mCfgMgr.getUserConfigPath().string());
QString globalPath = QString::fromStdString(mCfgMgr.getGlobalPath().string()); QString globalPath = QString::fromStdString(mCfgMgr.getGlobalPath().string());
QFile localDefault(QString("settings-default.cfg")); QFile localDefault(QString("settings-default.cfg"));
@ -652,7 +699,7 @@ bool Launcher::MainDialog::writeSettings()
mGraphicsPage->saveSettings(); mGraphicsPage->saveSettings();
mDataFilesPage->saveSettings(); mDataFilesPage->saveSettings();
QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string()); QString userPath = QString::fromStdString(mCfgMgr.getUserConfigPath().string());
QDir dir(userPath); QDir dir(userPath);
if (!dir.exists()) { if (!dir.exists()) {

@ -235,7 +235,7 @@ namespace
{ {
for ( bfs::recursive_directory_iterator end, dir(in); dir != end; ++dir ) for ( bfs::recursive_directory_iterator end, dir(in); dir != end; ++dir )
{ {
if(Misc::StringUtils::lowerCase(dir->path().filename().string()) == filename) if(Misc::StringUtils::ciEqual(dir->path().filename().string(), filename))
return dir->path(); return dir->path();
} }
} }
@ -243,7 +243,7 @@ namespace
{ {
for ( bfs::directory_iterator end, dir(in); dir != end; ++dir ) for ( bfs::directory_iterator end, dir(in); dir != end; ++dir )
{ {
if(Misc::StringUtils::lowerCase(dir->path().filename().string()) == filename) if(Misc::StringUtils::ciEqual(dir->path().filename().string(), filename))
return dir->path(); return dir->path();
} }
} }
@ -255,7 +255,7 @@ namespace
{ {
for(bfs::directory_iterator end, dir(in); dir != end; ++dir) for(bfs::directory_iterator end, dir(in); dir != end; ++dir)
{ {
if(Misc::StringUtils::lowerCase(dir->path().filename().string()) == filename) if(Misc::StringUtils::ciEqual(dir->path().filename().string(), filename))
return true; return true;
} }

@ -16,7 +16,7 @@ MwIniImporter::MwIniImporter()
const char *map[][2] = const char *map[][2] =
{ {
{ "fps", "General:Show FPS" }, { "fps", "General:Show FPS" },
{ "nosound", "General:Disable Audio" }, { "no-sound", "General:Disable Audio" },
{ 0, 0 } { 0, 0 }
}; };
const char *fallback[] = { const char *fallback[] = {
@ -623,6 +623,17 @@ MwIniImporter::MwIniImporter()
"Moons:Masser Fade Out Finish", "Moons:Masser Fade Out Finish",
"Moons:Script Color", "Moons:Script Color",
// blood
"Blood:Model 0",
"Blood:Model 1",
"Blood:Model 2",
"Blood:Texture 0",
"Blood:Texture 1",
"Blood:Texture 2",
"Blood:Texture Name 0",
"Blood:Texture Name 1",
"Blood:Texture Name 2",
0 0
}; };

@ -24,7 +24,7 @@ opencs_units (model/world
opencs_units_noqt (model/world opencs_units_noqt (model/world
universalid record commands columnbase scriptcontext cell refidcollection universalid record commands columnbase scriptcontext cell refidcollection
refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata
) )
opencs_hdrs_noqt (model/world opencs_hdrs_noqt (model/world
@ -38,7 +38,7 @@ opencs_units (model/tools
opencs_units_noqt (model/tools opencs_units_noqt (model/tools
mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck
birthsigncheck spellcheck birthsigncheck spellcheck referenceablecheck scriptcheck
) )
@ -60,7 +60,7 @@ opencs_hdrs_noqt (view/doc
opencs_units (view/world opencs_units (view/world
table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator
cellcreator referenceablecreator referencecreator scenesubview scenetoolbar scenetool cellcreator referenceablecreator referencecreator scenesubview scenetoolbar scenetool
scenetoolmode infocreator scenetoolmode infocreator scriptedit
) )
opencs_units (view/render opencs_units (view/render
@ -143,7 +143,7 @@ if(WIN32)
set(QT_USE_QTMAIN TRUE) set(QT_USE_QTMAIN TRUE)
endif(WIN32) endif(WIN32)
find_package(Qt4 COMPONENTS QtCore QtGui QtNetwork QtXml QtXmlPatterns REQUIRED) find_package(Qt4 COMPONENTS QtCore QtGui QtNetwork REQUIRED)
include(${QT_USE_FILE}) include(${QT_USE_FILE})
qt4_wrap_ui(OPENCS_UI_HDR ${OPENCS_UI}) qt4_wrap_ui(OPENCS_UI_HDR ${OPENCS_UI})

@ -86,10 +86,6 @@ void CS::Editor::setupDataFiles()
return; return;
} }
// Set the charset for reading the esm/esp files
// QString encoding = QString::fromStdString(variables["encoding"].as<std::string>());
//mFileDialog.setEncoding(encoding);
dataDirs.insert (dataDirs.end(), dataLocal.begin(), dataLocal.end()); dataDirs.insert (dataDirs.end(), dataLocal.begin(), dataLocal.end());
mDocumentManager.setResourceDir (variables["resources"].as<std::string>()); mDocumentManager.setResourceDir (variables["resources"].as<std::string>());
@ -214,6 +210,8 @@ int CS::Editor::run()
if (mLocal.empty()) if (mLocal.empty())
return 1; return 1;
// temporarily disable OGRE-integration (need to fix path problem first)
#if 0
// TODO: setting // TODO: setting
Ogre::Root::getSingleton().setRenderSystem(Ogre::Root::getSingleton().getRenderSystemByName("OpenGL Rendering Subsystem")); Ogre::Root::getSingleton().setRenderSystem(Ogre::Root::getSingleton().getRenderSystemByName("OpenGL Rendering Subsystem"));
@ -225,8 +223,12 @@ int CS::Editor::run()
params.insert(std::make_pair("FSAA", "0")); params.insert(std::make_pair("FSAA", "0"));
params.insert(std::make_pair("vsync", "false")); params.insert(std::make_pair("vsync", "false"));
params.insert(std::make_pair("hidden", "true")); params.insert(std::make_pair("hidden", "true"));
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
params.insert(std::make_pair("macAPI", "cocoa"));
#endif
Ogre::RenderWindow* hiddenWindow = Ogre::Root::getSingleton().createRenderWindow("InactiveHidden", 1, 1, false, &params); Ogre::RenderWindow* hiddenWindow = Ogre::Root::getSingleton().createRenderWindow("InactiveHidden", 1, 1, false, &params);
hiddenWindow->setActive(false); hiddenWindow->setActive(false);
#endif
mStartup.show(); mStartup.show();

@ -42,10 +42,13 @@ int main(int argc, char *argv[])
// TODO: Ogre startup shouldn't be here, but it currently has to: // TODO: Ogre startup shouldn't be here, but it currently has to:
// SceneWidget destructor will delete the created render window, which would be called _after_ Root has shut down :( // SceneWidget destructor will delete the created render window, which would be called _after_ Root has shut down :(
OgreInit::OgreInit ogreInit;
ogreInit.init("./opencsOgre.log"); // TODO log path?
Application mApplication (argc, argv); Application mApplication (argc, argv);
// temporarily disable OGRE-integration (need to fix path problem first)
#if 0
OgreInit::OgreInit ogreInit;
ogreInit.init("./opencsOgre.log"); // TODO log path?
#endif
#ifdef Q_OS_MAC #ifdef Q_OS_MAC
QDir dir(QCoreApplication::applicationDirPath()); QDir dir(QCoreApplication::applicationDirPath());

@ -2221,7 +2221,7 @@ void CSMDoc::Document::createBase()
CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, const std::vector< boost::filesystem::path >& files, const boost::filesystem::path& savePath, const boost::filesystem::path& resDir, bool new_) CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, const std::vector< boost::filesystem::path >& files, const boost::filesystem::path& savePath, const boost::filesystem::path& resDir, bool new_)
: mSavePath (savePath), mContentFiles (files), mTools (mData), mResDir(resDir), : mSavePath (savePath), mContentFiles (files), mTools (mData), mResDir(resDir),
mProjectPath ((configuration.getUserPath() / "projects") / mProjectPath ((configuration.getUserDataPath() / "projects") /
(savePath.filename().string() + ".project")), (savePath.filename().string() + ".project")),
mSaving (*this, mProjectPath) mSaving (*this, mProjectPath)
{ {
@ -2254,7 +2254,7 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, co
} }
else else
{ {
boost::filesystem::path locCustomFiltersPath (configuration.getUserPath()); boost::filesystem::path locCustomFiltersPath (configuration.getUserDataPath());
locCustomFiltersPath /= "defaultfilters"; locCustomFiltersPath /= "defaultfilters";
if (boost::filesystem::exists(locCustomFiltersPath)) if (boost::filesystem::exists(locCustomFiltersPath))

@ -71,7 +71,10 @@ namespace CSMDoc
public: public:
Document (const Files::ConfigurationManager& configuration, const std::vector< boost::filesystem::path >& files, const boost::filesystem::path& savePath, const boost::filesystem::path& resDir, bool new_); Document (const Files::ConfigurationManager& configuration,
const std::vector< boost::filesystem::path >& files,
const boost::filesystem::path& savePath,
const boost::filesystem::path& resDir, bool new_);
~Document(); ~Document();

@ -15,7 +15,7 @@
CSMDoc::DocumentManager::DocumentManager (const Files::ConfigurationManager& configuration) CSMDoc::DocumentManager::DocumentManager (const Files::ConfigurationManager& configuration)
: mConfiguration (configuration) : mConfiguration (configuration)
{ {
boost::filesystem::path projectPath = configuration.getUserPath() / "projects"; boost::filesystem::path projectPath = configuration.getUserDataPath() / "projects";
if (!boost::filesystem::is_directory (projectPath)) if (!boost::filesystem::is_directory (projectPath))
boost::filesystem::create_directories (projectPath); boost::filesystem::create_directories (projectPath);
@ -53,4 +53,4 @@ bool CSMDoc::DocumentManager::removeDocument (Document *document)
void CSMDoc::DocumentManager::setResourceDir (const boost::filesystem::path& parResDir) void CSMDoc::DocumentManager::setResourceDir (const boost::filesystem::path& parResDir)
{ {
mResDir = boost::filesystem::system_complete(parResDir); mResDir = boost::filesystem::system_complete(parResDir);
} }

@ -29,7 +29,9 @@ namespace CSMDoc
~DocumentManager(); ~DocumentManager();
Document *addDocument (const std::vector< boost::filesystem::path >& files, const boost::filesystem::path& savePath, bool new_); Document *addDocument (const std::vector< boost::filesystem::path >& files,
const boost::filesystem::path& savePath,
bool new_);
///< The ownership of the returned document is not transferred to the caller. ///< The ownership of the returned document is not transferred to the caller.
/// ///
/// \param new_ Do not load the last content file in \a files and instead create in an /// \param new_ Do not load the last content file in \a files and instead create in an

@ -133,16 +133,10 @@ void CSMDoc::WriteDialogueCollectionStage::perform (int stage, std::vector<std::
state==CSMWorld::RecordBase::State_ModifiedOnly || state==CSMWorld::RecordBase::State_ModifiedOnly ||
infoModified) infoModified)
{ {
// always write the topic record mState.getWriter().startRecord (topic.mModified.sRecordId);
std::string type;
for (int i=0; i<4; ++i)
/// \todo make endianess agnostic (change ESMWriter interface?)
type += reinterpret_cast<const char *> (&topic.mModified.sRecordId)[i];
mState.getWriter().startRecord (type);
mState.getWriter().writeHNCString ("NAME", topic.mModified.mId); mState.getWriter().writeHNCString ("NAME", topic.mModified.mId);
topic.mModified.save (mState.getWriter()); topic.mModified.save (mState.getWriter());
mState.getWriter().endRecord (type); mState.getWriter().endRecord (topic.mModified.sRecordId);
// write modified selected info records // write modified selected info records
for (CSMWorld::InfoCollection::RecordConstIterator iter (range.first); iter!=range.second; for (CSMWorld::InfoCollection::RecordConstIterator iter (range.first); iter!=range.second;
@ -178,15 +172,10 @@ void CSMDoc::WriteDialogueCollectionStage::perform (int stage, std::vector<std::
next->mModified.mId.substr (next->mModified.mId.find_last_of ('#')+1); next->mModified.mId.substr (next->mModified.mId.find_last_of ('#')+1);
} }
std::string type; mState.getWriter().startRecord (info.sRecordId);
for (int i=0; i<4; ++i)
/// \todo make endianess agnostic (change ESMWriter interface?)
type += reinterpret_cast<const char *> (&info.sRecordId)[i];
mState.getWriter().startRecord (type);
mState.getWriter().writeHNCString ("INAM", info.mId); mState.getWriter().writeHNCString ("INAM", info.mId);
info.save (mState.getWriter()); info.save (mState.getWriter());
mState.getWriter().endRecord (type); mState.getWriter().endRecord (info.sRecordId);
} }
} }
} }

@ -104,10 +104,10 @@ namespace CSMDoc
/// \todo make endianess agnostic (change ESMWriter interface?) /// \todo make endianess agnostic (change ESMWriter interface?)
type += reinterpret_cast<const char *> (&mCollection.getRecord (stage).mModified.sRecordId)[i]; type += reinterpret_cast<const char *> (&mCollection.getRecord (stage).mModified.sRecordId)[i];
mState.getWriter().startRecord (type); mState.getWriter().startRecord (mCollection.getRecord (stage).mModified.sRecordId);
mState.getWriter().writeHNCString ("NAME", mCollection.getId (stage)); mState.getWriter().writeHNCString ("NAME", mCollection.getId (stage));
mCollection.getRecord (stage).mModified.save (mState.getWriter()); mCollection.getRecord (stage).mModified.save (mState.getWriter());
mState.getWriter().endRecord (type); mState.getWriter().endRecord (mCollection.getRecord (stage).mModified.sRecordId);
} }
else if (state==CSMWorld::RecordBase::State_Deleted) else if (state==CSMWorld::RecordBase::State_Deleted)
{ {

@ -251,7 +251,7 @@ void CSMSettings::UserSettings::loadSettings (const QString &fileName)
bool localOk = loadFromFile(localFilePath); bool localOk = loadFromFile(localFilePath);
//user //user
mUserFilePath = QString::fromStdString(mCfgMgr.getUserPath().string()) + fileName; mUserFilePath = QString::fromStdString(mCfgMgr.getUserConfigPath().string()) + fileName;
loadFromFile(mUserFilePath); loadFromFile(mUserFilePath);
if (!(localOk || globalOk)) if (!(localOk || globalOk))

File diff suppressed because it is too large Load Diff

@ -0,0 +1,78 @@
#ifndef REFERENCEABLECHECKSTAGE_H
#define REFERENCEABLECHECKSTAGE_H
#include "../world/universalid.hpp"
#include "../doc/stage.hpp"
#include "../world/data.hpp"
#include "../world/refiddata.hpp"
namespace CSMTools
{
class ReferenceableCheckStage : public CSMDoc::Stage
{
public:
ReferenceableCheckStage(const CSMWorld::RefIdData& referenceable,
const CSMWorld::IdCollection<ESM::Race>& races,
const CSMWorld::IdCollection<ESM::Class>& classes,
const CSMWorld::IdCollection<ESM::Faction>& factions);
virtual void perform(int stage, std::vector< std::string >& messages);
virtual int setup();
private:
//CONCRETE CHECKS
void bookCheck(int stage, const CSMWorld::RefIdDataContainer< ESM::Book >& records, std::vector< std::string >& messages);
void activatorCheck(int stage, const CSMWorld::RefIdDataContainer< ESM::Activator >& records, std::vector< std::string >& messages);
void potionCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Potion>& records, std::vector<std::string>& messages);
void apparatusCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Apparatus>& records, std::vector<std::string>& messages);
void armorCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Armor>& records, std::vector<std::string>& messages);
void clothingCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Clothing>& records, std::vector<std::string>& messages);
void containerCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Container>& records, std::vector<std::string>& messages);
void creatureCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Creature>& records, std::vector<std::string>& messages);
void doorCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Door>& records, std::vector<std::string>& messages);
void ingredientCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Ingredient>& records, std::vector<std::string>& messages);
void creaturesLevListCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::CreatureLevList>& records, std::vector<std::string>& messages);
void itemLevelledListCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::ItemLevList>& records, std::vector<std::string>& messages);
void lightCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Light>& records, std::vector<std::string>& messages);
void lockpickCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Lockpick>& records, std::vector<std::string>& messages);
void miscCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Miscellaneous>& records, std::vector<std::string>& messages);
void npcCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::NPC>& records, std::vector<std::string>& messages);
void weaponCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Weapon>& records, std::vector<std::string>& messages);
void probeCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Probe>& records, std::vector<std::string>& messages);
void repairCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Repair>& records, std::vector<std::string>& messages);
void staticCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Static>& records, std::vector<std::string>& messages);
//FINAL CHECK
void finalCheck(std::vector<std::string>& messages);
//TEMPLATE CHECKS
template<typename ITEM> void inventoryItemCheck(const ITEM& someItem,
std::vector<std::string>& messages,
const std::string& someID,
bool enchantable); //for all enchantable items.
template<typename ITEM> void inventoryItemCheck(const ITEM& someItem,
std::vector<std::string>& messages,
const std::string& someID); //for non-enchantable items.
template<typename TOOL> void toolCheck(const TOOL& someTool,
std::vector<std::string>& messages,
const std::string& someID,
bool canbebroken); //for tools with uses.
template<typename TOOL> void toolCheck(const TOOL& someTool,
std::vector<std::string>& messages,
const std::string& someID); //for tools without uses.
template<typename LIST> void listCheck(const LIST& someList,
std::vector< std::string >& messages,
const std::string& someID);
const CSMWorld::RefIdData& mReferencables;
const CSMWorld::IdCollection<ESM::Race>& mRaces;
const CSMWorld::IdCollection<ESM::Class>& mClasses;
const CSMWorld::IdCollection<ESM::Faction>& mFactions;
bool mPlayerPresent;
};
}
#endif // REFERENCEABLECHECKSTAGE_H

@ -68,4 +68,4 @@ void CSMTools::ReportModel::add (const std::string& row)
const CSMWorld::UniversalId& CSMTools::ReportModel::getUniversalId (int row) const const CSMWorld::UniversalId& CSMTools::ReportModel::getUniversalId (int row) const
{ {
return mRows.at (row).first; return mRows.at (row).first;
} }

@ -0,0 +1,103 @@
#include "scriptcheck.hpp"
#include <components/compiler/tokenloc.hpp>
#include <components/compiler/scanner.hpp>
#include <components/compiler/fileparser.hpp>
#include <components/compiler/exception.hpp>
#include <components/compiler/extensions0.hpp>
#include "../world/data.hpp"
void CSMTools::ScriptCheckStage::report (const std::string& message, const Compiler::TokenLoc& loc,
Type type)
{
std::ostringstream stream;
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId);
stream << id.toString() << "|";
if (type==ErrorMessage)
stream << "error ";
else
stream << "warning ";
stream
<< "script " << mFile
<< ", line " << loc.mLine << ", column " << loc.mColumn
<< " (" << loc.mLiteral << "): " << message;
mMessages->push_back (stream.str());
}
void CSMTools::ScriptCheckStage::report (const std::string& message, Type type)
{
std::ostringstream stream;
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId);
stream << id.toString() << "|";
if (type==ErrorMessage)
stream << "error: ";
else
stream << "warning: ";
stream << message;
mMessages->push_back (stream.str());
}
CSMTools::ScriptCheckStage::ScriptCheckStage (const CSMWorld::Data& data)
: mData (data), mContext (data), mMessages (0)
{
/// \todo add an option to configure warning mode
setWarningsMode (0);
Compiler::registerExtensions (mExtensions);
mContext.setExtensions (&mExtensions);
}
int CSMTools::ScriptCheckStage::setup()
{
mContext.clear();
mMessages = 0;
mId.clear();
return mData.getScripts().getSize();
}
void CSMTools::ScriptCheckStage::perform (int stage, std::vector<std::string>& messages)
{
mMessages = &messages;
mId = mData.getScripts().getId (stage);
try
{
mFile = mData.getScripts().getRecord (stage).get().mId;
std::istringstream input (mData.getScripts().getRecord (stage).get().mScriptText);
Compiler::Scanner scanner (*this, input, mContext.getExtensions());
Compiler::FileParser parser (*this, mContext);
scanner.scan (parser);
}
catch (const Compiler::SourceException&)
{
// error has already been reported via error handler
}
catch (const std::exception& error)
{
std::ostringstream stream;
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId);
stream << id.toString() << "|Critical compile error: " << error.what();
messages.push_back (stream.str());
}
mMessages = 0;
}

@ -0,0 +1,41 @@
#ifndef CSM_TOOLS_SCRIPTCHECK_H
#define CSM_TOOLS_SCRIPTCHECK_H
#include <components/compiler/errorhandler.hpp>
#include <components/compiler/extensions.hpp>
#include "../doc/stage.hpp"
#include "../world/scriptcontext.hpp"
namespace CSMTools
{
/// \brief VerifyStage: make sure that scripts compile
class ScriptCheckStage : public CSMDoc::Stage, private Compiler::ErrorHandler
{
const CSMWorld::Data& mData;
Compiler::Extensions mExtensions;
CSMWorld::ScriptContext mContext;
std::string mId;
std::string mFile;
std::vector<std::string> *mMessages;
virtual void report (const std::string& message, const Compiler::TokenLoc& loc, Type type);
///< Report error to the user.
virtual void report (const std::string& message, Type type);
///< Report a file related error
public:
ScriptCheckStage (const CSMWorld::Data& data);
virtual int setup();
///< \return number of steps
virtual void perform (int stage, std::vector<std::string>& messages);
///< Messages resulting from this tage will be appended to \a messages.
};
}
#endif

@ -19,6 +19,8 @@
#include "regioncheck.hpp" #include "regioncheck.hpp"
#include "birthsigncheck.hpp" #include "birthsigncheck.hpp"
#include "spellcheck.hpp" #include "spellcheck.hpp"
#include "referenceablecheck.hpp"
#include "scriptcheck.hpp"
CSMDoc::Operation *CSMTools::Tools::get (int type) CSMDoc::Operation *CSMTools::Tools::get (int type)
{ {
@ -74,6 +76,10 @@ CSMDoc::Operation *CSMTools::Tools::getVerifier()
mVerifier->appendStage (new BirthsignCheckStage (mData.getBirthsigns())); mVerifier->appendStage (new BirthsignCheckStage (mData.getBirthsigns()));
mVerifier->appendStage (new SpellCheckStage (mData.getSpells())); mVerifier->appendStage (new SpellCheckStage (mData.getSpells()));
mVerifier->appendStage (new ReferenceableCheckStage (mData.getReferenceables().getDataSet(), mData.getRaces(), mData.getClasses(), mData.getFactions()));
mVerifier->appendStage (new ScriptCheckStage (mData));
} }
return mVerifier; return mVerifier;
@ -138,4 +144,5 @@ void CSMTools::Tools::verifierMessage (const QString& message, int type)
if (iter!=mActiveReports.end()) if (iter!=mActiveReports.end())
mReports[iter->second]->add (message.toStdString()); mReports[iter->second]->add (message.toStdString());
} }

@ -98,6 +98,10 @@ namespace CSMWorld
UniversalId::Type type = UniversalId::Type_None); UniversalId::Type type = UniversalId::Type_None);
///< \param type Will be ignored, unless the collection supports multiple record types ///< \param type Will be ignored, unless the collection supports multiple record types
virtual void cloneRecord(const std::string& origin,
const std::string& destination,
const UniversalId::Type type);
virtual int searchId (const std::string& id) const; virtual int searchId (const std::string& id) const;
////< Search record with \a id. ////< Search record with \a id.
/// \return index of record (if found) or -1 (not found) /// \return index of record (if found) or -1 (not found)
@ -193,6 +197,19 @@ namespace CSMWorld
return true; return true;
} }
template<typename ESXRecordT, typename IdAccessorT>
void Collection<ESXRecordT, IdAccessorT>::cloneRecord(const std::string& origin,
const std::string& destination,
const UniversalId::Type type)
{
Record<ESXRecordT> copy;
copy.mModified = getRecord(origin).get();
copy.mState = RecordBase::State_ModifiedOnly;
copy.get().mId = destination;
insertRecord(copy, getAppendIndex(destination, type));
}
template<typename ESXRecordT, typename IdAccessorT> template<typename ESXRecordT, typename IdAccessorT>
Collection<ESXRecordT, IdAccessorT>::Collection() Collection<ESXRecordT, IdAccessorT>::Collection()
{} {}

@ -74,6 +74,10 @@ namespace CSMWorld
UniversalId::Type type = UniversalId::Type_None) = 0; UniversalId::Type type = UniversalId::Type_None) = 0;
///< If the record type does not match, an exception is thrown. ///< If the record type does not match, an exception is thrown.
virtual void cloneRecord(const std::string& origin,
const std::string& destination,
const UniversalId::Type type) = 0;
virtual const RecordBase& getRecord (const std::string& id) const = 0; virtual const RecordBase& getRecord (const std::string& id) const = 0;
virtual const RecordBase& getRecord (int index) const = 0; virtual const RecordBase& getRecord (int index) const = 0;

@ -27,6 +27,47 @@ namespace CSMWorld
enum Display enum Display
{ {
Display_String, Display_String,
//CONCRETE TYPES STARTS HERE
Display_Skill,
Display_Class,
Display_Faction,
Display_Race,
Display_Sound,
Display_Region,
Display_Birthsign,
Display_Spell,
Display_Cell,
Display_Referenceable,
Display_Activator,
Display_Potion,
Display_Apparatus,
Display_Armor,
Display_Book,
Display_Clothing,
Display_Container,
Display_Creature,
Display_Door,
Display_Ingredient,
Display_CreatureLevelledList,
Display_ItemLevelledList,
Display_Light,
Display_Lockpick,
Display_Miscellaneous,
Display_Npc,
Display_Probe,
Display_Repair,
Display_Static,
Display_Weapon,
Display_Reference,
Display_Filter,
Display_Topic,
Display_Journal,
Display_TopicInfo,
Display_JournalInfo,
Display_Scene,
//CONCRETE TYPES ENDS HERE
Display_Integer, Display_Integer,
Display_Float, Display_Float,
Display_Var, Display_Var,

@ -373,7 +373,7 @@ namespace CSMWorld
SkillsColumn (int index, bool typePrefix = false, bool major = false) SkillsColumn (int index, bool typePrefix = false, bool major = false)
: Column<ESXRecordT> ((typePrefix ? ( : Column<ESXRecordT> ((typePrefix ? (
major ? Columns::ColumnId_MajorSkill1 : Columns::ColumnId_MinorSkill1) : major ? Columns::ColumnId_MajorSkill1 : Columns::ColumnId_MinorSkill1) :
Columns::ColumnId_Skill1) + index, ColumnBase::Display_String), Columns::ColumnId_Skill1) + index, ColumnBase::Display_Skill),
mIndex (index), mMajor (major) mIndex (index), mMajor (major)
{} {}
@ -598,7 +598,7 @@ namespace CSMWorld
struct SoundFileColumn : public Column<ESXRecordT> struct SoundFileColumn : public Column<ESXRecordT>
{ {
SoundFileColumn() SoundFileColumn()
: Column<ESXRecordT> (Columns::ColumnId_SoundFile, ColumnBase::Display_String) : Column<ESXRecordT> (Columns::ColumnId_SoundFile, ColumnBase::Display_Sound)
{} {}
virtual QVariant get (const Record<ESXRecordT>& record) const virtual QVariant get (const Record<ESXRecordT>& record) const
@ -811,7 +811,7 @@ namespace CSMWorld
template<typename ESXRecordT> template<typename ESXRecordT>
struct CellColumn : public Column<ESXRecordT> struct CellColumn : public Column<ESXRecordT>
{ {
CellColumn() : Column<ESXRecordT> (Columns::ColumnId_Cell, ColumnBase::Display_String) {} CellColumn() : Column<ESXRecordT> (Columns::ColumnId_Cell, ColumnBase::Display_Cell) {}
virtual QVariant get (const Record<ESXRecordT>& record) const virtual QVariant get (const Record<ESXRecordT>& record) const
{ {
@ -890,7 +890,7 @@ namespace CSMWorld
template<typename ESXRecordT> template<typename ESXRecordT>
struct OwnerColumn : public Column<ESXRecordT> struct OwnerColumn : public Column<ESXRecordT>
{ {
OwnerColumn() : Column<ESXRecordT> (Columns::ColumnId_Owner, ColumnBase::Display_String) {} OwnerColumn() : Column<ESXRecordT> (Columns::ColumnId_Owner, ColumnBase::Display_Npc) {}
virtual QVariant get (const Record<ESXRecordT>& record) const virtual QVariant get (const Record<ESXRecordT>& record) const
{ {
@ -915,7 +915,7 @@ namespace CSMWorld
template<typename ESXRecordT> template<typename ESXRecordT>
struct SoulColumn : public Column<ESXRecordT> struct SoulColumn : public Column<ESXRecordT>
{ {
SoulColumn() : Column<ESXRecordT> (Columns::ColumnId_Soul, ColumnBase::Display_String) {} SoulColumn() : Column<ESXRecordT> (Columns::ColumnId_Soul, ColumnBase::Display_Creature) {}
virtual QVariant get (const Record<ESXRecordT>& record) const virtual QVariant get (const Record<ESXRecordT>& record) const
{ {
@ -940,7 +940,7 @@ namespace CSMWorld
template<typename ESXRecordT> template<typename ESXRecordT>
struct FactionColumn : public Column<ESXRecordT> struct FactionColumn : public Column<ESXRecordT>
{ {
FactionColumn() : Column<ESXRecordT> (Columns::ColumnId_Faction, ColumnBase::Display_String) {} FactionColumn() : Column<ESXRecordT> (Columns::ColumnId_Faction, ColumnBase::Display_Faction) {}
virtual QVariant get (const Record<ESXRecordT>& record) const virtual QVariant get (const Record<ESXRecordT>& record) const
{ {
@ -1090,7 +1090,7 @@ namespace CSMWorld
struct TeleportCellColumn : public Column<ESXRecordT> struct TeleportCellColumn : public Column<ESXRecordT>
{ {
TeleportCellColumn() TeleportCellColumn()
: Column<ESXRecordT> (Columns::ColumnId_TeleportCell, ColumnBase::Display_String) : Column<ESXRecordT> (Columns::ColumnId_TeleportCell, ColumnBase::Display_Cell)
{} {}
virtual QVariant get (const Record<ESXRecordT>& record) const virtual QVariant get (const Record<ESXRecordT>& record) const
@ -1146,7 +1146,7 @@ namespace CSMWorld
template<typename ESXRecordT> template<typename ESXRecordT>
struct KeyColumn : public Column<ESXRecordT> struct KeyColumn : public Column<ESXRecordT>
{ {
KeyColumn() : Column<ESXRecordT> (Columns::ColumnId_Key, ColumnBase::Display_String) {} KeyColumn() : Column<ESXRecordT> (Columns::ColumnId_Key, ColumnBase::Display_Miscellaneous) {}
virtual QVariant get (const Record<ESXRecordT>& record) const virtual QVariant get (const Record<ESXRecordT>& record) const
{ {
@ -1485,7 +1485,7 @@ namespace CSMWorld
template<typename ESXRecordT> template<typename ESXRecordT>
struct RaceColumn : public Column<ESXRecordT> struct RaceColumn : public Column<ESXRecordT>
{ {
RaceColumn() : Column<ESXRecordT> (Columns::ColumnId_Race, ColumnBase::Display_String) {} RaceColumn() : Column<ESXRecordT> (Columns::ColumnId_Race, ColumnBase::Display_Race) {}
virtual QVariant get (const Record<ESXRecordT>& record) const virtual QVariant get (const Record<ESXRecordT>& record) const
{ {
@ -1510,7 +1510,7 @@ namespace CSMWorld
template<typename ESXRecordT> template<typename ESXRecordT>
struct ClassColumn : public Column<ESXRecordT> struct ClassColumn : public Column<ESXRecordT>
{ {
ClassColumn() : Column<ESXRecordT> (Columns::ColumnId_Class, ColumnBase::Display_String) {} ClassColumn() : Column<ESXRecordT> (Columns::ColumnId_Class, ColumnBase::Display_Class) {}
virtual QVariant get (const Record<ESXRecordT>& record) const virtual QVariant get (const Record<ESXRecordT>& record) const
{ {
@ -1535,7 +1535,7 @@ namespace CSMWorld
template<typename ESXRecordT> template<typename ESXRecordT>
struct PcFactionColumn : public Column<ESXRecordT> struct PcFactionColumn : public Column<ESXRecordT>
{ {
PcFactionColumn() : Column<ESXRecordT> (Columns::ColumnId_PcFaction, ColumnBase::Display_String) {} PcFactionColumn() : Column<ESXRecordT> (Columns::ColumnId_PcFaction, ColumnBase::Display_Faction) {}
virtual QVariant get (const Record<ESXRecordT>& record) const virtual QVariant get (const Record<ESXRecordT>& record) const
{ {

@ -220,7 +220,7 @@ int CSMWorld::Columns::getId (const std::string& name)
std::string name2 = Misc::StringUtils::lowerCase (name); std::string name2 = Misc::StringUtils::lowerCase (name);
for (int i=0; sNames[i].mName; ++i) for (int i=0; sNames[i].mName; ++i)
if (name2==Misc::StringUtils::lowerCase (sNames[i].mName)) if (Misc::StringUtils::ciEqual(sNames[i].mName, name2))
return sNames[i].mId; return sNames[i].mId;
return -1; return -1;
@ -263,7 +263,7 @@ namespace
static const char *sCreatureTypes[] = static const char *sCreatureTypes[] =
{ {
"Creature", "Deadra", "Undead", "Humanoid", 0 "Creature", "Daedra", "Undead", "Humanoid", 0
}; };
static const char *sWeaponTypes[] = static const char *sWeaponTypes[] =
@ -342,4 +342,4 @@ std::vector<std::string> CSMWorld::Columns::getEnums (ColumnId column)
} }
return enums; return enums;
} }

@ -4,10 +4,10 @@
#include <QAbstractItemModel> #include <QAbstractItemModel>
#include "idtable.hpp" #include "idtable.hpp"
#include "idtable.hpp" #include <components/misc/stringops.hpp>
CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelIndex& index, CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelIndex& index,
const QVariant& new_, QUndoCommand *parent) const QVariant& new_, QUndoCommand* parent)
: QUndoCommand (parent), mModel (model), mIndex (index), mNew (new_) : QUndoCommand (parent), mModel (model), mIndex (index), mNew (new_)
{ {
mOld = mModel.data (mIndex, Qt::EditRole); mOld = mModel.data (mIndex, Qt::EditRole);
@ -25,7 +25,7 @@ void CSMWorld::ModifyCommand::undo()
mModel.setData (mIndex, mOld); mModel.setData (mIndex, mOld);
} }
CSMWorld::CreateCommand::CreateCommand (IdTable& model, const std::string& id, QUndoCommand *parent) CSMWorld::CreateCommand::CreateCommand (IdTable& model, const std::string& id, QUndoCommand* parent)
: QUndoCommand (parent), mModel (model), mId (id), mType (UniversalId::Type_None) : QUndoCommand (parent), mModel (model), mId (id), mType (UniversalId::Type_None)
{ {
setText (("Create record " + id).c_str()); setText (("Create record " + id).c_str());
@ -54,7 +54,7 @@ void CSMWorld::CreateCommand::undo()
mModel.removeRow (mModel.getModelIndex (mId, 0).row()); mModel.removeRow (mModel.getModelIndex (mId, 0).row());
} }
CSMWorld::RevertCommand::RevertCommand (IdTable& model, const std::string& id, QUndoCommand *parent) CSMWorld::RevertCommand::RevertCommand (IdTable& model, const std::string& id, QUndoCommand* parent)
: QUndoCommand (parent), mModel (model), mId (id), mOld (0) : QUndoCommand (parent), mModel (model), mId (id), mOld (0)
{ {
setText (("Revert record " + id).c_str()); setText (("Revert record " + id).c_str());
@ -89,7 +89,7 @@ void CSMWorld::RevertCommand::undo()
mModel.setRecord (mId, *mOld); mModel.setRecord (mId, *mOld);
} }
CSMWorld::DeleteCommand::DeleteCommand (IdTable& model, const std::string& id, QUndoCommand *parent) CSMWorld::DeleteCommand::DeleteCommand (IdTable& model, const std::string& id, QUndoCommand* parent)
: QUndoCommand (parent), mModel (model), mId (id), mOld (0) : QUndoCommand (parent), mModel (model), mId (id), mOld (0)
{ {
setText (("Delete record " + id).c_str()); setText (("Delete record " + id).c_str());
@ -126,7 +126,7 @@ void CSMWorld::DeleteCommand::undo()
CSMWorld::ReorderRowsCommand::ReorderRowsCommand (IdTable& model, int baseIndex, CSMWorld::ReorderRowsCommand::ReorderRowsCommand (IdTable& model, int baseIndex,
const std::vector<int>& newOrder) const std::vector<int>& newOrder)
: mModel (model), mBaseIndex (baseIndex), mNewOrder (newOrder) : mModel (model), mBaseIndex (baseIndex), mNewOrder (newOrder)
{} {}
@ -140,8 +140,35 @@ void CSMWorld::ReorderRowsCommand::undo()
int size = static_cast<int> (mNewOrder.size()); int size = static_cast<int> (mNewOrder.size());
std::vector<int> reverse (size); std::vector<int> reverse (size);
for (int i=0; i<size; ++i) for (int i=0; i< size; ++i)
reverse.at (mNewOrder[i]) = i; reverse.at (mNewOrder[i]) = i;
mModel.reorderRows (mBaseIndex, reverse); mModel.reorderRows (mBaseIndex, reverse);
}
CSMWorld::CloneCommand::CloneCommand (CSMWorld::IdTable& model,
const std::string& idOrigin,
const std::string& IdDestination,
const CSMWorld::UniversalId::Type type,
QUndoCommand* parent) :
QUndoCommand (parent),
mModel (model),
mIdOrigin (idOrigin),
mIdDestination (Misc::StringUtils::lowerCase (IdDestination)),
mType (type)
{
setText ( ("Clone record " + idOrigin + " to the " + IdDestination).c_str());
}
void CSMWorld::CloneCommand::redo()
{
mModel.cloneRecord (mIdOrigin, mIdDestination, mType);
for (std::map<int, QVariant>::const_iterator iter (mValues.begin()); iter != mValues.end(); ++iter)
mModel.setData (mModel.getModelIndex (mIdDestination, iter->first), iter->second);
}
void CSMWorld::CloneCommand::undo()
{
mModel.removeRow (mModel.getModelIndex (mIdDestination, 0).row());
} }

@ -39,6 +39,26 @@ namespace CSMWorld
virtual void undo(); virtual void undo();
}; };
class CloneCommand : public QUndoCommand
{
IdTable& mModel;
std::string mIdOrigin;
std::string mIdDestination;
UniversalId::Type mType;
std::map<int, QVariant> mValues;
public:
CloneCommand (IdTable& model, const std::string& idOrigin,
const std::string& IdDestination,
const UniversalId::Type type,
QUndoCommand* parent = 0);
virtual void redo();
virtual void undo();
};
class CreateCommand : public QUndoCommand class CreateCommand : public QUndoCommand
{ {
IdTable& mModel; IdTable& mModel;

@ -154,14 +154,17 @@ CSMWorld::Data::Data() : mRefs (mCells)
mTopics.addColumn (new StringIdColumn<ESM::Dialogue>); mTopics.addColumn (new StringIdColumn<ESM::Dialogue>);
mTopics.addColumn (new RecordStateColumn<ESM::Dialogue>); mTopics.addColumn (new RecordStateColumn<ESM::Dialogue>);
mTopics.addColumn (new FixedRecordTypeColumn<ESM::Dialogue> (UniversalId::Type_Topic));
mTopics.addColumn (new DialogueTypeColumn<ESM::Dialogue>); mTopics.addColumn (new DialogueTypeColumn<ESM::Dialogue>);
mJournals.addColumn (new StringIdColumn<ESM::Dialogue>); mJournals.addColumn (new StringIdColumn<ESM::Dialogue>);
mJournals.addColumn (new RecordStateColumn<ESM::Dialogue>); mJournals.addColumn (new RecordStateColumn<ESM::Dialogue>);
mJournals.addColumn (new FixedRecordTypeColumn<ESM::Dialogue> (UniversalId::Type_Journal));
mJournals.addColumn (new DialogueTypeColumn<ESM::Dialogue> (true)); mJournals.addColumn (new DialogueTypeColumn<ESM::Dialogue> (true));
mTopicInfos.addColumn (new StringIdColumn<Info> (true)); mTopicInfos.addColumn (new StringIdColumn<Info> (true));
mTopicInfos.addColumn (new RecordStateColumn<Info>); mTopicInfos.addColumn (new RecordStateColumn<Info>);
mTopicInfos.addColumn (new FixedRecordTypeColumn<Info> (UniversalId::Type_TopicInfo));
mTopicInfos.addColumn (new TopicColumn<Info> (false)); mTopicInfos.addColumn (new TopicColumn<Info> (false));
mTopicInfos.addColumn (new ActorColumn<Info>); mTopicInfos.addColumn (new ActorColumn<Info>);
mTopicInfos.addColumn (new RaceColumn<Info>); mTopicInfos.addColumn (new RaceColumn<Info>);
@ -178,6 +181,7 @@ CSMWorld::Data::Data() : mRefs (mCells)
mJournalInfos.addColumn (new StringIdColumn<Info> (true)); mJournalInfos.addColumn (new StringIdColumn<Info> (true));
mJournalInfos.addColumn (new RecordStateColumn<Info>); mJournalInfos.addColumn (new RecordStateColumn<Info>);
mJournalInfos.addColumn (new FixedRecordTypeColumn<Info> (UniversalId::Type_Journal));
mJournalInfos.addColumn (new TopicColumn<Info> (true)); mJournalInfos.addColumn (new TopicColumn<Info> (true));
mJournalInfos.addColumn (new QuestStatusTypeColumn<Info>); mJournalInfos.addColumn (new QuestStatusTypeColumn<Info>);
mJournalInfos.addColumn (new QuestIndexColumn<Info>); mJournalInfos.addColumn (new QuestIndexColumn<Info>);
@ -194,6 +198,7 @@ CSMWorld::Data::Data() : mRefs (mCells)
mRefs.addColumn (new StringIdColumn<CellRef> (true)); mRefs.addColumn (new StringIdColumn<CellRef> (true));
mRefs.addColumn (new RecordStateColumn<CellRef>); mRefs.addColumn (new RecordStateColumn<CellRef>);
mRefs.addColumn (new FixedRecordTypeColumn<CellRef> (UniversalId::Type_Reference));
mRefs.addColumn (new CellColumn<CellRef>); mRefs.addColumn (new CellColumn<CellRef>);
mRefs.addColumn (new IdColumn<CellRef>); mRefs.addColumn (new IdColumn<CellRef>);
mRefs.addColumn (new PosColumn<CellRef> (&CellRef::mPos, 0, false)); mRefs.addColumn (new PosColumn<CellRef> (&CellRef::mPos, 0, false));
@ -224,6 +229,7 @@ CSMWorld::Data::Data() : mRefs (mCells)
mFilters.addColumn (new StringIdColumn<CSMFilter::Filter>); mFilters.addColumn (new StringIdColumn<CSMFilter::Filter>);
mFilters.addColumn (new RecordStateColumn<CSMFilter::Filter>); mFilters.addColumn (new RecordStateColumn<CSMFilter::Filter>);
mFilters.addColumn (new FixedRecordTypeColumn<CSMFilter::Filter> (UniversalId::Type_Filter));
mFilters.addColumn (new FilterColumn<CSMFilter::Filter>); mFilters.addColumn (new FilterColumn<CSMFilter::Filter>);
mFilters.addColumn (new DescriptionColumn<CSMFilter::Filter>); mFilters.addColumn (new DescriptionColumn<CSMFilter::Filter>);
mFilters.addColumn (new ScopeColumn<CSMFilter::Filter>); mFilters.addColumn (new ScopeColumn<CSMFilter::Filter>);

@ -124,6 +124,17 @@ void CSMWorld::IdTable::addRecord (const std::string& id, UniversalId::Type type
endInsertRows(); endInsertRows();
} }
void CSMWorld::IdTable::cloneRecord(const std::string& origin,
const std::string& destination,
CSMWorld::UniversalId::Type type)
{
int index = mIdCollection->getAppendIndex (destination);
beginInsertRows (QModelIndex(), index, index);
mIdCollection->cloneRecord(origin, destination, type);
endInsertRows();
}
QModelIndex CSMWorld::IdTable::getModelIndex (const std::string& id, int column) const QModelIndex CSMWorld::IdTable::getModelIndex (const std::string& id, int column) const
{ {
return index (mIdCollection->getIndex (id), column); return index (mIdCollection->getIndex (id), column);

@ -63,6 +63,10 @@ namespace CSMWorld
void addRecord (const std::string& id, UniversalId::Type type = UniversalId::Type_None); void addRecord (const std::string& id, UniversalId::Type type = UniversalId::Type_None);
///< \param type Will be ignored, unless the collection supports multiple record types ///< \param type Will be ignored, unless the collection supports multiple record types
void cloneRecord(const std::string& origin,
const std::string& destination,
UniversalId::Type type = UniversalId::Type_None);
QModelIndex getModelIndex (const std::string& id, int column) const; QModelIndex getModelIndex (const std::string& id, int column) const;
void setRecord (const std::string& id, const RecordBase& record); void setRecord (const std::string& id, const RecordBase& record);

@ -33,7 +33,9 @@ bool CSMWorld::IdTableProxyModel::filterAcceptsRow (int sourceRow, const QModelI
CSMWorld::IdTableProxyModel::IdTableProxyModel (QObject *parent) CSMWorld::IdTableProxyModel::IdTableProxyModel (QObject *parent)
: QSortFilterProxyModel (parent) : QSortFilterProxyModel (parent)
{} {
setSortCaseSensitivity (Qt::CaseInsensitive);
}
QModelIndex CSMWorld::IdTableProxyModel::getModelIndex (const std::string& id, int column) const QModelIndex CSMWorld::IdTableProxyModel::getModelIndex (const std::string& id, int column) const
{ {

@ -67,7 +67,7 @@ int CSMWorld::InfoCollection::getIndex (const std::string& id, const std::string
std::pair<RecordConstIterator, RecordConstIterator> range = getTopicRange (topic); std::pair<RecordConstIterator, RecordConstIterator> range = getTopicRange (topic);
for (; range.first!=range.second; ++range.first) for (; range.first!=range.second; ++range.first)
if (Misc::StringUtils::lowerCase (range.first->get().mId)==fullId) if (Misc::StringUtils::ciEqual(range.first->get().mId, fullId))
return std::distance (getRecords().begin(), range.first); return std::distance (getRecords().begin(), range.first);
return -1; return -1;
@ -177,8 +177,8 @@ CSMWorld::InfoCollection::Range CSMWorld::InfoCollection::getTopicRange (const s
RecordConstIterator end = begin; RecordConstIterator end = begin;
for (; end!=getRecords().end(); ++end) for (; end!=getRecords().end(); ++end)
if (Misc::StringUtils::lowerCase (end->get().mTopicId)!=topic2) if (!Misc::StringUtils::ciEqual(end->get().mTopicId, topic2))
break; break;
return Range (begin, end); return Range (begin, end);
} }

@ -8,6 +8,5 @@ void CSMWorld::CellRef::load (ESM::ESMReader &esm, Cell& cell, const std::string
mId = id; mId = id;
mCell = cell.mId; mCell = cell.mId;
if (!mDeleted) cell.addRef (mId);
cell.addRef (mId);
} }

@ -5,6 +5,8 @@
#include "ref.hpp" #include "ref.hpp"
#include "cell.hpp" #include "cell.hpp"
#include "universalid.hpp"
#include "record.hpp"
void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool base) void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool base)
{ {
@ -14,7 +16,8 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool
CellRef ref; CellRef ref;
while (cell2.getNextRef (reader, ref)) bool deleted = false;
while (cell2.getNextRef (reader, ref, deleted))
{ {
/// \todo handle deleted and moved references /// \todo handle deleted and moved references
ref.load (reader, cell2, getNewId()); ref.load (reader, cell2, getNewId());
@ -34,4 +37,15 @@ std::string CSMWorld::RefCollection::getNewId()
std::ostringstream stream; std::ostringstream stream;
stream << "ref#" << mNextId++; stream << "ref#" << mNextId++;
return stream.str(); return stream.str();
}
void CSMWorld::RefCollection::cloneRecord(const std::string& origin,
const std::string& destination,
const CSMWorld::UniversalId::Type type,
const CSMWorld::UniversalId::ArgumentType argumentType)
{
Record<CSMWorld::CellRef> clone(getRecord(origin));
clone.mState = CSMWorld::RecordBase::State_ModifiedOnly;
clone.get().mId = destination;
insertRecord(clone, getAppendIndex(destination, type), type);
} }

@ -8,6 +8,7 @@
namespace CSMWorld namespace CSMWorld
{ {
struct Cell; struct Cell;
struct UniversalId;
/// \brief References in cells /// \brief References in cells
class RefCollection : public Collection<CellRef> class RefCollection : public Collection<CellRef>
@ -25,6 +26,11 @@ namespace CSMWorld
///< Load a sequence of references. ///< Load a sequence of references.
std::string getNewId(); std::string getNewId();
void cloneRecord(const std::string& origin,
const std::string& destination,
const CSMWorld::UniversalId::Type type,
const CSMWorld::UniversalId::ArgumentType argumentType);
}; };
} }

@ -31,6 +31,7 @@ namespace CSMWorld
///< If the data type does not match an exception is thrown. ///< If the data type does not match an exception is thrown.
virtual std::string getId (const RecordBase& record) const = 0; virtual std::string getId (const RecordBase& record) const = 0;
virtual void setId(RecordBase& record, const std::string& id) = 0;
}; };
} }

@ -34,6 +34,8 @@ namespace CSMWorld
BaseRefIdAdapter (UniversalId::Type type, const BaseColumns& base); BaseRefIdAdapter (UniversalId::Type type, const BaseColumns& base);
virtual std::string getId (const RecordBase& record) const; virtual std::string getId (const RecordBase& record) const;
virtual void setId (RecordBase& record, const std::string& id);
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
const; const;
@ -50,6 +52,12 @@ namespace CSMWorld
: mType (type), mBase (base) : mType (type), mBase (base)
{} {}
template<typename RecordT>
void BaseRefIdAdapter<RecordT>::setId (RecordBase& record, const std::string& id)
{
(dynamic_cast<Record<RecordT>&> (record).get().mId) = id;
}
template<typename RecordT> template<typename RecordT>
std::string BaseRefIdAdapter<RecordT>::getId (const RecordBase& record) const std::string BaseRefIdAdapter<RecordT>::getId (const RecordBase& record) const
{ {

@ -2,6 +2,7 @@
#include "refidcollection.hpp" #include "refidcollection.hpp"
#include <stdexcept> #include <stdexcept>
#include <memory>
#include <components/esm/esmreader.hpp> #include <components/esm/esmreader.hpp>
@ -58,7 +59,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
mColumns.push_back (RefIdColumn (Columns::ColumnId_Name, ColumnBase::Display_String)); mColumns.push_back (RefIdColumn (Columns::ColumnId_Name, ColumnBase::Display_String));
nameColumns.mName = &mColumns.back(); nameColumns.mName = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Script, ColumnBase::Display_String)); mColumns.push_back (RefIdColumn (Columns::ColumnId_Script, ColumnBase::Display_Script));
nameColumns.mScript = &mColumns.back(); nameColumns.mScript = &mColumns.back();
InventoryColumns inventoryColumns (nameColumns); InventoryColumns inventoryColumns (nameColumns);
@ -181,7 +182,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
unsigned int mFlag; unsigned int mFlag;
} sCreatureFlagTable[] = } sCreatureFlagTable[] =
{ {
{ Columns::ColumnId_Biped, ESM::Creature::Biped }, { Columns::ColumnId_Biped, ESM::Creature::Bipedal },
{ Columns::ColumnId_HasWeapon, ESM::Creature::Weapon }, { Columns::ColumnId_HasWeapon, ESM::Creature::Weapon },
{ Columns::ColumnId_NoMovement, ESM::Creature::None }, { Columns::ColumnId_NoMovement, ESM::Creature::None },
{ Columns::ColumnId_Swims, ESM::Creature::Swims }, { Columns::ColumnId_Swims, ESM::Creature::Swims },
@ -213,10 +214,10 @@ CSMWorld::RefIdCollection::RefIdCollection()
creatureColumns.mFlags.insert (std::make_pair (respawn, ESM::Creature::Respawn)); creatureColumns.mFlags.insert (std::make_pair (respawn, ESM::Creature::Respawn));
mColumns.push_back (RefIdColumn (Columns::ColumnId_OpenSound, ColumnBase::Display_String)); mColumns.push_back (RefIdColumn (Columns::ColumnId_OpenSound, ColumnBase::Display_Sound));
const RefIdColumn *openSound = &mColumns.back(); const RefIdColumn *openSound = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_CloseSound, ColumnBase::Display_String)); mColumns.push_back (RefIdColumn (Columns::ColumnId_CloseSound, ColumnBase::Display_Sound));
const RefIdColumn *closeSound = &mColumns.back(); const RefIdColumn *closeSound = &mColumns.back();
LightColumns lightColumns (inventoryColumns); LightColumns lightColumns (inventoryColumns);
@ -230,7 +231,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
mColumns.push_back (RefIdColumn (Columns::ColumnId_Colour, ColumnBase::Display_Integer)); mColumns.push_back (RefIdColumn (Columns::ColumnId_Colour, ColumnBase::Display_Integer));
lightColumns.mColor = &mColumns.back(); lightColumns.mColor = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Sound, ColumnBase::Display_String)); mColumns.push_back (RefIdColumn (Columns::ColumnId_Sound, ColumnBase::Display_Sound));
lightColumns.mSound = &mColumns.back(); lightColumns.mSound = &mColumns.back();
static const struct static const struct
@ -262,13 +263,13 @@ CSMWorld::RefIdCollection::RefIdCollection()
NpcColumns npcColumns (actorsColumns); NpcColumns npcColumns (actorsColumns);
mColumns.push_back (RefIdColumn (Columns::ColumnId_Race, ColumnBase::Display_String)); mColumns.push_back (RefIdColumn (Columns::ColumnId_Race, ColumnBase::Display_Race));
npcColumns.mRace = &mColumns.back(); npcColumns.mRace = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Class, ColumnBase::Display_String)); mColumns.push_back (RefIdColumn (Columns::ColumnId_Class, ColumnBase::Display_Class));
npcColumns.mClass = &mColumns.back(); npcColumns.mClass = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Faction, ColumnBase::Display_String)); mColumns.push_back (RefIdColumn (Columns::ColumnId_Faction, ColumnBase::Display_Faction));
npcColumns.mFaction = &mColumns.back(); npcColumns.mFaction = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::Columnid_Hair, ColumnBase::Display_String)); mColumns.push_back (RefIdColumn (Columns::Columnid_Hair, ColumnBase::Display_String));
@ -431,7 +432,7 @@ void CSMWorld::RefIdCollection::removeRows (int index, int count)
void CSMWorld::RefIdCollection::appendBlankRecord (const std::string& id, UniversalId::Type type) void CSMWorld::RefIdCollection::appendBlankRecord (const std::string& id, UniversalId::Type type)
{ {
mData.appendRecord (type, id); mData.appendRecord (type, id, false);
} }
int CSMWorld::RefIdCollection::searchId (const std::string& id) const int CSMWorld::RefIdCollection::searchId (const std::string& id) const
@ -449,6 +450,16 @@ void CSMWorld::RefIdCollection::replace (int index, const RecordBase& record)
mData.getRecord (mData.globalToLocalIndex (index)).assign (record); mData.getRecord (mData.globalToLocalIndex (index)).assign (record);
} }
void CSMWorld::RefIdCollection::cloneRecord(const std::string& origin,
const std::string& destination,
const CSMWorld::UniversalId::Type type)
{
std::auto_ptr<RecordBase> newRecord(mData.getRecord(mData.searchId(origin)).clone());
newRecord->mState = RecordBase::State_ModifiedOnly;
mAdapters.find(type)->second->setId(*newRecord, destination);
mData.insertRecord(*newRecord, type, destination);
}
void CSMWorld::RefIdCollection::appendRecord (const RecordBase& record, void CSMWorld::RefIdCollection::appendRecord (const RecordBase& record,
UniversalId::Type type) UniversalId::Type type)
{ {
@ -456,7 +467,7 @@ void CSMWorld::RefIdCollection::appendRecord (const RecordBase& record,
int index = mData.getAppendIndex (type); int index = mData.getAppendIndex (type);
mData.appendRecord (type, id); mData.appendRecord (type, id, false);
mData.getRecord (mData.globalToLocalIndex (index)).assign (record); mData.getRecord (mData.globalToLocalIndex (index)).assign (record);
} }
@ -504,7 +515,7 @@ void CSMWorld::RefIdCollection::load (ESM::ESMReader& reader, bool base, Univers
{ {
// new record // new record
int index = mData.getAppendIndex (type); int index = mData.getAppendIndex (type);
mData.appendRecord (type, id); mData.appendRecord (type, id, base);
RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (index); RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (index);
@ -549,3 +560,9 @@ void CSMWorld::RefIdCollection::save (int index, ESM::ESMWriter& writer) const
{ {
mData.save (index, writer); mData.save (index, writer);
} }
const CSMWorld::RefIdData& CSMWorld::RefIdCollection::getDataSet() const
{
return mData;
}

@ -69,6 +69,10 @@ namespace CSMWorld
virtual void removeRows (int index, int count); virtual void removeRows (int index, int count);
virtual void cloneRecord(const std::string& origin,
const std::string& destination,
const UniversalId::Type type);
virtual void appendBlankRecord (const std::string& id, UniversalId::Type type); virtual void appendBlankRecord (const std::string& id, UniversalId::Type type);
///< \param type Will be ignored, unless the collection supports multiple record types ///< \param type Will be ignored, unless the collection supports multiple record types
@ -107,7 +111,10 @@ namespace CSMWorld
/// \return Success? /// \return Success?
void save (int index, ESM::ESMWriter& writer) const; void save (int index, ESM::ESMWriter& writer) const;
const RefIdData& getDataSet() const; //I can't figure out a better name for this one :(
}; };
} }
#endif #endif

@ -131,7 +131,7 @@ CSMWorld::RecordBase& CSMWorld::RefIdData::getRecord (const LocalIndex& index)
return iter->second->getRecord (index.first); return iter->second->getRecord (index.first);
} }
void CSMWorld::RefIdData::appendRecord (UniversalId::Type type, const std::string& id) void CSMWorld::RefIdData::appendRecord (UniversalId::Type type, const std::string& id, bool base)
{ {
std::map<UniversalId::Type, RefIdDataContainerBase *>::iterator iter = std::map<UniversalId::Type, RefIdDataContainerBase *>::iterator iter =
mRecordContainers.find (type); mRecordContainers.find (type);
@ -139,7 +139,7 @@ void CSMWorld::RefIdData::appendRecord (UniversalId::Type type, const std::strin
if (iter==mRecordContainers.end()) if (iter==mRecordContainers.end())
throw std::logic_error ("invalid local index type"); throw std::logic_error ("invalid local index type");
iter->second->appendRecord (id); iter->second->appendRecord (id, base);
mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (id), mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (id),
LocalIndex (iter->second->getSize()-1, type))); LocalIndex (iter->second->getSize()-1, type)));
@ -230,4 +230,118 @@ void CSMWorld::RefIdData::save (int index, ESM::ESMWriter& writer) const
throw std::logic_error ("invalid local index type"); throw std::logic_error ("invalid local index type");
iter->second->save (localIndex.first, writer); iter->second->save (localIndex.first, writer);
} }
const CSMWorld::RefIdDataContainer< ESM::Book >& CSMWorld::RefIdData::getBooks() const
{
return mBooks;
}
const CSMWorld::RefIdDataContainer< ESM::Activator >& CSMWorld::RefIdData::getActivators() const
{
return mActivators;
}
const CSMWorld::RefIdDataContainer< ESM::Potion >& CSMWorld::RefIdData::getPotions() const
{
return mPotions;
}
const CSMWorld::RefIdDataContainer< ESM::Apparatus >& CSMWorld::RefIdData::getApparati() const
{
return mApparati;
}
const CSMWorld::RefIdDataContainer< ESM::Armor >& CSMWorld::RefIdData::getArmors() const
{
return mArmors;
}
const CSMWorld::RefIdDataContainer< ESM::Clothing >& CSMWorld::RefIdData::getClothing() const
{
return mClothing;
}
const CSMWorld::RefIdDataContainer< ESM::Container >& CSMWorld::RefIdData::getContainers() const
{
return mContainers;
}
const CSMWorld::RefIdDataContainer< ESM::Creature >& CSMWorld::RefIdData::getCreatures() const
{
return mCreatures;
}
const CSMWorld::RefIdDataContainer< ESM::Door >& CSMWorld::RefIdData::getDoors() const
{
return mDoors;
}
const CSMWorld::RefIdDataContainer< ESM::Ingredient >& CSMWorld::RefIdData::getIngredients() const
{
return mIngredients;
}
const CSMWorld::RefIdDataContainer< ESM::CreatureLevList >& CSMWorld::RefIdData::getCreatureLevelledLists() const
{
return mCreatureLevelledLists;
}
const CSMWorld::RefIdDataContainer< ESM::ItemLevList >& CSMWorld::RefIdData::getItemLevelledList() const
{
return mItemLevelledLists;
}
const CSMWorld::RefIdDataContainer< ESM::Light >& CSMWorld::RefIdData::getLights() const
{
return mLights;
}
const CSMWorld::RefIdDataContainer< ESM::Lockpick >& CSMWorld::RefIdData::getLocpicks() const
{
return mLockpicks;
}
const CSMWorld::RefIdDataContainer< ESM::Miscellaneous >& CSMWorld::RefIdData::getMiscellaneous() const
{
return mMiscellaneous;
}
const CSMWorld::RefIdDataContainer< ESM::NPC >& CSMWorld::RefIdData::getNPCs() const
{
return mNpcs;
}
const CSMWorld::RefIdDataContainer< ESM::Weapon >& CSMWorld::RefIdData::getWeapons() const
{
return mWeapons;
}
const CSMWorld::RefIdDataContainer< ESM::Probe >& CSMWorld::RefIdData::getProbes() const
{
return mProbes;
}
const CSMWorld::RefIdDataContainer< ESM::Repair >& CSMWorld::RefIdData::getRepairs() const
{
return mRepairs;
}
const CSMWorld::RefIdDataContainer< ESM::Static >& CSMWorld::RefIdData::getStatics() const
{
return mStatics;
}
void CSMWorld::RefIdData::insertRecord(CSMWorld::RecordBase& record, CSMWorld::UniversalId::Type type, const std::string& id)
{
std::map<UniversalId::Type, RefIdDataContainerBase *>::iterator iter =
mRecordContainers.find (type);
if (iter==mRecordContainers.end())
throw std::logic_error ("invalid local index type");
iter->second->insertRecord(record);
mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (id),
LocalIndex (iter->second->getSize()-1, type)));
}

@ -45,7 +45,9 @@ namespace CSMWorld
virtual RecordBase& getRecord (int index)= 0; virtual RecordBase& getRecord (int index)= 0;
virtual void appendRecord (const std::string& id) = 0; virtual void appendRecord (const std::string& id, bool base) = 0;
virtual void insertRecord (RecordBase& record) = 0;
virtual void load (int index, ESM::ESMReader& reader, bool base) = 0; virtual void load (int index, ESM::ESMReader& reader, bool base) = 0;
@ -67,7 +69,9 @@ namespace CSMWorld
virtual RecordBase& getRecord (int index); virtual RecordBase& getRecord (int index);
virtual void appendRecord (const std::string& id); virtual void appendRecord (const std::string& id, bool base);
virtual void insertRecord (RecordBase& record);
virtual void load (int index, ESM::ESMReader& reader, bool base); virtual void load (int index, ESM::ESMReader& reader, bool base);
@ -78,6 +82,13 @@ namespace CSMWorld
virtual void save (int index, ESM::ESMWriter& writer) const; virtual void save (int index, ESM::ESMWriter& writer) const;
}; };
template<typename RecordT>
void RefIdDataContainer<RecordT>::insertRecord(RecordBase& record)
{
Record<RecordT>& newRecord = dynamic_cast<Record<RecordT>& >(record);
mContainer.push_back(newRecord);
}
template<typename RecordT> template<typename RecordT>
int RefIdDataContainer<RecordT>::getSize() const int RefIdDataContainer<RecordT>::getSize() const
{ {
@ -97,12 +108,15 @@ namespace CSMWorld
} }
template<typename RecordT> template<typename RecordT>
void RefIdDataContainer<RecordT>::appendRecord (const std::string& id) void RefIdDataContainer<RecordT>::appendRecord (const std::string& id, bool base)
{ {
Record<RecordT> record; Record<RecordT> record;
record.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly;
record.mBase.mId = id;
record.mModified.mId = id; record.mModified.mId = id;
record.mModified.blank(); (base ? record.mBase : record.mModified).blank();
record.mState = RecordBase::State_ModifiedOnly;
mContainer.push_back (record); mContainer.push_back (record);
} }
@ -136,15 +150,10 @@ namespace CSMWorld
if (state==CSMWorld::RecordBase::State_Modified || if (state==CSMWorld::RecordBase::State_Modified ||
state==CSMWorld::RecordBase::State_ModifiedOnly) state==CSMWorld::RecordBase::State_ModifiedOnly)
{ {
std::string type; writer.startRecord (mContainer.at (index).mModified.sRecordId);
for (int i=0; i<4; ++i)
/// \todo make endianess agnostic (change ESMWriter interface?)
type += reinterpret_cast<const char *> (&mContainer.at (index).mModified.sRecordId)[i];
writer.startRecord (type);
writer.writeHNCString ("NAME", getId (index)); writer.writeHNCString ("NAME", getId (index));
mContainer.at (index).mModified.save (writer); mContainer.at (index).mModified.save (writer);
writer.endRecord (type); writer.endRecord (mContainer.at (index).mModified.sRecordId);
} }
else if (state==CSMWorld::RecordBase::State_Deleted) else if (state==CSMWorld::RecordBase::State_Deleted)
{ {
@ -201,11 +210,13 @@ namespace CSMWorld
void erase (int index, int count); void erase (int index, int count);
void insertRecord(CSMWorld::RecordBase& record, CSMWorld::UniversalId::Type type, const std::string& id);
const RecordBase& getRecord (const LocalIndex& index) const; const RecordBase& getRecord (const LocalIndex& index) const;
RecordBase& getRecord (const LocalIndex& index); RecordBase& getRecord (const LocalIndex& index);
void appendRecord (UniversalId::Type type, const std::string& id); void appendRecord (UniversalId::Type type, const std::string& id, bool base);
int getAppendIndex (UniversalId::Type type) const; int getAppendIndex (UniversalId::Type type) const;
@ -219,7 +230,33 @@ namespace CSMWorld
/// \param listDeleted include deleted record in the list /// \param listDeleted include deleted record in the list
void save (int index, ESM::ESMWriter& writer) const; void save (int index, ESM::ESMWriter& writer) const;
//RECORD CONTAINERS ACCESS METHODS
const RefIdDataContainer<ESM::Book>& getBooks() const;
const RefIdDataContainer<ESM::Activator>& getActivators() const;
const RefIdDataContainer<ESM::Potion>& getPotions() const;
const RefIdDataContainer<ESM::Apparatus>& getApparati() const;
const RefIdDataContainer<ESM::Armor>& getArmors() const;
const RefIdDataContainer<ESM::Clothing>& getClothing() const;
const RefIdDataContainer<ESM::Container>& getContainers() const;
const RefIdDataContainer<ESM::Creature>& getCreatures() const;
const RefIdDataContainer<ESM::Door>& getDoors() const;
const RefIdDataContainer<ESM::Ingredient>& getIngredients() const;
const RefIdDataContainer<ESM::CreatureLevList>& getCreatureLevelledLists() const;
const RefIdDataContainer<ESM::ItemLevList>& getItemLevelledList() const;
const RefIdDataContainer<ESM::Light>& getLights() const;
const RefIdDataContainer<ESM::Lockpick>& getLocpicks() const;
const RefIdDataContainer<ESM::Miscellaneous>& getMiscellaneous() const;
const RefIdDataContainer<ESM::NPC>& getNPCs() const;
const RefIdDataContainer<ESM::Weapon >& getWeapons() const;
const RefIdDataContainer<ESM::Probe >& getProbes() const;
const RefIdDataContainer<ESM::Repair>& getRepairs() const;
const RefIdDataContainer<ESM::Static>& getStatics() const;
}; };
} }
#endif #endif

@ -5,23 +5,92 @@
#include <components/misc/stringops.hpp> #include <components/misc/stringops.hpp>
#include <components/compiler/quickfileparser.hpp>
#include <components/compiler/nullerrorhandler.hpp>
#include <components/compiler/scanner.hpp>
#include "data.hpp" #include "data.hpp"
CSMWorld::ScriptContext::ScriptContext (const Data& data) : mData (data), mIdsUpdated (false) {} CSMWorld::ScriptContext::ScriptContext (const Data& data) : mData (data), mIdsUpdated (false) {}
bool CSMWorld::ScriptContext::canDeclareLocals() const bool CSMWorld::ScriptContext::canDeclareLocals() const
{ {
return false; return true;
} }
char CSMWorld::ScriptContext::getGlobalType (const std::string& name) const char CSMWorld::ScriptContext::getGlobalType (const std::string& name) const
{ {
int index = mData.getGlobals().searchId (name);
if (index!=-1)
{
switch (mData.getGlobals().getRecord (index).get().mValue.getType())
{
case ESM::VT_Short: return 's';
case ESM::VT_Long: return 'l';
case ESM::VT_Float: return 'f';
default: return ' ';
}
}
return ' '; return ' ';
} }
char CSMWorld::ScriptContext::getMemberType (const std::string& name, const std::string& id) const std::pair<char, bool> CSMWorld::ScriptContext::getMemberType (const std::string& name,
const std::string& id) const
{ {
return ' '; /// \todo invalidate locals cache on change to scripts
std::string id2 = Misc::StringUtils::lowerCase (id);
int index = mData.getScripts().searchId (id2);
bool reference = false;
if (index!=-1)
{
// ID is not a script ID. Search for a matching referenceable instead.
index = mData.getReferenceables().searchId (id2);
if (index!=-1)
{
// Referenceable found.
int columnIndex = mData.getReferenceables().searchColumnIndex (Columns::ColumnId_Script);
if (columnIndex!=-1)
{
id2 = Misc::StringUtils::lowerCase (mData.getReferenceables().
getData (index, columnIndex).toString().toUtf8().constData());
if (!id2.empty())
{
// Referenceable has a script -> use it.
index = mData.getScripts().searchId (id2);
reference = true;
}
}
}
}
if (index==-1)
return std::make_pair (' ', false);
std::map<std::string, Compiler::Locals>::iterator iter = mLocals.find (id2);
if (iter==mLocals.end())
{
Compiler::Locals locals;
Compiler::NullErrorHandler errorHandler;
std::istringstream stream (mData.getScripts().getRecord (index).get().mScriptText);
Compiler::QuickFileParser parser (errorHandler, *this, locals);
Compiler::Scanner scanner (errorHandler, stream, getExtensions());
scanner.scan (parser);
iter = mLocals.insert (std::make_pair (id2, locals)).first;
}
return std::make_pair (iter->second.getType (Misc::StringUtils::lowerCase (name)), reference);
} }
bool CSMWorld::ScriptContext::isId (const std::string& name) const bool CSMWorld::ScriptContext::isId (const std::string& name) const
@ -31,6 +100,7 @@ bool CSMWorld::ScriptContext::isId (const std::string& name) const
mIds = mData.getIds(); mIds = mData.getIds();
std::for_each (mIds.begin(), mIds.end(), &Misc::StringUtils::lowerCase); std::for_each (mIds.begin(), mIds.end(), &Misc::StringUtils::lowerCase);
std::sort (mIds.begin(), mIds.end());
mIdsUpdated = true; mIdsUpdated = true;
} }
@ -38,7 +108,19 @@ bool CSMWorld::ScriptContext::isId (const std::string& name) const
return std::binary_search (mIds.begin(), mIds.end(), Misc::StringUtils::lowerCase (name)); return std::binary_search (mIds.begin(), mIds.end(), Misc::StringUtils::lowerCase (name));
} }
bool CSMWorld::ScriptContext::isJournalId (const std::string& name) const
{
return mData.getJournals().searchId (name)!=-1;
}
void CSMWorld::ScriptContext::invalidateIds() void CSMWorld::ScriptContext::invalidateIds()
{ {
mIdsUpdated = false; mIdsUpdated = false;
}
void CSMWorld::ScriptContext::clear()
{
mIds.clear();
mIdsUpdated = false;
mLocals.clear();
} }

@ -3,8 +3,10 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <map>
#include <components/compiler/context.hpp> #include <components/compiler/context.hpp>
#include <components/compiler/locals.hpp>
namespace CSMWorld namespace CSMWorld
{ {
@ -15,6 +17,7 @@ namespace CSMWorld
const Data& mData; const Data& mData;
mutable std::vector<std::string> mIds; mutable std::vector<std::string> mIds;
mutable bool mIdsUpdated; mutable bool mIdsUpdated;
mutable std::map<std::string, Compiler::Locals> mLocals;
public: public:
@ -26,13 +29,23 @@ namespace CSMWorld
virtual char getGlobalType (const std::string& name) const; virtual char getGlobalType (const std::string& name) const;
///< 'l: long, 's': short, 'f': float, ' ': does not exist. ///< 'l: long, 's': short, 'f': float, ' ': does not exist.
virtual char getMemberType (const std::string& name, const std::string& id) const; virtual std::pair<char, bool> getMemberType (const std::string& name,
///< 'l: long, 's': short, 'f': float, ' ': does not exist. const std::string& id) const;
///< Return type of member variable \a name in script \a id or in script of reference of
/// \a id
/// \return first: 'l: long, 's': short, 'f': float, ' ': does not exist.
/// second: true: script of reference
virtual bool isId (const std::string& name) const; virtual bool isId (const std::string& name) const;
///< Does \a name match an ID, that can be referenced? ///< Does \a name match an ID, that can be referenced?
virtual bool isJournalId (const std::string& name) const;
///< Does \a name match a journal ID?
void invalidateIds(); void invalidateIds();
void clear();
///< Remove all cached data.
}; };
} }

@ -0,0 +1,285 @@
#include "tablemimedata.hpp"
#include <string>
#include "universalid.hpp"
#include "columnbase.hpp"
CSMWorld::TableMimeData::TableMimeData (UniversalId id, const CSMDoc::Document& document) :
mDocument(document)
{
mUniversalId.push_back (id);
mObjectsFormats << QString::fromStdString ("tabledata/" + id.getTypeName());
}
CSMWorld::TableMimeData::TableMimeData (std::vector< CSMWorld::UniversalId >& id, const CSMDoc::Document& document) :
mUniversalId (id), mDocument(document)
{
for (std::vector<UniversalId>::iterator it (mUniversalId.begin()); it != mUniversalId.end(); ++it)
{
mObjectsFormats << QString::fromStdString ("tabledata/" + it->getTypeName());
}
}
QStringList CSMWorld::TableMimeData::formats() const
{
return mObjectsFormats;
}
CSMWorld::TableMimeData::~TableMimeData()
{
}
std::string CSMWorld::TableMimeData::getIcon() const
{
if (mUniversalId.empty())
{
throw ("TableMimeData holds no UniversalId");
}
std::string tmpIcon;
bool firstIteration = true;
for (unsigned i = 0; i < mUniversalId.size(); ++i)
{
if (firstIteration)
{
firstIteration = false;
tmpIcon = mUniversalId[i].getIcon();
continue;
}
if (tmpIcon != mUniversalId[i].getIcon())
{
return ":/multitype.png"; //icon stolen from gnome
}
tmpIcon = mUniversalId[i].getIcon();
}
return mUniversalId.begin()->getIcon(); //All objects are of the same type;
}
std::vector< CSMWorld::UniversalId > CSMWorld::TableMimeData::getData() const
{
return mUniversalId;
}
bool CSMWorld::TableMimeData::holdsType (CSMWorld::UniversalId::Type type) const
{
for (std::vector<UniversalId>::const_iterator it = mUniversalId.begin(); it != mUniversalId.end(); ++it)
{
if (it->getType() == type)
{
return true;
}
}
return false;
}
bool CSMWorld::TableMimeData::holdsType (CSMWorld::ColumnBase::Display type) const
{
for (std::vector<UniversalId>::const_iterator it = mUniversalId.begin(); it != mUniversalId.end(); ++it)
{
if (it->getType() == convertEnums (type))
{
return true;
}
}
return false;
}
CSMWorld::UniversalId CSMWorld::TableMimeData::returnMatching (CSMWorld::UniversalId::Type type) const
{
for (std::vector<UniversalId>::const_iterator it = mUniversalId.begin(); it != mUniversalId.end(); ++it)
{
if (it->getType() == type)
{
return *it;
}
}
throw ("TableMimeData object does not hold object of the seeked type");
}
CSMWorld::UniversalId CSMWorld::TableMimeData::returnMatching (CSMWorld::ColumnBase::Display type) const
{
for (std::vector<UniversalId>::const_iterator it = mUniversalId.begin(); it != mUniversalId.end(); ++it)
{
if (it->getType() == convertEnums (type))
{
return *it;
}
}
throw ("TableMimeData object does not hold object of the seeked type");
}
bool CSMWorld::TableMimeData::fromDocument (const CSMDoc::Document& document) const
{
return &document == &mDocument;
}
CSMWorld::UniversalId::Type CSMWorld::TableMimeData::convertEnums (CSMWorld::ColumnBase::Display type) const
{
switch (type)
{
case CSMWorld::ColumnBase::Display_Race:
return CSMWorld::UniversalId::Type_Race;
break;
case CSMWorld::ColumnBase::Display_Skill:
return CSMWorld::UniversalId::Type_Skill;
break;
case CSMWorld::ColumnBase::Display_Class:
return CSMWorld::UniversalId::Type_Class;
break;
case CSMWorld::ColumnBase::Display_Faction:
return CSMWorld::UniversalId::Type_Faction;
break;
case CSMWorld::ColumnBase::Display_Sound:
return CSMWorld::UniversalId::Type_Sound;
break;
case CSMWorld::ColumnBase::Display_Region:
return CSMWorld::UniversalId::Type_Region;
break;
case CSMWorld::ColumnBase::Display_Birthsign:
return CSMWorld::UniversalId::Type_Birthsign;
break;
case CSMWorld::ColumnBase::Display_Spell:
return CSMWorld::UniversalId::Type_Spell;
break;
case CSMWorld::ColumnBase::Display_Cell:
return CSMWorld::UniversalId::Type_Cell;
break;
case CSMWorld::ColumnBase::Display_Referenceable:
return CSMWorld::UniversalId::Type_Referenceable;
break;
case CSMWorld::ColumnBase::Display_Activator:
return CSMWorld::UniversalId::Type_Activator;
break;
case CSMWorld::ColumnBase::Display_Potion:
return CSMWorld::UniversalId::Type_Potion;
break;
case CSMWorld::ColumnBase::Display_Apparatus:
return CSMWorld::UniversalId::Type_Apparatus;
break;
case CSMWorld::ColumnBase::Display_Armor:
return CSMWorld::UniversalId::Type_Armor;
break;
case CSMWorld::ColumnBase::Display_Book:
return CSMWorld::UniversalId::Type_Book;
break;
case CSMWorld::ColumnBase::Display_Clothing:
return CSMWorld::UniversalId::Type_Clothing;
break;
case CSMWorld::ColumnBase::Display_Container:
return CSMWorld::UniversalId::Type_Container;
break;
case CSMWorld::ColumnBase::Display_Creature:
return CSMWorld::UniversalId::Type_Creature;
break;
case CSMWorld::ColumnBase::Display_Door:
return CSMWorld::UniversalId::Type_Door;
break;
case CSMWorld::ColumnBase::Display_Ingredient:
return CSMWorld::UniversalId::Type_Ingredient;
break;
case CSMWorld::ColumnBase::Display_CreatureLevelledList:
return CSMWorld::UniversalId::Type_CreatureLevelledList;
break;
case CSMWorld::ColumnBase::Display_ItemLevelledList:
return CSMWorld::UniversalId::Type_ItemLevelledList;
break;
case CSMWorld::ColumnBase::Display_Light:
return CSMWorld::UniversalId::Type_Light;
break;
case CSMWorld::ColumnBase::Display_Lockpick:
return CSMWorld::UniversalId::Type_Lockpick;
break;
case CSMWorld::ColumnBase::Display_Miscellaneous:
return CSMWorld::UniversalId::Type_Miscellaneous;
break;
case CSMWorld::ColumnBase::Display_Npc:
return CSMWorld::UniversalId::Type_Npc;
break;
case CSMWorld::ColumnBase::Display_Probe:
return CSMWorld::UniversalId::Type_Probe;
break;
case CSMWorld::ColumnBase::Display_Repair:
return CSMWorld::UniversalId::Type_Repair;
break;
case CSMWorld::ColumnBase::Display_Static:
return CSMWorld::UniversalId::Type_Static;
break;
case CSMWorld::ColumnBase::Display_Weapon:
return CSMWorld::UniversalId::Type_Weapon;
break;
case CSMWorld::ColumnBase::Display_Reference:
return CSMWorld::UniversalId::Type_Reference;
break;
case CSMWorld::ColumnBase::Display_Filter:
return CSMWorld::UniversalId::Type_Filter;
break;
case CSMWorld::ColumnBase::Display_Topic:
return CSMWorld::UniversalId::Type_Topic;
break;
case CSMWorld::ColumnBase::Display_Journal:
return CSMWorld::UniversalId::Type_Journal;
break;
case CSMWorld::ColumnBase::Display_TopicInfo:
return CSMWorld::UniversalId::Type_TopicInfo;
break;
case CSMWorld::ColumnBase::Display_JournalInfo:
return CSMWorld::UniversalId::Type_JournalInfo;
break;
case CSMWorld::ColumnBase::Display_Scene:
return CSMWorld::UniversalId::Type_Scene;
break;
case CSMWorld::ColumnBase::Display_Script:
return CSMWorld::UniversalId::Type_Script;
break;
default:
return CSMWorld::UniversalId::Type_None;
break;
}
}
// kate: indent-mode cstyle; indent-width 4; replace-tabs on;

@ -0,0 +1,61 @@
#ifndef TABLEMIMEDATA_H
#define TABLEMIMEDATA_H
#include <vector>
#include <QtCore/QMimeData>
#include <QStringList>
#include "universalid.hpp"
#include "columnbase.hpp"
namespace CSMDoc
{
class Document;
}
namespace CSMWorld
{
/// \brief Subclass of QmimeData, augmented to contain and transport UniversalIds.
///
/// This class provides way to construct mimedata object holding the universalid copy
/// Universalid is used in the majority of the tables to store type, id, argument types.
/// This way universalid grants a way to retrive record from the concrete table.
/// Please note, that tablemimedata object can hold multiple universalIds in the vector.
class TableMimeData : public QMimeData
{
public:
TableMimeData(UniversalId id, const CSMDoc::Document& document);
TableMimeData(std::vector<UniversalId>& id, const CSMDoc::Document& document);
~TableMimeData();
virtual QStringList formats() const;
std::string getIcon() const;
std::vector<UniversalId> getData() const;
bool holdsType(UniversalId::Type type) const;
bool holdsType(CSMWorld::ColumnBase::Display type) const;
bool fromDocument(const CSMDoc::Document& document) const;
UniversalId returnMatching(UniversalId::Type type) const;
UniversalId returnMatching(CSMWorld::ColumnBase::Display type) const;
private:
std::vector<UniversalId> mUniversalId;
QStringList mObjectsFormats;
const CSMDoc::Document& mDocument;
CSMWorld::UniversalId::Type convertEnums(CSMWorld::ColumnBase::Display type) const;
};
}
#endif // TABLEMIMEDATA_H

@ -4,6 +4,7 @@
#include <ostream> #include <ostream>
#include <stdexcept> #include <stdexcept>
#include <sstream> #include <sstream>
#include <iostream>
namespace namespace
{ {
@ -186,7 +187,6 @@ CSMWorld::UniversalId::UniversalId (Type type, const std::string& id)
mClass = sIdArg[i].mClass; mClass = sIdArg[i].mClass;
return; return;
} }
throw std::logic_error ("invalid ID argument UniversalId type"); throw std::logic_error ("invalid ID argument UniversalId type");
} }

@ -6,6 +6,7 @@
#include <OgreRoot.h> #include <OgreRoot.h>
#include <OgreRenderWindow.h> #include <OgreRenderWindow.h>
#include <OgreEntity.h> #include <OgreEntity.h>
#include <OgreCamera.h>
namespace CSVRender namespace CSVRender
{ {
@ -66,6 +67,10 @@ namespace CSVRender
params.insert(std::make_pair("title", windowTitle.str())); params.insert(std::make_pair("title", windowTitle.str()));
params.insert(std::make_pair("FSAA", "0")); // TODO setting params.insert(std::make_pair("FSAA", "0")); // TODO setting
params.insert(std::make_pair("vsync", "false")); // TODO setting params.insert(std::make_pair("vsync", "false")); // TODO setting
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
params.insert(std::make_pair("macAPI", "cocoa"));
params.insert(std::make_pair("macAPICocoaUseNSView", "true"));
#endif
mWindow = Ogre::Root::getSingleton().createRenderWindow(windowTitle.str(), this->width(), this->height(), false, &params); mWindow = Ogre::Root::getSingleton().createRenderWindow(windowTitle.str(), this->width(), this->height(), false, &params);
mWindow->addViewport(mCamera)->setBackgroundColour(Ogre::ColourValue(0.3,0.3,0.3,1)); mWindow->addViewport(mCamera)->setBackgroundColour(Ogre::ColourValue(0.3,0.3,0.3,1));

@ -61,6 +61,7 @@ void CSVWorld::CellCreator::reset()
mX->setValue (0); mX->setValue (0);
mY->setValue (0); mY->setValue (0);
mType->setCurrentIndex (0); mType->setCurrentIndex (0);
setType(0);
GenericCreator::reset(); GenericCreator::reset();
} }
@ -78,4 +79,25 @@ void CSVWorld::CellCreator::setType (int index)
void CSVWorld::CellCreator::valueChanged (int index) void CSVWorld::CellCreator::valueChanged (int index)
{ {
update(); update();
} }
void CSVWorld::CellCreator::cloneMode(const std::string& originId,
const CSMWorld::UniversalId::Type type)
{
CSVWorld::GenericCreator::cloneMode(originId, type);
if (*(originId.begin()) == '#') //if originid points to the exterior cell
{
setType(1); //enable x and y controls
mType->setCurrentIndex(1);
} else {
setType(0);
mType->setCurrentIndex(0);
}
}
void CSVWorld::CellCreator::toggleWidgets(bool active)
{
CSVWorld::GenericCreator::toggleWidgets(active);
mType->setEnabled(active);
}

@ -29,6 +29,11 @@ namespace CSVWorld
virtual void reset(); virtual void reset();
virtual void toggleWidgets(bool active = true);
virtual void cloneMode(const std::string& originId,
const CSMWorld::UniversalId::Type type);
private slots: private slots:
void setType (int index); void setType (int index);

@ -2,6 +2,7 @@
#define CSV_WORLD_CREATOR_H #define CSV_WORLD_CREATOR_H
#include <QWidget> #include <QWidget>
#include "../../model/world/universalid.hpp"
class QUndoStack; class QUndoStack;
@ -24,8 +25,13 @@ namespace CSVWorld
virtual void reset() = 0; virtual void reset() = 0;
virtual void cloneMode(const std::string& originId,
const CSMWorld::UniversalId::Type type) = 0;
virtual void setEditLock (bool locked) = 0; virtual void setEditLock (bool locked) = 0;
virtual void toggleWidgets(bool active = true) = 0;
signals: signals:
void done(); void done();

@ -57,8 +57,15 @@ const CSMWorld::UniversalId& CSVWorld::GenericCreator::getCollectionId() const
} }
CSVWorld::GenericCreator::GenericCreator (CSMWorld::Data& data, QUndoStack& undoStack, CSVWorld::GenericCreator::GenericCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id, bool relaxedIdRules) const CSMWorld::UniversalId& id, bool relaxedIdRules):
: mData (data), mUndoStack (undoStack), mListId (id), mLocked (false)
mData (data),
mUndoStack (undoStack),
mListId (id),
mLocked (false),
mCloneMode(false),
mClonedType(CSMWorld::UniversalId::Type_None)
{ {
mLayout = new QHBoxLayout; mLayout = new QHBoxLayout;
mLayout->setContentsMargins (0, 0, 0, 0); mLayout->setContentsMargins (0, 0, 0, 0);
@ -89,6 +96,7 @@ void CSVWorld::GenericCreator::setEditLock (bool locked)
void CSVWorld::GenericCreator::reset() void CSVWorld::GenericCreator::reset()
{ {
mCloneMode = false;
mId->setText (""); mId->setText ("");
update(); update();
} }
@ -120,16 +128,40 @@ void CSVWorld::GenericCreator::create()
{ {
if (!mLocked) if (!mLocked)
{ {
std::string id = getId(); if (mCloneMode)
{
std::string id = getId();
std::auto_ptr<CSMWorld::CloneCommand> command (new CSMWorld::CloneCommand (
dynamic_cast<CSMWorld::IdTable&> (*mData.getTableModel(mListId)), mClonedId, id, mClonedType));
mUndoStack.push(command.release());
std::auto_ptr<CSMWorld::CreateCommand> command (new CSMWorld::CreateCommand ( emit done();
emit requestFocus(id);
} else {
std::string id = getId();
std::auto_ptr<CSMWorld::CreateCommand> command (new CSMWorld::CreateCommand (
dynamic_cast<CSMWorld::IdTable&> (*mData.getTableModel (mListId)), id)); dynamic_cast<CSMWorld::IdTable&> (*mData.getTableModel (mListId)), id));
configureCreateCommand (*command); configureCreateCommand (*command);
mUndoStack.push (command.release()); mUndoStack.push (command.release());
emit done(); emit done();
emit requestFocus (id); emit requestFocus (id);
}
} }
} }
void CSVWorld::GenericCreator::cloneMode(const std::string& originId,
const CSMWorld::UniversalId::Type type)
{
mCloneMode = true;
mClonedId = originId;
mClonedType = type;
}
void CSVWorld::GenericCreator::toggleWidgets(bool active)
{
}

@ -1,6 +1,7 @@
#ifndef CSV_WORLD_GENERICCREATOR_H #ifndef CSV_WORLD_GENERICCREATOR_H
#define CSV_WORLD_GENERICCREATOR_H #define CSV_WORLD_GENERICCREATOR_H
class QString;
class QPushButton; class QPushButton;
class QLineEdit; class QLineEdit;
class QHBoxLayout; class QHBoxLayout;
@ -28,6 +29,11 @@ namespace CSVWorld
std::string mErrors; std::string mErrors;
QHBoxLayout *mLayout; QHBoxLayout *mLayout;
bool mLocked; bool mLocked;
std::string mClonedId;
CSMWorld::UniversalId::Type mClonedType;
protected:
bool mCloneMode;
protected: protected:
@ -57,11 +63,15 @@ namespace CSVWorld
virtual void reset(); virtual void reset();
virtual void toggleWidgets (bool active = true);
virtual void cloneMode(const std::string& originId,
const CSMWorld::UniversalId::Type type);
virtual std::string getErrors() const; virtual std::string getErrors() const;
///< Return formatted error descriptions for the current state of the creator. if an empty ///< Return formatted error descriptions for the current state of the creator. if an empty
/// string is returned, there is no error. /// string is returned, there is no error.
private slots: private slots:
void textChanged (const QString& text); void textChanged (const QString& text);

@ -40,4 +40,10 @@ void CSVWorld::ReferenceableCreator::reset()
{ {
mType->setCurrentIndex (0); mType->setCurrentIndex (0);
GenericCreator::reset(); GenericCreator::reset();
} }
void CSVWorld::ReferenceableCreator::toggleWidgets(bool active)
{
CSVWorld::GenericCreator::toggleWidgets(active);
mType->setEnabled(active);
}

@ -23,6 +23,7 @@ namespace CSVWorld
const CSMWorld::UniversalId& id); const CSMWorld::UniversalId& id);
virtual void reset(); virtual void reset();
virtual void toggleWidgets(bool active = true);
}; };
} }

@ -40,15 +40,20 @@ CSVWorld::ReferenceCreator::ReferenceCreator (CSMWorld::Data& data, QUndoStack&
void CSVWorld::ReferenceCreator::reset() void CSVWorld::ReferenceCreator::reset()
{ {
GenericCreator::reset();
mCell->setText (""); mCell->setText ("");
mId = getData().getReferences().getNewId(); mId = getData().getReferences().getNewId();
GenericCreator::reset();
} }
std::string CSVWorld::ReferenceCreator::getErrors() const std::string CSVWorld::ReferenceCreator::getErrors() const
{ {
std::string errors = GenericCreator::getErrors(); std::string errors = GenericCreator::getErrors();
if (mCloneMode)
{
return errors;
}
std::string cell = mCell->text().toUtf8().constData(); std::string cell = mCell->text().toUtf8().constData();
if (cell.empty()) if (cell.empty())
@ -72,4 +77,17 @@ std::string CSVWorld::ReferenceCreator::getErrors() const
void CSVWorld::ReferenceCreator::cellChanged() void CSVWorld::ReferenceCreator::cellChanged()
{ {
update(); update();
} }
void CSVWorld::ReferenceCreator::toggleWidgets(bool active)
{
CSVWorld::GenericCreator::toggleWidgets(active);
mCell->setEnabled(active);
}
void CSVWorld::ReferenceCreator::cloneMode(const std::string& originId,
const CSMWorld::UniversalId::Type type)
{
CSVWorld::GenericCreator::cloneMode(originId, type);
cellChanged(); //otherwise ok button will remain disabled
}

@ -25,7 +25,11 @@ namespace CSVWorld
ReferenceCreator (CSMWorld::Data& data, QUndoStack& undoStack, ReferenceCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id); const CSMWorld::UniversalId& id);
virtual void cloneMode(const std::string& originId,
const CSMWorld::UniversalId::Type type);
virtual void reset(); virtual void reset();
virtual void toggleWidgets(bool active = true);
virtual std::string getErrors() const; virtual std::string getErrors() const;
///< Return formatted error descriptions for the current state of the creator. if an empty ///< Return formatted error descriptions for the current state of the creator. if an empty

@ -43,12 +43,26 @@ toolbar->addTool (new SceneToolMode (toolbar));
toolbar->addTool (new SceneToolMode (toolbar)); toolbar->addTool (new SceneToolMode (toolbar));
layout2->addWidget (toolbar, 0); layout2->addWidget (toolbar, 0);
// temporarily disable OGRE-integration (need to fix path problem first)
#if 0
CSVRender::SceneWidget* sceneWidget = new CSVRender::SceneWidget(this); CSVRender::SceneWidget* sceneWidget = new CSVRender::SceneWidget(this);
layout2->addWidget (sceneWidget, 1); layout2->addWidget (sceneWidget, 1);
layout->insertLayout (0, layout2, 1); layout->insertLayout (0, layout2, 1);
#endif
/// \todo replace with rendering widget
QPalette palette2 (palette());
palette2.setColor (QPalette::Background, Qt::white);
QLabel *placeholder = new QLabel ("Here goes the 3D scene", this);
placeholder->setAutoFillBackground (true);
placeholder->setPalette (palette2);
placeholder->setAlignment (Qt::AlignHCenter);
layout2->addWidget (placeholder, 1);
layout->insertLayout (0, layout2, 1);
CSVFilter::FilterBox *filterBox = new CSVFilter::FilterBox (document.getData(), this); CSVFilter::FilterBox *filterBox = new CSVFilter::FilterBox (document.getData(), this);

@ -0,0 +1,88 @@
#include "scriptedit.hpp"
#include <algorithm>
#include <QDragEnterEvent>
#include <QRegExp>
#include <QString>
#include "../../model/world/universalid.hpp"
#include "../../model/world/tablemimedata.hpp"
CSVWorld::ScriptEdit::ScriptEdit (QWidget* parent, const CSMDoc::Document& document) :
QTextEdit (parent),
mDocument (document),
mWhiteListQoutes("^[a-z|_]{1}[a-z|0-9|_]{0,}$", Qt::CaseInsensitive)
{
mAllowedTypes <<CSMWorld::UniversalId::Type_Journal
<<CSMWorld::UniversalId::Type_Global
<<CSMWorld::UniversalId::Type_Topic
<<CSMWorld::UniversalId::Type_Sound
<<CSMWorld::UniversalId::Type_Spell
<<CSMWorld::UniversalId::Type_Cell
<<CSMWorld::UniversalId::Type_Referenceable
<<CSMWorld::UniversalId::Type_Activator
<<CSMWorld::UniversalId::Type_Potion
<<CSMWorld::UniversalId::Type_Apparatus
<<CSMWorld::UniversalId::Type_Armor
<<CSMWorld::UniversalId::Type_Book
<<CSMWorld::UniversalId::Type_Clothing
<<CSMWorld::UniversalId::Type_Container
<<CSMWorld::UniversalId::Type_Creature
<<CSMWorld::UniversalId::Type_Door
<<CSMWorld::UniversalId::Type_Ingredient
<<CSMWorld::UniversalId::Type_CreatureLevelledList
<<CSMWorld::UniversalId::Type_ItemLevelledList
<<CSMWorld::UniversalId::Type_Light
<<CSMWorld::UniversalId::Type_Lockpick
<<CSMWorld::UniversalId::Type_Miscellaneous
<<CSMWorld::UniversalId::Type_Npc
<<CSMWorld::UniversalId::Type_Probe
<<CSMWorld::UniversalId::Type_Repair
<<CSMWorld::UniversalId::Type_Static
<<CSMWorld::UniversalId::Type_Weapon;
}
void CSVWorld::ScriptEdit::dragEnterEvent (QDragEnterEvent* event)
{
setTextCursor (cursorForPosition (event->pos()));
event->acceptProposedAction();
}
void CSVWorld::ScriptEdit::dragMoveEvent (QDragMoveEvent* event)
{
setTextCursor (cursorForPosition (event->pos()));
event->accept();
}
void CSVWorld::ScriptEdit::dropEvent (QDropEvent* event)
{
const CSMWorld::TableMimeData* mime = dynamic_cast<const CSMWorld::TableMimeData*> (event->mimeData());
setTextCursor (cursorForPosition (event->pos()));
if (mime->fromDocument (mDocument))
{
std::vector<CSMWorld::UniversalId> records (mime->getData());
for (std::vector<CSMWorld::UniversalId>::iterator it = records.begin(); it != records.end(); ++it)
{
if (mAllowedTypes.contains (it->getType()))
{
if (stringNeedsQuote(it->getId()))
{
insertPlainText(QString::fromStdString ('"' + it->getId() + '"'));
} else {
insertPlainText(QString::fromStdString (it->getId()));
}
}
}
}
}
bool CSVWorld::ScriptEdit::stringNeedsQuote (const std::string& id) const
{
const QString string(QString::fromStdString(id)); //<regex> is only for c++11, so let's use qregexp for now.
//I'm not quite sure when do we need to put quotes. To be safe we will use quotes for anything other than…
return !(string.contains(mWhiteListQoutes));
}

@ -0,0 +1,39 @@
#ifndef SCRIPTEDIT_H
#define SCRIPTEDIT_H
#include <qtextedit.h>
#include <QVector>
#include "../../model/world/universalid.hpp"
class QWidget;
class QRegExp;
namespace CSMDoc
{
class Document;
}
namespace CSVWorld
{
class ScriptEdit : public QTextEdit
{
Q_OBJECT
public:
ScriptEdit (QWidget* parent, const CSMDoc::Document& document);
private:
QVector<CSMWorld::UniversalId::Type> mAllowedTypes;
const CSMDoc::Document& mDocument;
const QRegExp mWhiteListQoutes;
void dragEnterEvent (QDragEnterEvent* event);
void dropEvent (QDropEvent* event);
void dragMoveEvent (QDragMoveEvent* event);
bool stringNeedsQuote(const std::string& id) const;
};
}
#endif // SCRIPTEDIT_H

@ -13,6 +13,7 @@
#include "../../model/world/idtable.hpp" #include "../../model/world/idtable.hpp"
#include "scripthighlighter.hpp" #include "scripthighlighter.hpp"
#include "scriptedit.hpp"
CSVWorld::ScriptSubView::ChangeLock::ChangeLock (ScriptSubView& view) : mView (view) CSVWorld::ScriptSubView::ChangeLock::ChangeLock (ScriptSubView& view) : mView (view)
{ {
@ -27,7 +28,7 @@ CSVWorld::ScriptSubView::ChangeLock::~ChangeLock()
CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document)
: SubView (id), mDocument (document), mColumn (-1), mChangeLocked (0) : SubView (id), mDocument (document), mColumn (-1), mChangeLocked (0)
{ {
setWidget (mEditor = new QTextEdit (this)); setWidget (mEditor = new ScriptEdit (this, mDocument));
mEditor->setAcceptRichText (false); mEditor->setAcceptRichText (false);
mEditor->setLineWrapMode (QTextEdit::NoWrap); mEditor->setLineWrapMode (QTextEdit::NoWrap);

@ -6,6 +6,8 @@
#include <QAction> #include <QAction>
#include <QMenu> #include <QMenu>
#include <QContextMenuEvent> #include <QContextMenuEvent>
#include <QString>
#include <QtCore/qnamespace.h>
#include "../../model/world/data.hpp" #include "../../model/world/data.hpp"
#include "../../model/world/commands.hpp" #include "../../model/world/commands.hpp"
@ -13,6 +15,8 @@
#include "../../model/world/idtable.hpp" #include "../../model/world/idtable.hpp"
#include "../../model/world/record.hpp" #include "../../model/world/record.hpp"
#include "../../model/world/columns.hpp" #include "../../model/world/columns.hpp"
#include "../../model/world/tablemimedata.hpp"
#include "../../model/world/tablemimedata.hpp"
#include "recordstatusdelegate.hpp" #include "recordstatusdelegate.hpp"
#include "util.hpp" #include "util.hpp"
@ -28,7 +32,11 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event)
if (!mEditLock) if (!mEditLock)
{ {
if (selectedRows.size()==1) if (selectedRows.size()==1)
{
menu.addAction (mEditAction); menu.addAction (mEditAction);
if (mCreateAction)
menu.addAction(mCloneAction);
}
if (mCreateAction) if (mCreateAction)
menu.addAction (mCreateAction); menu.addAction (mCreateAction);
@ -84,7 +92,7 @@ std::vector<std::string> CSVWorld::Table::listRevertableSelectedIds() const
QModelIndexList selectedRows = selectionModel()->selectedRows(); QModelIndexList selectedRows = selectionModel()->selectedRows();
for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end(); for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end();
++iter) ++iter)
{ {
QModelIndex index = mProxyModel->mapToSource (mProxyModel->index (iter->row(), 0)); QModelIndex index = mProxyModel->mapToSource (mProxyModel->index (iter->row(), 0));
@ -154,8 +162,8 @@ std::vector<std::string> CSVWorld::Table::listDeletableSelectedIds() const
} }
CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack, CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack,
bool createAndDelete, bool sorting) bool createAndDelete, bool sorting, const CSMDoc::Document& document)
: mUndoStack (undoStack), mCreateAction (0), mEditLock (false), mRecordStatusDisplay (0) : mUndoStack (undoStack), mCreateAction (0), mCloneAction(0), mEditLock (false), mRecordStatusDisplay (0), mDocument(document)
{ {
mModel = &dynamic_cast<CSMWorld::IdTable&> (*data.getTableModel (id)); mModel = &dynamic_cast<CSMWorld::IdTable&> (*data.getTableModel (id));
@ -199,6 +207,10 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, Q
mCreateAction = new QAction (tr ("Add Record"), this); mCreateAction = new QAction (tr ("Add Record"), this);
connect (mCreateAction, SIGNAL (triggered()), this, SIGNAL (createRequest())); connect (mCreateAction, SIGNAL (triggered()), this, SIGNAL (createRequest()));
addAction (mCreateAction); addAction (mCreateAction);
mCloneAction = new QAction (tr ("Clone Record"), this);
connect(mCloneAction, SIGNAL (triggered()), this, SLOT (cloneRecord()));
addAction(mCloneAction);
} }
mRevertAction = new QAction (tr ("Revert Record"), this); mRevertAction = new QAction (tr ("Revert Record"), this);
@ -227,6 +239,8 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, Q
connect (selectionModel(), SIGNAL (selectionChanged (const QItemSelection&, const QItemSelection&)), connect (selectionModel(), SIGNAL (selectionChanged (const QItemSelection&, const QItemSelection&)),
this, SLOT (selectionSizeUpdate ())); this, SLOT (selectionSizeUpdate ()));
setAcceptDrops(true);
} }
void CSVWorld::Table::setEditLock (bool locked) void CSVWorld::Table::setEditLock (bool locked)
@ -295,6 +309,19 @@ void CSVWorld::Table::editRecord()
} }
} }
void CSVWorld::Table::cloneRecord()
{
if (!mEditLock)
{
QModelIndexList selectedRows = selectionModel()->selectedRows();
const CSMWorld::UniversalId& toClone = getUniversalId(selectedRows.begin()->row());
if (selectedRows.size()==1 && !mModel->getRecord(toClone.getId()).isDeleted())
{
emit cloneRequest (toClone);
}
}
}
void CSVWorld::Table::moveUpRecord() void CSVWorld::Table::moveUpRecord()
{ {
QModelIndexList selectedRows = selectionModel()->selectedRows(); QModelIndexList selectedRows = selectionModel()->selectedRows();
@ -411,3 +438,72 @@ void CSVWorld::Table::recordFilterChanged (boost::shared_ptr<CSMFilter::Node> fi
{ {
mProxyModel->setFilter (filter); mProxyModel->setFilter (filter);
} }
void CSVWorld::Table::mouseMoveEvent (QMouseEvent* event)
{
if (event->buttons() & Qt::LeftButton)
{
QModelIndexList selectedRows = selectionModel()->selectedRows();
if (selectedRows.size() == 0)
{
return;
}
QDrag* drag = new QDrag (this);
CSMWorld::TableMimeData* mime = NULL;
if (selectedRows.size() == 1)
{
mime = new CSMWorld::TableMimeData (getUniversalId (selectedRows.begin()->row()), mDocument);
}
else
{
std::vector<CSMWorld::UniversalId> idToDrag;
foreach (QModelIndex it, selectedRows) //I had a dream. Dream where you could use C++11 in OpenMW.
{
idToDrag.push_back (getUniversalId (it.row()));
}
mime = new CSMWorld::TableMimeData (idToDrag, mDocument);
}
drag->setMimeData (mime);
drag->setPixmap (QString::fromStdString (mime->getIcon()));
drag->exec();
}
}
void CSVWorld::Table::dragEnterEvent(QDragEnterEvent *event)
{
event->acceptProposedAction();
}
void CSVWorld::Table::dropEvent(QDropEvent *event)
{
QModelIndex index = indexAt (event->pos());
const CSMWorld::TableMimeData* mime = dynamic_cast<const CSMWorld::TableMimeData*> (event->mimeData());
if (mime->fromDocument (mDocument))
{
CSMWorld::ColumnBase::Display display = static_cast<CSMWorld::ColumnBase::Display>
(mModel->headerData (index.column(), Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt());
if (mime->holdsType (display))
{
CSMWorld::UniversalId record (mime->returnMatching (display));
std::auto_ptr<CSMWorld::ModifyCommand> command (new CSMWorld::ModifyCommand
(*mProxyModel, index, QVariant (QString::fromStdString (record.getId()))));
mUndoStack.push (command.release());
}
} //TODO handle drops from different document
}
void CSVWorld::Table::dragMoveEvent(QDragMoveEvent *event)
{
event->accept();
}

@ -5,9 +5,14 @@
#include <string> #include <string>
#include <QTableView> #include <QTableView>
#include <QtGui/qevent.h>
#include "../../model/filter/node.hpp" #include "../../model/filter/node.hpp"
namespace CSMDoc {
class Document;
}
class QUndoStack; class QUndoStack;
class QAction; class QAction;
@ -32,6 +37,7 @@ namespace CSVWorld
QUndoStack& mUndoStack; QUndoStack& mUndoStack;
QAction *mEditAction; QAction *mEditAction;
QAction *mCreateAction; QAction *mCreateAction;
QAction *mCloneAction;
QAction *mRevertAction; QAction *mRevertAction;
QAction *mDeleteAction; QAction *mDeleteAction;
QAction *mMoveUpAction; QAction *mMoveUpAction;
@ -41,6 +47,10 @@ namespace CSVWorld
bool mEditLock; bool mEditLock;
int mRecordStatusDisplay; int mRecordStatusDisplay;
/// \brief This variable is used exclusivly for checking if dropEvents came from the same document. Most likely you
/// should NOT use it for anything else.
const CSMDoc::Document& mDocument;
private: private:
void contextMenuEvent (QContextMenuEvent *event); void contextMenuEvent (QContextMenuEvent *event);
@ -49,9 +59,20 @@ namespace CSVWorld
std::vector<std::string> listDeletableSelectedIds() const; std::vector<std::string> listDeletableSelectedIds() const;
void mouseMoveEvent(QMouseEvent *event);
void dragEnterEvent(QDragEnterEvent *event);
void dropEvent(QDropEvent *event);
void dragMoveEvent(QDragMoveEvent *event);
public: public:
Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack, bool createAndDelete, bool sorting); Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack, bool createAndDelete,
bool sorting, const CSMDoc::Document& document);
///< \param createAndDelete Allow creation and deletion of records. ///< \param createAndDelete Allow creation and deletion of records.
/// \param sorting Allow changing order of rows in the view via column headers. /// \param sorting Allow changing order of rows in the view via column headers.
@ -73,6 +94,7 @@ namespace CSVWorld
/// \param modified Number of added and modified records /// \param modified Number of added and modified records
void createRequest(); void createRequest();
void cloneRequest(const CSMWorld::UniversalId&);
private slots: private slots:
@ -82,6 +104,8 @@ namespace CSVWorld
void editRecord(); void editRecord();
void cloneRecord();
void moveUpRecord(); void moveUpRecord();
void moveDownRecord(); void moveDownRecord();

@ -153,7 +153,19 @@ void CSVWorld::TableBottomBox::tableSizeChanged (int size, int deleted, int modi
void CSVWorld::TableBottomBox::createRequest() void CSVWorld::TableBottomBox::createRequest()
{ {
mCreator->reset(); mCreator->reset();
mCreator->toggleWidgets(true);
mLayout->setCurrentWidget (mCreator); mLayout->setCurrentWidget (mCreator);
setVisible (true); setVisible (true);
mCreating = true; mCreating = true;
} }
void CSVWorld::TableBottomBox::cloneRequest(const std::string& id,
const CSMWorld::UniversalId::Type type)
{
mCreator->reset();
mCreator->cloneMode(id, type);
mLayout->setCurrentWidget(mCreator);
mCreator->toggleWidgets(false);
setVisible (true);
mCreating = true;
}

@ -2,6 +2,7 @@
#define CSV_WORLD_BOTTOMBOX_H #define CSV_WORLD_BOTTOMBOX_H
#include <QWidget> #include <QWidget>
#include <apps/opencs/model/world/universalid.hpp>
class QLabel; class QLabel;
class QStackedLayout; class QStackedLayout;
@ -76,6 +77,8 @@ namespace CSVWorld
/// \param modified Number of added and modified records /// \param modified Number of added and modified records
void createRequest(); void createRequest();
void cloneRequest(const std::string& id,
const CSMWorld::UniversalId::Type type);
}; };
} }

@ -6,7 +6,6 @@
#include "../../model/doc/document.hpp" #include "../../model/doc/document.hpp"
#include "../filter/filterbox.hpp" #include "../filter/filterbox.hpp"
#include "table.hpp" #include "table.hpp"
#include "tablebottombox.hpp" #include "tablebottombox.hpp"
#include "creator.hpp" #include "creator.hpp"
@ -23,7 +22,7 @@ CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::D
new TableBottomBox (creatorFactory, document.getData(), document.getUndoStack(), id, this), 0); new TableBottomBox (creatorFactory, document.getData(), document.getUndoStack(), id, this), 0);
layout->insertWidget (0, mTable = layout->insertWidget (0, mTable =
new Table (id, document.getData(), document.getUndoStack(), mBottom->canCreateAndDelete(), sorting), 2); new Table (id, document.getData(), document.getUndoStack(), mBottom->canCreateAndDelete(), sorting, document), 2);
CSVFilter::FilterBox *filterBox = new CSVFilter::FilterBox (document.getData(), this); CSVFilter::FilterBox *filterBox = new CSVFilter::FilterBox (document.getData(), this);
@ -46,8 +45,15 @@ CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::D
mTable->selectionSizeUpdate(); mTable->selectionSizeUpdate();
if (mBottom->canCreateAndDelete()) if (mBottom->canCreateAndDelete())
{
connect (mTable, SIGNAL (createRequest()), mBottom, SLOT (createRequest())); connect (mTable, SIGNAL (createRequest()), mBottom, SLOT (createRequest()));
connect (mTable, SIGNAL (cloneRequest(const CSMWorld::UniversalId&)), this,
SLOT(cloneRequest(const CSMWorld::UniversalId&)));
connect (this, SIGNAL(cloneRequest(const std::string&, const CSMWorld::UniversalId::Type)),
mBottom, SLOT(cloneRequest(const std::string&, const CSMWorld::UniversalId::Type)));
}
connect (mBottom, SIGNAL (requestFocus (const std::string&)), connect (mBottom, SIGNAL (requestFocus (const std::string&)),
mTable, SLOT (requestFocus (const std::string&))); mTable, SLOT (requestFocus (const std::string&)));
@ -75,4 +81,9 @@ void CSVWorld::TableSubView::updateEditorSetting(const QString &settingName, con
void CSVWorld::TableSubView::setStatusBar (bool show) void CSVWorld::TableSubView::setStatusBar (bool show)
{ {
mBottom->setStatusBar (show); mBottom->setStatusBar (show);
} }
void CSVWorld::TableSubView::cloneRequest(const CSMWorld::UniversalId& toClone)
{
emit cloneRequest(toClone.getId(), toClone.getType());
}

@ -5,6 +5,11 @@
class QModelIndex; class QModelIndex;
namespace CSMWorld
{
class IdTable;
}
namespace CSMDoc namespace CSMDoc
{ {
class Document; class Document;
@ -34,9 +39,14 @@ namespace CSVWorld
virtual void setStatusBar (bool show); virtual void setStatusBar (bool show);
signals:
void cloneRequest(const std::string&,
const CSMWorld::UniversalId::Type);
private slots: private slots:
void editRequest (int row); void editRequest (int row);
void cloneRequest (const CSMWorld::UniversalId& toClone);
}; };
} }

@ -1,7 +1,3 @@
# config file
configure_file ("${CMAKE_CURRENT_SOURCE_DIR}/config.hpp.cmake" "${CMAKE_CURRENT_SOURCE_DIR}/config.hpp")
# local files # local files
set(GAME set(GAME
main.cpp main.cpp
@ -12,15 +8,14 @@ if(NOT WIN32)
endif() endif()
set(GAME_HEADER set(GAME_HEADER
engine.hpp engine.hpp
config.hpp
) )
source_group(game FILES ${GAME} ${GAME_HEADER}) source_group(game FILES ${GAME} ${GAME_HEADER})
add_openmw_dir (mwrender add_openmw_dir (mwrender
renderingmanager debugging sky camera animation npcanimation creatureanimation activatoranimation renderingmanager debugging sky camera animation npcanimation creatureanimation activatoranimation
actors objects renderinginterface localmap occlusionquery water shadows actors objects renderinginterface localmap occlusionquery water shadows
compositors characterpreview externalrendering globalmap videoplayer ripplesimulation refraction characterpreview globalmap videoplayer ripplesimulation refraction
terrainstorage terrainstorage renderconst effectmanager
) )
add_openmw_dir (mwinput add_openmw_dir (mwinput
@ -74,14 +69,21 @@ add_openmw_dir (mwmechanics
mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects
drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow
aiescort aiactivate aicombat repair enchanting pathfinding security spellsuccess spellcasting aiescort aiactivate aicombat repair enchanting pathfinding security spellsuccess spellcasting
disease pickpocket levelledlist combat steering
)
add_openmw_dir (mwstate
statemanagerimp charactermanager character
) )
add_openmw_dir (mwbase add_openmw_dir (mwbase
environment world scriptmanager dialoguemanager journal soundmanager mechanicsmanager environment world scriptmanager dialoguemanager journal soundmanager mechanicsmanager
inputmanager windowmanager inputmanager windowmanager statemanager
) )
# Main executable # Main executable
set(BOOST_COMPONENTS system filesystem program_options thread wave)
find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS})
IF(OGRE_STATIC) IF(OGRE_STATIC)
ADD_DEFINITIONS(-DENABLE_PLUGIN_OctreeSceneManager -DENABLE_PLUGIN_ParticleFX -DENABLE_PLUGIN_GL) ADD_DEFINITIONS(-DENABLE_PLUGIN_OctreeSceneManager -DENABLE_PLUGIN_ParticleFX -DENABLE_PLUGIN_GL)
@ -111,6 +113,7 @@ add_definitions(${SOUND_DEFINE})
target_link_libraries(openmw target_link_libraries(openmw
${OGRE_LIBRARIES} ${OGRE_LIBRARIES}
${OGRE_STATIC_PLUGINS} ${OGRE_STATIC_PLUGINS}
${SHINY_LIBRARIES}
${Boost_LIBRARIES} ${Boost_LIBRARIES}
${OPENAL_LIBRARY} ${OPENAL_LIBRARY}
${SOUND_INPUT_LIBRARY} ${SOUND_INPUT_LIBRARY}
@ -118,7 +121,6 @@ target_link_libraries(openmw
${MYGUI_LIBRARIES} ${MYGUI_LIBRARIES}
${SDL2_LIBRARY} ${SDL2_LIBRARY}
${MYGUI_PLATFORM_LIBRARIES} ${MYGUI_PLATFORM_LIBRARIES}
${SHINY_LIBRARIES}
"oics" "oics"
"sdl4ogre" "sdl4ogre"
components components
@ -137,12 +139,6 @@ if (UNIX AND NOT APPLE)
target_link_libraries(openmw ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries(openmw ${CMAKE_THREAD_LIBS_INIT})
endif() endif()
# Workaround for binutil => 2.23 problem when linking, should be fixed eventually upstream
if (UNIX AND NOT APPLE)
target_link_libraries(openmw dl Xt)
endif()
if(APPLE) if(APPLE)
find_library(COCOA_FRAMEWORK Cocoa) find_library(COCOA_FRAMEWORK Cocoa)
find_library(IOKIT_FRAMEWORK IOKit) find_library(IOKIT_FRAMEWORK IOKit)

@ -6,6 +6,7 @@
#include <sys/wait.h> #include <sys/wait.h>
#include <sys/param.h> #include <sys/param.h>
#include <sys/ucontext.h> #include <sys/ucontext.h>
#include <sys/utsname.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <limits.h> #include <limits.h>
@ -42,78 +43,78 @@ static char altstack[SIGSTKSZ];
static struct { static struct {
int signum; int signum;
pid_t pid; pid_t pid;
int has_siginfo; int has_siginfo;
siginfo_t siginfo; siginfo_t siginfo;
char buf[1024]; char buf[1024];
} crash_info; } crash_info;
static const struct { static const struct {
const char *name; const char *name;
int signum; int signum;
} signals[] = { } signals[] = {
{ "Segmentation fault", SIGSEGV }, { "Segmentation fault", SIGSEGV },
{ "Illegal instruction", SIGILL }, { "Illegal instruction", SIGILL },
{ "FPU exception", SIGFPE }, { "FPU exception", SIGFPE },
{ "System BUS error", SIGBUS }, { "System BUS error", SIGBUS },
{ NULL, 0 } { NULL, 0 }
}; };
static const struct { static const struct {
int code; int code;
const char *name; const char *name;
} sigill_codes[] = { } sigill_codes[] = {
#ifndef __FreeBSD__ #ifndef __FreeBSD__
{ ILL_ILLOPC, "Illegal opcode" }, { ILL_ILLOPC, "Illegal opcode" },
{ ILL_ILLOPN, "Illegal operand" }, { ILL_ILLOPN, "Illegal operand" },
{ ILL_ILLADR, "Illegal addressing mode" }, { ILL_ILLADR, "Illegal addressing mode" },
{ ILL_ILLTRP, "Illegal trap" }, { ILL_ILLTRP, "Illegal trap" },
{ ILL_PRVOPC, "Privileged opcode" }, { ILL_PRVOPC, "Privileged opcode" },
{ ILL_PRVREG, "Privileged register" }, { ILL_PRVREG, "Privileged register" },
{ ILL_COPROC, "Coprocessor error" }, { ILL_COPROC, "Coprocessor error" },
{ ILL_BADSTK, "Internal stack error" }, { ILL_BADSTK, "Internal stack error" },
#endif #endif
{ 0, NULL } { 0, NULL }
}; };
static const struct { static const struct {
int code; int code;
const char *name; const char *name;
} sigfpe_codes[] = { } sigfpe_codes[] = {
{ FPE_INTDIV, "Integer divide by zero" }, { FPE_INTDIV, "Integer divide by zero" },
{ FPE_INTOVF, "Integer overflow" }, { FPE_INTOVF, "Integer overflow" },
{ FPE_FLTDIV, "Floating point divide by zero" }, { FPE_FLTDIV, "Floating point divide by zero" },
{ FPE_FLTOVF, "Floating point overflow" }, { FPE_FLTOVF, "Floating point overflow" },
{ FPE_FLTUND, "Floating point underflow" }, { FPE_FLTUND, "Floating point underflow" },
{ FPE_FLTRES, "Floating point inexact result" }, { FPE_FLTRES, "Floating point inexact result" },
{ FPE_FLTINV, "Floating point invalid operation" }, { FPE_FLTINV, "Floating point invalid operation" },
{ FPE_FLTSUB, "Subscript out of range" }, { FPE_FLTSUB, "Subscript out of range" },
{ 0, NULL } { 0, NULL }
}; };
static const struct { static const struct {
int code; int code;
const char *name; const char *name;
} sigsegv_codes[] = { } sigsegv_codes[] = {
#ifndef __FreeBSD__ #ifndef __FreeBSD__
{ SEGV_MAPERR, "Address not mapped to object" }, { SEGV_MAPERR, "Address not mapped to object" },
{ SEGV_ACCERR, "Invalid permissions for mapped object" }, { SEGV_ACCERR, "Invalid permissions for mapped object" },
#endif #endif
{ 0, NULL } { 0, NULL }
}; };
static const struct { static const struct {
int code; int code;
const char *name; const char *name;
} sigbus_codes[] = { } sigbus_codes[] = {
#ifndef __FreeBSD__ #ifndef __FreeBSD__
{ BUS_ADRALN, "Invalid address alignment" }, { BUS_ADRALN, "Invalid address alignment" },
{ BUS_ADRERR, "Non-existent physical address" }, { BUS_ADRERR, "Non-existent physical address" },
{ BUS_OBJERR, "Object specific hardware error" }, { BUS_OBJERR, "Object specific hardware error" },
#endif #endif
{ 0, NULL } { 0, NULL }
}; };
static int (*cc_user_info)(char*, char*); static int (*cc_user_info)(char*, char*);
@ -121,314 +122,318 @@ static int (*cc_user_info)(char*, char*);
static void gdb_info(pid_t pid) static void gdb_info(pid_t pid)
{ {
char respfile[64]; char respfile[64];
char cmd_buf[128]; char cmd_buf[128];
FILE *f; FILE *f;
int fd; int fd;
/* Create a temp file to put gdb commands into */ /* Create a temp file to put gdb commands into */
strcpy(respfile, "gdb-respfile-XXXXXX"); strcpy(respfile, "gdb-respfile-XXXXXX");
if((fd=mkstemp(respfile)) >= 0 && (f=fdopen(fd, "w")) != NULL) if((fd=mkstemp(respfile)) >= 0 && (f=fdopen(fd, "w")) != NULL)
{ {
fprintf(f, "attach %d\n" fprintf(f, "attach %d\n"
"shell echo \"\"\n" "shell echo \"\"\n"
"shell echo \"* Loaded Libraries\"\n" "shell echo \"* Loaded Libraries\"\n"
"info sharedlibrary\n" "info sharedlibrary\n"
"shell echo \"\"\n" "shell echo \"\"\n"
"shell echo \"* Threads\"\n" "shell echo \"* Threads\"\n"
"info threads\n" "info threads\n"
"shell echo \"\"\n" "shell echo \"\"\n"
"shell echo \"* FPU Status\"\n" "shell echo \"* FPU Status\"\n"
"info float\n" "info float\n"
"shell echo \"\"\n" "shell echo \"\"\n"
"shell echo \"* Registers\"\n" "shell echo \"* Registers\"\n"
"info registers\n" "info registers\n"
"shell echo \"\"\n" "shell echo \"\"\n"
"shell echo \"* Backtrace\"\n" "shell echo \"* Backtrace\"\n"
"thread apply all backtrace full\n" "thread apply all backtrace full\n"
"detach\n" "detach\n"
"quit\n", pid); "quit\n", pid);
fclose(f); fclose(f);
/* Run gdb and print process info. */ /* Run gdb and print process info. */
snprintf(cmd_buf, sizeof(cmd_buf), "gdb --quiet --batch --command=%s", respfile); snprintf(cmd_buf, sizeof(cmd_buf), "gdb --quiet --batch --command=%s", respfile);
printf("Executing: %s\n", cmd_buf); printf("Executing: %s\n", cmd_buf);
fflush(stdout); fflush(stdout);
system(cmd_buf); system(cmd_buf);
/* Clean up */ /* Clean up */
remove(respfile); remove(respfile);
} }
else else
{ {
/* Error creating temp file */ /* Error creating temp file */
if(fd >= 0) if(fd >= 0)
{ {
close(fd); close(fd);
remove(respfile); remove(respfile);
} }
printf("!!! Could not create gdb command file\n"); printf("!!! Could not create gdb command file\n");
} }
fflush(stdout); fflush(stdout);
} }
static void sys_info(void) static void sys_info(void)
{ {
#ifdef __unix__ #ifdef __unix__
system("echo \"System: `uname -a`\""); struct utsname info;
putchar('\n'); if(uname(&info))
fflush(stdout); printf("!!! Failed to get system information\n");
else
printf("System: %s %s %s %s %s\n",
info.sysname, info.nodename, info.release, info.version, info.machine);
fflush(stdout);
#endif #endif
} }
static size_t safe_write(int fd, const void *buf, size_t len) static size_t safe_write(int fd, const void *buf, size_t len)
{ {
size_t ret = 0; size_t ret = 0;
while(ret < len) while(ret < len)
{ {
ssize_t rem; ssize_t rem;
if((rem=write(fd, (const char*)buf+ret, len-ret)) == -1) if((rem=write(fd, (const char*)buf+ret, len-ret)) == -1)
{ {
if(errno == EINTR) if(errno == EINTR)
continue; continue;
break; break;
} }
ret += rem; ret += rem;
} }
return ret; return ret;
} }
static void crash_catcher(int signum, siginfo_t *siginfo, void *context) static void crash_catcher(int signum, siginfo_t *siginfo, void *context)
{ {
//ucontext_t *ucontext = (ucontext_t*)context; //ucontext_t *ucontext = (ucontext_t*)context;
pid_t dbg_pid; pid_t dbg_pid;
int fd[2]; int fd[2];
/* Make sure the effective uid is the real uid */ /* Make sure the effective uid is the real uid */
if(getuid() != geteuid()) if(getuid() != geteuid())
{ {
raise(signum); raise(signum);
return; return;
} }
safe_write(STDERR_FILENO, fatal_err, sizeof(fatal_err)-1); safe_write(STDERR_FILENO, fatal_err, sizeof(fatal_err)-1);
if(pipe(fd) == -1) if(pipe(fd) == -1)
{ {
safe_write(STDERR_FILENO, pipe_err, sizeof(pipe_err)-1); safe_write(STDERR_FILENO, pipe_err, sizeof(pipe_err)-1);
raise(signum); raise(signum);
return; return;
} }
crash_info.signum = signum; crash_info.signum = signum;
crash_info.pid = getpid(); crash_info.pid = getpid();
crash_info.has_siginfo = !!siginfo; crash_info.has_siginfo = !!siginfo;
if(siginfo) if(siginfo)
crash_info.siginfo = *siginfo; crash_info.siginfo = *siginfo;
if(cc_user_info) if(cc_user_info)
cc_user_info(crash_info.buf, crash_info.buf+sizeof(crash_info.buf)); cc_user_info(crash_info.buf, crash_info.buf+sizeof(crash_info.buf));
/* Fork off to start a crash handler */ /* Fork off to start a crash handler */
switch((dbg_pid=fork())) switch((dbg_pid=fork()))
{ {
/* Error */ /* Error */
case -1: case -1:
safe_write(STDERR_FILENO, fork_err, sizeof(fork_err)-1); safe_write(STDERR_FILENO, fork_err, sizeof(fork_err)-1);
raise(signum); raise(signum);
return; return;
case 0: case 0:
dup2(fd[0], STDIN_FILENO); dup2(fd[0], STDIN_FILENO);
close(fd[0]); close(fd[0]);
close(fd[1]); close(fd[1]);
execl(argv0, argv0, crash_switch, NULL); execl(argv0, argv0, crash_switch, NULL);
safe_write(STDERR_FILENO, exec_err, sizeof(exec_err)-1); safe_write(STDERR_FILENO, exec_err, sizeof(exec_err)-1);
_exit(1); _exit(1);
default: default:
#ifdef __linux__ #ifdef __linux__
prctl(PR_SET_PTRACER, dbg_pid, 0, 0, 0); prctl(PR_SET_PTRACER, dbg_pid, 0, 0, 0);
#endif #endif
safe_write(fd[1], &crash_info, sizeof(crash_info)); safe_write(fd[1], &crash_info, sizeof(crash_info));
close(fd[0]); close(fd[0]);
close(fd[1]); close(fd[1]);
/* Wait; we'll be killed when gdb is done */ /* Wait; we'll be killed when gdb is done */
do { do {
int status; int status;
if(waitpid(dbg_pid, &status, 0) == dbg_pid && if(waitpid(dbg_pid, &status, 0) == dbg_pid &&
(WIFEXITED(status) || WIFSIGNALED(status))) (WIFEXITED(status) || WIFSIGNALED(status)))
{ {
/* The debug process died before it could kill us */ /* The debug process died before it could kill us */
raise(signum); raise(signum);
break; break;
} }
} while(1); } while(1);
} }
} }
static void crash_handler(const char *logfile) static void crash_handler(const char *logfile)
{ {
const char *sigdesc = ""; const char *sigdesc = "";
int i; int i;
if(fread(&crash_info, sizeof(crash_info), 1, stdin) != 1) if(fread(&crash_info, sizeof(crash_info), 1, stdin) != 1)
{ {
fprintf(stderr, "!!! Failed to retrieve info from crashed process\n"); fprintf(stderr, "!!! Failed to retrieve info from crashed process\n");
exit(1); exit(1);
} }
/* Get the signal description */ /* Get the signal description */
for(i = 0;signals[i].name;++i) for(i = 0;signals[i].name;++i)
{ {
if(signals[i].signum == crash_info.signum) if(signals[i].signum == crash_info.signum)
{ {
sigdesc = signals[i].name; sigdesc = signals[i].name;
break; break;
} }
} }
if(crash_info.has_siginfo) if(crash_info.has_siginfo)
{ {
switch(crash_info.signum) switch(crash_info.signum)
{ {
case SIGSEGV: case SIGSEGV:
for(i = 0;sigsegv_codes[i].name;++i) for(i = 0;sigsegv_codes[i].name;++i)
{ {
if(sigsegv_codes[i].code == crash_info.siginfo.si_code) if(sigsegv_codes[i].code == crash_info.siginfo.si_code)
{ {
sigdesc = sigsegv_codes[i].name; sigdesc = sigsegv_codes[i].name;
break; break;
} }
} }
break; break;
case SIGFPE: case SIGFPE:
for(i = 0;sigfpe_codes[i].name;++i) for(i = 0;sigfpe_codes[i].name;++i)
{ {
if(sigfpe_codes[i].code == crash_info.siginfo.si_code) if(sigfpe_codes[i].code == crash_info.siginfo.si_code)
{ {
sigdesc = sigfpe_codes[i].name; sigdesc = sigfpe_codes[i].name;
break; break;
} }
} }
break; break;
case SIGILL: case SIGILL:
for(i = 0;sigill_codes[i].name;++i) for(i = 0;sigill_codes[i].name;++i)
{ {
if(sigill_codes[i].code == crash_info.siginfo.si_code) if(sigill_codes[i].code == crash_info.siginfo.si_code)
{ {
sigdesc = sigill_codes[i].name; sigdesc = sigill_codes[i].name;
break; break;
} }
} }
break; break;
case SIGBUS: case SIGBUS:
for(i = 0;sigbus_codes[i].name;++i) for(i = 0;sigbus_codes[i].name;++i)
{ {
if(sigbus_codes[i].code == crash_info.siginfo.si_code) if(sigbus_codes[i].code == crash_info.siginfo.si_code)
{ {
sigdesc = sigbus_codes[i].name; sigdesc = sigbus_codes[i].name;
break; break;
} }
} }
break; break;
} }
} }
fprintf(stderr, "%s (signal %i)\n", sigdesc, crash_info.signum); fprintf(stderr, "%s (signal %i)\n", sigdesc, crash_info.signum);
if(crash_info.has_siginfo) if(crash_info.has_siginfo)
fprintf(stderr, "Address: %p\n", crash_info.siginfo.si_addr); fprintf(stderr, "Address: %p\n", crash_info.siginfo.si_addr);
fputc('\n', stderr); fputc('\n', stderr);
if(logfile) if(logfile)
{ {
/* Create crash log file and redirect shell output to it */ /* Create crash log file and redirect shell output to it */
if(freopen(logfile, "wa", stdout) != stdout) if(freopen(logfile, "wa", stdout) != stdout)
{ {
fprintf(stderr, "!!! Could not create %s following signal\n", logfile); fprintf(stderr, "!!! Could not create %s following signal\n", logfile);
exit(1); exit(1);
} }
fprintf(stderr, "Generating %s and killing process %d, please wait... ", logfile, crash_info.pid); fprintf(stderr, "Generating %s and killing process %d, please wait... ", logfile, crash_info.pid);
printf("*** Fatal Error ***\n" printf("*** Fatal Error ***\n"
"%s (signal %i)\n", sigdesc, crash_info.signum); "%s (signal %i)\n", sigdesc, crash_info.signum);
if(crash_info.has_siginfo) if(crash_info.has_siginfo)
printf("Address: %p\n", crash_info.siginfo.si_addr); printf("Address: %p\n", crash_info.siginfo.si_addr);
fputc('\n', stdout); fputc('\n', stdout);
fflush(stdout); fflush(stdout);
} }
sys_info(); sys_info();
crash_info.buf[sizeof(crash_info.buf)-1] = '\0'; crash_info.buf[sizeof(crash_info.buf)-1] = '\0';
printf("%s\n", crash_info.buf); printf("%s\n", crash_info.buf);
fflush(stdout); fflush(stdout);
if(crash_info.pid > 0) if(crash_info.pid > 0)
{ {
gdb_info(crash_info.pid); gdb_info(crash_info.pid);
kill(crash_info.pid, SIGKILL); kill(crash_info.pid, SIGKILL);
} }
if(logfile) if(logfile)
{ {
char cwd[MAXPATHLEN]; char cwd[MAXPATHLEN];
getcwd(cwd, MAXPATHLEN); getcwd(cwd, MAXPATHLEN);
std::string message = "OpenMW has encountered a fatal error.\nCrash log saved to '" + std::string(cwd) + "/" + std::string(logfile) + "'.\n Please report this to https://bugs.openmw.org !"; std::string message = "OpenMW has encountered a fatal error.\nCrash log saved to '" + std::string(cwd) + "/" + std::string(logfile) + "'.\n Please report this to https://bugs.openmw.org !";
SDL_ShowSimpleMessageBox(0, "Fatal Error", message.c_str(), NULL); SDL_ShowSimpleMessageBox(0, "Fatal Error", message.c_str(), NULL);
} }
exit(0); exit(0);
} }
int cc_install_handlers(int argc, char **argv, int num_signals, int *signals, const char *logfile, int (*user_info)(char*, char*)) int cc_install_handlers(int argc, char **argv, int num_signals, int *signals, const char *logfile, int (*user_info)(char*, char*))
{ {
struct sigaction sa; struct sigaction sa;
stack_t altss; stack_t altss;
int retval; int retval;
if(argc == 2 && strcmp(argv[1], crash_switch) == 0) if(argc == 2 && strcmp(argv[1], crash_switch) == 0)
crash_handler(logfile); crash_handler(logfile);
cc_user_info = user_info; cc_user_info = user_info;
if(argv[0][0] == '/') if(argv[0][0] == '/')
snprintf(argv0, sizeof(argv0), "%s", argv[0]); snprintf(argv0, sizeof(argv0), "%s", argv[0]);
else else
{ {
getcwd(argv0, sizeof(argv0)); getcwd(argv0, sizeof(argv0));
retval = strlen(argv0); retval = strlen(argv0);
snprintf(argv0+retval, sizeof(argv0)-retval, "/%s", argv[0]); snprintf(argv0+retval, sizeof(argv0)-retval, "/%s", argv[0]);
} }
/* Set an alternate signal stack so SIGSEGVs caused by stack overflows /* Set an alternate signal stack so SIGSEGVs caused by stack overflows
* still run */ * still run */
altss.ss_sp = altstack; altss.ss_sp = altstack;
altss.ss_flags = 0; altss.ss_flags = 0;
altss.ss_size = sizeof(altstack); altss.ss_size = sizeof(altstack);
sigaltstack(&altss, NULL); sigaltstack(&altss, NULL);
memset(&sa, 0, sizeof(sa)); memset(&sa, 0, sizeof(sa));
sa.sa_sigaction = crash_catcher; sa.sa_sigaction = crash_catcher;
sa.sa_flags = SA_RESETHAND | SA_NODEFER | SA_SIGINFO | SA_ONSTACK; sa.sa_flags = SA_RESETHAND | SA_NODEFER | SA_SIGINFO | SA_ONSTACK;
sigemptyset(&sa.sa_mask); sigemptyset(&sa.sa_mask);
retval = 0; retval = 0;
while(num_signals--) while(num_signals--)
{ {
if((*signals != SIGSEGV && *signals != SIGILL && *signals != SIGFPE && *signals != SIGABRT && if((*signals != SIGSEGV && *signals != SIGILL && *signals != SIGFPE && *signals != SIGABRT &&
*signals != SIGBUS) || sigaction(*signals, &sa, NULL) == -1) *signals != SIGBUS) || sigaction(*signals, &sa, NULL) == -1)
{ {
*signals = 0; *signals = 0;
retval = -1; retval = -1;
} }
++signals; ++signals;
} }
return retval; return retval;
} }

@ -7,6 +7,8 @@
#include <MyGUI_WidgetManager.h> #include <MyGUI_WidgetManager.h>
#include <SDL.h>
#include <components/compiler/extensions0.hpp> #include <components/compiler/extensions0.hpp>
#include <components/bsa/bsa_archive.hpp> #include <components/bsa/bsa_archive.hpp>
@ -41,8 +43,7 @@
#include "mwmechanics/mechanicsmanagerimp.hpp" #include "mwmechanics/mechanicsmanagerimp.hpp"
#include "mwstate/statemanagerimp.hpp"
#include <SDL.h>
void OMW::Engine::executeLocalScripts() void OMW::Engine::executeLocalScripts()
{ {
@ -65,10 +66,6 @@ void OMW::Engine::executeLocalScripts()
localScripts.setIgnore (MWWorld::Ptr()); localScripts.setIgnore (MWWorld::Ptr());
} }
void OMW::Engine::setAnimationVerbose(bool animverbose)
{
}
bool OMW::Engine::frameStarted (const Ogre::FrameEvent& evt) bool OMW::Engine::frameStarted (const Ogre::FrameEvent& evt)
{ {
bool paused = MWBase::Environment::get().getWindowManager()->isGuiMode(); bool paused = MWBase::Environment::get().getWindowManager()->isGuiMode();
@ -92,31 +89,47 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
if (mUseSound) if (mUseSound)
MWBase::Environment::get().getSoundManager()->update(frametime); MWBase::Environment::get().getSoundManager()->update(frametime);
// global scripts bool paused = MWBase::Environment::get().getWindowManager()->isGuiMode();
MWBase::Environment::get().getScriptManager()->getGlobalScripts().run();
bool changed = MWBase::Environment::get().getWorld()->hasCellChanged(); // update game state
MWBase::Environment::get().getStateManager()->update (frametime);
// local scripts if (MWBase::Environment::get().getStateManager()->getState()==
executeLocalScripts(); // This does not handle the case where a global script causes a cell MWBase::StateManager::State_Running)
// change, followed by a cell change in a local script during the same {
// frame. // global scripts
MWBase::Environment::get().getScriptManager()->getGlobalScripts().run();
// passing of time bool changed = MWBase::Environment::get().getWorld()->hasCellChanged();
if (!MWBase::Environment::get().getWindowManager()->isGuiMode())
MWBase::Environment::get().getWorld()->advanceTime(
frametime*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/3600);
// local scripts
executeLocalScripts(); // This does not handle the case where a global script causes a
// cell change, followed by a cell change in a local script during
// the same frame.
if (changed) // keep change flag for another frame, if cell changed happened in local script
MWBase::Environment::get().getWorld()->markCellAsUnchanged();
if (!paused)
MWBase::Environment::get().getWorld()->advanceTime(
frametime*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/3600);
}
if (changed) // keep change flag for another frame, if cell changed happend in local script
MWBase::Environment::get().getWorld()->markCellAsUnchanged();
// update actors // update actors
MWBase::Environment::get().getMechanicsManager()->update(frametime, MWBase::Environment::get().getMechanicsManager()->update(frametime,
MWBase::Environment::get().getWindowManager()->isGuiMode()); paused);
if (MWBase::Environment::get().getStateManager()->getState()==
MWBase::StateManager::State_Running)
{
MWWorld::Ptr player = mEnvironment.getWorld()->getPlayerPtr();
if(!paused && player.getClass().getCreatureStats(player).isDead())
MWBase::Environment::get().getStateManager()->endGame();
}
// update world // update world
MWBase::Environment::get().getWorld()->update(frametime, MWBase::Environment::get().getWindowManager()->isGuiMode()); MWBase::Environment::get().getWorld()->update(frametime, paused);
// update GUI // update GUI
Ogre::RenderWindow* window = mOgre->getWindow(); Ogre::RenderWindow* window = mOgre->getWindow();
@ -139,9 +152,10 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager)
: mOgre (0) : mOgre (0)
, mFpsLevel(0) , mFpsLevel(0)
, mVerboseScripts (false) , mVerboseScripts (false)
, mNewGame (false) , mSkipMenu (false)
, mUseSound (true) , mUseSound (true)
, mCompileAll (false) , mCompileAll (false)
, mWarningsMode (1)
, mScriptContext (0) , mScriptContext (0)
, mFSStrict (false) , mFSStrict (false)
, mScriptConsoleMode (false) , mScriptConsoleMode (false)
@ -161,6 +175,7 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager)
//kindly ask SDL not to trash our OGL context //kindly ask SDL not to trash our OGL context
//might this be related to http://bugzilla.libsdl.org/show_bug.cgi?id=748 ? //might this be related to http://bugzilla.libsdl.org/show_bug.cgi?id=748 ?
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software"); SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software");
SDL_SetMainReady();
if(SDL_Init(flags) != 0) if(SDL_Init(flags) != 0)
{ {
throw std::runtime_error("Could not initialize SDL! " + std::string(SDL_GetError())); throw std::runtime_error("Could not initialize SDL! " + std::string(SDL_GetError()));
@ -268,12 +283,7 @@ void OMW::Engine::setCell (const std::string& cellName)
void OMW::Engine::addContentFile(const std::string& file) void OMW::Engine::addContentFile(const std::string& file)
{ {
if (file.find_last_of(".") == std::string::npos) mContentFiles.push_back(file);
{
throw std::runtime_error("Missing extension in content file!");
}
mContentFiles.push_back(file);
} }
void OMW::Engine::setScriptsVerbosity(bool scriptsVerbosity) void OMW::Engine::setScriptsVerbosity(bool scriptsVerbosity)
@ -281,9 +291,9 @@ void OMW::Engine::setScriptsVerbosity(bool scriptsVerbosity)
mVerboseScripts = scriptsVerbosity; mVerboseScripts = scriptsVerbosity;
} }
void OMW::Engine::setNewGame(bool newGame) void OMW::Engine::setSkipMenu (bool skipMenu)
{ {
mNewGame = newGame; mSkipMenu = skipMenu;
} }
std::string OMW::Engine::loadSettings (Settings::Manager & settings) std::string OMW::Engine::loadSettings (Settings::Manager & settings)
@ -301,7 +311,7 @@ std::string OMW::Engine::loadSettings (Settings::Manager & settings)
throw std::runtime_error ("No default settings file found! Make sure the file \"settings-default.cfg\" was properly installed."); throw std::runtime_error ("No default settings file found! Make sure the file \"settings-default.cfg\" was properly installed.");
// load user settings if they exist, otherwise just load the default settings as user settings // load user settings if they exist, otherwise just load the default settings as user settings
const std::string settingspath = mCfgMgr.getUserPath().string() + "/settings.cfg"; const std::string settingspath = mCfgMgr.getUserConfigPath().string() + "/settings.cfg";
if (boost::filesystem::exists(settingspath)) if (boost::filesystem::exists(settingspath))
settings.loadUser(settingspath); settings.loadUser(settingspath);
else if (boost::filesystem::exists(localdefault)) else if (boost::filesystem::exists(localdefault))
@ -313,18 +323,25 @@ std::string OMW::Engine::loadSettings (Settings::Manager & settings)
// load nif overrides // load nif overrides
NifOverrides::Overrides nifOverrides; NifOverrides::Overrides nifOverrides;
if (boost::filesystem::exists(mCfgMgr.getLocalPath().string() + "/transparency-overrides.cfg")) std::string transparencyOverrides = "/transparency-overrides.cfg";
nifOverrides.loadTransparencyOverrides(mCfgMgr.getLocalPath().string() + "/transparency-overrides.cfg"); std::string materialOverrides = "/material-overrides.cfg";
else if (boost::filesystem::exists(mCfgMgr.getGlobalPath().string() + "/transparency-overrides.cfg")) if (boost::filesystem::exists(mCfgMgr.getLocalPath().string() + transparencyOverrides))
nifOverrides.loadTransparencyOverrides(mCfgMgr.getGlobalPath().string() + "/transparency-overrides.cfg"); nifOverrides.loadTransparencyOverrides(mCfgMgr.getLocalPath().string() + transparencyOverrides);
else if (boost::filesystem::exists(mCfgMgr.getGlobalPath().string() + transparencyOverrides))
settings.setBool("hardware cursors", "GUI", true); nifOverrides.loadTransparencyOverrides(mCfgMgr.getGlobalPath().string() + transparencyOverrides);
if (boost::filesystem::exists(mCfgMgr.getLocalPath().string() + materialOverrides))
nifOverrides.loadMaterialOverrides(mCfgMgr.getLocalPath().string() + materialOverrides);
else if (boost::filesystem::exists(mCfgMgr.getGlobalPath().string() + materialOverrides))
nifOverrides.loadMaterialOverrides(mCfgMgr.getGlobalPath().string() + materialOverrides);
return settingspath; return settingspath;
} }
void OMW::Engine::prepareEngine (Settings::Manager & settings) void OMW::Engine::prepareEngine (Settings::Manager & settings)
{ {
mEnvironment.setStateManager (
new MWState::StateManager (mCfgMgr.getUserDataPath() / "saves", mContentFiles.at (0)));
Nif::NIFFile::CacheLock cachelock; Nif::NIFFile::CacheLock cachelock;
std::string renderSystem = settings.getString("render system", "Video"); std::string renderSystem = settings.getString("render system", "Video");
@ -373,7 +390,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
// Create input and UI first to set up a bootstrapping environment for // Create input and UI first to set up a bootstrapping environment for
// showing a loading screen and keeping the window responsive while doing so // showing a loading screen and keeping the window responsive while doing so
std::string keybinderUser = (mCfgMgr.getUserPath() / "input.xml").string(); std::string keybinderUser = (mCfgMgr.getUserConfigPath() / "input.xml").string();
bool keybinderUserExists = boost::filesystem::exists(keybinderUser); bool keybinderUserExists = boost::filesystem::exists(keybinderUser);
MWInput::InputManager* input = new MWInput::InputManager (*mOgre, *this, keybinderUser, keybinderUserExists, mGrab); MWInput::InputManager* input = new MWInput::InputManager (*mOgre, *this, keybinderUser, keybinderUserExists, mGrab);
mEnvironment.setInputManager (input); mEnvironment.setInputManager (input);
@ -391,10 +408,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
input->setPlayer(&mEnvironment.getWorld()->getPlayer()); input->setPlayer(&mEnvironment.getWorld()->getPlayer());
window->initUI(); window->initUI();
if (mNewGame)
// still redundant work here: recreate CharacterCreation(),
// double update visibility etc.
window->setNewGame(true);
window->renderWorldMap(); window->renderWorldMap();
//Load translation data //Load translation data
@ -402,7 +415,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
for (size_t i = 0; i < mContentFiles.size(); i++) for (size_t i = 0; i < mContentFiles.size(); i++)
mTranslationDataStorage.loadTranslationData(mFileCollections, mContentFiles[i]); mTranslationDataStorage.loadTranslationData(mFileCollections, mContentFiles[i]);
Compiler::registerExtensions (mExtensions); Compiler::registerExtensions (mExtensions);
// Create sound system // Create sound system
mEnvironment.setSoundManager (new MWSound::SoundManager(mUseSound)); mEnvironment.setSoundManager (new MWSound::SoundManager(mUseSound));
@ -412,7 +425,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
mScriptContext->setExtensions (&mExtensions); mScriptContext->setExtensions (&mExtensions);
mEnvironment.setScriptManager (new MWScript::ScriptManager (MWBase::Environment::get().getWorld()->getStore(), mEnvironment.setScriptManager (new MWScript::ScriptManager (MWBase::Environment::get().getWorld()->getStore(),
mVerboseScripts, *mScriptContext)); mVerboseScripts, *mScriptContext, mWarningsMode));
// Create game mechanics system // Create game mechanics system
MWMechanics::MechanicsManager* mechanics = new MWMechanics::MechanicsManager; MWMechanics::MechanicsManager* mechanics = new MWMechanics::MechanicsManager;
@ -426,12 +439,12 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
mechanics->buildPlayer(); mechanics->buildPlayer();
window->updatePlayer(); window->updatePlayer();
if (!mNewGame) // load cell
{ ESM::Position pos;
// load cell MWBase::World *world = MWBase::Environment::get().getWorld();
ESM::Position pos;
MWBase::World *world = MWBase::Environment::get().getWorld();
if (!mCellName.empty())
{
if (world->findExteriorPosition(mCellName, pos)) { if (world->findExteriorPosition(mCellName, pos)) {
world->changeToExteriorCell (pos); world->changeToExteriorCell (pos);
} }
@ -441,7 +454,11 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
} }
} }
else else
mEnvironment.getWorld()->startNewGame(); {
pos.pos[0] = pos.pos[1] = pos.pos[2] = 0;
pos.rot[0] = pos.rot[1] = pos.pos[2] = 0;
world->changeToExteriorCell (pos);
}
Ogre::FrameEvent event; Ogre::FrameEvent event;
event.timeSinceLastEvent = 0; event.timeSinceLastEvent = 0;
@ -467,7 +484,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
void OMW::Engine::go() void OMW::Engine::go()
{ {
assert (!mCellName.empty());
assert (!mContentFiles.empty()); assert (!mContentFiles.empty());
assert (!mOgre); assert (!mOgre);
@ -488,8 +504,14 @@ void OMW::Engine::go()
if (!mStartupScript.empty()) if (!mStartupScript.empty())
MWBase::Environment::get().getWindowManager()->executeInConsole (mStartupScript); MWBase::Environment::get().getWindowManager()->executeInConsole (mStartupScript);
// start in main menu
if (!mSkipMenu)
MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu);
else
MWBase::Environment::get().getStateManager()->newGame (true);
// Start the main rendering loop // Start the main rendering loop
while (!mEnvironment.getRequestExit()) while (!mEnvironment.get().getStateManager()->hasQuitRequest())
Ogre::Root::getSingleton().renderOneFrame(); Ogre::Root::getSingleton().renderOneFrame();
// Save user settings // Save user settings
@ -508,15 +530,20 @@ void OMW::Engine::activate()
if (ptr.isEmpty()) if (ptr.isEmpty())
return; return;
if (ptr.getClass().getName(ptr) == "") // objects without name presented to user can never be activated
return;
MWScript::InterpreterContext interpreterContext (&ptr.getRefData().getLocals(), ptr); MWScript::InterpreterContext interpreterContext (&ptr.getRefData().getLocals(), ptr);
boost::shared_ptr<MWWorld::Action> action = boost::shared_ptr<MWWorld::Action> action =
MWWorld::Class::get (ptr).activate (ptr, MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); MWWorld::Class::get (ptr).activate (ptr, MWBase::Environment::get().getWorld()->getPlayerPtr());
interpreterContext.activate (ptr, action); interpreterContext.activate (ptr, action);
std::string script = MWWorld::Class::get (ptr).getScript (ptr); std::string script = MWWorld::Class::get (ptr).getScript (ptr);
MWBase::Environment::get().getWorld()->breakInvisibility(MWBase::Environment::get().getWorld()->getPlayerPtr());
if (!script.empty()) if (!script.empty())
{ {
MWBase::Environment::get().getWorld()->getLocalScripts().setIgnore (ptr); MWBase::Environment::get().getWorld()->getLocalScripts().setIgnore (ptr);
@ -534,7 +561,7 @@ void OMW::Engine::screenshot()
// Count screenshots. // Count screenshots.
int shotCount = 0; int shotCount = 0;
const std::string screenshotPath = mCfgMgr.getUserPath().string(); const std::string& screenshotPath = mCfgMgr.getUserDataPath().string();
// Find the first unused filename with a do-while // Find the first unused filename with a do-while
std::ostringstream stream; std::ostringstream stream;
@ -586,8 +613,12 @@ void OMW::Engine::setStartupScript (const std::string& path)
mStartupScript = path; mStartupScript = path;
} }
void OMW::Engine::setActivationDistanceOverride (int distance) void OMW::Engine::setActivationDistanceOverride (int distance)
{ {
mActivationDistanceOverride = distance; mActivationDistanceOverride = distance;
} }
void OMW::Engine::setWarningsMode (int mode)
{
mWarningsMode = mode;
}

@ -71,9 +71,10 @@ namespace OMW
std::vector<std::string> mContentFiles; std::vector<std::string> mContentFiles;
int mFpsLevel; int mFpsLevel;
bool mVerboseScripts; bool mVerboseScripts;
bool mNewGame; bool mSkipMenu;
bool mUseSound; bool mUseSound;
bool mCompileAll; bool mCompileAll;
int mWarningsMode;
std::string mFocusName; std::string mFocusName;
std::map<std::string,std::string> mFallbackMap; std::map<std::string,std::string> mFallbackMap;
bool mScriptConsoleMode; bool mScriptConsoleMode;
@ -151,8 +152,7 @@ namespace OMW
/// Disable or enable all sounds /// Disable or enable all sounds
void setSoundUsage(bool soundUsage); void setSoundUsage(bool soundUsage);
/// Start as a new game. void setSkipMenu (bool skipMenu);
void setNewGame(bool newGame);
void setGrabMouse(bool grab) { mGrab = grab; } void setGrabMouse(bool grab) { mGrab = grab; }
@ -171,8 +171,6 @@ namespace OMW
/// Font encoding /// Font encoding
void setEncoding(const ToUTF8::FromType& encoding); void setEncoding(const ToUTF8::FromType& encoding);
void setAnimationVerbose(bool animverbose);
void setFallbackValues(std::map<std::string,std::string> map); void setFallbackValues(std::map<std::string,std::string> map);
/// Enable console-only script functionality /// Enable console-only script functionality
@ -184,6 +182,8 @@ namespace OMW
/// Override the game setting specified activation distance. /// Override the game setting specified activation distance.
void setActivationDistanceOverride (int distance); void setActivationDistanceOverride (int distance);
void setWarningsMode (int mode);
private: private:
Files::ConfigurationManager& mCfgMgr; Files::ConfigurationManager& mCfgMgr;
}; };

@ -1,10 +1,10 @@
#include <iostream> #include <iostream>
#include <cstdio> #include <cstdio>
#include <components/version/version.hpp>
#include <components/files/configurationmanager.hpp> #include <components/files/configurationmanager.hpp>
#include <SDL_messagebox.h> #include <SDL.h>
#include <SDL_main.h>
#include "engine.hpp" #include "engine.hpp"
#if defined(_WIN32) && !defined(_CONSOLE) #if defined(_WIN32) && !defined(_CONSOLE)
@ -12,6 +12,7 @@
#include <boost/iostreams/stream_buffer.hpp> #include <boost/iostreams/stream_buffer.hpp>
// For OutputDebugString // For OutputDebugString
#define WIN32_LEAN_AND_MEAN
#include <Windows.h> #include <Windows.h>
// makes __argc and __argv available on windows // makes __argc and __argv available on windows
#include <cstdlib> #include <cstdlib>
@ -30,8 +31,6 @@ extern int is_debugger_attached(void);
#include <OSX/macUtils.h> #include <OSX/macUtils.h>
#endif #endif
#include "config.hpp"
#include <boost/version.hpp> #include <boost/version.hpp>
/** /**
* Workaround for problems with whitespaces in paths in older versions of Boost library * Workaround for problems with whitespaces in paths in older versions of Boost library
@ -116,16 +115,13 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
("resources", bpo::value<std::string>()->default_value("resources"), ("resources", bpo::value<std::string>()->default_value("resources"),
"set resources directory") "set resources directory")
("start", bpo::value<std::string>()->default_value("Beshara"), ("start", bpo::value<std::string>()->default_value(""),
"set initial cell") "set initial cell")
("content", bpo::value<StringsVector>()->default_value(StringsVector(), "") ("content", bpo::value<StringsVector>()->default_value(StringsVector(), "")
->multitoken(), "content file(s): esm/esp, or omwgame/omwaddon") ->multitoken(), "content file(s): esm/esp, or omwgame/omwaddon")
("anim-verbose", bpo::value<bool>()->implicit_value(true) ("no-sound", bpo::value<bool>()->implicit_value(true)
->default_value(false), "output animation indices files")
("nosound", bpo::value<bool>()->implicit_value(true)
->default_value(false), "disable all sounds") ->default_value(false), "disable all sounds")
("script-verbose", bpo::value<bool>()->implicit_value(true) ("script-verbose", bpo::value<bool>()->implicit_value(true)
@ -140,8 +136,15 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
("script-run", bpo::value<std::string>()->default_value(""), ("script-run", bpo::value<std::string>()->default_value(""),
"select a file containing a list of console commands that is executed on startup") "select a file containing a list of console commands that is executed on startup")
("new-game", bpo::value<bool>()->implicit_value(true) ("script-warn", bpo::value<int>()->implicit_value (1)
->default_value(false), "activate char gen/new game mechanics") ->default_value (1),
"handling of warnings when compiling scripts\n"
"\t0 - ignore warning\n"
"\t1 - show warning but consider script as correctly compiled anyway\n"
"\t2 - treat warnings as errors")
("skip-menu", bpo::value<bool>()->implicit_value(true)
->default_value(false), "skip main menu on game startup")
("fs-strict", bpo::value<bool>()->implicit_value(true) ("fs-strict", bpo::value<bool>()->implicit_value(true)
->default_value(false), "strict file system handling (no case folding)") ->default_value(false), "strict file system handling (no case folding)")
@ -169,8 +172,6 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
bpo::store(valid_opts, variables); bpo::store(valid_opts, variables);
bpo::notify(variables); bpo::notify(variables);
cfgMgr.readConfiguration(variables, desc);
bool run = true; bool run = true;
if (variables.count ("help")) if (variables.count ("help"))
@ -188,6 +189,8 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
if (!run) if (!run)
return false; return false;
cfgMgr.readConfiguration(variables, desc);
engine.setGrabMouse(!variables.count("no-grab")); engine.setGrabMouse(!variables.count("no-grab"));
// Font encoding settings // Font encoding settings
@ -235,17 +238,17 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
// startup-settings // startup-settings
engine.setCell(variables["start"].as<std::string>()); engine.setCell(variables["start"].as<std::string>());
engine.setNewGame(variables["new-game"].as<bool>()); engine.setSkipMenu (variables["skip-menu"].as<bool>());
// other settings // other settings
engine.setSoundUsage(!variables["nosound"].as<bool>()); engine.setSoundUsage(!variables["no-sound"].as<bool>());
engine.setScriptsVerbosity(variables["script-verbose"].as<bool>()); engine.setScriptsVerbosity(variables["script-verbose"].as<bool>());
engine.setCompileAll(variables["script-all"].as<bool>()); engine.setCompileAll(variables["script-all"].as<bool>());
engine.setAnimationVerbose(variables["anim-verbose"].as<bool>());
engine.setFallbackValues(variables["fallback"].as<FallbackMap>().mMap); engine.setFallbackValues(variables["fallback"].as<FallbackMap>().mMap);
engine.setScriptConsoleMode (variables["script-console"].as<bool>()); engine.setScriptConsoleMode (variables["script-console"].as<bool>());
engine.setStartupScript (variables["script-run"].as<std::string>()); engine.setStartupScript (variables["script-run"].as<std::string>());
engine.setActivationDistanceOverride (variables["activate-dist"].as<int>()); engine.setActivationDistanceOverride (variables["activate-dist"].as<int>());
engine.setWarningsMode (variables["script-warn"].as<int>());
return true; return true;
} }
@ -283,7 +286,7 @@ int main(int argc, char**argv)
catch (std::exception &e) catch (std::exception &e)
{ {
#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX || OGRE_PLATFORM == OGRE_PLATFORM_APPLE #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX || OGRE_PLATFORM == OGRE_PLATFORM_APPLE
if (isatty(fileno(stdin))) if (isatty(fileno(stdin)) || !SDL_WasInit(SDL_INIT_VIDEO))
std::cerr << "\nERROR: " << e.what() << std::endl; std::cerr << "\nERROR: " << e.what() << std::endl;
else else
#endif #endif

@ -3,6 +3,14 @@
#include <string> #include <string>
#include <libs/platform/stdint.h>
namespace ESM
{
class ESMReader;
class ESMWriter;
}
namespace MWWorld namespace MWWorld
{ {
class Ptr; class Ptr;
@ -51,7 +59,13 @@ namespace MWBase
virtual void persuade (int type) = 0; virtual void persuade (int type) = 0;
virtual int getTemporaryDispositionChange () const = 0; virtual int getTemporaryDispositionChange () const = 0;
virtual void applyTemporaryDispositionChange (int delta) = 0; virtual void applyDispositionChange (int delta) = 0;
virtual int countSavedGameRecords() const = 0;
virtual void write (ESM::ESMWriter& writer) const = 0;
virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0;
}; };
} }

@ -11,13 +11,14 @@
#include "mechanicsmanager.hpp" #include "mechanicsmanager.hpp"
#include "inputmanager.hpp" #include "inputmanager.hpp"
#include "windowmanager.hpp" #include "windowmanager.hpp"
#include "statemanager.hpp"
MWBase::Environment *MWBase::Environment::sThis = 0; MWBase::Environment *MWBase::Environment::sThis = 0;
bool MWBase::Environment::sExit = false;
MWBase::Environment::Environment() MWBase::Environment::Environment()
: mWorld (0), mSoundManager (0), mScriptManager (0), mWindowManager (0), : mWorld (0), mSoundManager (0), mScriptManager (0), mWindowManager (0),
mMechanicsManager (0), mDialogueManager (0), mJournal (0), mInputManager (0), mFrameDuration (0) mMechanicsManager (0), mDialogueManager (0), mJournal (0), mInputManager (0), mFrameDuration (0),
mStateManager (0)
{ {
assert (!sThis); assert (!sThis);
sThis = this; sThis = this;
@ -69,6 +70,11 @@ void MWBase::Environment::setInputManager (InputManager *inputManager)
mInputManager = inputManager; mInputManager = inputManager;
} }
void MWBase::Environment::setStateManager (StateManager *stateManager)
{
mStateManager = stateManager;
}
void MWBase::Environment::setFrameDuration (float duration) void MWBase::Environment::setFrameDuration (float duration)
{ {
mFrameDuration = duration; mFrameDuration = duration;
@ -122,6 +128,12 @@ MWBase::InputManager *MWBase::Environment::getInputManager() const
return mInputManager; return mInputManager;
} }
MWBase::StateManager *MWBase::Environment::getStateManager() const
{
assert (mStateManager);
return mStateManager;
}
float MWBase::Environment::getFrameDuration() const float MWBase::Environment::getFrameDuration() const
{ {
return mFrameDuration; return mFrameDuration;
@ -141,17 +153,20 @@ void MWBase::Environment::cleanup()
delete mScriptManager; delete mScriptManager;
mScriptManager = 0; mScriptManager = 0;
delete mWindowManager;
mWindowManager = 0;
delete mWorld; delete mWorld;
mWorld = 0; mWorld = 0;
delete mSoundManager; delete mSoundManager;
mSoundManager = 0; mSoundManager = 0;
delete mWindowManager;
mWindowManager = 0;
delete mInputManager; delete mInputManager;
mInputManager = 0; mInputManager = 0;
delete mStateManager;
mStateManager = 0;
} }
const MWBase::Environment& MWBase::Environment::get() const MWBase::Environment& MWBase::Environment::get()

@ -11,6 +11,7 @@ namespace MWBase
class MechanicsManager; class MechanicsManager;
class InputManager; class InputManager;
class WindowManager; class WindowManager;
class StateManager;
/// \brief Central hub for mw-subsystems /// \brief Central hub for mw-subsystems
/// ///
@ -30,10 +31,9 @@ namespace MWBase
DialogueManager *mDialogueManager; DialogueManager *mDialogueManager;
Journal *mJournal; Journal *mJournal;
InputManager *mInputManager; InputManager *mInputManager;
StateManager *mStateManager;
float mFrameDuration; float mFrameDuration;
static bool sExit;
Environment (const Environment&); Environment (const Environment&);
///< not implemented ///< not implemented
@ -46,9 +46,6 @@ namespace MWBase
~Environment(); ~Environment();
static void setRequestExit () { sExit = true; }
static bool getRequestExit () { return sExit; }
void setWorld (World *world); void setWorld (World *world);
void setSoundManager (SoundManager *soundManager); void setSoundManager (SoundManager *soundManager);
@ -65,6 +62,8 @@ namespace MWBase
void setInputManager (InputManager *inputManager); void setInputManager (InputManager *inputManager);
void setStateManager (StateManager *stateManager);
void setFrameDuration (float duration); void setFrameDuration (float duration);
///< Set length of current frame in seconds. ///< Set length of current frame in seconds.
@ -84,6 +83,8 @@ namespace MWBase
InputManager *getInputManager() const; InputManager *getInputManager() const;
StateManager *getStateManager() const;
float getFrameDuration() const; float getFrameDuration() const;
void cleanup(); void cleanup();

@ -5,10 +5,18 @@
#include <deque> #include <deque>
#include <map> #include <map>
#include <libs/platform/stdint.h>
#include "../mwdialogue/journalentry.hpp" #include "../mwdialogue/journalentry.hpp"
#include "../mwdialogue/topic.hpp" #include "../mwdialogue/topic.hpp"
#include "../mwdialogue/quest.hpp" #include "../mwdialogue/quest.hpp"
namespace ESM
{
class ESMReader;
class ESMWriter;
}
namespace MWBase namespace MWBase
{ {
/// \brief Interface for the player's journal (implemented in MWDialogue) /// \brief Interface for the player's journal (implemented in MWDialogue)
@ -46,7 +54,7 @@ namespace MWBase
virtual int getJournalIndex (const std::string& id) const = 0; virtual int getJournalIndex (const std::string& id) const = 0;
///< Get the journal index. ///< Get the journal index.
virtual void addTopic (const std::string& topicId, const std::string& infoId) = 0; virtual void addTopic (const std::string& topicId, const std::string& infoId, const std::string& actorName) = 0;
virtual TEntryIter begin() const = 0; virtual TEntryIter begin() const = 0;
///< Iterator pointing to the begin of the main journal. ///< Iterator pointing to the begin of the main journal.
@ -69,6 +77,12 @@ namespace MWBase
virtual TTopicIter topicEnd() const = 0; virtual TTopicIter topicEnd() const = 0;
///< Iterator pointing past the last topic. ///< Iterator pointing past the last topic.
virtual int countSavedGameRecords() const = 0;
virtual void write (ESM::ESMWriter& writer) const = 0;
virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0;
}; };
} }

@ -3,6 +3,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <list>
namespace Ogre namespace Ogre
{ {
@ -76,8 +77,12 @@ namespace MWBase
virtual void setPlayerClass (const ESM::Class& class_) = 0; virtual void setPlayerClass (const ESM::Class& class_) = 0;
///< Set player class to custom class. ///< Set player class to custom class.
virtual void restoreDynamicStats() = 0; virtual void rest(bool sleep) = 0;
///< If the player is sleeping, this should be called every hour. ///< If the player is sleeping or waiting, this should be called every hour.
/// @param sleep is the player sleeping or waiting?
virtual int getHoursToRest() const = 0;
///< Calculate how many hours the player needs to rest in order to be fully healed
virtual int getBarterOffer(const MWWorld::Ptr& ptr,int basePrice, bool buying) = 0; virtual int getBarterOffer(const MWWorld::Ptr& ptr,int basePrice, bool buying) = 0;
///< This is used by every service to determine the price of objects given the trading skills of the player and NPC. ///< This is used by every service to determine the price of objects given the trading skills of the player and NPC.
@ -88,6 +93,36 @@ namespace MWBase
virtual int countDeaths (const std::string& id) const = 0; virtual int countDeaths (const std::string& id) const = 0;
///< Return the number of deaths for actors with the given ID. ///< Return the number of deaths for actors with the given ID.
/// Check if \a observer is potentially aware of \a ptr. Does not do a line of sight check!
virtual bool awarenessCheck (const MWWorld::Ptr& ptr, const MWWorld::Ptr& observer) = 0;
enum OffenseType
{
OT_Theft, // Taking items owned by an NPC or a faction you are not a member of
OT_Assault, // Attacking a peaceful NPC
OT_Murder, // Murdering a peaceful NPC
OT_Trespassing, // Staying in a cell you are not allowed in (where is this defined?)
OT_SleepingInOwnedBed, // Sleeping in a bed owned by an NPC or a faction you are not a member of
OT_Pickpocket // Entering pickpocket mode, leaving it, and being detected. Any items stolen are a separate crime (Theft)
};
/**
* @brief Commit a crime. If any actors witness the crime and report it,
* reportCrime will be called automatically.
* @param arg Depends on \a type, e.g. for Theft, the value of the item that was stolen.
* @return was the crime reported?
*/
virtual bool commitCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim,
OffenseType type, int arg=0) = 0;
virtual void reportCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim,
OffenseType type, int arg=0) = 0;
/// Utility to check if taking this item is illegal and calling commitCrime if so
virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, int count) = 0;
/// Utility to check if opening (i.e. unlocking) this object is illegal and calling commitCrime if so
virtual void objectOpened (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item) = 0;
/// Attempt sleeping in a bed. If this is illegal, call commitCrime.
/// @return was it illegal, and someone saw you doing it?
virtual bool sleepInBed (const MWWorld::Ptr& ptr, const MWWorld::Ptr& bed) = 0;
enum PersuasionType enum PersuasionType
{ {
PT_Admire, PT_Admire,
@ -101,28 +136,35 @@ namespace MWBase
float currentTemporaryDispositionDelta, bool& success, float& tempChange, float& permChange) = 0; float currentTemporaryDispositionDelta, bool& success, float& tempChange, float& permChange) = 0;
///< Perform a persuasion action on NPC ///< Perform a persuasion action on NPC
virtual void forceStateUpdate(const MWWorld::Ptr &ptr) = 0; virtual void forceStateUpdate(const MWWorld::Ptr &ptr) = 0;
///< Forces an object to refresh its animation state. ///< Forces an object to refresh its animation state.
virtual void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number=1) = 0;
///< Run animation for a MW-reference. Calls to this function for references that are currently not
/// in the scene should be ignored.
///
/// \param mode 0 normal, 1 immediate start, 2 immediate loop
/// \param count How many times the animation should be run
virtual void skipAnimation(const MWWorld::Ptr& ptr) = 0;
///< Skip the animation for the given MW-reference for one frame. Calls to this function for
/// references that are currently not in the scene should be ignored.
virtual bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName) = 0;
virtual void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number=1) = 0; /// Update magic effects for an actor. Usually done automatically once per frame, but if we're currently
///< Run animation for a MW-reference. Calls to this function for references that are currently not /// paused we may want to do it manually (after equipping permanent enchantment)
/// in the scene should be ignored. virtual void updateMagicEffects (const MWWorld::Ptr& ptr) = 0;
///
/// \param mode 0 normal, 1 immediate start, 2 immediate loop
/// \param count How many times the animation should be run
virtual void skipAnimation(const MWWorld::Ptr& ptr) = 0; virtual void toggleAI() = 0;
///< Skip the animation for the given MW-reference for one frame. Calls to this function for virtual bool isAIActive() = 0;
/// references that are currently not in the scene should be ignored.
virtual bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName) = 0; virtual void getObjectsInRange (const Ogre::Vector3& position, float radius, std::vector<MWWorld::Ptr>& objects) = 0;
/// Update magic effects for an actor. Usually done automatically once per frame, but if we're currently ///return the list of actors which are following the given actor (ie AiFollow is active and the target is the actor)
/// paused we may want to do it manually (after equipping permanent enchantment) virtual std::list<MWWorld::Ptr> getActorsFollowing(const MWWorld::Ptr& actor) = 0;
virtual void updateMagicEffects (const MWWorld::Ptr& ptr) = 0;
virtual void toggleAI() = 0; virtual void playerLoaded() = 0;
virtual bool isAIActive() = 0;
}; };
} }

@ -35,8 +35,6 @@ namespace MWBase
virtual ~ScriptManager() {} virtual ~ScriptManager() {}
virtual void resetGlobalScripts() = 0;
virtual void run (const std::string& name, Interpreter::Context& interpreterContext) = 0; virtual void run (const std::string& name, Interpreter::Context& interpreterContext) = 0;
///< Run the script with the given name (compile first, if not compiled yet) ///< Run the script with the given name (compile first, if not compiled yet)

@ -147,6 +147,10 @@ namespace MWBase
virtual void update(float duration) = 0; virtual void update(float duration) = 0;
virtual void setListenerPosDir(const Ogre::Vector3 &pos, const Ogre::Vector3 &dir, const Ogre::Vector3 &up) = 0; virtual void setListenerPosDir(const Ogre::Vector3 &pos, const Ogre::Vector3 &dir, const Ogre::Vector3 &up) = 0;
virtual void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated) = 0;
virtual void clear() = 0;
}; };
} }

@ -0,0 +1,81 @@
#ifndef GAME_MWSTATE_STATEMANAGER_H
#define GAME_MWSTATE_STATEMANAGER_H
#include <vector>
#include <string>
namespace MWState
{
struct Slot;
class Character;
}
namespace MWBase
{
/// \brief Interface for game state manager (implemented in MWState)
class StateManager
{
public:
enum State
{
State_NoGame,
State_Ended,
State_Running
};
typedef std::vector<MWState::Character>::const_iterator CharacterIterator;
private:
StateManager (const StateManager&);
///< not implemented
StateManager& operator= (const StateManager&);
///< not implemented
public:
StateManager() {}
virtual ~StateManager() {}
virtual void requestQuit() = 0;
virtual bool hasQuitRequest() const = 0;
virtual void askLoadRecent() = 0;
virtual State getState() const = 0;
virtual void newGame (bool bypass = false) = 0;
///< Start a new game.
///
/// \param bypass Skip new game mechanics.
virtual void endGame() = 0;
virtual void saveGame (const std::string& description, const MWState::Slot *slot = 0) = 0;
///< Write a saved game to \a slot or create a new slot if \a slot == 0.
///
/// \note Slot must belong to the current character.
virtual void loadGame (const MWState::Character *character, const MWState::Slot *slot) = 0;
///< Load a saved game file from \a slot.
///
/// \note \a slot must belong to \a character.
virtual MWState::Character *getCurrentCharacter (bool create = true) = 0;
///< \param create Create a new character, if there is no current character.
virtual CharacterIterator characterBegin() = 0;
///< Any call to SaveGame and getCurrentCharacter can invalidate the returned
/// iterator.
virtual CharacterIterator characterEnd() = 0;
virtual void update (float duration) = 0;
};
}
#endif

@ -33,6 +33,8 @@ namespace OEngine
namespace ESM namespace ESM
{ {
struct Class; struct Class;
class ESMReader;
class ESMWriter;
} }
namespace MWWorld namespace MWWorld
@ -55,6 +57,12 @@ namespace MWGui
class InventoryWindow; class InventoryWindow;
class ContainerWindow; class ContainerWindow;
class DialogueWindow; class DialogueWindow;
enum ShowInDialogueMode {
ShowInDialogueMode_IfPossible,
ShowInDialogueMode_Only,
ShowInDialogueMode_Never
};
} }
namespace SFO namespace SFO
@ -137,8 +145,8 @@ namespace MWBase
virtual void wmUpdateFps(float fps, unsigned int triangleCount, unsigned int batchCount) = 0; virtual void wmUpdateFps(float fps, unsigned int triangleCount, unsigned int batchCount) = 0;
/// Set value for the given ID. /// Set value for the given ID.
virtual void setValue (const std::string& id, const MWMechanics::Stat<int>& value) = 0; virtual void setValue (const std::string& id, const MWMechanics::AttributeValue& value) = 0;
virtual void setValue (int parSkill, const MWMechanics::Stat<float>& value) = 0; virtual void setValue (int parSkill, const MWMechanics::SkillValue& value) = 0;
virtual void setValue (const std::string& id, const MWMechanics::DynamicStat<float>& value) = 0; virtual void setValue (const std::string& id, const MWMechanics::DynamicStat<float>& value) = 0;
virtual void setValue (const std::string& id, const std::string& value) = 0; virtual void setValue (const std::string& id, const std::string& value) = 0;
virtual void setValue (const std::string& id, int value) = 0; virtual void setValue (const std::string& id, int value) = 0;
@ -204,6 +212,7 @@ namespace MWBase
virtual void activateQuickKey (int index) = 0; virtual void activateQuickKey (int index) = 0;
virtual std::string getSelectedSpell() = 0;
virtual void setSelectedSpell(const std::string& spellId, int successChancePercent) = 0; virtual void setSelectedSpell(const std::string& spellId, int successChancePercent) = 0;
virtual void setSelectedEnchantItem(const MWWorld::Ptr& item) = 0; virtual void setSelectedEnchantItem(const MWWorld::Ptr& item) = 0;
virtual void setSelectedWeapon(const MWWorld::Ptr& item) = 0; virtual void setSelectedWeapon(const MWWorld::Ptr& item) = 0;
@ -223,20 +232,17 @@ namespace MWBase
virtual void removeDialog(OEngine::GUI::Layout* dialog) = 0; virtual void removeDialog(OEngine::GUI::Layout* dialog) = 0;
///< Hides dialog and schedules dialog to be deleted. ///< Hides dialog and schedules dialog to be deleted.
virtual void messageBox (const std::string& message, const std::vector<std::string>& buttons = std::vector<std::string>(), bool showInDialogueModeOnly = false) = 0; virtual void messageBox (const std::string& message, const std::vector<std::string>& buttons = std::vector<std::string>(), enum MWGui::ShowInDialogueMode showInDialogueMode = MWGui::ShowInDialogueMode_IfPossible) = 0;
virtual void staticMessageBox(const std::string& message) = 0; virtual void staticMessageBox(const std::string& message) = 0;
virtual void removeStaticMessageBox() = 0; virtual void removeStaticMessageBox() = 0;
virtual void enterPressed () = 0;
virtual void activateKeyPressed () = 0;
virtual int readPressedButton() = 0; virtual int readPressedButton() = 0;
///< returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox) ///< returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox)
virtual void onFrame (float frameDuration) = 0; virtual void onFrame (float frameDuration) = 0;
/// \todo get rid of this stuff. Move it to the respective UI element classes, if needed. /// \todo get rid of this stuff. Move it to the respective UI element classes, if needed.
virtual std::map<int, MWMechanics::Stat<float> > getPlayerSkillValues() = 0; virtual std::map<int, MWMechanics::SkillValue > getPlayerSkillValues() = 0;
virtual std::map<int, MWMechanics::Stat<int> > getPlayerAttributeValues() = 0; virtual std::map<int, MWMechanics::AttributeValue > getPlayerAttributeValues() = 0;
virtual SkillList getPlayerMinorSkills() = 0; virtual SkillList getPlayerMinorSkills() = 0;
virtual SkillList getPlayerMajorSkills() = 0; virtual SkillList getPlayerMajorSkills() = 0;
@ -281,12 +287,19 @@ namespace MWBase
virtual const Translation::Storage& getTranslationDataStorage() const = 0; virtual const Translation::Storage& getTranslationDataStorage() const = 0;
/// Warning: do not use MyGUI::InputManager::setKeyFocusWidget directly. Instead use this.
virtual void setKeyFocusWidget (MyGUI::Widget* widget) = 0; virtual void setKeyFocusWidget (MyGUI::Widget* widget) = 0;
virtual Loading::Listener* getLoadingScreen() = 0; virtual Loading::Listener* getLoadingScreen() = 0;
/// Should the cursor be visible? /// Should the cursor be visible?
virtual bool getCursorVisible() = 0; virtual bool getCursorVisible() = 0;
/// Clear all savegame-specific data
virtual void clear() = 0;
virtual void write (ESM::ESMWriter& writer) = 0;
virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0;
}; };
} }

@ -2,6 +2,7 @@
#define GAME_MWBASE_WORLD_H #define GAME_MWBASE_WORLD_H
#include <vector> #include <vector>
#include <map>
#include <components/settings/settings.hpp> #include <components/settings/settings.hpp>
@ -30,17 +31,18 @@ namespace OEngine
namespace ESM namespace ESM
{ {
class ESMReader; class ESMReader;
class ESMWriter;
struct Position; struct Position;
struct Cell; struct Cell;
struct Class; struct Class;
struct Potion; struct Potion;
struct Spell; struct Spell;
struct NPC; struct NPC;
struct CellId;
} }
namespace MWRender namespace MWRender
{ {
class ExternalRendering;
class Animation; class Animation;
} }
@ -80,7 +82,6 @@ namespace MWBase
Render_CollisionDebug, Render_CollisionDebug,
Render_Wireframe, Render_Wireframe,
Render_Pathgrid, Render_Pathgrid,
Render_Compositors,
Render_BoundingBoxes Render_BoundingBoxes
}; };
@ -96,13 +97,26 @@ namespace MWBase
virtual void startNewGame() = 0; virtual void startNewGame() = 0;
virtual void clear() = 0;
virtual int countSavedGameRecords() const = 0;
virtual void write (ESM::ESMWriter& writer) const = 0;
virtual void readRecord (ESM::ESMReader& reader, int32_t type,
const std::map<int, int>& contentFileMap) = 0;
virtual OEngine::Render::Fader* getFader() = 0; virtual OEngine::Render::Fader* getFader() = 0;
///< \ŧodo remove this function. Rendering details should not be exposed. ///< \todo remove this function. Rendering details should not be exposed.
virtual MWWorld::CellStore *getExterior (int x, int y) = 0; virtual MWWorld::CellStore *getExterior (int x, int y) = 0;
virtual MWWorld::CellStore *getInterior (const std::string& name) = 0; virtual MWWorld::CellStore *getInterior (const std::string& name) = 0;
virtual MWWorld::CellStore *getCell (const ESM::CellId& id) = 0;
virtual void useDeathCamera() = 0;
virtual void setWaterHeight(const float height) = 0; virtual void setWaterHeight(const float height) = 0;
virtual void toggleWater() = 0; virtual void toggleWater() = 0;
@ -114,6 +128,7 @@ namespace MWBase
virtual const MWWorld::Fallback *getFallback () const = 0; virtual const MWWorld::Fallback *getFallback () const = 0;
virtual MWWorld::Player& getPlayer() = 0; virtual MWWorld::Player& getPlayer() = 0;
virtual MWWorld::Ptr getPlayerPtr() = 0;
virtual const MWWorld::ESMStore& getStore() const = 0; virtual const MWWorld::ESMStore& getStore() const = 0;
@ -131,7 +146,7 @@ namespace MWBase
virtual Ogre::Vector2 getNorthVector (MWWorld::CellStore* cell) = 0; virtual Ogre::Vector2 getNorthVector (MWWorld::CellStore* cell) = 0;
///< get north vector (OGRE coordinates) for given interior cell ///< get north vector (OGRE coordinates) for given interior cell
virtual std::vector<DoorMarker> getDoorMarkers (MWWorld::CellStore* cell) = 0; virtual void getDoorMarkers (MWWorld::CellStore* cell, std::vector<DoorMarker>& out) = 0;
///< get a list of teleport door markers for a given cell, to be displayed on the local map ///< get a list of teleport door markers for a given cell, to be displayed on the local map
virtual void getInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y) = 0; virtual void getInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y) = 0;
@ -140,16 +155,26 @@ namespace MWBase
virtual bool isPositionExplored (float nX, float nY, int x, int y, bool interior) = 0; virtual bool isPositionExplored (float nX, float nY, int x, int y, bool interior) = 0;
///< see MWRender::LocalMap::isPositionExplored ///< see MWRender::LocalMap::isPositionExplored
virtual MWWorld::Globals::Data& getGlobalVariable (const std::string& name) = 0; virtual void setGlobalInt (const std::string& name, int value) = 0;
///< Set value independently from real type.
virtual void setGlobalFloat (const std::string& name, float value) = 0;
///< Set value independently from real type.
virtual int getGlobalInt (const std::string& name) const = 0;
///< Get value independently from real type.
virtual MWWorld::Globals::Data getGlobalVariable (const std::string& name) const = 0; virtual float getGlobalFloat (const std::string& name) const = 0;
///< Get value independently from real type.
virtual char getGlobalVariableType (const std::string& name) const = 0; virtual char getGlobalVariableType (const std::string& name) const = 0;
///< Return ' ', if there is no global variable with this name. ///< Return ' ', if there is no global variable with this name.
virtual std::vector<std::string> getGlobals () const = 0; virtual std::string getCellName (const MWWorld::CellStore *cell = 0) const = 0;
///< Return name of the cell.
virtual std::string getCurrentCellName() const = 0; ///
/// \note If cell==0, the cell the player is currently in will be used instead to
/// generate a name.
virtual void removeRefScript (MWWorld::RefData *ref) = 0; virtual void removeRefScript (MWWorld::RefData *ref) = 0;
//< Remove the script attached to ref from mLocalScripts //< Remove the script attached to ref from mLocalScripts
@ -158,6 +183,10 @@ namespace MWBase
///< Return a pointer to a liveCellRef with the given name. ///< Return a pointer to a liveCellRef with the given name.
/// \param activeOnly do non search inactive cells. /// \param activeOnly do non search inactive cells.
virtual MWWorld::Ptr searchPtr (const std::string& name, bool activeOnly) = 0;
///< Return a pointer to a liveCellRef with the given name.
/// \param activeOnly do non search inactive cells.
virtual MWWorld::Ptr getPtrViaHandle (const std::string& handle) = 0; virtual MWWorld::Ptr getPtrViaHandle (const std::string& handle) = 0;
///< Return a pointer to a liveCellRef with the given Ogre handle. ///< Return a pointer to a liveCellRef with the given Ogre handle.
@ -182,8 +211,12 @@ namespace MWBase
virtual void setDay (int day) = 0; virtual void setDay (int day) = 0;
///< Set in-game time day. ///< Set in-game time day.
virtual int getDay() = 0; virtual int getDay() const = 0;
virtual int getMonth() = 0; virtual int getMonth() const = 0;
virtual int getYear() const = 0;
virtual std::string getMonthName (int month = -1) const = 0;
///< Return name of month (-1: current month)
virtual MWWorld::TimeStamp getTimeStamp() const = 0; virtual MWWorld::TimeStamp getTimeStamp() const = 0;
///< Return current in-game time stamp. ///< Return current in-game time stamp.
@ -212,6 +245,8 @@ namespace MWBase
virtual void changeToExteriorCell (const ESM::Position& position) = 0; virtual void changeToExteriorCell (const ESM::Position& position) = 0;
///< Move to exterior cell. ///< Move to exterior cell.
virtual void changeToCell (const ESM::CellId& cellId, const ESM::Position& position) = 0;
virtual const ESM::Cell *getExterior (const std::string& cellName) const = 0; virtual const ESM::Cell *getExterior (const std::string& cellName) const = 0;
///< Return a cell matching the given name or a 0-pointer, if there is no such cell. ///< Return a cell matching the given name or a 0-pointer, if there is no such cell.
@ -222,7 +257,7 @@ namespace MWBase
/// Returns a pointer to the object the provided object would hit (if within the /// Returns a pointer to the object the provided object would hit (if within the
/// specified distance), and the point where the hit occurs. This will attempt to /// specified distance), and the point where the hit occurs. This will attempt to
/// use the "Head" node as a basis. /// use the "Head" node, or alternatively the "Bip01 Head" node as a basis.
virtual std::pair<MWWorld::Ptr,Ogre::Vector3> getHitContact(const MWWorld::Ptr &ptr, float distance) = 0; virtual std::pair<MWWorld::Ptr,Ogre::Vector3> getHitContact(const MWWorld::Ptr &ptr, float distance) = 0;
virtual void adjustPosition (const MWWorld::Ptr& ptr) = 0; virtual void adjustPosition (const MWWorld::Ptr& ptr) = 0;
@ -333,7 +368,7 @@ namespace MWBase
virtual bool isSwimming(const MWWorld::Ptr &object) const = 0; virtual bool isSwimming(const MWWorld::Ptr &object) const = 0;
///Is the head of the creature underwater? ///Is the head of the creature underwater?
virtual bool isSubmerged(const MWWorld::Ptr &object) const = 0; virtual bool isSubmerged(const MWWorld::Ptr &object) const = 0;
virtual bool isUnderwater(const MWWorld::Ptr::CellStore* cell, const Ogre::Vector3 &pos) const = 0; virtual bool isUnderwater(const MWWorld::CellStore* cell, const Ogre::Vector3 &pos) const = 0;
virtual bool isOnGround(const MWWorld::Ptr &ptr) const = 0; virtual bool isOnGround(const MWWorld::Ptr &ptr) const = 0;
virtual void togglePOV() = 0; virtual void togglePOV() = 0;
@ -367,8 +402,6 @@ namespace MWBase
virtual void enableActorCollision(const MWWorld::Ptr& actor, bool enable) = 0; virtual void enableActorCollision(const MWWorld::Ptr& actor, bool enable) = 0;
virtual void setupExternalRendering (MWRender::ExternalRendering& rendering) = 0;
virtual int canRest() = 0; virtual int canRest() = 0;
///< check if the player is allowed to rest \n ///< check if the player is allowed to rest \n
/// 0 - yes \n /// 0 - yes \n
@ -383,6 +416,7 @@ namespace MWBase
virtual void playVideo(const std::string& name, bool allowSkipping) = 0; virtual void playVideo(const std::string& name, bool allowSkipping) = 0;
virtual void stopVideo() = 0; virtual void stopVideo() = 0;
virtual void frameStarted (float dt, bool paused) = 0; virtual void frameStarted (float dt, bool paused) = 0;
virtual void screenshot (Ogre::Image& image, int w, int h) = 0;
/// Find default position inside exterior cell specified by name /// Find default position inside exterior cell specified by name
/// \return false if exterior with given name not exists, true otherwise /// \return false if exterior with given name not exists, true otherwise
@ -415,10 +449,61 @@ namespace MWBase
virtual bool toggleGodMode() = 0; virtual bool toggleGodMode() = 0;
/**
* @brief startSpellCast attempt to start casting a spell. Might fail immediately if conditions are not met.
* @param actor
* @return true if the spell can be casted (i.e. the animation should start)
*/
virtual bool startSpellCast (const MWWorld::Ptr& actor) = 0;
virtual void castSpell (const MWWorld::Ptr& actor) = 0; virtual void castSpell (const MWWorld::Ptr& actor) = 0;
virtual void launchProjectile (const std::string& id, bool stack, const ESM::EffectList& effects, virtual void launchProjectile (const std::string& id, bool stack, const ESM::EffectList& effects,
const MWWorld::Ptr& actor, const std::string& sourceName) = 0; const MWWorld::Ptr& actor, const std::string& sourceName) = 0;
virtual const std::vector<std::string>& getContentFiles() const = 0;
virtual void breakInvisibility (const MWWorld::Ptr& actor) = 0;
// Are we in an exterior or pseudo-exterior cell and it's night?
virtual bool isDark() const = 0;
virtual bool findInteriorPositionInWorldSpace(MWWorld::CellStore* cell, Ogre::Vector3& result) = 0;
/// Teleports \a ptr to the closest reference of \a id (e.g. DivineMarker, PrisonMarker, TempleMarker)
/// @note id must be lower case
virtual void teleportToClosestMarker (const MWWorld::Ptr& ptr,
const std::string& id) = 0;
enum DetectionType
{
Detect_Enchantment,
Detect_Key,
Detect_Creature
};
/// List all references (filtered by \a type) detected by \a ptr. The range
/// is determined by the current magnitude of the "Detect X" magic effect belonging to \a type.
/// @note This also works for references in containers.
virtual void listDetectedReferences (const MWWorld::Ptr& ptr, std::vector<MWWorld::Ptr>& out,
DetectionType type) = 0;
/// Update the value of some globals according to the world state, which may be used by dialogue entries.
/// This should be called when initiating a dialogue.
virtual void updateDialogueGlobals() = 0;
/// Moves all stolen items from \a ptr to the closest evidence chest.
virtual void confiscateStolenItems(const MWWorld::Ptr& ptr) = 0;
virtual void goToJail () = 0;
/// Spawn a random creature from a levelled list next to the player
virtual void spawnRandomCreature(const std::string& creatureList) = 0;
/// Spawn a blood effect for \a ptr at \a worldPosition
virtual void spawnBloodEffect (const MWWorld::Ptr& ptr, const Ogre::Vector3& worldPosition) = 0;
virtual void explodeSpell (const Ogre::Vector3& origin, const MWWorld::Ptr& object, const ESM::EffectList& effects,
const MWWorld::Ptr& caster, const std::string& id, const std::string& sourceName) = 0;
}; };
} }

@ -96,7 +96,11 @@ namespace MWClass
std::string text; std::string text;
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) if (MWBase::Environment::get().getWindowManager()->getFullHelp())
{
text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner");
text += MWGui::ToolTips::getMiscString(ref->mRef.mFaction, "Faction");
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
}
info.text = text; info.text = text;
return info; return info;

@ -124,10 +124,11 @@ namespace MWClass
std::string text; std::string text;
text += "\n#{sQuality}: " + MWGui::ToolTips::toString(ref->mBase->mData.mQuality); text += "\n#{sQuality}: " + MWGui::ToolTips::toString(ref->mBase->mData.mQuality);
text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight);
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); text += MWGui::ToolTips::getValueString(getValue(ptr), "#{sValue}");
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner");
text += MWGui::ToolTips::getMiscString(ref->mRef.mFaction, "Faction");
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
} }
info.text = text; info.text = text;

@ -17,7 +17,6 @@
#include "../mwworld/physicssystem.hpp" #include "../mwworld/physicssystem.hpp"
#include "../mwworld/nullaction.hpp" #include "../mwworld/nullaction.hpp"
#include "../mwworld/containerstore.hpp" #include "../mwworld/containerstore.hpp"
#include "../mwworld/player.hpp"
#include "../mwrender/objects.hpp" #include "../mwrender/objects.hpp"
#include "../mwrender/renderinginterface.hpp" #include "../mwrender/renderinginterface.hpp"
@ -172,7 +171,7 @@ namespace MWClass
if (ptr.getCellRef().mCharge == -1) if (ptr.getCellRef().mCharge == -1)
return ref->mBase->mData.mValue; return ref->mBase->mData.mValue;
else else
return ref->mBase->mData.mValue * (ptr.getCellRef().mCharge / getItemMaxHealth(ptr)); return ref->mBase->mData.mValue * (static_cast<float>(ptr.getCellRef().mCharge) / getItemMaxHealth(ptr));
} }
void Armor::registerSelf() void Armor::registerSelf()
@ -248,10 +247,11 @@ namespace MWClass
+ MWGui::ToolTips::toString(ref->mBase->mData.mHealth); + MWGui::ToolTips::toString(ref->mBase->mData.mHealth);
text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight) + " (" + typeText + ")"; text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight) + " (" + typeText + ")";
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); text += MWGui::ToolTips::getValueString(getValue(ptr), "#{sValue}");
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner");
text += MWGui::ToolTips::getMiscString(ref->mRef.mFaction, "Faction");
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
} }
@ -289,16 +289,20 @@ namespace MWClass
std::pair<int, std::string> Armor::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const std::pair<int, std::string> Armor::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const
{ {
MWWorld::InventoryStore& invStore = MWWorld::Class::get(npc).getInventoryStore(npc); MWWorld::InventoryStore& invStore = npc.getClass().getInventoryStore(npc);
if (ptr.getCellRef().mCharge == 0)
return std::make_pair(0, "#{sInventoryMessage1}");
// slots that this item can be equipped in // slots that this item can be equipped in
std::pair<std::vector<int>, bool> slots_ = MWWorld::Class::get(ptr).getEquipmentSlots(ptr); std::pair<std::vector<int>, bool> slots_ = MWWorld::Class::get(ptr).getEquipmentSlots(ptr);
std::string npcRace = npc.get<ESM::NPC>()->mBase->mRace; if (slots_.first.empty())
return std::make_pair(0, "");
for (std::vector<int>::const_iterator slot=slots_.first.begin(); if (npc.getClass().isNpc())
slot!=slots_.first.end(); ++slot)
{ {
std::string npcRace = npc.get<ESM::NPC>()->mBase->mRace;
// Beast races cannot equip shoes / boots, or full helms (head part vs hair part) // Beast races cannot equip shoes / boots, or full helms (head part vs hair part)
const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(npcRace); const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(npcRace);
@ -306,29 +310,20 @@ namespace MWClass
{ {
std::vector<ESM::PartReference> parts = ptr.get<ESM::Armor>()->mBase->mParts.mParts; std::vector<ESM::PartReference> parts = ptr.get<ESM::Armor>()->mBase->mParts.mParts;
if(*slot == MWWorld::InventoryStore::Slot_Helmet) for(std::vector<ESM::PartReference>::iterator itr = parts.begin(); itr != parts.end(); ++itr)
{
for(std::vector<ESM::PartReference>::iterator itr = parts.begin(); itr != parts.end(); ++itr)
{
if((*itr).mPart == ESM::PRT_Head)
{
return std::make_pair(0, "#{sNotifyMessage13}");
}
}
}
if (*slot == MWWorld::InventoryStore::Slot_Boots)
{ {
for(std::vector<ESM::PartReference>::iterator itr = parts.begin(); itr != parts.end(); ++itr) if((*itr).mPart == ESM::PRT_Head)
{ return std::make_pair(0, "#{sNotifyMessage13}");
if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot) if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot)
{ return std::make_pair(0, "#{sNotifyMessage14}");
return std::make_pair(0, "#{sNotifyMessage14}");
}
}
} }
} }
}
for (std::vector<int>::const_iterator slot=slots_.first.begin();
slot!=slots_.first.end(); ++slot)
{
// If equipping a shield, check if there's a twohanded weapon conflicting with it
if(*slot == MWWorld::InventoryStore::Slot_CarriedLeft) if(*slot == MWWorld::InventoryStore::Slot_CarriedLeft)
{ {
MWWorld::ContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); MWWorld::ContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
@ -371,12 +366,12 @@ namespace MWClass
return MWWorld::Ptr(&cell.mArmors.insert(*ref), &cell); return MWWorld::Ptr(&cell.mArmors.insert(*ref), &cell);
} }
float Armor::getEnchantmentPoints (const MWWorld::Ptr& ptr) const int Armor::getEnchantmentPoints (const MWWorld::Ptr& ptr) const
{ {
MWWorld::LiveCellRef<ESM::Armor> *ref = MWWorld::LiveCellRef<ESM::Armor> *ref =
ptr.get<ESM::Armor>(); ptr.get<ESM::Armor>();
return ref->mBase->mData.mEnchant/10.f; return ref->mBase->mData.mEnchant;
} }
bool Armor::canSell (const MWWorld::Ptr& item, int npcServices) const bool Armor::canSell (const MWWorld::Ptr& item, int npcServices) const

@ -79,7 +79,7 @@ namespace MWClass
virtual std::string getModel(const MWWorld::Ptr &ptr) const; virtual std::string getModel(const MWWorld::Ptr &ptr) const;
virtual float getEnchantmentPoints (const MWWorld::Ptr& ptr) const; virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const;
virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const;
}; };

@ -136,10 +136,11 @@ namespace MWClass
std::string text; std::string text;
text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight);
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); text += MWGui::ToolTips::getValueString(getValue(ptr), "#{sValue}");
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner");
text += MWGui::ToolTips::getMiscString(ref->mRef.mFaction, "Faction");
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
} }
@ -188,12 +189,12 @@ namespace MWClass
return MWWorld::Ptr(&cell.mBooks.insert(*ref), &cell); return MWWorld::Ptr(&cell.mBooks.insert(*ref), &cell);
} }
float Book::getEnchantmentPoints (const MWWorld::Ptr& ptr) const int Book::getEnchantmentPoints (const MWWorld::Ptr& ptr) const
{ {
MWWorld::LiveCellRef<ESM::Book> *ref = MWWorld::LiveCellRef<ESM::Book> *ref =
ptr.get<ESM::Book>(); ptr.get<ESM::Book>();
return ref->mBase->mData.mEnchant/10.f; return ref->mBase->mData.mEnchant;
} }
bool Book::canSell (const MWWorld::Ptr& item, int npcServices) const bool Book::canSell (const MWWorld::Ptr& item, int npcServices) const

@ -58,7 +58,7 @@ namespace MWClass
virtual std::string getModel(const MWWorld::Ptr &ptr) const; virtual std::string getModel(const MWWorld::Ptr &ptr) const;
virtual float getEnchantmentPoints (const MWWorld::Ptr& ptr) const; virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const;
virtual float getWeight (const MWWorld::Ptr& ptr) const; virtual float getWeight (const MWWorld::Ptr& ptr) const;

@ -14,7 +14,6 @@
#include "../mwworld/cellstore.hpp" #include "../mwworld/cellstore.hpp"
#include "../mwworld/physicssystem.hpp" #include "../mwworld/physicssystem.hpp"
#include "../mwworld/nullaction.hpp" #include "../mwworld/nullaction.hpp"
#include "../mwworld/player.hpp"
#include "../mwgui/tooltips.hpp" #include "../mwgui/tooltips.hpp"
@ -191,10 +190,11 @@ namespace MWClass
std::string text; std::string text;
text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight);
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); text += MWGui::ToolTips::getValueString(getValue(ptr), "#{sValue}");
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner");
text += MWGui::ToolTips::getMiscString(ref->mRef.mFaction, "Faction");
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
} }
@ -235,11 +235,12 @@ namespace MWClass
// slots that this item can be equipped in // slots that this item can be equipped in
std::pair<std::vector<int>, bool> slots_ = MWWorld::Class::get(ptr).getEquipmentSlots(ptr); std::pair<std::vector<int>, bool> slots_ = MWWorld::Class::get(ptr).getEquipmentSlots(ptr);
std::string npcRace = npc.get<ESM::NPC>()->mBase->mRace; if (slots_.first.empty())
return std::make_pair(0, "");
for (std::vector<int>::const_iterator slot=slots_.first.begin(); if (npc.getClass().isNpc())
slot!=slots_.first.end(); ++slot)
{ {
std::string npcRace = npc.get<ESM::NPC>()->mBase->mRace;
// Beast races cannot equip shoes / boots, or full helms (head part vs hair part) // Beast races cannot equip shoes / boots, or full helms (head part vs hair part)
const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(npcRace); const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(npcRace);
@ -247,25 +248,16 @@ namespace MWClass
{ {
std::vector<ESM::PartReference> parts = ptr.get<ESM::Clothing>()->mBase->mParts.mParts; std::vector<ESM::PartReference> parts = ptr.get<ESM::Clothing>()->mBase->mParts.mParts;
if(*slot == MWWorld::InventoryStore::Slot_Helmet) for(std::vector<ESM::PartReference>::iterator itr = parts.begin(); itr != parts.end(); ++itr)
{ {
for(std::vector<ESM::PartReference>::iterator itr = parts.begin(); itr != parts.end(); ++itr) if((*itr).mPart == ESM::PRT_Head)
{ return std::make_pair(0, "#{sNotifyMessage13}");
if((*itr).mPart == ESM::PRT_Head) if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot)
return std::make_pair(0, "#{sNotifyMessage13}"); return std::make_pair(0, "#{sNotifyMessage15}");
}
}
if (*slot == MWWorld::InventoryStore::Slot_Boots)
{
for(std::vector<ESM::PartReference>::iterator itr = parts.begin(); itr != parts.end(); ++itr)
{
if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot)
return std::make_pair(0, "#{sNotifyMessage15}");
}
} }
} }
} }
return std::make_pair (1, ""); return std::make_pair (1, "");
} }
@ -287,12 +279,12 @@ namespace MWClass
return MWWorld::Ptr(&cell.mClothes.insert(*ref), &cell); return MWWorld::Ptr(&cell.mClothes.insert(*ref), &cell);
} }
float Clothing::getEnchantmentPoints (const MWWorld::Ptr& ptr) const int Clothing::getEnchantmentPoints (const MWWorld::Ptr& ptr) const
{ {
MWWorld::LiveCellRef<ESM::Clothing> *ref = MWWorld::LiveCellRef<ESM::Clothing> *ref =
ptr.get<ESM::Clothing>(); ptr.get<ESM::Clothing>();
return ref->mBase->mData.mEnchant/10.f; return ref->mBase->mData.mEnchant;
} }
bool Clothing::canSell (const MWWorld::Ptr& item, int npcServices) const bool Clothing::canSell (const MWWorld::Ptr& item, int npcServices) const

@ -71,7 +71,7 @@ namespace MWClass
virtual std::string getModel(const MWWorld::Ptr &ptr) const; virtual std::string getModel(const MWWorld::Ptr &ptr) const;
virtual float getEnchantmentPoints (const MWWorld::Ptr& ptr) const; virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const;
virtual float getWeight (const MWWorld::Ptr& ptr) const; virtual float getWeight (const MWWorld::Ptr& ptr) const;

@ -2,6 +2,7 @@
#include "container.hpp" #include "container.hpp"
#include <components/esm/loadcont.hpp> #include <components/esm/loadcont.hpp>
#include <components/esm/containerstate.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
@ -16,7 +17,6 @@
#include "../mwworld/actionopen.hpp" #include "../mwworld/actionopen.hpp"
#include "../mwworld/actiontrap.hpp" #include "../mwworld/actiontrap.hpp"
#include "../mwworld/physicssystem.hpp" #include "../mwworld/physicssystem.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/inventorystore.hpp" #include "../mwworld/inventorystore.hpp"
#include "../mwgui/tooltips.hpp" #include "../mwgui/tooltips.hpp"
@ -53,7 +53,7 @@ namespace MWClass
ptr.get<ESM::Container>(); ptr.get<ESM::Container>();
data->mContainerStore.fill( data->mContainerStore.fill(
ref->mBase->mInventory, ptr.getCellRef().mOwner, MWBase::Environment::get().getWorld()->getStore()); ref->mBase->mInventory, ptr.getCellRef().mOwner, ptr.getCellRef().mFaction, MWBase::Environment::get().getWorld()->getStore());
// store // store
ptr.getRefData().setCustomData (data.release()); ptr.getRefData().setCustomData (data.release());
@ -108,7 +108,7 @@ namespace MWClass
const std::string lockedSound = "LockedChest"; const std::string lockedSound = "LockedChest";
const std::string trapActivationSound = "Disarm Trap Fail"; const std::string trapActivationSound = "Disarm Trap Fail";
MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayer().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr();
MWWorld::InventoryStore& invStore = MWWorld::Class::get(player).getInventoryStore(player); MWWorld::InventoryStore& invStore = MWWorld::Class::get(player).getInventoryStore(player);
bool needKey = ptr.getCellRef().mLockLevel>0; bool needKey = ptr.getCellRef().mLockLevel>0;
@ -216,6 +216,7 @@ namespace MWClass
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner");
text += MWGui::ToolTips::getMiscString(ref->mRef.mFaction, "Faction");
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
} }
@ -258,4 +259,26 @@ namespace MWClass
return MWWorld::Ptr(&cell.mContainers.insert(*ref), &cell); return MWWorld::Ptr(&cell.mContainers.insert(*ref), &cell);
} }
void Container::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
const
{
const ESM::ContainerState& state2 = dynamic_cast<const ESM::ContainerState&> (state);
ensureCustomData (ptr);
dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mContainerStore.
readState (state2.mInventory);
}
void Container::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
const
{
ESM::ContainerState& state2 = dynamic_cast<ESM::ContainerState&> (state);
ensureCustomData (ptr);
dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mContainerStore.
writeState (state2.mInventory);
}
} }

@ -54,6 +54,14 @@ namespace MWClass
virtual void unlock (const MWWorld::Ptr& ptr) const; virtual void unlock (const MWWorld::Ptr& ptr) const;
///< Unlock object ///< Unlock object
virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
const;
///< Read additional state from \a state into \a ptr.
virtual void writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
const;
///< Write additional state from \a ptr into \a state.
static void registerSelf(); static void registerSelf();
virtual std::string getModel(const MWWorld::Ptr &ptr) const; virtual std::string getModel(const MWWorld::Ptr &ptr) const;

@ -2,10 +2,12 @@
#include "creature.hpp" #include "creature.hpp"
#include <components/esm/loadcrea.hpp> #include <components/esm/loadcrea.hpp>
#include <components/esm/creaturestate.hpp>
#include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/creaturestats.hpp"
#include "../mwmechanics/magiceffects.hpp" #include "../mwmechanics/magiceffects.hpp"
#include "../mwmechanics/movement.hpp" #include "../mwmechanics/movement.hpp"
#include "../mwmechanics/spellcasting.hpp"
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/mechanicsmanager.hpp"
@ -26,22 +28,30 @@
#include "../mwgui/tooltips.hpp" #include "../mwgui/tooltips.hpp"
#include "../mwworld/inventorystore.hpp"
#include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/npcstats.hpp"
#include "../mwmechanics/combat.hpp"
namespace namespace
{ {
struct CustomData : public MWWorld::CustomData struct CustomData : public MWWorld::CustomData
{ {
MWMechanics::CreatureStats mCreatureStats; MWMechanics::CreatureStats mCreatureStats;
MWWorld::ContainerStore mContainerStore; MWWorld::ContainerStore* mContainerStore; // may be InventoryStore for some creatures
MWMechanics::Movement mMovement; MWMechanics::Movement mMovement;
virtual MWWorld::CustomData *clone() const; virtual MWWorld::CustomData *clone() const;
CustomData() : mContainerStore(0) {}
virtual ~CustomData() { delete mContainerStore; }
}; };
MWWorld::CustomData *CustomData::clone() const MWWorld::CustomData *CustomData::clone() const
{ {
return new CustomData (*this); CustomData* cloned = new CustomData (*this);
cloned->mContainerStore = mContainerStore->clone();
return cloned;
} }
} }
@ -61,6 +71,17 @@ namespace MWClass
fMinWalkSpeedCreature = gmst.find("fMinWalkSpeedCreature"); fMinWalkSpeedCreature = gmst.find("fMinWalkSpeedCreature");
fMaxWalkSpeedCreature = gmst.find("fMaxWalkSpeedCreature"); fMaxWalkSpeedCreature = gmst.find("fMaxWalkSpeedCreature");
fEncumberedMoveEffect = gmst.find("fEncumberedMoveEffect");
fSneakSpeedMultiplier = gmst.find("fSneakSpeedMultiplier");
fAthleticsRunBonus = gmst.find("fAthleticsRunBonus");
fBaseRunMultiplier = gmst.find("fBaseRunMultiplier");
fMinFlySpeed = gmst.find("fMinFlySpeed");
fMaxFlySpeed = gmst.find("fMaxFlySpeed");
fSwimRunBase = gmst.find("fSwimRunBase");
fSwimRunAthleticsMult = gmst.find("fSwimRunAthleticsMult");
fKnockDownMult = gmst.find("fKnockDownMult");
iKnockDownOddsMult = gmst.find("iKnockDownOddsMult");
iKnockDownOddsBase = gmst.find("iKnockDownOddsBase");
inited = true; inited = true;
} }
@ -68,14 +89,14 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>(); MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
// creature stats // creature stats
data->mCreatureStats.getAttribute(0).set (ref->mBase->mData.mStrength); data->mCreatureStats.setAttribute(ESM::Attribute::Strength, ref->mBase->mData.mStrength);
data->mCreatureStats.getAttribute(1).set (ref->mBase->mData.mIntelligence); data->mCreatureStats.setAttribute(ESM::Attribute::Intelligence, ref->mBase->mData.mIntelligence);
data->mCreatureStats.getAttribute(2).set (ref->mBase->mData.mWillpower); data->mCreatureStats.setAttribute(ESM::Attribute::Willpower, ref->mBase->mData.mWillpower);
data->mCreatureStats.getAttribute(3).set (ref->mBase->mData.mAgility); data->mCreatureStats.setAttribute(ESM::Attribute::Agility, ref->mBase->mData.mAgility);
data->mCreatureStats.getAttribute(4).set (ref->mBase->mData.mSpeed); data->mCreatureStats.setAttribute(ESM::Attribute::Speed, ref->mBase->mData.mSpeed);
data->mCreatureStats.getAttribute(5).set (ref->mBase->mData.mEndurance); data->mCreatureStats.setAttribute(ESM::Attribute::Endurance, ref->mBase->mData.mEndurance);
data->mCreatureStats.getAttribute(6).set (ref->mBase->mData.mPersonality); data->mCreatureStats.setAttribute(ESM::Attribute::Personality, ref->mBase->mData.mPersonality);
data->mCreatureStats.getAttribute(7).set (ref->mBase->mData.mLuck); data->mCreatureStats.setAttribute(ESM::Attribute::Luck, ref->mBase->mData.mLuck);
data->mCreatureStats.setHealth (ref->mBase->mData.mHealth); data->mCreatureStats.setHealth (ref->mBase->mData.mHealth);
data->mCreatureStats.setMagicka (ref->mBase->mData.mMana); data->mCreatureStats.setMagicka (ref->mBase->mData.mMana);
data->mCreatureStats.setFatigue (ref->mBase->mData.mFatigue); data->mCreatureStats.setFatigue (ref->mBase->mData.mFatigue);
@ -84,10 +105,10 @@ namespace MWClass
data->mCreatureStats.getAiSequence().fill(ref->mBase->mAiPackage); data->mCreatureStats.getAiSequence().fill(ref->mBase->mAiPackage);
data->mCreatureStats.setAiSetting (0, ref->mBase->mAiData.mHello); data->mCreatureStats.setAiSetting (MWMechanics::CreatureStats::AI_Hello, ref->mBase->mAiData.mHello);
data->mCreatureStats.setAiSetting (1, ref->mBase->mAiData.mFight); data->mCreatureStats.setAiSetting (MWMechanics::CreatureStats::AI_Fight, ref->mBase->mAiData.mFight);
data->mCreatureStats.setAiSetting (2, ref->mBase->mAiData.mFlee); data->mCreatureStats.setAiSetting (MWMechanics::CreatureStats::AI_Flee, ref->mBase->mAiData.mFlee);
data->mCreatureStats.setAiSetting (3, ref->mBase->mAiData.mAlarm); data->mCreatureStats.setAiSetting (MWMechanics::CreatureStats::AI_Alarm, ref->mBase->mAiData.mAlarm);
// spells // spells
for (std::vector<std::string>::const_iterator iter (ref->mBase->mSpells.mList.begin()); for (std::vector<std::string>::const_iterator iter (ref->mBase->mSpells.mList.begin());
@ -95,13 +116,23 @@ namespace MWClass
data->mCreatureStats.getSpells().add (*iter); data->mCreatureStats.getSpells().add (*iter);
// inventory // inventory
data->mContainerStore.fill(ref->mBase->mInventory, getId(ptr), if (ref->mBase->mFlags & ESM::Creature::Weapon)
MWBase::Environment::get().getWorld()->getStore()); data->mContainerStore = new MWWorld::InventoryStore();
else
data->mContainerStore.add("gold_001", ref->mBase->mData.mGold, ptr); data->mContainerStore = new MWWorld::ContainerStore();
// store // store
ptr.getRefData().setCustomData (data.release()); ptr.getRefData().setCustomData (data.release());
getContainerStore(ptr).fill(ref->mBase->mInventory, getId(ptr), "",
MWBase::Environment::get().getWorld()->getStore());
// TODO: this is not quite correct, in vanilla the merchant's gold pool is not available in his inventory.
// (except for gold you gave him)
getContainerStore(ptr).add(MWWorld::ContainerStore::sGoldId, ref->mBase->mData.mGold, ptr);
if (ref->mBase->mFlags & ESM::Creature::Weapon)
getInventoryStore(ptr).autoEquip(ptr);
} }
} }
@ -120,8 +151,10 @@ namespace MWClass
void Creature::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const void Creature::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
{ {
MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
MWRender::Actors& actors = renderingInterface.getActors(); MWRender::Actors& actors = renderingInterface.getActors();
actors.insertCreature(ptr); actors.insertCreature(ptr, ref->mBase->mFlags & ESM::Creature::Weapon);
} }
void Creature::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const void Creature::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const
@ -163,6 +196,144 @@ namespace MWClass
void Creature::hit(const MWWorld::Ptr& ptr, int type) const void Creature::hit(const MWWorld::Ptr& ptr, int type) const
{ {
MWWorld::LiveCellRef<ESM::Creature> *ref =
ptr.get<ESM::Creature>();
const MWWorld::Store<ESM::GameSetting> &gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
MWMechanics::CreatureStats &stats = getCreatureStats(ptr);
// Get the weapon used (if hand-to-hand, weapon = inv.end())
MWWorld::Ptr weapon;
if (ptr.getClass().hasInventoryStore(ptr))
{
MWWorld::InventoryStore &inv = getInventoryStore(ptr);
MWWorld::ContainerStoreIterator weaponslot = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
if (weaponslot != inv.end() && weaponslot->getTypeName() == typeid(ESM::Weapon).name())
weapon = *weaponslot;
}
// Reduce fatigue
// somewhat of a guess, but using the weapon weight makes sense
const float fFatigueAttackBase = gmst.find("fFatigueAttackBase")->getFloat();
const float fFatigueAttackMult = gmst.find("fFatigueAttackMult")->getFloat();
const float fWeaponFatigueMult = gmst.find("fWeaponFatigueMult")->getFloat();
MWMechanics::DynamicStat<float> fatigue = stats.getFatigue();
const float normalizedEncumbrance = getEncumbrance(ptr) / getCapacity(ptr);
float fatigueLoss = fFatigueAttackBase + normalizedEncumbrance * fFatigueAttackMult;
if (!weapon.isEmpty())
fatigueLoss += weapon.getClass().getWeight(weapon) * stats.getAttackStrength() * fWeaponFatigueMult;
fatigue.setCurrent(fatigue.getCurrent() - fatigueLoss);
stats.setFatigue(fatigue);
// TODO: where is the distance defined?
float dist = 200.f;
if (!weapon.isEmpty())
{
const float fCombatDistance = gmst.find("fCombatDistance")->getFloat();
dist = fCombatDistance * weapon.get<ESM::Weapon>()->mBase->mData.mReach;
}
std::pair<MWWorld::Ptr, Ogre::Vector3> result = MWBase::Environment::get().getWorld()->getHitContact(ptr, dist);
if (result.first.isEmpty())
return; // Didn't hit anything
MWWorld::Ptr victim = result.first;
if (!victim.getClass().isActor())
return; // Can't hit non-actors
Ogre::Vector3 hitPosition = result.second;
MWMechanics::CreatureStats &otherstats = victim.getClass().getCreatureStats(victim);
const MWMechanics::MagicEffects &mageffects = stats.getMagicEffects();
float hitchance = ref->mBase->mData.mCombat +
(stats.getAttribute(ESM::Attribute::Agility).getModified() / 5.0f) +
(stats.getAttribute(ESM::Attribute::Luck).getModified() / 10.0f);
hitchance *= stats.getFatigueTerm();
hitchance += mageffects.get(ESM::MagicEffect::FortifyAttack).mMagnitude -
mageffects.get(ESM::MagicEffect::Blind).mMagnitude;
hitchance -= otherstats.getEvasion();
if((::rand()/(RAND_MAX+1.0)) > hitchance/100.0f)
{
victim.getClass().onHit(victim, 0.0f, false, MWWorld::Ptr(), ptr, false);
return;
}
int min,max;
switch (type)
{
case 0:
min = ref->mBase->mData.mAttack[0];
max = ref->mBase->mData.mAttack[1];
break;
case 1:
min = ref->mBase->mData.mAttack[2];
max = ref->mBase->mData.mAttack[3];
break;
case 2:
default:
min = ref->mBase->mData.mAttack[4];
max = ref->mBase->mData.mAttack[5];
break;
}
// I think this should be random, since attack1-3 animations don't have an attack strength like NPCs do
float damage = min + (max - min) * ::rand()/(RAND_MAX+1.0);
if (!weapon.isEmpty())
{
const bool weaphashealth = get(weapon).hasItemHealth(weapon);
const unsigned char *attack = NULL;
if(type == ESM::Weapon::AT_Chop)
attack = weapon.get<ESM::Weapon>()->mBase->mData.mChop;
else if(type == ESM::Weapon::AT_Slash)
attack = weapon.get<ESM::Weapon>()->mBase->mData.mSlash;
else if(type == ESM::Weapon::AT_Thrust)
attack = weapon.get<ESM::Weapon>()->mBase->mData.mThrust;
if(attack)
{
float weaponDamage = attack[0] + ((attack[1]-attack[0])*stats.getAttackStrength());
weaponDamage *= 0.5f + (stats.getAttribute(ESM::Attribute::Luck).getModified() / 100.0f);
if(weaphashealth)
{
int weapmaxhealth = weapon.get<ESM::Weapon>()->mBase->mData.mHealth;
if(weapon.getCellRef().mCharge == -1)
weapon.getCellRef().mCharge = weapmaxhealth;
weaponDamage *= float(weapon.getCellRef().mCharge) / weapmaxhealth;
}
if (!MWBase::Environment::get().getWorld()->getGodModeState())
weapon.getCellRef().mCharge -= std::min(std::max(1,
(int)(damage * gmst.find("fWeaponDamageMult")->getFloat())), weapon.getCellRef().mCharge);
// Weapon broken? unequip it
if (weapon.getCellRef().mCharge == 0)
weapon = *getInventoryStore(ptr).unequipItem(weapon, ptr);
damage += weaponDamage;
}
// Apply "On hit" enchanted weapons
std::string enchantmentName = !weapon.isEmpty() ? weapon.getClass().getEnchantment(weapon) : "";
if (!enchantmentName.empty())
{
const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().find(
enchantmentName);
if (enchantment->mData.mType == ESM::Enchantment::WhenStrikes)
{
MWMechanics::CastSpell cast(ptr, victim);
cast.mHitPosition = hitPosition;
cast.cast(weapon);
}
}
}
if (!weapon.isEmpty() && MWMechanics::blockMeleeAttack(ptr, victim, weapon, damage))
damage = 0;
if (damage > 0)
MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, hitPosition);
victim.getClass().onHit(victim, damage, true, weapon, ptr, true);
} }
void Creature::onHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, bool successful) const void Creature::onHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, bool successful) const
@ -189,18 +360,60 @@ namespace MWClass
ptr.getRefData().getLocals().setVarByInt(script, "onpchitme", 1); ptr.getRefData().getLocals().setVarByInt(script, "onpchitme", 1);
} }
if(ishealth) if (damage > 0.0f && !object.isEmpty())
MWMechanics::resistNormalWeapon(ptr, attacker, object, damage);
if (damage > 0.f)
{ {
if(damage > 0.0f) // Check for knockdown
float agilityTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * fKnockDownMult->getFloat();
float knockdownTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified()
* iKnockDownOddsMult->getInt() * 0.01 + iKnockDownOddsBase->getInt();
int roll = std::rand()/ (static_cast<double> (RAND_MAX) + 1) * 100; // [0, 99]
if (ishealth && agilityTerm <= damage && knockdownTerm <= roll)
{
getCreatureStats(ptr).setKnockedDown(true);
}
else
getCreatureStats(ptr).setHitRecovery(true); // Is this supposed to always occur?
if(ishealth)
{
MWBase::Environment::get().getSoundManager()->playSound3D(ptr, "Health Damage", 1.0f, 1.0f); MWBase::Environment::get().getSoundManager()->playSound3D(ptr, "Health Damage", 1.0f, 1.0f);
float health = getCreatureStats(ptr).getHealth().getCurrent() - damage; float health = getCreatureStats(ptr).getHealth().getCurrent() - damage;
setActorHealth(ptr, health, attacker); setActorHealth(ptr, health, attacker);
}
else
{
MWMechanics::DynamicStat<float> fatigue(getCreatureStats(ptr).getFatigue());
fatigue.setCurrent(fatigue.getCurrent() - damage, true);
getCreatureStats(ptr).setFatigue(fatigue);
}
} }
else }
void Creature::block(const MWWorld::Ptr &ptr) const
{
MWWorld::InventoryStore& inv = getInventoryStore(ptr);
MWWorld::ContainerStoreIterator shield = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft);
if (shield == inv.end())
return;
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
switch(shield->getClass().getEquipmentSkill(*shield))
{ {
MWMechanics::DynamicStat<float> fatigue(getCreatureStats(ptr).getFatigue()); case ESM::Skill::LightArmor:
fatigue.setCurrent(fatigue.getCurrent() - damage); sndMgr->playSound3D(ptr, "Light Armor Hit", 1.0f, 1.0f);
getCreatureStats(ptr).setFatigue(fatigue); break;
case ESM::Skill::MediumArmor:
sndMgr->playSound3D(ptr, "Medium Armor Hit", 1.0f, 1.0f);
break;
case ESM::Skill::HeavyArmor:
sndMgr->playSound3D(ptr, "Heavy Armor Hit", 1.0f, 1.0f);
break;
default:
return;
} }
} }
@ -243,18 +456,33 @@ namespace MWClass
return boost::shared_ptr<MWWorld::Action>(new MWWorld::ActionTalk(ptr)); return boost::shared_ptr<MWWorld::Action>(new MWWorld::ActionTalk(ptr));
} }
MWWorld::ContainerStore& Creature::getContainerStore (const MWWorld::Ptr& ptr) MWWorld::ContainerStore& Creature::getContainerStore (const MWWorld::Ptr& ptr) const
const
{ {
ensureCustomData (ptr); ensureCustomData (ptr);
return dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mContainerStore; return *dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mContainerStore;
}
MWWorld::InventoryStore& Creature::getInventoryStore(const MWWorld::Ptr &ptr) const
{
MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
if (ref->mBase->mFlags & ESM::Creature::Weapon)
return dynamic_cast<MWWorld::InventoryStore&>(getContainerStore(ptr));
else
throw std::runtime_error("this creature has no inventory store");
}
bool Creature::hasInventoryStore(const MWWorld::Ptr &ptr) const
{
MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
return (ref->mBase->mFlags & ESM::Creature::Weapon);
} }
std::string Creature::getScript (const MWWorld::Ptr& ptr) const std::string Creature::getScript (const MWWorld::Ptr& ptr) const
{ {
MWWorld::LiveCellRef<ESM::Creature> *ref = MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
ptr.get<ESM::Creature>();
return ref->mBase->mScript; return ref->mBase->mScript;
} }
@ -284,10 +512,51 @@ namespace MWClass
float Creature::getSpeed(const MWWorld::Ptr &ptr) const float Creature::getSpeed(const MWWorld::Ptr &ptr) const
{ {
MWMechanics::CreatureStats& stats = getCreatureStats(ptr); MWMechanics::CreatureStats& stats = getCreatureStats(ptr);
float walkSpeed = fMinWalkSpeedCreature->getFloat() + 0.01 * stats.getAttribute(ESM::Attribute::Speed).getModified() float walkSpeed = fMinWalkSpeedCreature->getFloat() + 0.01 * stats.getAttribute(ESM::Attribute::Speed).getModified()
* (fMaxWalkSpeedCreature->getFloat() - fMinWalkSpeedCreature->getFloat()); * (fMaxWalkSpeedCreature->getFloat() - fMinWalkSpeedCreature->getFloat());
/// \todo what about the rest?
return walkSpeed; const MWBase::World *world = MWBase::Environment::get().getWorld();
const MWMechanics::MagicEffects &mageffects = stats.getMagicEffects();
const float normalizedEncumbrance = getEncumbrance(ptr) / getCapacity(ptr);
bool running = ptr.getClass().getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Run);
float runSpeed = walkSpeed*(0.01f * getSkill(ptr, ESM::Skill::Athletics) *
fAthleticsRunBonus->getFloat() + fBaseRunMultiplier->getFloat());
float moveSpeed;
if(normalizedEncumbrance >= 1.0f)
moveSpeed = 0.0f;
else if(isFlying(ptr) || (mageffects.get(ESM::MagicEffect::Levitate).mMagnitude > 0 &&
world->isLevitationEnabled()))
{
float flySpeed = 0.01f*(stats.getAttribute(ESM::Attribute::Speed).getModified() +
mageffects.get(ESM::MagicEffect::Levitate).mMagnitude);
flySpeed = fMinFlySpeed->getFloat() + flySpeed*(fMaxFlySpeed->getFloat() - fMinFlySpeed->getFloat());
flySpeed *= 1.0f - fEncumberedMoveEffect->getFloat() * normalizedEncumbrance;
flySpeed = std::max(0.0f, flySpeed);
moveSpeed = flySpeed;
}
else if(world->isSwimming(ptr))
{
float swimSpeed = walkSpeed;
if(running)
swimSpeed = runSpeed;
swimSpeed *= 1.0f + 0.01f * mageffects.get(ESM::MagicEffect::SwiftSwim).mMagnitude;
swimSpeed *= fSwimRunBase->getFloat() + 0.01f*getSkill(ptr, ESM::Skill::Athletics) *
fSwimRunAthleticsMult->getFloat();
moveSpeed = swimSpeed;
}
else if(running)
moveSpeed = runSpeed;
else
moveSpeed = walkSpeed;
if(getMovementSettings(ptr).mPosition[0] != 0 && getMovementSettings(ptr).mPosition[1] == 0)
moveSpeed *= 0.75f;
return moveSpeed;
} }
MWMechanics::Movement& Creature::getMovementSettings (const MWWorld::Ptr& ptr) const MWMechanics::Movement& Creature::getMovementSettings (const MWWorld::Ptr& ptr) const
@ -413,6 +682,14 @@ namespace MWClass
return MWWorld::Ptr(&cell.mCreatures.insert(*ref), &cell); return MWWorld::Ptr(&cell.mCreatures.insert(*ref), &cell);
} }
bool Creature::isFlying(const MWWorld::Ptr &ptr) const
{
MWWorld::LiveCellRef<ESM::Creature> *ref =
ptr.get<ESM::Creature>();
return ref->mBase->mFlags & ESM::Creature::Flies;
}
int Creature::getSndGenTypeFromName(const MWWorld::Ptr &ptr, const std::string &name) int Creature::getSndGenTypeFromName(const MWWorld::Ptr &ptr, const std::string &name)
{ {
if(name == "left") if(name == "left")
@ -451,6 +728,76 @@ namespace MWClass
throw std::runtime_error(std::string("Unexpected soundgen type: ")+name); throw std::runtime_error(std::string("Unexpected soundgen type: ")+name);
} }
int Creature::getSkill(const MWWorld::Ptr &ptr, int skill) const
{
MWWorld::LiveCellRef<ESM::Creature> *ref =
ptr.get<ESM::Creature>();
const ESM::Skill* skillRecord = MWBase::Environment::get().getWorld()->getStore().get<ESM::Skill>().find(skill);
switch (skillRecord->mData.mSpecialization)
{
case ESM::Class::Combat:
return ref->mBase->mData.mCombat;
case ESM::Class::Magic:
return ref->mBase->mData.mMagic;
case ESM::Class::Stealth:
return ref->mBase->mData.mStealth;
default:
throw std::runtime_error("invalid specialisation");
}
}
int Creature::getBloodTexture(const MWWorld::Ptr &ptr) const
{
MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
if (ref->mBase->mFlags & ESM::Creature::Skeleton)
return 1;
if (ref->mBase->mFlags & ESM::Creature::Metal)
return 2;
return 0;
}
void Creature::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
const
{
const ESM::CreatureState& state2 = dynamic_cast<const ESM::CreatureState&> (state);
ensureCustomData (ptr);
CustomData& customData = dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData());
customData.mContainerStore->readState (state2.mInventory);
customData.mCreatureStats.readState (state2.mCreatureStats);
}
void Creature::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
const
{
ESM::CreatureState& state2 = dynamic_cast<ESM::CreatureState&> (state);
ensureCustomData (ptr);
CustomData& customData = dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData());
customData.mContainerStore->writeState (state2.mInventory);
customData.mCreatureStats.writeState (state2.mCreatureStats);
}
const ESM::GameSetting* Creature::fMinWalkSpeedCreature; const ESM::GameSetting* Creature::fMinWalkSpeedCreature;
const ESM::GameSetting* Creature::fMaxWalkSpeedCreature; const ESM::GameSetting* Creature::fMaxWalkSpeedCreature;
const ESM::GameSetting *Creature::fEncumberedMoveEffect;
const ESM::GameSetting *Creature::fSneakSpeedMultiplier;
const ESM::GameSetting *Creature::fAthleticsRunBonus;
const ESM::GameSetting *Creature::fBaseRunMultiplier;
const ESM::GameSetting *Creature::fMinFlySpeed;
const ESM::GameSetting *Creature::fMaxFlySpeed;
const ESM::GameSetting *Creature::fSwimRunBase;
const ESM::GameSetting *Creature::fSwimRunAthleticsMult;
const ESM::GameSetting *Creature::fKnockDownMult;
const ESM::GameSetting *Creature::iKnockDownOddsMult;
const ESM::GameSetting *Creature::iKnockDownOddsBase;
} }

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save