forked from mirror/openmw-tes3mp
Merge remote-tracking branch 'upstream/master' into HEAD
Conflicts: CMakeLists.txt components/CMakeLists.txt components/config/gamesettings.cpp
This commit is contained in:
commit
c54217d008
575 changed files with 21357 additions and 8848 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -3,7 +3,6 @@ CMakeFiles
|
|||
*/CMakeFiles
|
||||
CMakeCache.txt
|
||||
cmake_install.cmake
|
||||
CMakeLists.txt.user
|
||||
Makefile
|
||||
makefile
|
||||
build
|
||||
|
@ -22,6 +21,8 @@ Doxygen
|
|||
.project
|
||||
.settings
|
||||
.directory
|
||||
## qt-creator
|
||||
CMakeLists.txt.user*
|
||||
|
||||
## resources
|
||||
data
|
||||
|
@ -39,6 +40,7 @@ resources
|
|||
|
||||
## generated objects
|
||||
apps/openmw/config.hpp
|
||||
components/version/version.hpp
|
||||
Docs/mainpage.hpp
|
||||
moc_*.cxx
|
||||
*.cxx_parameters
|
||||
|
|
20
.travis.yml
20
.travis.yml
|
@ -4,18 +4,18 @@ compiler:
|
|||
branches:
|
||||
only:
|
||||
- master
|
||||
- next
|
||||
- /openmw-.*$/
|
||||
before_install:
|
||||
- pwd
|
||||
- git submodule update --init --recursive
|
||||
- git fetch --tags
|
||||
- echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse"
|
||||
- echo "yes" | sudo apt-add-repository ppa:openmw/openmw
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -qq libboost-all-dev libgtest-dev google-mock libzzip-dev uuid-dev
|
||||
- sudo apt-get install -qq libqt4-dev libxaw7-dev libxrandr-dev libfreeimage-dev libpng-dev
|
||||
- sudo apt-get install -qq libopenal-dev libmpg123-dev libsndfile1-dev
|
||||
- sudo apt-get install -qq libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev libpostproc-dev
|
||||
- sudo apt-get install -qq libbullet-dev libogre-1.8-dev libmygui-dev libsdl2-dev libunshield-dev
|
||||
- sudo apt-get install -qq libboost-all-dev libgtest-dev google-mock
|
||||
- sudo apt-get install -qq libqt4-dev
|
||||
- sudo apt-get install -qq libopenal-dev
|
||||
- sudo apt-get install -qq libavcodec-dev libavformat-dev libavutil-dev libswscale-dev
|
||||
- sudo apt-get install -qq libbullet-dev libogre-1.9-dev libmygui-dev libsdl2-dev libunshield-dev
|
||||
- sudo mkdir /usr/src/gtest/build
|
||||
- cd /usr/src/gtest/build
|
||||
- sudo cmake .. -DBUILD_SHARED_LIBS=1
|
||||
|
@ -37,3 +37,9 @@ notifications:
|
|||
email:
|
||||
on_success: change
|
||||
on_failure: always
|
||||
irc:
|
||||
channels:
|
||||
- "chat.freenode.net#openmw"
|
||||
on_success: change
|
||||
on_failure: always
|
||||
|
||||
|
|
149
CMakeLists.txt
149
CMakeLists.txt
|
@ -4,25 +4,36 @@ if (APPLE)
|
|||
set(APP_BUNDLE_NAME "${CMAKE_PROJECT_NAME}.app")
|
||||
|
||||
set(APP_BUNDLE_DIR "${OpenMW_BINARY_DIR}/${APP_BUNDLE_NAME}")
|
||||
|
||||
set(CMAKE_EXE_LINKER_FLAGS "-F /Library/Frameworks")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "-F /Library/Frameworks")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "-F /Library/Frameworks")
|
||||
endif (APPLE)
|
||||
|
||||
# Macros
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/)
|
||||
|
||||
include (OpenMWMacros)
|
||||
include(OpenMWMacros)
|
||||
|
||||
# Version
|
||||
|
||||
set (OPENMW_VERSION_MAJOR 0)
|
||||
set (OPENMW_VERSION_MINOR 27)
|
||||
set (OPENMW_VERSION_RELEASE 0)
|
||||
include(GetGitRevisionDescription)
|
||||
|
||||
set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}")
|
||||
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_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
|
||||
|
||||
|
@ -94,14 +105,10 @@ set(OENGINE_GUI
|
|||
)
|
||||
|
||||
set(OENGINE_BULLET
|
||||
${LIBDIR}/openengine/bullet/btKinematicCharacterController.cpp
|
||||
${LIBDIR}/openengine/bullet/btKinematicCharacterController.h
|
||||
${LIBDIR}/openengine/bullet/BtOgre.cpp
|
||||
${LIBDIR}/openengine/bullet/BtOgreExtras.h
|
||||
${LIBDIR}/openengine/bullet/BtOgreGP.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.hpp
|
||||
${LIBDIR}/openengine/bullet/BulletShapeLoader.cpp
|
||||
|
@ -186,19 +193,16 @@ if (WIN32)
|
|||
set(Boost_USE_STATIC_LIBS ON)
|
||||
set(PLATFORM_INCLUDE_DIR "platform")
|
||||
add_definitions(-DBOOST_ALL_NO_LIB)
|
||||
|
||||
# Suppress WinMain(), provided by SDL
|
||||
add_definitions(-DSDL_MAIN_HANDLED)
|
||||
else (WIN32)
|
||||
set(PLATFORM_INCLUDE_DIR "")
|
||||
find_path (UUID_INCLUDE_DIR uuid/uuid.h)
|
||||
include_directories(${UUID_INCLUDE_DIR})
|
||||
endif (WIN32)
|
||||
if (MSVC10)
|
||||
set(PLATFORM_INCLUDE_DIR "")
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
set(Boost_USE_STATIC_LIBS ON)
|
||||
endif (APPLE)
|
||||
|
||||
# Dependencies
|
||||
|
||||
# Fix for not visible pthreads functions for linker with glibc 2.15
|
||||
|
@ -213,7 +217,7 @@ if (HAVE_UNORDERED_MAP)
|
|||
endif ()
|
||||
|
||||
|
||||
set(BOOST_COMPONENTS system filesystem program_options thread date_time wave)
|
||||
set(BOOST_COMPONENTS system filesystem program_options)
|
||||
|
||||
IF(BOOST_STATIC)
|
||||
set(Boost_USE_STATIC_LIBS ON)
|
||||
|
@ -241,7 +245,6 @@ include_directories("."
|
|||
${MYGUI_INCLUDE_DIRS}
|
||||
${MYGUI_PLATFORM_INCLUDE_DIRS}
|
||||
${OPENAL_INCLUDE_DIR}
|
||||
${UUID_INCLUDE_DIR}
|
||||
${LIBDIR}
|
||||
)
|
||||
|
||||
|
@ -250,10 +253,15 @@ link_directories(${SDL2_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR} ${MY
|
|||
if (APPLE)
|
||||
# List used Ogre plugins
|
||||
SET(USED_OGRE_PLUGINS ${OGRE_RenderSystem_GL_LIBRARY_REL}
|
||||
${OGRE_Plugin_OctreeSceneManager_LIBRARY_REL}
|
||||
${OGRE_Plugin_CgProgramManager_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}})
|
||||
set(OGRE_PLUGINS_REL_FOUND TRUE)
|
||||
endif ()
|
||||
|
@ -268,8 +276,6 @@ if (APPLE)
|
|||
set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_DBG})
|
||||
endif ()
|
||||
|
||||
#set(OGRE_PLUGIN_DIR "${OGRE_PLUGIN_DIR}/")
|
||||
|
||||
configure_file(${OpenMW_SOURCE_DIR}/files/mac/Info.plist
|
||||
"${APP_BUNDLE_DIR}/Contents/Info.plist")
|
||||
|
||||
|
@ -291,7 +297,8 @@ endif()
|
|||
add_definitions(-DOGRE_PLUGIN_DIR_REL="${OGRE_PLUGIN_DIR_REL}")
|
||||
add_definitions(-DOGRE_PLUGIN_DIR_DBG="${OGRE_PLUGIN_DIR_DBG}")
|
||||
if (APPLE AND OPENMW_OSX_DEPLOYMENT)
|
||||
add_definitions(-DOGRE_PLUGIN_DIR="${APP_BUNDLE_NAME}/Contents/Plugins")
|
||||
# make it empty so plugin loading code can check this and try to find plugins inside app bundle
|
||||
add_definitions(-DOGRE_PLUGIN_DIR="")
|
||||
else()
|
||||
add_definitions(-DOGRE_PLUGIN_DIR="${OGRE_PLUGIN_DIR}")
|
||||
endif()
|
||||
|
@ -324,7 +331,7 @@ configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg
|
|||
|
||||
configure_file(${OpenMW_SOURCE_DIR}/files/opencs.cfg
|
||||
"${OpenMW_BINARY_DIR}/opencs.cfg")
|
||||
|
||||
|
||||
configure_file(${OpenMW_SOURCE_DIR}/files/opencs/defaultfilters
|
||||
"${OpenMW_BINARY_DIR}/resources/defaultfilters" COPYONLY)
|
||||
|
||||
|
@ -415,46 +422,6 @@ IF(NOT WIN32 AND NOT APPLE)
|
|||
# Install 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")
|
||||
|
||||
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)
|
||||
|
||||
if(WIN32)
|
||||
|
@ -705,14 +672,14 @@ if (APPLE)
|
|||
set(CPACK_GENERATOR "DragNDrop")
|
||||
set(CPACK_PACKAGE_VERSION ${OPENMW_VERSION})
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR ${OPENMW_VERSION_MAJOR})
|
||||
set(CPACK_PACKAGE_VERSION_MINOR ${OPENMW_VERSION_MINO})
|
||||
set(CPACK_PACKAGE_VERSION_MINOR ${OPENMW_VERSION_MINOR})
|
||||
set(CPACK_PACKAGE_VERSION_PATCH ${OPENMW_VERSION_RELEASE})
|
||||
|
||||
set(OPENMW_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}")
|
||||
|
||||
set(OPENCS_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/OpenCS.app")
|
||||
set(OPENCS_BUNDLE_NAME "OpenCS.app")
|
||||
set(OPENCS_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}")
|
||||
|
||||
set(PLUGINS "")
|
||||
set(ABSOLUTE_PLUGINS "")
|
||||
|
||||
foreach (PLUGIN ${USED_OGRE_PLUGINS})
|
||||
|
@ -720,12 +687,36 @@ if (APPLE)
|
|||
set(ABSOLUTE_PLUGINS ${PLUGIN_ABS} ${ABSOLUTE_PLUGINS})
|
||||
endforeach ()
|
||||
|
||||
set(PLUGIN_INSTALL_BASE "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}/Contents/Plugins")
|
||||
install(FILES ${ABSOLUTE_PLUGINS} DESTINATION "${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}/Contents/Plugins" COMPONENT Runtime)
|
||||
foreach (PLUGIN ${ABSOLUTE_PLUGINS})
|
||||
get_filename_component(PLUGIN_RELATIVE ${PLUGIN} NAME)
|
||||
set(PLUGINS ${PLUGINS} "${PLUGIN_INSTALL_BASE}/${PLUGIN_RELATIVE}")
|
||||
endforeach ()
|
||||
install(CODE "
|
||||
set(BU_CHMOD_BUNDLE_ITEMS ON)
|
||||
include(BundleUtilities)
|
||||
" COMPONENT Runtime)
|
||||
|
||||
# installs used plugins in bundle at given path (bundle_path must be relative to ${CMAKE_INSTALL_PREFIX})
|
||||
# and returns list of install paths for all installed plugins
|
||||
function (install_plugins_for_bundle bundle_path plugins_var)
|
||||
set(RELATIVE_PLUGIN_INSTALL_BASE "${bundle_path}/Contents/Frameworks")
|
||||
|
||||
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
|
||||
set(DIRS "")
|
||||
|
@ -738,6 +729,7 @@ if (APPLE)
|
|||
# Current limitations:
|
||||
# 1. Handles only frameworks, not simple libs
|
||||
INSTALL(CODE "
|
||||
cmake_policy(SET CMP0009 OLD)
|
||||
set(CMAKE_FIND_LIBRARY_PREFIXES ${CMAKE_FIND_LIBRARY_PREFIXES})
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
|
||||
set(CMAKE_SYSTEM_FRAMEWORK_PATH ${CMAKE_SYSTEM_FRAMEWORK_PATH})
|
||||
|
@ -769,11 +761,8 @@ if (APPLE)
|
|||
endif()
|
||||
endfunction(gp_resolve_item_override)
|
||||
|
||||
cmake_policy(SET CMP0009 OLD)
|
||||
set(BU_CHMOD_BUNDLE_ITEMS ON)
|
||||
include(BundleUtilities)
|
||||
fixup_bundle(\"${OPENMW_APP}\" \"${PLUGINS}\" \"${DIRS}\")
|
||||
fixup_bundle(\"${OPENCS_APP}\" \"\" \"${DIRS}\")
|
||||
fixup_bundle(\"${OPENCS_APP}\" \"${OPENCS_PLUGINS}\" \"${DIRS}\")
|
||||
" COMPONENT Runtime)
|
||||
include(CPack)
|
||||
endif (APPLE)
|
||||
|
|
|
@ -236,7 +236,9 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info)
|
|||
// Loop through all the references
|
||||
ESM::CellRef ref;
|
||||
if(!quiet) std::cout << " References:\n";
|
||||
while(cell.getNextRef(esm, ref))
|
||||
|
||||
bool deleted = false;
|
||||
while(cell.getNextRef(esm, ref, deleted))
|
||||
{
|
||||
if (save) {
|
||||
info.data.mCellRefs[&cell].push_back(ref);
|
||||
|
@ -244,13 +246,14 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info)
|
|||
|
||||
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 << " Owner: '" << ref.mOwner << "'\n";
|
||||
std::cout << " Enchantment charge: '" << ref.mEnchantmentCharge << "'\n";
|
||||
std::cout << " Uses/health: '" << ref.mCharge << "'\n";
|
||||
std::cout << " Gold value: '" << ref.mGoldValue << "'\n";
|
||||
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::Swims) properties += "Swims ";
|
||||
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::Weapon) properties += "Weapon ";
|
||||
if (flags & ESM::Creature::Skeleton) properties += "Skeleton ";
|
||||
|
@ -691,7 +691,7 @@ std::string creatureFlags(int flags)
|
|||
ESM::Creature::Walks|
|
||||
ESM::Creature::Swims|
|
||||
ESM::Creature::Flies|
|
||||
ESM::Creature::Biped|
|
||||
ESM::Creature::Bipedal|
|
||||
ESM::Creature::Respawn|
|
||||
ESM::Creature::Weapon|
|
||||
ESM::Creature::Skeleton|
|
||||
|
@ -717,16 +717,26 @@ std::string landFlags(int flags)
|
|||
return properties;
|
||||
}
|
||||
|
||||
std::string leveledListFlags(int flags)
|
||||
std::string itemListFlags(int flags)
|
||||
{
|
||||
std::string properties = "";
|
||||
if (flags == 0) properties += "[None] ";
|
||||
if (flags & ESM::LeveledListBase::AllLevels) properties += "AllLevels ";
|
||||
// This flag apparently not present on creature lists...
|
||||
if (flags & ESM::LeveledListBase::Each) properties += "Each ";
|
||||
if (flags & ESM::ItemLevList::AllLevels) properties += "AllLevels ";
|
||||
if (flags & ESM::ItemLevList::Each) properties += "Each ";
|
||||
int unused = (0xFFFFFFFF ^
|
||||
(ESM::LeveledListBase::AllLevels|
|
||||
ESM::LeveledListBase::Each));
|
||||
(ESM::ItemLevList::AllLevels|
|
||||
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 ";
|
||||
properties += str(boost::format("(0x%08X)") % flags);
|
||||
return properties;
|
||||
|
@ -764,34 +774,19 @@ std::string magicEffectFlags(int flags)
|
|||
{
|
||||
std::string properties = "";
|
||||
if (flags == 0) properties += "[None] ";
|
||||
// Enchanting & SpellMaking occur on the same list of effects.
|
||||
// "EXTRA SPELL" appears in the construction set under both the
|
||||
// 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::TargetAttribute) properties += "TargetAttribute ";
|
||||
if (flags & ESM::MagicEffect::TargetSkill) properties += "TargetSkill ";
|
||||
if (flags & ESM::MagicEffect::NoDuration) properties += "NoDuration ";
|
||||
if (flags & 0x00000008) properties += "NoMagnitude ";
|
||||
if (flags & 0x00000010) properties += "Negative ";
|
||||
if (flags & 0x00000020) properties += "Unknown1 ";
|
||||
// ESM componet says 0x800 is negative, but none of the magic
|
||||
// effects have this flags set.
|
||||
if (flags & ESM::MagicEffect::Negative) properties += "Unused ";
|
||||
// Since only Chameleon has this flag it could be anything
|
||||
// that uniquely distinguishes Chameleon.
|
||||
if (flags & 0x00002000) properties += "Chameleon ";
|
||||
if (flags & 0x00004000) properties += "Bound ";
|
||||
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 & ESM::MagicEffect::NoMagnitude) properties += "NoMagnitude ";
|
||||
if (flags & ESM::MagicEffect::Harmful) properties += "Harmful ";
|
||||
if (flags & ESM::MagicEffect::ContinuousVfx) properties += "ContinuousVFX ";
|
||||
if (flags & ESM::MagicEffect::CastSelf) properties += "CastSelf ";
|
||||
if (flags & ESM::MagicEffect::CastTouch) properties += "CastTouch ";
|
||||
if (flags & ESM::MagicEffect::CastTarget) properties += "CastTarget ";
|
||||
if (flags & ESM::MagicEffect::UncappedDamage) properties += "UncappedDamage ";
|
||||
if (flags & ESM::MagicEffect::NonRecastable) properties += "NonRecastable ";
|
||||
if (flags & ESM::MagicEffect::Unreflectable) properties += "Unreflectable ";
|
||||
if (flags & ESM::MagicEffect::CasterLinked) properties += "CasterLinked ";
|
||||
if (flags & 0xFFFC0000) properties += "Invalid ";
|
||||
properties += str(boost::format("(0x%08X)") % flags);
|
||||
return properties;
|
||||
|
|
|
@ -50,7 +50,8 @@ std::string cellFlags(int flags);
|
|||
std::string containerFlags(int flags);
|
||||
std::string creatureFlags(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 magicEffectFlags(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 << " Duration: " << p.mWander.mDuration << std::endl;
|
||||
std::cout << " Time of Day: " << (int)p.mWander.mTimeOfDay << std::endl;
|
||||
if (p.mWander.mUnk != 1)
|
||||
std::cout << " Unknown: " << (int)p.mWander.mUnk << std::endl;
|
||||
if (p.mWander.mShouldRepeat != 1)
|
||||
std::cout << " Should repeat: " << (bool)p.mWander.mShouldRepeat << std::endl;
|
||||
|
||||
std::cout << " Idle: ";
|
||||
for (int i = 0; i != 8; i++)
|
||||
|
@ -834,7 +834,7 @@ template<>
|
|||
void Record<ESM::CreatureLevList>::print()
|
||||
{
|
||||
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::vector<ESM::LeveledListBase::LevelItem>::iterator iit;
|
||||
for (iit = mData.mList.begin(); iit != mData.mList.end(); iit++)
|
||||
|
@ -846,11 +846,11 @@ template<>
|
|||
void Record<ESM::ItemLevList>::print()
|
||||
{
|
||||
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::vector<ESM::LeveledListBase::LevelItem>::iterator 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;
|
||||
}
|
||||
|
||||
|
@ -958,7 +958,7 @@ void Record<ESM::MagicEffect>::print()
|
|||
std::cout << " RGB Color: " << "("
|
||||
<< mData.mData.mRed << ","
|
||||
<< mData.mData.mGreen << ","
|
||||
<< mData.mData.mGreen << ")" << std::endl;
|
||||
<< mData.mData.mBlue << ")" << std::endl;
|
||||
}
|
||||
|
||||
template<>
|
||||
|
@ -989,8 +989,7 @@ void Record<ESM::NPC>::print()
|
|||
std::cout << " Faction: " << mData.mFaction << std::endl;
|
||||
std::cout << " Flags: " << npcFlags(mData.mFlags) << std::endl;
|
||||
|
||||
// Seriously?
|
||||
if (mData.mNpdt52.mGold == -10)
|
||||
if (mData.mNpdtType == ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS)
|
||||
{
|
||||
std::cout << " Level: " << mData.mNpdt12.mLevel << 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 << " Skills:" << std::endl;
|
||||
for (int i = 0; i != 27; i++)
|
||||
for (int i = 0; i != ESM::Skill::Length; i++)
|
||||
std::cout << " " << skillLabel(i) << ": "
|
||||
<< (int)((unsigned char)mData.mNpdt52.mSkills[i]) << std::endl;
|
||||
|
||||
|
|
|
@ -132,8 +132,3 @@ if (BUILD_WITH_CODE_COVERAGE)
|
|||
target_link_libraries(omwlauncher gcov)
|
||||
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[])
|
||||
{
|
||||
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software");
|
||||
SDL_SetMainReady();
|
||||
if (SDL_Init(SDL_INIT_VIDEO) != 0)
|
||||
{
|
||||
qDebug() << "SDL_Init failed: " << QString::fromStdString(SDL_GetError());
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
#include "maindialog.hpp"
|
||||
|
||||
#include <components/version/version.hpp>
|
||||
|
||||
#include <QLabel>
|
||||
#include <QDate>
|
||||
#include <QTime>
|
||||
#include <QPushButton>
|
||||
#include <QFontDatabase>
|
||||
#include <QInputDialog>
|
||||
|
@ -67,6 +72,22 @@ Launcher::MainDialog::MainDialog(QWidget *parent)
|
|||
// Remove what's this? button
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -219,7 +240,7 @@ bool Launcher::MainDialog::showFirstRunDialog()
|
|||
}
|
||||
|
||||
// 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);
|
||||
|
||||
if (!file.exists()) {
|
||||
|
@ -334,7 +355,7 @@ bool Launcher::MainDialog::setupLauncherSettings()
|
|||
{
|
||||
mLauncherSettings.setMultiValueEnabled(true);
|
||||
|
||||
QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string());
|
||||
QString userPath = QString::fromStdString(mCfgMgr.getUserConfigPath().string());
|
||||
|
||||
QStringList paths;
|
||||
paths.append(QString("launcher.cfg"));
|
||||
|
@ -440,9 +461,35 @@ bool Launcher::expansions(Launcher::UnshieldThread& cd)
|
|||
|
||||
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());
|
||||
|
||||
// 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;
|
||||
paths.append(userPath + QString("openmw.cfg"));
|
||||
paths.append(QString("openmw.cfg"));
|
||||
|
@ -565,7 +612,7 @@ bool Launcher::MainDialog::setupGraphicsSettings()
|
|||
{
|
||||
mGraphicsSettings.setMultiValueEnabled(false);
|
||||
|
||||
QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string());
|
||||
QString userPath = QString::fromStdString(mCfgMgr.getUserConfigPath().string());
|
||||
QString globalPath = QString::fromStdString(mCfgMgr.getGlobalPath().string());
|
||||
|
||||
QFile localDefault(QString("settings-default.cfg"));
|
||||
|
@ -652,7 +699,7 @@ bool Launcher::MainDialog::writeSettings()
|
|||
mGraphicsPage->saveSettings();
|
||||
mDataFilesPage->saveSettings();
|
||||
|
||||
QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string());
|
||||
QString userPath = QString::fromStdString(mCfgMgr.getUserConfigPath().string());
|
||||
QDir dir(userPath);
|
||||
|
||||
if (!dir.exists()) {
|
||||
|
|
|
@ -235,7 +235,7 @@ namespace
|
|||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -243,7 +243,7 @@ namespace
|
|||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -255,7 +255,7 @@ namespace
|
|||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ MwIniImporter::MwIniImporter()
|
|||
const char *map[][2] =
|
||||
{
|
||||
{ "fps", "General:Show FPS" },
|
||||
{ "nosound", "General:Disable Audio" },
|
||||
{ "no-sound", "General:Disable Audio" },
|
||||
{ 0, 0 }
|
||||
};
|
||||
const char *fallback[] = {
|
||||
|
@ -623,6 +623,17 @@ MwIniImporter::MwIniImporter()
|
|||
"Moons:Masser Fade Out Finish",
|
||||
"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
|
||||
};
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ opencs_units (model/world
|
|||
|
||||
opencs_units_noqt (model/world
|
||||
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
|
||||
|
@ -38,7 +38,7 @@ opencs_units (model/tools
|
|||
|
||||
opencs_units_noqt (model/tools
|
||||
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
|
||||
table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator
|
||||
cellcreator referenceablecreator referencecreator scenesubview scenetoolbar scenetool
|
||||
scenetoolmode infocreator
|
||||
scenetoolmode infocreator scriptedit
|
||||
)
|
||||
|
||||
opencs_units (view/render
|
||||
|
@ -143,7 +143,7 @@ if(WIN32)
|
|||
set(QT_USE_QTMAIN TRUE)
|
||||
endif(WIN32)
|
||||
|
||||
find_package(Qt4 COMPONENTS QtCore QtGui QtNetwork QtXml QtXmlPatterns REQUIRED)
|
||||
find_package(Qt4 COMPONENTS QtCore QtGui QtNetwork REQUIRED)
|
||||
include(${QT_USE_FILE})
|
||||
|
||||
qt4_wrap_ui(OPENCS_UI_HDR ${OPENCS_UI})
|
||||
|
|
|
@ -86,10 +86,6 @@ void CS::Editor::setupDataFiles()
|
|||
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());
|
||||
|
||||
mDocumentManager.setResourceDir (variables["resources"].as<std::string>());
|
||||
|
@ -214,6 +210,8 @@ int CS::Editor::run()
|
|||
if (mLocal.empty())
|
||||
return 1;
|
||||
|
||||
// temporarily disable OGRE-integration (need to fix path problem first)
|
||||
#if 0
|
||||
// TODO: setting
|
||||
Ogre::Root::getSingleton().setRenderSystem(Ogre::Root::getSingleton().getRenderSystemByName("OpenGL Rendering Subsystem"));
|
||||
|
||||
|
@ -225,8 +223,12 @@ int CS::Editor::run()
|
|||
params.insert(std::make_pair("FSAA", "0"));
|
||||
params.insert(std::make_pair("vsync", "false"));
|
||||
params.insert(std::make_pair("hidden", "true"));
|
||||
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
|
||||
params.insert(std::make_pair("macAPI", "cocoa"));
|
||||
#endif
|
||||
Ogre::RenderWindow* hiddenWindow = Ogre::Root::getSingleton().createRenderWindow("InactiveHidden", 1, 1, false, ¶ms);
|
||||
hiddenWindow->setActive(false);
|
||||
#endif
|
||||
|
||||
mStartup.show();
|
||||
|
||||
|
|
|
@ -42,10 +42,13 @@ int main(int argc, char *argv[])
|
|||
|
||||
// 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 :(
|
||||
OgreInit::OgreInit ogreInit;
|
||||
ogreInit.init("./opencsOgre.log"); // TODO log path?
|
||||
|
||||
Application mApplication (argc, argv);
|
||||
// temporarily disable OGRE-integration (need to fix path problem first)
|
||||
#if 0
|
||||
OgreInit::OgreInit ogreInit;
|
||||
ogreInit.init("./opencsOgre.log"); // TODO log path?
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
QDir dir(QCoreApplication::applicationDirPath());
|
||||
|
|
|
@ -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_)
|
||||
: mSavePath (savePath), mContentFiles (files), mTools (mData), mResDir(resDir),
|
||||
mProjectPath ((configuration.getUserPath() / "projects") /
|
||||
mProjectPath ((configuration.getUserDataPath() / "projects") /
|
||||
(savePath.filename().string() + ".project")),
|
||||
mSaving (*this, mProjectPath)
|
||||
{
|
||||
|
@ -2254,7 +2254,7 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, co
|
|||
}
|
||||
else
|
||||
{
|
||||
boost::filesystem::path locCustomFiltersPath (configuration.getUserPath());
|
||||
boost::filesystem::path locCustomFiltersPath (configuration.getUserDataPath());
|
||||
locCustomFiltersPath /= "defaultfilters";
|
||||
|
||||
if (boost::filesystem::exists(locCustomFiltersPath))
|
||||
|
|
|
@ -71,7 +71,10 @@ namespace CSMDoc
|
|||
|
||||
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();
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
CSMDoc::DocumentManager::DocumentManager (const Files::ConfigurationManager& configuration)
|
||||
: mConfiguration (configuration)
|
||||
{
|
||||
boost::filesystem::path projectPath = configuration.getUserPath() / "projects";
|
||||
boost::filesystem::path projectPath = configuration.getUserDataPath() / "projects";
|
||||
|
||||
if (!boost::filesystem::is_directory (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)
|
||||
{
|
||||
mResDir = boost::filesystem::system_complete(parResDir);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,9 @@ namespace CSMDoc
|
|||
|
||||
~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.
|
||||
///
|
||||
/// \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 ||
|
||||
infoModified)
|
||||
{
|
||||
// always write the topic record
|
||||
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().startRecord (topic.mModified.sRecordId);
|
||||
mState.getWriter().writeHNCString ("NAME", topic.mModified.mId);
|
||||
topic.mModified.save (mState.getWriter());
|
||||
mState.getWriter().endRecord (type);
|
||||
mState.getWriter().endRecord (topic.mModified.sRecordId);
|
||||
|
||||
// write modified selected info records
|
||||
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);
|
||||
}
|
||||
|
||||
std::string type;
|
||||
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().startRecord (info.sRecordId);
|
||||
mState.getWriter().writeHNCString ("INAM", info.mId);
|
||||
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?)
|
||||
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));
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -251,7 +251,7 @@ void CSMSettings::UserSettings::loadSettings (const QString &fileName)
|
|||
bool localOk = loadFromFile(localFilePath);
|
||||
|
||||
//user
|
||||
mUserFilePath = QString::fromStdString(mCfgMgr.getUserPath().string()) + fileName;
|
||||
mUserFilePath = QString::fromStdString(mCfgMgr.getUserConfigPath().string()) + fileName;
|
||||
loadFromFile(mUserFilePath);
|
||||
|
||||
if (!(localOk || globalOk))
|
||||
|
|
1095
apps/opencs/model/tools/referenceablecheck.cpp
Normal file
1095
apps/opencs/model/tools/referenceablecheck.cpp
Normal file
File diff suppressed because it is too large
Load diff
78
apps/opencs/model/tools/referenceablecheck.hpp
Normal file
78
apps/opencs/model/tools/referenceablecheck.hpp
Normal file
|
@ -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
|
||||
{
|
||||
return mRows.at (row).first;
|
||||
}
|
||||
}
|
||||
|
|
103
apps/opencs/model/tools/scriptcheck.cpp
Normal file
103
apps/opencs/model/tools/scriptcheck.cpp
Normal file
|
@ -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;
|
||||
}
|
41
apps/opencs/model/tools/scriptcheck.hpp
Normal file
41
apps/opencs/model/tools/scriptcheck.hpp
Normal file
|
@ -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 "birthsigncheck.hpp"
|
||||
#include "spellcheck.hpp"
|
||||
#include "referenceablecheck.hpp"
|
||||
#include "scriptcheck.hpp"
|
||||
|
||||
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 SpellCheckStage (mData.getSpells()));
|
||||
|
||||
mVerifier->appendStage (new ReferenceableCheckStage (mData.getReferenceables().getDataSet(), mData.getRaces(), mData.getClasses(), mData.getFactions()));
|
||||
|
||||
mVerifier->appendStage (new ScriptCheckStage (mData));
|
||||
}
|
||||
|
||||
return mVerifier;
|
||||
|
@ -138,4 +144,5 @@ void CSMTools::Tools::verifierMessage (const QString& message, int type)
|
|||
|
||||
if (iter!=mActiveReports.end())
|
||||
mReports[iter->second]->add (message.toStdString());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -98,6 +98,10 @@ namespace CSMWorld
|
|||
UniversalId::Type type = UniversalId::Type_None);
|
||||
///< \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;
|
||||
////< Search record with \a id.
|
||||
/// \return index of record (if found) or -1 (not found)
|
||||
|
@ -193,6 +197,19 @@ namespace CSMWorld
|
|||
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>
|
||||
Collection<ESXRecordT, IdAccessorT>::Collection()
|
||||
{}
|
||||
|
|
|
@ -74,6 +74,10 @@ namespace CSMWorld
|
|||
UniversalId::Type type = UniversalId::Type_None) = 0;
|
||||
///< 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 (int index) const = 0;
|
||||
|
|
|
@ -27,6 +27,47 @@ namespace CSMWorld
|
|||
enum Display
|
||||
{
|
||||
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_Float,
|
||||
Display_Var,
|
||||
|
|
|
@ -373,7 +373,7 @@ namespace CSMWorld
|
|||
SkillsColumn (int index, bool typePrefix = false, bool major = false)
|
||||
: Column<ESXRecordT> ((typePrefix ? (
|
||||
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)
|
||||
{}
|
||||
|
||||
|
@ -598,7 +598,7 @@ namespace CSMWorld
|
|||
struct SoundFileColumn : public Column<ESXRecordT>
|
||||
{
|
||||
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
|
||||
|
@ -811,7 +811,7 @@ namespace CSMWorld
|
|||
template<typename 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
|
||||
{
|
||||
|
@ -890,7 +890,7 @@ namespace CSMWorld
|
|||
template<typename 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
|
||||
{
|
||||
|
@ -915,7 +915,7 @@ namespace CSMWorld
|
|||
template<typename 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
|
||||
{
|
||||
|
@ -940,7 +940,7 @@ namespace CSMWorld
|
|||
template<typename 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
|
||||
{
|
||||
|
@ -1090,7 +1090,7 @@ namespace CSMWorld
|
|||
struct TeleportCellColumn : public Column<ESXRecordT>
|
||||
{
|
||||
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
|
||||
|
@ -1146,7 +1146,7 @@ namespace CSMWorld
|
|||
template<typename 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
|
||||
{
|
||||
|
@ -1485,7 +1485,7 @@ namespace CSMWorld
|
|||
template<typename 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
|
||||
{
|
||||
|
@ -1510,7 +1510,7 @@ namespace CSMWorld
|
|||
template<typename 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
|
||||
{
|
||||
|
@ -1535,7 +1535,7 @@ namespace CSMWorld
|
|||
template<typename 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
|
||||
{
|
||||
|
|
|
@ -220,7 +220,7 @@ int CSMWorld::Columns::getId (const std::string& name)
|
|||
std::string name2 = Misc::StringUtils::lowerCase (name);
|
||||
|
||||
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 -1;
|
||||
|
@ -263,7 +263,7 @@ namespace
|
|||
|
||||
static const char *sCreatureTypes[] =
|
||||
{
|
||||
"Creature", "Deadra", "Undead", "Humanoid", 0
|
||||
"Creature", "Daedra", "Undead", "Humanoid", 0
|
||||
};
|
||||
|
||||
static const char *sWeaponTypes[] =
|
||||
|
@ -342,4 +342,4 @@ std::vector<std::string> CSMWorld::Columns::getEnums (ColumnId column)
|
|||
}
|
||||
|
||||
return enums;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,10 +4,10 @@
|
|||
#include <QAbstractItemModel>
|
||||
|
||||
#include "idtable.hpp"
|
||||
#include "idtable.hpp"
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
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_)
|
||||
{
|
||||
mOld = mModel.data (mIndex, Qt::EditRole);
|
||||
|
@ -25,7 +25,7 @@ void CSMWorld::ModifyCommand::undo()
|
|||
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)
|
||||
{
|
||||
setText (("Create record " + id).c_str());
|
||||
|
@ -54,7 +54,7 @@ void CSMWorld::CreateCommand::undo()
|
|||
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)
|
||||
{
|
||||
setText (("Revert record " + id).c_str());
|
||||
|
@ -89,7 +89,7 @@ void CSMWorld::RevertCommand::undo()
|
|||
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)
|
||||
{
|
||||
setText (("Delete record " + id).c_str());
|
||||
|
@ -126,7 +126,7 @@ void CSMWorld::DeleteCommand::undo()
|
|||
|
||||
|
||||
CSMWorld::ReorderRowsCommand::ReorderRowsCommand (IdTable& model, int baseIndex,
|
||||
const std::vector<int>& newOrder)
|
||||
const std::vector<int>& newOrder)
|
||||
: mModel (model), mBaseIndex (baseIndex), mNewOrder (newOrder)
|
||||
{}
|
||||
|
||||
|
@ -140,8 +140,35 @@ void CSMWorld::ReorderRowsCommand::undo()
|
|||
int size = static_cast<int> (mNewOrder.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;
|
||||
|
||||
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();
|
||||
};
|
||||
|
||||
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
|
||||
{
|
||||
IdTable& mModel;
|
||||
|
|
|
@ -154,14 +154,17 @@ CSMWorld::Data::Data() : mRefs (mCells)
|
|||
|
||||
mTopics.addColumn (new StringIdColumn<ESM::Dialogue>);
|
||||
mTopics.addColumn (new RecordStateColumn<ESM::Dialogue>);
|
||||
mTopics.addColumn (new FixedRecordTypeColumn<ESM::Dialogue> (UniversalId::Type_Topic));
|
||||
mTopics.addColumn (new DialogueTypeColumn<ESM::Dialogue>);
|
||||
|
||||
mJournals.addColumn (new StringIdColumn<ESM::Dialogue>);
|
||||
mJournals.addColumn (new RecordStateColumn<ESM::Dialogue>);
|
||||
mJournals.addColumn (new FixedRecordTypeColumn<ESM::Dialogue> (UniversalId::Type_Journal));
|
||||
mJournals.addColumn (new DialogueTypeColumn<ESM::Dialogue> (true));
|
||||
|
||||
mTopicInfos.addColumn (new StringIdColumn<Info> (true));
|
||||
mTopicInfos.addColumn (new RecordStateColumn<Info>);
|
||||
mTopicInfos.addColumn (new FixedRecordTypeColumn<Info> (UniversalId::Type_TopicInfo));
|
||||
mTopicInfos.addColumn (new TopicColumn<Info> (false));
|
||||
mTopicInfos.addColumn (new ActorColumn<Info>);
|
||||
mTopicInfos.addColumn (new RaceColumn<Info>);
|
||||
|
@ -178,6 +181,7 @@ CSMWorld::Data::Data() : mRefs (mCells)
|
|||
|
||||
mJournalInfos.addColumn (new StringIdColumn<Info> (true));
|
||||
mJournalInfos.addColumn (new RecordStateColumn<Info>);
|
||||
mJournalInfos.addColumn (new FixedRecordTypeColumn<Info> (UniversalId::Type_Journal));
|
||||
mJournalInfos.addColumn (new TopicColumn<Info> (true));
|
||||
mJournalInfos.addColumn (new QuestStatusTypeColumn<Info>);
|
||||
mJournalInfos.addColumn (new QuestIndexColumn<Info>);
|
||||
|
@ -194,6 +198,7 @@ CSMWorld::Data::Data() : mRefs (mCells)
|
|||
|
||||
mRefs.addColumn (new StringIdColumn<CellRef> (true));
|
||||
mRefs.addColumn (new RecordStateColumn<CellRef>);
|
||||
mRefs.addColumn (new FixedRecordTypeColumn<CellRef> (UniversalId::Type_Reference));
|
||||
mRefs.addColumn (new CellColumn<CellRef>);
|
||||
mRefs.addColumn (new IdColumn<CellRef>);
|
||||
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 RecordStateColumn<CSMFilter::Filter>);
|
||||
mFilters.addColumn (new FixedRecordTypeColumn<CSMFilter::Filter> (UniversalId::Type_Filter));
|
||||
mFilters.addColumn (new FilterColumn<CSMFilter::Filter>);
|
||||
mFilters.addColumn (new DescriptionColumn<CSMFilter::Filter>);
|
||||
mFilters.addColumn (new ScopeColumn<CSMFilter::Filter>);
|
||||
|
|
|
@ -124,6 +124,17 @@ void CSMWorld::IdTable::addRecord (const std::string& id, UniversalId::Type type
|
|||
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
|
||||
{
|
||||
return index (mIdCollection->getIndex (id), column);
|
||||
|
|
|
@ -63,6 +63,10 @@ namespace CSMWorld
|
|||
void addRecord (const std::string& id, UniversalId::Type type = UniversalId::Type_None);
|
||||
///< \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;
|
||||
|
||||
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)
|
||||
: QSortFilterProxyModel (parent)
|
||||
{}
|
||||
{
|
||||
setSortCaseSensitivity (Qt::CaseInsensitive);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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 -1;
|
||||
|
@ -177,8 +177,8 @@ CSMWorld::InfoCollection::Range CSMWorld::InfoCollection::getTopicRange (const s
|
|||
RecordConstIterator end = begin;
|
||||
|
||||
for (; end!=getRecords().end(); ++end)
|
||||
if (Misc::StringUtils::lowerCase (end->get().mTopicId)!=topic2)
|
||||
if (!Misc::StringUtils::ciEqual(end->get().mTopicId, topic2))
|
||||
break;
|
||||
|
||||
return Range (begin, end);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,5 @@ void CSMWorld::CellRef::load (ESM::ESMReader &esm, Cell& cell, const std::string
|
|||
mId = id;
|
||||
mCell = cell.mId;
|
||||
|
||||
if (!mDeleted)
|
||||
cell.addRef (mId);
|
||||
cell.addRef (mId);
|
||||
}
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
#include "ref.hpp"
|
||||
#include "cell.hpp"
|
||||
#include "universalid.hpp"
|
||||
#include "record.hpp"
|
||||
|
||||
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;
|
||||
|
||||
while (cell2.getNextRef (reader, ref))
|
||||
bool deleted = false;
|
||||
while (cell2.getNextRef (reader, ref, deleted))
|
||||
{
|
||||
/// \todo handle deleted and moved references
|
||||
ref.load (reader, cell2, getNewId());
|
||||
|
@ -34,4 +37,15 @@ std::string CSMWorld::RefCollection::getNewId()
|
|||
std::ostringstream stream;
|
||||
stream << "ref#" << mNextId++;
|
||||
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
|
||||
{
|
||||
struct Cell;
|
||||
struct UniversalId;
|
||||
|
||||
/// \brief References in cells
|
||||
class RefCollection : public Collection<CellRef>
|
||||
|
@ -25,6 +26,11 @@ namespace CSMWorld
|
|||
///< Load a sequence of references.
|
||||
|
||||
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.
|
||||
|
||||
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);
|
||||
|
||||
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)
|
||||
const;
|
||||
|
@ -50,6 +52,12 @@ namespace CSMWorld
|
|||
: 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>
|
||||
std::string BaseRefIdAdapter<RecordT>::getId (const RecordBase& record) const
|
||||
{
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "refidcollection.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <memory>
|
||||
|
||||
#include <components/esm/esmreader.hpp>
|
||||
|
||||
|
@ -58,7 +59,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
|
|||
|
||||
mColumns.push_back (RefIdColumn (Columns::ColumnId_Name, ColumnBase::Display_String));
|
||||
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();
|
||||
|
||||
InventoryColumns inventoryColumns (nameColumns);
|
||||
|
@ -181,7 +182,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
|
|||
unsigned int mFlag;
|
||||
} sCreatureFlagTable[] =
|
||||
{
|
||||
{ Columns::ColumnId_Biped, ESM::Creature::Biped },
|
||||
{ Columns::ColumnId_Biped, ESM::Creature::Bipedal },
|
||||
{ Columns::ColumnId_HasWeapon, ESM::Creature::Weapon },
|
||||
{ Columns::ColumnId_NoMovement, ESM::Creature::None },
|
||||
{ Columns::ColumnId_Swims, ESM::Creature::Swims },
|
||||
|
@ -213,10 +214,10 @@ CSMWorld::RefIdCollection::RefIdCollection()
|
|||
|
||||
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();
|
||||
|
||||
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();
|
||||
|
||||
LightColumns lightColumns (inventoryColumns);
|
||||
|
@ -230,7 +231,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
|
|||
mColumns.push_back (RefIdColumn (Columns::ColumnId_Colour, ColumnBase::Display_Integer));
|
||||
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();
|
||||
|
||||
static const struct
|
||||
|
@ -262,13 +263,13 @@ CSMWorld::RefIdCollection::RefIdCollection()
|
|||
|
||||
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();
|
||||
|
||||
mColumns.push_back (RefIdColumn (Columns::ColumnId_Class, ColumnBase::Display_String));
|
||||
mColumns.push_back (RefIdColumn (Columns::ColumnId_Class, ColumnBase::Display_Class));
|
||||
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();
|
||||
|
||||
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)
|
||||
{
|
||||
mData.appendRecord (type, id);
|
||||
mData.appendRecord (type, id, false);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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,
|
||||
UniversalId::Type type)
|
||||
{
|
||||
|
@ -456,7 +467,7 @@ void CSMWorld::RefIdCollection::appendRecord (const RecordBase& record,
|
|||
|
||||
int index = mData.getAppendIndex (type);
|
||||
|
||||
mData.appendRecord (type, id);
|
||||
mData.appendRecord (type, id, false);
|
||||
|
||||
mData.getRecord (mData.globalToLocalIndex (index)).assign (record);
|
||||
}
|
||||
|
@ -504,7 +515,7 @@ void CSMWorld::RefIdCollection::load (ESM::ESMReader& reader, bool base, Univers
|
|||
{
|
||||
// new record
|
||||
int index = mData.getAppendIndex (type);
|
||||
mData.appendRecord (type, id);
|
||||
mData.appendRecord (type, id, base);
|
||||
|
||||
RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (index);
|
||||
|
||||
|
@ -549,3 +560,9 @@ void CSMWorld::RefIdCollection::save (int index, ESM::ESMWriter& writer) const
|
|||
{
|
||||
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 cloneRecord(const std::string& origin,
|
||||
const std::string& destination,
|
||||
const 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
|
||||
|
||||
|
@ -107,7 +111,10 @@ namespace CSMWorld
|
|||
/// \return Success?
|
||||
|
||||
void save (int index, ESM::ESMWriter& writer) const;
|
||||
|
||||
const RefIdData& getDataSet() const; //I can't figure out a better name for this one :(
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -131,7 +131,7 @@ CSMWorld::RecordBase& CSMWorld::RefIdData::getRecord (const LocalIndex& index)
|
|||
return iter->second->getRecord (index.first);
|
||||
}
|
||||
|
||||
void CSMWorld::RefIdData::appendRecord (UniversalId::Type type, const std::string& id)
|
||||
void CSMWorld::RefIdData::appendRecord (UniversalId::Type type, const std::string& id, bool base)
|
||||
{
|
||||
std::map<UniversalId::Type, RefIdDataContainerBase *>::iterator iter =
|
||||
mRecordContainers.find (type);
|
||||
|
@ -139,7 +139,7 @@ void CSMWorld::RefIdData::appendRecord (UniversalId::Type type, const std::strin
|
|||
if (iter==mRecordContainers.end())
|
||||
throw std::logic_error ("invalid local index type");
|
||||
|
||||
iter->second->appendRecord (id);
|
||||
iter->second->appendRecord (id, base);
|
||||
|
||||
mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (id),
|
||||
LocalIndex (iter->second->getSize()-1, type)));
|
||||
|
@ -230,4 +230,118 @@ void CSMWorld::RefIdData::save (int index, ESM::ESMWriter& writer) const
|
|||
throw std::logic_error ("invalid local index type");
|
||||
|
||||
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 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;
|
||||
|
||||
|
@ -67,7 +69,9 @@ namespace CSMWorld
|
|||
|
||||
virtual RecordBase& getRecord (int index);
|
||||
|
||||
virtual void appendRecord (const std::string& id);
|
||||
virtual void appendRecord (const std::string& id, bool base);
|
||||
|
||||
virtual void insertRecord (RecordBase& record);
|
||||
|
||||
virtual void load (int index, ESM::ESMReader& reader, bool base);
|
||||
|
||||
|
@ -78,6 +82,13 @@ namespace CSMWorld
|
|||
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>
|
||||
int RefIdDataContainer<RecordT>::getSize() const
|
||||
{
|
||||
|
@ -97,12 +108,15 @@ namespace CSMWorld
|
|||
}
|
||||
|
||||
template<typename RecordT>
|
||||
void RefIdDataContainer<RecordT>::appendRecord (const std::string& id)
|
||||
void RefIdDataContainer<RecordT>::appendRecord (const std::string& id, bool base)
|
||||
{
|
||||
Record<RecordT> record;
|
||||
|
||||
record.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly;
|
||||
|
||||
record.mBase.mId = id;
|
||||
record.mModified.mId = id;
|
||||
record.mModified.blank();
|
||||
record.mState = RecordBase::State_ModifiedOnly;
|
||||
(base ? record.mBase : record.mModified).blank();
|
||||
|
||||
mContainer.push_back (record);
|
||||
}
|
||||
|
@ -136,15 +150,10 @@ namespace CSMWorld
|
|||
if (state==CSMWorld::RecordBase::State_Modified ||
|
||||
state==CSMWorld::RecordBase::State_ModifiedOnly)
|
||||
{
|
||||
std::string type;
|
||||
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.startRecord (mContainer.at (index).mModified.sRecordId);
|
||||
writer.writeHNCString ("NAME", getId (index));
|
||||
mContainer.at (index).mModified.save (writer);
|
||||
writer.endRecord (type);
|
||||
writer.endRecord (mContainer.at (index).mModified.sRecordId);
|
||||
}
|
||||
else if (state==CSMWorld::RecordBase::State_Deleted)
|
||||
{
|
||||
|
@ -201,11 +210,13 @@ namespace CSMWorld
|
|||
|
||||
void erase (int index, int count);
|
||||
|
||||
void insertRecord(CSMWorld::RecordBase& record, CSMWorld::UniversalId::Type type, const std::string& id);
|
||||
|
||||
const RecordBase& getRecord (const LocalIndex& index) const;
|
||||
|
||||
RecordBase& getRecord (const LocalIndex& index);
|
||||
|
||||
void appendRecord (UniversalId::Type type, const std::string& id);
|
||||
void appendRecord (UniversalId::Type type, const std::string& id, bool base);
|
||||
|
||||
int getAppendIndex (UniversalId::Type type) const;
|
||||
|
||||
|
@ -219,7 +230,33 @@ namespace CSMWorld
|
|||
/// \param listDeleted include deleted record in the list
|
||||
|
||||
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
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -5,23 +5,92 @@
|
|||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
#include <components/compiler/quickfileparser.hpp>
|
||||
#include <components/compiler/nullerrorhandler.hpp>
|
||||
#include <components/compiler/scanner.hpp>
|
||||
|
||||
#include "data.hpp"
|
||||
|
||||
CSMWorld::ScriptContext::ScriptContext (const Data& data) : mData (data), mIdsUpdated (false) {}
|
||||
|
||||
bool CSMWorld::ScriptContext::canDeclareLocals() const
|
||||
{
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
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 ' ';
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -31,6 +100,7 @@ bool CSMWorld::ScriptContext::isId (const std::string& name) const
|
|||
mIds = mData.getIds();
|
||||
|
||||
std::for_each (mIds.begin(), mIds.end(), &Misc::StringUtils::lowerCase);
|
||||
std::sort (mIds.begin(), mIds.end());
|
||||
|
||||
mIdsUpdated = true;
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
bool CSMWorld::ScriptContext::isJournalId (const std::string& name) const
|
||||
{
|
||||
return mData.getJournals().searchId (name)!=-1;
|
||||
}
|
||||
|
||||
void CSMWorld::ScriptContext::invalidateIds()
|
||||
{
|
||||
mIdsUpdated = false;
|
||||
}
|
||||
|
||||
void CSMWorld::ScriptContext::clear()
|
||||
{
|
||||
mIds.clear();
|
||||
mIdsUpdated = false;
|
||||
mLocals.clear();
|
||||
}
|
|
@ -3,8 +3,10 @@
|
|||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include <components/compiler/context.hpp>
|
||||
#include <components/compiler/locals.hpp>
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
|
@ -15,6 +17,7 @@ namespace CSMWorld
|
|||
const Data& mData;
|
||||
mutable std::vector<std::string> mIds;
|
||||
mutable bool mIdsUpdated;
|
||||
mutable std::map<std::string, Compiler::Locals> mLocals;
|
||||
|
||||
public:
|
||||
|
||||
|
@ -26,13 +29,23 @@ namespace CSMWorld
|
|||
virtual char getGlobalType (const std::string& name) const;
|
||||
///< 'l: long, 's': short, 'f': float, ' ': does not exist.
|
||||
|
||||
virtual char getMemberType (const std::string& name, const std::string& id) const;
|
||||
///< 'l: long, 's': short, 'f': float, ' ': does not exist.
|
||||
virtual std::pair<char, bool> getMemberType (const std::string& name,
|
||||
const std::string& id) const;
|
||||
///< Return type of member variable \a name in script \a id or in script of reference of
|
||||
/// \a id
|
||||
/// \return first: 'l: long, 's': short, 'f': float, ' ': does not exist.
|
||||
/// second: true: script of reference
|
||||
|
||||
virtual bool isId (const std::string& name) const;
|
||||
///< Does \a name match an ID, that can be referenced?
|
||||
|
||||
virtual bool isJournalId (const std::string& name) const;
|
||||
///< Does \a name match a journal ID?
|
||||
|
||||
void invalidateIds();
|
||||
|
||||
void clear();
|
||||
///< Remove all cached data.
|
||||
};
|
||||
}
|
||||
|
||||
|
|
285
apps/opencs/model/world/tablemimedata.cpp
Normal file
285
apps/opencs/model/world/tablemimedata.cpp
Normal file
|
@ -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;
|
61
apps/opencs/model/world/tablemimedata.hpp
Normal file
61
apps/opencs/model/world/tablemimedata.hpp
Normal file
|
@ -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 <stdexcept>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
@ -186,7 +187,6 @@ CSMWorld::UniversalId::UniversalId (Type type, const std::string& id)
|
|||
mClass = sIdArg[i].mClass;
|
||||
return;
|
||||
}
|
||||
|
||||
throw std::logic_error ("invalid ID argument UniversalId type");
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <OgreRoot.h>
|
||||
#include <OgreRenderWindow.h>
|
||||
#include <OgreEntity.h>
|
||||
#include <OgreCamera.h>
|
||||
|
||||
namespace CSVRender
|
||||
{
|
||||
|
@ -66,6 +67,10 @@ namespace CSVRender
|
|||
params.insert(std::make_pair("title", windowTitle.str()));
|
||||
params.insert(std::make_pair("FSAA", "0")); // TODO setting
|
||||
params.insert(std::make_pair("vsync", "false")); // TODO setting
|
||||
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
|
||||
params.insert(std::make_pair("macAPI", "cocoa"));
|
||||
params.insert(std::make_pair("macAPICocoaUseNSView", "true"));
|
||||
#endif
|
||||
|
||||
mWindow = Ogre::Root::getSingleton().createRenderWindow(windowTitle.str(), this->width(), this->height(), false, ¶ms);
|
||||
mWindow->addViewport(mCamera)->setBackgroundColour(Ogre::ColourValue(0.3,0.3,0.3,1));
|
||||
|
|
|
@ -61,6 +61,7 @@ void CSVWorld::CellCreator::reset()
|
|||
mX->setValue (0);
|
||||
mY->setValue (0);
|
||||
mType->setCurrentIndex (0);
|
||||
setType(0);
|
||||
GenericCreator::reset();
|
||||
}
|
||||
|
||||
|
@ -78,4 +79,25 @@ void CSVWorld::CellCreator::setType (int index)
|
|||
void CSVWorld::CellCreator::valueChanged (int index)
|
||||
{
|
||||
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 toggleWidgets(bool active = true);
|
||||
|
||||
virtual void cloneMode(const std::string& originId,
|
||||
const CSMWorld::UniversalId::Type type);
|
||||
|
||||
private slots:
|
||||
|
||||
void setType (int index);
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define CSV_WORLD_CREATOR_H
|
||||
|
||||
#include <QWidget>
|
||||
#include "../../model/world/universalid.hpp"
|
||||
|
||||
class QUndoStack;
|
||||
|
||||
|
@ -24,8 +25,13 @@ namespace CSVWorld
|
|||
|
||||
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 toggleWidgets(bool active = true) = 0;
|
||||
|
||||
signals:
|
||||
|
||||
void done();
|
||||
|
|
|
@ -57,8 +57,15 @@ const CSMWorld::UniversalId& CSVWorld::GenericCreator::getCollectionId() const
|
|||
}
|
||||
|
||||
CSVWorld::GenericCreator::GenericCreator (CSMWorld::Data& data, QUndoStack& undoStack,
|
||||
const CSMWorld::UniversalId& id, bool relaxedIdRules)
|
||||
: mData (data), mUndoStack (undoStack), mListId (id), mLocked (false)
|
||||
const CSMWorld::UniversalId& id, bool relaxedIdRules):
|
||||
|
||||
mData (data),
|
||||
mUndoStack (undoStack),
|
||||
mListId (id),
|
||||
mLocked (false),
|
||||
mCloneMode(false),
|
||||
mClonedType(CSMWorld::UniversalId::Type_None)
|
||||
|
||||
{
|
||||
mLayout = new QHBoxLayout;
|
||||
mLayout->setContentsMargins (0, 0, 0, 0);
|
||||
|
@ -89,6 +96,7 @@ void CSVWorld::GenericCreator::setEditLock (bool locked)
|
|||
|
||||
void CSVWorld::GenericCreator::reset()
|
||||
{
|
||||
mCloneMode = false;
|
||||
mId->setText ("");
|
||||
update();
|
||||
}
|
||||
|
@ -120,16 +128,40 @@ void CSVWorld::GenericCreator::create()
|
|||
{
|
||||
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));
|
||||
|
||||
std::auto_ptr<CSMWorld::CreateCommand> command (new CSMWorld::CreateCommand (
|
||||
mUndoStack.push(command.release());
|
||||
|
||||
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));
|
||||
|
||||
configureCreateCommand (*command);
|
||||
configureCreateCommand (*command);
|
||||
|
||||
mUndoStack.push (command.release());
|
||||
mUndoStack.push (command.release());
|
||||
|
||||
emit done();
|
||||
emit requestFocus (id);
|
||||
emit done();
|
||||
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
|
||||
#define CSV_WORLD_GENERICCREATOR_H
|
||||
|
||||
class QString;
|
||||
class QPushButton;
|
||||
class QLineEdit;
|
||||
class QHBoxLayout;
|
||||
|
@ -28,6 +29,11 @@ namespace CSVWorld
|
|||
std::string mErrors;
|
||||
QHBoxLayout *mLayout;
|
||||
bool mLocked;
|
||||
std::string mClonedId;
|
||||
CSMWorld::UniversalId::Type mClonedType;
|
||||
|
||||
protected:
|
||||
bool mCloneMode;
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -57,11 +63,15 @@ namespace CSVWorld
|
|||
|
||||
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;
|
||||
///< Return formatted error descriptions for the current state of the creator. if an empty
|
||||
/// string is returned, there is no error.
|
||||
|
||||
|
||||
private slots:
|
||||
|
||||
void textChanged (const QString& text);
|
||||
|
|
|
@ -40,4 +40,10 @@ void CSVWorld::ReferenceableCreator::reset()
|
|||
{
|
||||
mType->setCurrentIndex (0);
|
||||
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);
|
||||
|
||||
virtual void reset();
|
||||
virtual void toggleWidgets(bool active = true);
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
@ -40,15 +40,20 @@ CSVWorld::ReferenceCreator::ReferenceCreator (CSMWorld::Data& data, QUndoStack&
|
|||
|
||||
void CSVWorld::ReferenceCreator::reset()
|
||||
{
|
||||
GenericCreator::reset();
|
||||
mCell->setText ("");
|
||||
mId = getData().getReferences().getNewId();
|
||||
GenericCreator::reset();
|
||||
}
|
||||
|
||||
std::string CSVWorld::ReferenceCreator::getErrors() const
|
||||
{
|
||||
std::string errors = GenericCreator::getErrors();
|
||||
|
||||
if (mCloneMode)
|
||||
{
|
||||
return errors;
|
||||
}
|
||||
|
||||
std::string cell = mCell->text().toUtf8().constData();
|
||||
|
||||
if (cell.empty())
|
||||
|
@ -72,4 +77,17 @@ std::string CSVWorld::ReferenceCreator::getErrors() const
|
|||
void CSVWorld::ReferenceCreator::cellChanged()
|
||||
{
|
||||
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,
|
||||
const CSMWorld::UniversalId& id);
|
||||
|
||||
virtual void cloneMode(const std::string& originId,
|
||||
const CSMWorld::UniversalId::Type type);
|
||||
|
||||
virtual void reset();
|
||||
virtual void toggleWidgets(bool active = true);
|
||||
|
||||
virtual std::string getErrors() const;
|
||||
///< 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));
|
||||
layout2->addWidget (toolbar, 0);
|
||||
|
||||
|
||||
// temporarily disable OGRE-integration (need to fix path problem first)
|
||||
#if 0
|
||||
CSVRender::SceneWidget* sceneWidget = new CSVRender::SceneWidget(this);
|
||||
|
||||
layout2->addWidget (sceneWidget, 1);
|
||||
|
||||
layout->insertLayout (0, layout2, 1);
|
||||
#endif
|
||||
/// \todo replace with rendering widget
|
||||
QPalette palette2 (palette());
|
||||
palette2.setColor (QPalette::Background, Qt::white);
|
||||
QLabel *placeholder = new QLabel ("Here goes the 3D scene", this);
|
||||
placeholder->setAutoFillBackground (true);
|
||||
placeholder->setPalette (palette2);
|
||||
placeholder->setAlignment (Qt::AlignHCenter);
|
||||
|
||||
layout2->addWidget (placeholder, 1);
|
||||
|
||||
layout->insertLayout (0, layout2, 1);
|
||||
|
||||
|
||||
CSVFilter::FilterBox *filterBox = new CSVFilter::FilterBox (document.getData(), this);
|
||||
|
||||
|
|
88
apps/opencs/view/world/scriptedit.cpp
Normal file
88
apps/opencs/view/world/scriptedit.cpp
Normal file
|
@ -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));
|
||||
}
|
39
apps/opencs/view/world/scriptedit.hpp
Normal file
39
apps/opencs/view/world/scriptedit.hpp
Normal file
|
@ -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 "scripthighlighter.hpp"
|
||||
#include "scriptedit.hpp"
|
||||
|
||||
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)
|
||||
: SubView (id), mDocument (document), mColumn (-1), mChangeLocked (0)
|
||||
{
|
||||
setWidget (mEditor = new QTextEdit (this));
|
||||
setWidget (mEditor = new ScriptEdit (this, mDocument));
|
||||
|
||||
mEditor->setAcceptRichText (false);
|
||||
mEditor->setLineWrapMode (QTextEdit::NoWrap);
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#include <QAction>
|
||||
#include <QMenu>
|
||||
#include <QContextMenuEvent>
|
||||
#include <QString>
|
||||
#include <QtCore/qnamespace.h>
|
||||
|
||||
#include "../../model/world/data.hpp"
|
||||
#include "../../model/world/commands.hpp"
|
||||
|
@ -13,6 +15,8 @@
|
|||
#include "../../model/world/idtable.hpp"
|
||||
#include "../../model/world/record.hpp"
|
||||
#include "../../model/world/columns.hpp"
|
||||
#include "../../model/world/tablemimedata.hpp"
|
||||
#include "../../model/world/tablemimedata.hpp"
|
||||
|
||||
#include "recordstatusdelegate.hpp"
|
||||
#include "util.hpp"
|
||||
|
@ -28,7 +32,11 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event)
|
|||
if (!mEditLock)
|
||||
{
|
||||
if (selectedRows.size()==1)
|
||||
{
|
||||
menu.addAction (mEditAction);
|
||||
if (mCreateAction)
|
||||
menu.addAction(mCloneAction);
|
||||
}
|
||||
|
||||
if (mCreateAction)
|
||||
menu.addAction (mCreateAction);
|
||||
|
@ -84,7 +92,7 @@ std::vector<std::string> CSVWorld::Table::listRevertableSelectedIds() const
|
|||
QModelIndexList selectedRows = selectionModel()->selectedRows();
|
||||
|
||||
for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end();
|
||||
++iter)
|
||||
++iter)
|
||||
{
|
||||
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,
|
||||
bool createAndDelete, bool sorting)
|
||||
: mUndoStack (undoStack), mCreateAction (0), mEditLock (false), mRecordStatusDisplay (0)
|
||||
bool createAndDelete, bool sorting, const CSMDoc::Document& document)
|
||||
: mUndoStack (undoStack), mCreateAction (0), mCloneAction(0), mEditLock (false), mRecordStatusDisplay (0), mDocument(document)
|
||||
{
|
||||
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);
|
||||
connect (mCreateAction, SIGNAL (triggered()), this, SIGNAL (createRequest()));
|
||||
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);
|
||||
|
@ -227,6 +239,8 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, Q
|
|||
|
||||
connect (selectionModel(), SIGNAL (selectionChanged (const QItemSelection&, const QItemSelection&)),
|
||||
this, SLOT (selectionSizeUpdate ()));
|
||||
|
||||
setAcceptDrops(true);
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
QModelIndexList selectedRows = selectionModel()->selectedRows();
|
||||
|
@ -411,3 +438,72 @@ void CSVWorld::Table::recordFilterChanged (boost::shared_ptr<CSMFilter::Node> fi
|
|||
{
|
||||
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 <QTableView>
|
||||
#include <QtGui/qevent.h>
|
||||
|
||||
#include "../../model/filter/node.hpp"
|
||||
|
||||
namespace CSMDoc {
|
||||
class Document;
|
||||
}
|
||||
|
||||
class QUndoStack;
|
||||
class QAction;
|
||||
|
||||
|
@ -32,6 +37,7 @@ namespace CSVWorld
|
|||
QUndoStack& mUndoStack;
|
||||
QAction *mEditAction;
|
||||
QAction *mCreateAction;
|
||||
QAction *mCloneAction;
|
||||
QAction *mRevertAction;
|
||||
QAction *mDeleteAction;
|
||||
QAction *mMoveUpAction;
|
||||
|
@ -41,6 +47,10 @@ namespace CSVWorld
|
|||
bool mEditLock;
|
||||
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:
|
||||
|
||||
void contextMenuEvent (QContextMenuEvent *event);
|
||||
|
@ -49,9 +59,20 @@ namespace CSVWorld
|
|||
|
||||
std::vector<std::string> listDeletableSelectedIds() const;
|
||||
|
||||
void mouseMoveEvent(QMouseEvent *event);
|
||||
|
||||
void dragEnterEvent(QDragEnterEvent *event);
|
||||
|
||||
void dropEvent(QDropEvent *event);
|
||||
|
||||
void dragMoveEvent(QDragMoveEvent *event);
|
||||
|
||||
|
||||
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 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
|
||||
|
||||
void createRequest();
|
||||
void cloneRequest(const CSMWorld::UniversalId&);
|
||||
|
||||
private slots:
|
||||
|
||||
|
@ -82,6 +104,8 @@ namespace CSVWorld
|
|||
|
||||
void editRecord();
|
||||
|
||||
void cloneRecord();
|
||||
|
||||
void moveUpRecord();
|
||||
|
||||
void moveDownRecord();
|
||||
|
|
|
@ -153,7 +153,19 @@ void CSVWorld::TableBottomBox::tableSizeChanged (int size, int deleted, int modi
|
|||
void CSVWorld::TableBottomBox::createRequest()
|
||||
{
|
||||
mCreator->reset();
|
||||
mCreator->toggleWidgets(true);
|
||||
mLayout->setCurrentWidget (mCreator);
|
||||
setVisible (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
|
||||
|
||||
#include <QWidget>
|
||||
#include <apps/opencs/model/world/universalid.hpp>
|
||||
|
||||
class QLabel;
|
||||
class QStackedLayout;
|
||||
|
@ -76,6 +77,8 @@ namespace CSVWorld
|
|||
/// \param modified Number of added and modified records
|
||||
|
||||
void createRequest();
|
||||
void cloneRequest(const std::string& id,
|
||||
const CSMWorld::UniversalId::Type type);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
#include "../../model/doc/document.hpp"
|
||||
|
||||
#include "../filter/filterbox.hpp"
|
||||
|
||||
#include "table.hpp"
|
||||
#include "tablebottombox.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);
|
||||
|
||||
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);
|
||||
|
||||
|
@ -46,8 +45,15 @@ CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::D
|
|||
mTable->selectionSizeUpdate();
|
||||
|
||||
if (mBottom->canCreateAndDelete())
|
||||
{
|
||||
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&)),
|
||||
mTable, SLOT (requestFocus (const std::string&)));
|
||||
|
||||
|
@ -75,4 +81,9 @@ void CSVWorld::TableSubView::updateEditorSetting(const QString &settingName, con
|
|||
void CSVWorld::TableSubView::setStatusBar (bool show)
|
||||
{
|
||||
mBottom->setStatusBar (show);
|
||||
}
|
||||
}
|
||||
|
||||
void CSVWorld::TableSubView::cloneRequest(const CSMWorld::UniversalId& toClone)
|
||||
{
|
||||
emit cloneRequest(toClone.getId(), toClone.getType());
|
||||
}
|
||||
|
|
|
@ -5,6 +5,11 @@
|
|||
|
||||
class QModelIndex;
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
class IdTable;
|
||||
}
|
||||
|
||||
namespace CSMDoc
|
||||
{
|
||||
class Document;
|
||||
|
@ -34,9 +39,14 @@ namespace CSVWorld
|
|||
|
||||
virtual void setStatusBar (bool show);
|
||||
|
||||
signals:
|
||||
void cloneRequest(const std::string&,
|
||||
const CSMWorld::UniversalId::Type);
|
||||
|
||||
private slots:
|
||||
|
||||
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
|
||||
set(GAME
|
||||
main.cpp
|
||||
|
@ -12,15 +8,14 @@ if(NOT WIN32)
|
|||
endif()
|
||||
set(GAME_HEADER
|
||||
engine.hpp
|
||||
config.hpp
|
||||
)
|
||||
source_group(game FILES ${GAME} ${GAME_HEADER})
|
||||
|
||||
add_openmw_dir (mwrender
|
||||
renderingmanager debugging sky camera animation npcanimation creatureanimation activatoranimation
|
||||
actors objects renderinginterface localmap occlusionquery water shadows
|
||||
compositors characterpreview externalrendering globalmap videoplayer ripplesimulation refraction
|
||||
terrainstorage
|
||||
characterpreview globalmap videoplayer ripplesimulation refraction
|
||||
terrainstorage renderconst effectmanager
|
||||
)
|
||||
|
||||
add_openmw_dir (mwinput
|
||||
|
@ -74,14 +69,21 @@ add_openmw_dir (mwmechanics
|
|||
mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects
|
||||
drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow
|
||||
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
|
||||
environment world scriptmanager dialoguemanager journal soundmanager mechanicsmanager
|
||||
inputmanager windowmanager
|
||||
inputmanager windowmanager statemanager
|
||||
)
|
||||
|
||||
# Main executable
|
||||
set(BOOST_COMPONENTS system filesystem program_options thread wave)
|
||||
find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS})
|
||||
|
||||
IF(OGRE_STATIC)
|
||||
ADD_DEFINITIONS(-DENABLE_PLUGIN_OctreeSceneManager -DENABLE_PLUGIN_ParticleFX -DENABLE_PLUGIN_GL)
|
||||
|
@ -111,6 +113,7 @@ add_definitions(${SOUND_DEFINE})
|
|||
target_link_libraries(openmw
|
||||
${OGRE_LIBRARIES}
|
||||
${OGRE_STATIC_PLUGINS}
|
||||
${SHINY_LIBRARIES}
|
||||
${Boost_LIBRARIES}
|
||||
${OPENAL_LIBRARY}
|
||||
${SOUND_INPUT_LIBRARY}
|
||||
|
@ -118,7 +121,6 @@ target_link_libraries(openmw
|
|||
${MYGUI_LIBRARIES}
|
||||
${SDL2_LIBRARY}
|
||||
${MYGUI_PLATFORM_LIBRARIES}
|
||||
${SHINY_LIBRARIES}
|
||||
"oics"
|
||||
"sdl4ogre"
|
||||
components
|
||||
|
@ -137,12 +139,6 @@ if (UNIX AND NOT APPLE)
|
|||
target_link_libraries(openmw ${CMAKE_THREAD_LIBS_INIT})
|
||||
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)
|
||||
find_library(COCOA_FRAMEWORK Cocoa)
|
||||
find_library(IOKIT_FRAMEWORK IOKit)
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <sys/wait.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/ucontext.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
|
@ -42,78 +43,78 @@ static char altstack[SIGSTKSZ];
|
|||
|
||||
|
||||
static struct {
|
||||
int signum;
|
||||
pid_t pid;
|
||||
int has_siginfo;
|
||||
siginfo_t siginfo;
|
||||
char buf[1024];
|
||||
int signum;
|
||||
pid_t pid;
|
||||
int has_siginfo;
|
||||
siginfo_t siginfo;
|
||||
char buf[1024];
|
||||
} crash_info;
|
||||
|
||||
|
||||
static const struct {
|
||||
const char *name;
|
||||
int signum;
|
||||
const char *name;
|
||||
int signum;
|
||||
} signals[] = {
|
||||
{ "Segmentation fault", SIGSEGV },
|
||||
{ "Illegal instruction", SIGILL },
|
||||
{ "FPU exception", SIGFPE },
|
||||
{ "System BUS error", SIGBUS },
|
||||
{ NULL, 0 }
|
||||
{ "Segmentation fault", SIGSEGV },
|
||||
{ "Illegal instruction", SIGILL },
|
||||
{ "FPU exception", SIGFPE },
|
||||
{ "System BUS error", SIGBUS },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
static const struct {
|
||||
int code;
|
||||
const char *name;
|
||||
int code;
|
||||
const char *name;
|
||||
} sigill_codes[] = {
|
||||
#ifndef __FreeBSD__
|
||||
{ ILL_ILLOPC, "Illegal opcode" },
|
||||
{ ILL_ILLOPN, "Illegal operand" },
|
||||
{ ILL_ILLADR, "Illegal addressing mode" },
|
||||
{ ILL_ILLTRP, "Illegal trap" },
|
||||
{ ILL_PRVOPC, "Privileged opcode" },
|
||||
{ ILL_PRVREG, "Privileged register" },
|
||||
{ ILL_COPROC, "Coprocessor error" },
|
||||
{ ILL_BADSTK, "Internal stack error" },
|
||||
#endif
|
||||
{ 0, NULL }
|
||||
#ifndef __FreeBSD__
|
||||
{ ILL_ILLOPC, "Illegal opcode" },
|
||||
{ ILL_ILLOPN, "Illegal operand" },
|
||||
{ ILL_ILLADR, "Illegal addressing mode" },
|
||||
{ ILL_ILLTRP, "Illegal trap" },
|
||||
{ ILL_PRVOPC, "Privileged opcode" },
|
||||
{ ILL_PRVREG, "Privileged register" },
|
||||
{ ILL_COPROC, "Coprocessor error" },
|
||||
{ ILL_BADSTK, "Internal stack error" },
|
||||
#endif
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static const struct {
|
||||
int code;
|
||||
const char *name;
|
||||
int code;
|
||||
const char *name;
|
||||
} sigfpe_codes[] = {
|
||||
{ FPE_INTDIV, "Integer divide by zero" },
|
||||
{ FPE_INTOVF, "Integer overflow" },
|
||||
{ FPE_FLTDIV, "Floating point divide by zero" },
|
||||
{ FPE_FLTOVF, "Floating point overflow" },
|
||||
{ FPE_FLTUND, "Floating point underflow" },
|
||||
{ FPE_FLTRES, "Floating point inexact result" },
|
||||
{ FPE_FLTINV, "Floating point invalid operation" },
|
||||
{ FPE_FLTSUB, "Subscript out of range" },
|
||||
{ 0, NULL }
|
||||
{ FPE_INTDIV, "Integer divide by zero" },
|
||||
{ FPE_INTOVF, "Integer overflow" },
|
||||
{ FPE_FLTDIV, "Floating point divide by zero" },
|
||||
{ FPE_FLTOVF, "Floating point overflow" },
|
||||
{ FPE_FLTUND, "Floating point underflow" },
|
||||
{ FPE_FLTRES, "Floating point inexact result" },
|
||||
{ FPE_FLTINV, "Floating point invalid operation" },
|
||||
{ FPE_FLTSUB, "Subscript out of range" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static const struct {
|
||||
int code;
|
||||
const char *name;
|
||||
int code;
|
||||
const char *name;
|
||||
} sigsegv_codes[] = {
|
||||
#ifndef __FreeBSD__
|
||||
{ SEGV_MAPERR, "Address not mapped to object" },
|
||||
{ SEGV_ACCERR, "Invalid permissions for mapped object" },
|
||||
#endif
|
||||
{ 0, NULL }
|
||||
#ifndef __FreeBSD__
|
||||
{ SEGV_MAPERR, "Address not mapped to object" },
|
||||
{ SEGV_ACCERR, "Invalid permissions for mapped object" },
|
||||
#endif
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static const struct {
|
||||
int code;
|
||||
const char *name;
|
||||
int code;
|
||||
const char *name;
|
||||
} sigbus_codes[] = {
|
||||
#ifndef __FreeBSD__
|
||||
{ BUS_ADRALN, "Invalid address alignment" },
|
||||
{ BUS_ADRERR, "Non-existent physical address" },
|
||||
{ BUS_OBJERR, "Object specific hardware error" },
|
||||
#endif
|
||||
{ 0, NULL }
|
||||
#ifndef __FreeBSD__
|
||||
{ BUS_ADRALN, "Invalid address alignment" },
|
||||
{ BUS_ADRERR, "Non-existent physical address" },
|
||||
{ BUS_OBJERR, "Object specific hardware error" },
|
||||
#endif
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
char respfile[64];
|
||||
char cmd_buf[128];
|
||||
FILE *f;
|
||||
int fd;
|
||||
char respfile[64];
|
||||
char cmd_buf[128];
|
||||
FILE *f;
|
||||
int fd;
|
||||
|
||||
/* Create a temp file to put gdb commands into */
|
||||
strcpy(respfile, "gdb-respfile-XXXXXX");
|
||||
if((fd=mkstemp(respfile)) >= 0 && (f=fdopen(fd, "w")) != NULL)
|
||||
{
|
||||
fprintf(f, "attach %d\n"
|
||||
"shell echo \"\"\n"
|
||||
"shell echo \"* Loaded Libraries\"\n"
|
||||
"info sharedlibrary\n"
|
||||
"shell echo \"\"\n"
|
||||
"shell echo \"* Threads\"\n"
|
||||
"info threads\n"
|
||||
"shell echo \"\"\n"
|
||||
"shell echo \"* FPU Status\"\n"
|
||||
"info float\n"
|
||||
"shell echo \"\"\n"
|
||||
"shell echo \"* Registers\"\n"
|
||||
"info registers\n"
|
||||
"shell echo \"\"\n"
|
||||
"shell echo \"* Backtrace\"\n"
|
||||
"thread apply all backtrace full\n"
|
||||
"detach\n"
|
||||
"quit\n", pid);
|
||||
fclose(f);
|
||||
/* Create a temp file to put gdb commands into */
|
||||
strcpy(respfile, "gdb-respfile-XXXXXX");
|
||||
if((fd=mkstemp(respfile)) >= 0 && (f=fdopen(fd, "w")) != NULL)
|
||||
{
|
||||
fprintf(f, "attach %d\n"
|
||||
"shell echo \"\"\n"
|
||||
"shell echo \"* Loaded Libraries\"\n"
|
||||
"info sharedlibrary\n"
|
||||
"shell echo \"\"\n"
|
||||
"shell echo \"* Threads\"\n"
|
||||
"info threads\n"
|
||||
"shell echo \"\"\n"
|
||||
"shell echo \"* FPU Status\"\n"
|
||||
"info float\n"
|
||||
"shell echo \"\"\n"
|
||||
"shell echo \"* Registers\"\n"
|
||||
"info registers\n"
|
||||
"shell echo \"\"\n"
|
||||
"shell echo \"* Backtrace\"\n"
|
||||
"thread apply all backtrace full\n"
|
||||
"detach\n"
|
||||
"quit\n", pid);
|
||||
fclose(f);
|
||||
|
||||
/* Run gdb and print process info. */
|
||||
snprintf(cmd_buf, sizeof(cmd_buf), "gdb --quiet --batch --command=%s", respfile);
|
||||
printf("Executing: %s\n", cmd_buf);
|
||||
fflush(stdout);
|
||||
/* Run gdb and print process info. */
|
||||
snprintf(cmd_buf, sizeof(cmd_buf), "gdb --quiet --batch --command=%s", respfile);
|
||||
printf("Executing: %s\n", cmd_buf);
|
||||
fflush(stdout);
|
||||
|
||||
system(cmd_buf);
|
||||
/* Clean up */
|
||||
remove(respfile);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Error creating temp file */
|
||||
if(fd >= 0)
|
||||
{
|
||||
close(fd);
|
||||
remove(respfile);
|
||||
}
|
||||
printf("!!! Could not create gdb command file\n");
|
||||
}
|
||||
fflush(stdout);
|
||||
system(cmd_buf);
|
||||
/* Clean up */
|
||||
remove(respfile);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Error creating temp file */
|
||||
if(fd >= 0)
|
||||
{
|
||||
close(fd);
|
||||
remove(respfile);
|
||||
}
|
||||
printf("!!! Could not create gdb command file\n");
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
static void sys_info(void)
|
||||
{
|
||||
#ifdef __unix__
|
||||
system("echo \"System: `uname -a`\"");
|
||||
putchar('\n');
|
||||
fflush(stdout);
|
||||
struct utsname info;
|
||||
if(uname(&info))
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
static size_t safe_write(int fd, const void *buf, size_t len)
|
||||
{
|
||||
size_t ret = 0;
|
||||
while(ret < len)
|
||||
{
|
||||
ssize_t rem;
|
||||
if((rem=write(fd, (const char*)buf+ret, len-ret)) == -1)
|
||||
{
|
||||
if(errno == EINTR)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
ret += rem;
|
||||
}
|
||||
return ret;
|
||||
size_t ret = 0;
|
||||
while(ret < len)
|
||||
{
|
||||
ssize_t rem;
|
||||
if((rem=write(fd, (const char*)buf+ret, len-ret)) == -1)
|
||||
{
|
||||
if(errno == EINTR)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
ret += rem;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void crash_catcher(int signum, siginfo_t *siginfo, void *context)
|
||||
{
|
||||
//ucontext_t *ucontext = (ucontext_t*)context;
|
||||
pid_t dbg_pid;
|
||||
int fd[2];
|
||||
pid_t dbg_pid;
|
||||
int fd[2];
|
||||
|
||||
/* Make sure the effective uid is the real uid */
|
||||
if(getuid() != geteuid())
|
||||
{
|
||||
raise(signum);
|
||||
return;
|
||||
}
|
||||
/* Make sure the effective uid is the real uid */
|
||||
if(getuid() != geteuid())
|
||||
{
|
||||
raise(signum);
|
||||
return;
|
||||
}
|
||||
|
||||
safe_write(STDERR_FILENO, fatal_err, sizeof(fatal_err)-1);
|
||||
if(pipe(fd) == -1)
|
||||
{
|
||||
safe_write(STDERR_FILENO, pipe_err, sizeof(pipe_err)-1);
|
||||
raise(signum);
|
||||
return;
|
||||
}
|
||||
safe_write(STDERR_FILENO, fatal_err, sizeof(fatal_err)-1);
|
||||
if(pipe(fd) == -1)
|
||||
{
|
||||
safe_write(STDERR_FILENO, pipe_err, sizeof(pipe_err)-1);
|
||||
raise(signum);
|
||||
return;
|
||||
}
|
||||
|
||||
crash_info.signum = signum;
|
||||
crash_info.pid = getpid();
|
||||
crash_info.has_siginfo = !!siginfo;
|
||||
if(siginfo)
|
||||
crash_info.siginfo = *siginfo;
|
||||
if(cc_user_info)
|
||||
cc_user_info(crash_info.buf, crash_info.buf+sizeof(crash_info.buf));
|
||||
crash_info.signum = signum;
|
||||
crash_info.pid = getpid();
|
||||
crash_info.has_siginfo = !!siginfo;
|
||||
if(siginfo)
|
||||
crash_info.siginfo = *siginfo;
|
||||
if(cc_user_info)
|
||||
cc_user_info(crash_info.buf, crash_info.buf+sizeof(crash_info.buf));
|
||||
|
||||
/* Fork off to start a crash handler */
|
||||
switch((dbg_pid=fork()))
|
||||
{
|
||||
/* Error */
|
||||
case -1:
|
||||
safe_write(STDERR_FILENO, fork_err, sizeof(fork_err)-1);
|
||||
raise(signum);
|
||||
return;
|
||||
/* Fork off to start a crash handler */
|
||||
switch((dbg_pid=fork()))
|
||||
{
|
||||
/* Error */
|
||||
case -1:
|
||||
safe_write(STDERR_FILENO, fork_err, sizeof(fork_err)-1);
|
||||
raise(signum);
|
||||
return;
|
||||
|
||||
case 0:
|
||||
dup2(fd[0], STDIN_FILENO);
|
||||
close(fd[0]);
|
||||
close(fd[1]);
|
||||
case 0:
|
||||
dup2(fd[0], STDIN_FILENO);
|
||||
close(fd[0]);
|
||||
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);
|
||||
_exit(1);
|
||||
safe_write(STDERR_FILENO, exec_err, sizeof(exec_err)-1);
|
||||
_exit(1);
|
||||
|
||||
default:
|
||||
default:
|
||||
#ifdef __linux__
|
||||
prctl(PR_SET_PTRACER, dbg_pid, 0, 0, 0);
|
||||
prctl(PR_SET_PTRACER, dbg_pid, 0, 0, 0);
|
||||
#endif
|
||||
safe_write(fd[1], &crash_info, sizeof(crash_info));
|
||||
close(fd[0]);
|
||||
close(fd[1]);
|
||||
safe_write(fd[1], &crash_info, sizeof(crash_info));
|
||||
close(fd[0]);
|
||||
close(fd[1]);
|
||||
|
||||
/* Wait; we'll be killed when gdb is done */
|
||||
do {
|
||||
int status;
|
||||
if(waitpid(dbg_pid, &status, 0) == dbg_pid &&
|
||||
(WIFEXITED(status) || WIFSIGNALED(status)))
|
||||
{
|
||||
/* The debug process died before it could kill us */
|
||||
raise(signum);
|
||||
break;
|
||||
}
|
||||
} while(1);
|
||||
}
|
||||
/* Wait; we'll be killed when gdb is done */
|
||||
do {
|
||||
int status;
|
||||
if(waitpid(dbg_pid, &status, 0) == dbg_pid &&
|
||||
(WIFEXITED(status) || WIFSIGNALED(status)))
|
||||
{
|
||||
/* The debug process died before it could kill us */
|
||||
raise(signum);
|
||||
break;
|
||||
}
|
||||
} while(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void crash_handler(const char *logfile)
|
||||
{
|
||||
const char *sigdesc = "";
|
||||
const char *sigdesc = "";
|
||||
int i;
|
||||
|
||||
if(fread(&crash_info, sizeof(crash_info), 1, stdin) != 1)
|
||||
{
|
||||
fprintf(stderr, "!!! Failed to retrieve info from crashed process\n");
|
||||
exit(1);
|
||||
}
|
||||
if(fread(&crash_info, sizeof(crash_info), 1, stdin) != 1)
|
||||
{
|
||||
fprintf(stderr, "!!! Failed to retrieve info from crashed process\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Get the signal description */
|
||||
for(i = 0;signals[i].name;++i)
|
||||
{
|
||||
if(signals[i].signum == crash_info.signum)
|
||||
{
|
||||
sigdesc = signals[i].name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Get the signal description */
|
||||
for(i = 0;signals[i].name;++i)
|
||||
{
|
||||
if(signals[i].signum == crash_info.signum)
|
||||
{
|
||||
sigdesc = signals[i].name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(crash_info.has_siginfo)
|
||||
{
|
||||
switch(crash_info.signum)
|
||||
{
|
||||
case SIGSEGV:
|
||||
for(i = 0;sigsegv_codes[i].name;++i)
|
||||
{
|
||||
if(sigsegv_codes[i].code == crash_info.siginfo.si_code)
|
||||
{
|
||||
sigdesc = sigsegv_codes[i].name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
if(crash_info.has_siginfo)
|
||||
{
|
||||
switch(crash_info.signum)
|
||||
{
|
||||
case SIGSEGV:
|
||||
for(i = 0;sigsegv_codes[i].name;++i)
|
||||
{
|
||||
if(sigsegv_codes[i].code == crash_info.siginfo.si_code)
|
||||
{
|
||||
sigdesc = sigsegv_codes[i].name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SIGFPE:
|
||||
for(i = 0;sigfpe_codes[i].name;++i)
|
||||
{
|
||||
if(sigfpe_codes[i].code == crash_info.siginfo.si_code)
|
||||
{
|
||||
sigdesc = sigfpe_codes[i].name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SIGFPE:
|
||||
for(i = 0;sigfpe_codes[i].name;++i)
|
||||
{
|
||||
if(sigfpe_codes[i].code == crash_info.siginfo.si_code)
|
||||
{
|
||||
sigdesc = sigfpe_codes[i].name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SIGILL:
|
||||
for(i = 0;sigill_codes[i].name;++i)
|
||||
{
|
||||
if(sigill_codes[i].code == crash_info.siginfo.si_code)
|
||||
{
|
||||
sigdesc = sigill_codes[i].name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SIGILL:
|
||||
for(i = 0;sigill_codes[i].name;++i)
|
||||
{
|
||||
if(sigill_codes[i].code == crash_info.siginfo.si_code)
|
||||
{
|
||||
sigdesc = sigill_codes[i].name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SIGBUS:
|
||||
for(i = 0;sigbus_codes[i].name;++i)
|
||||
{
|
||||
if(sigbus_codes[i].code == crash_info.siginfo.si_code)
|
||||
{
|
||||
sigdesc = sigbus_codes[i].name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "%s (signal %i)\n", sigdesc, crash_info.signum);
|
||||
if(crash_info.has_siginfo)
|
||||
fprintf(stderr, "Address: %p\n", crash_info.siginfo.si_addr);
|
||||
fputc('\n', stderr);
|
||||
case SIGBUS:
|
||||
for(i = 0;sigbus_codes[i].name;++i)
|
||||
{
|
||||
if(sigbus_codes[i].code == crash_info.siginfo.si_code)
|
||||
{
|
||||
sigdesc = sigbus_codes[i].name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "%s (signal %i)\n", sigdesc, crash_info.signum);
|
||||
if(crash_info.has_siginfo)
|
||||
fprintf(stderr, "Address: %p\n", crash_info.siginfo.si_addr);
|
||||
fputc('\n', stderr);
|
||||
|
||||
if(logfile)
|
||||
{
|
||||
/* Create crash log file and redirect shell output to it */
|
||||
if(freopen(logfile, "wa", stdout) != stdout)
|
||||
{
|
||||
fprintf(stderr, "!!! Could not create %s following signal\n", logfile);
|
||||
exit(1);
|
||||
}
|
||||
fprintf(stderr, "Generating %s and killing process %d, please wait... ", logfile, crash_info.pid);
|
||||
if(logfile)
|
||||
{
|
||||
/* Create crash log file and redirect shell output to it */
|
||||
if(freopen(logfile, "wa", stdout) != stdout)
|
||||
{
|
||||
fprintf(stderr, "!!! Could not create %s following signal\n", logfile);
|
||||
exit(1);
|
||||
}
|
||||
fprintf(stderr, "Generating %s and killing process %d, please wait... ", logfile, crash_info.pid);
|
||||
|
||||
printf("*** Fatal Error ***\n"
|
||||
"%s (signal %i)\n", sigdesc, crash_info.signum);
|
||||
if(crash_info.has_siginfo)
|
||||
printf("Address: %p\n", crash_info.siginfo.si_addr);
|
||||
fputc('\n', stdout);
|
||||
fflush(stdout);
|
||||
}
|
||||
printf("*** Fatal Error ***\n"
|
||||
"%s (signal %i)\n", sigdesc, crash_info.signum);
|
||||
if(crash_info.has_siginfo)
|
||||
printf("Address: %p\n", crash_info.siginfo.si_addr);
|
||||
fputc('\n', stdout);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
sys_info();
|
||||
sys_info();
|
||||
|
||||
crash_info.buf[sizeof(crash_info.buf)-1] = '\0';
|
||||
printf("%s\n", crash_info.buf);
|
||||
fflush(stdout);
|
||||
crash_info.buf[sizeof(crash_info.buf)-1] = '\0';
|
||||
printf("%s\n", crash_info.buf);
|
||||
fflush(stdout);
|
||||
|
||||
if(crash_info.pid > 0)
|
||||
{
|
||||
gdb_info(crash_info.pid);
|
||||
kill(crash_info.pid, SIGKILL);
|
||||
}
|
||||
if(crash_info.pid > 0)
|
||||
{
|
||||
gdb_info(crash_info.pid);
|
||||
kill(crash_info.pid, SIGKILL);
|
||||
}
|
||||
|
||||
if(logfile)
|
||||
{
|
||||
if(logfile)
|
||||
{
|
||||
char 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 !";
|
||||
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*))
|
||||
{
|
||||
struct sigaction sa;
|
||||
stack_t altss;
|
||||
int retval;
|
||||
struct sigaction sa;
|
||||
stack_t altss;
|
||||
int retval;
|
||||
|
||||
if(argc == 2 && strcmp(argv[1], crash_switch) == 0)
|
||||
crash_handler(logfile);
|
||||
if(argc == 2 && strcmp(argv[1], crash_switch) == 0)
|
||||
crash_handler(logfile);
|
||||
|
||||
cc_user_info = user_info;
|
||||
cc_user_info = user_info;
|
||||
|
||||
if(argv[0][0] == '/')
|
||||
snprintf(argv0, sizeof(argv0), "%s", argv[0]);
|
||||
else
|
||||
{
|
||||
getcwd(argv0, sizeof(argv0));
|
||||
retval = strlen(argv0);
|
||||
snprintf(argv0+retval, sizeof(argv0)-retval, "/%s", argv[0]);
|
||||
}
|
||||
if(argv[0][0] == '/')
|
||||
snprintf(argv0, sizeof(argv0), "%s", argv[0]);
|
||||
else
|
||||
{
|
||||
getcwd(argv0, sizeof(argv0));
|
||||
retval = strlen(argv0);
|
||||
snprintf(argv0+retval, sizeof(argv0)-retval, "/%s", argv[0]);
|
||||
}
|
||||
|
||||
/* Set an alternate signal stack so SIGSEGVs caused by stack overflows
|
||||
* still run */
|
||||
altss.ss_sp = altstack;
|
||||
altss.ss_flags = 0;
|
||||
altss.ss_size = sizeof(altstack);
|
||||
sigaltstack(&altss, NULL);
|
||||
/* Set an alternate signal stack so SIGSEGVs caused by stack overflows
|
||||
* still run */
|
||||
altss.ss_sp = altstack;
|
||||
altss.ss_flags = 0;
|
||||
altss.ss_size = sizeof(altstack);
|
||||
sigaltstack(&altss, NULL);
|
||||
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_sigaction = crash_catcher;
|
||||
sa.sa_flags = SA_RESETHAND | SA_NODEFER | SA_SIGINFO | SA_ONSTACK;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_sigaction = crash_catcher;
|
||||
sa.sa_flags = SA_RESETHAND | SA_NODEFER | SA_SIGINFO | SA_ONSTACK;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
|
||||
retval = 0;
|
||||
while(num_signals--)
|
||||
{
|
||||
retval = 0;
|
||||
while(num_signals--)
|
||||
{
|
||||
if((*signals != SIGSEGV && *signals != SIGILL && *signals != SIGFPE && *signals != SIGABRT &&
|
||||
*signals != SIGBUS) || sigaction(*signals, &sa, NULL) == -1)
|
||||
{
|
||||
*signals = 0;
|
||||
retval = -1;
|
||||
}
|
||||
++signals;
|
||||
}
|
||||
return retval;
|
||||
*signals != SIGBUS) || sigaction(*signals, &sa, NULL) == -1)
|
||||
{
|
||||
*signals = 0;
|
||||
retval = -1;
|
||||
}
|
||||
++signals;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include <MyGUI_WidgetManager.h>
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include <components/compiler/extensions0.hpp>
|
||||
|
||||
#include <components/bsa/bsa_archive.hpp>
|
||||
|
@ -41,8 +43,7 @@
|
|||
|
||||
#include "mwmechanics/mechanicsmanagerimp.hpp"
|
||||
|
||||
|
||||
#include <SDL.h>
|
||||
#include "mwstate/statemanagerimp.hpp"
|
||||
|
||||
void OMW::Engine::executeLocalScripts()
|
||||
{
|
||||
|
@ -65,10 +66,6 @@ void OMW::Engine::executeLocalScripts()
|
|||
localScripts.setIgnore (MWWorld::Ptr());
|
||||
}
|
||||
|
||||
void OMW::Engine::setAnimationVerbose(bool animverbose)
|
||||
{
|
||||
}
|
||||
|
||||
bool OMW::Engine::frameStarted (const Ogre::FrameEvent& evt)
|
||||
{
|
||||
bool paused = MWBase::Environment::get().getWindowManager()->isGuiMode();
|
||||
|
@ -92,31 +89,47 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
|
|||
if (mUseSound)
|
||||
MWBase::Environment::get().getSoundManager()->update(frametime);
|
||||
|
||||
// global scripts
|
||||
MWBase::Environment::get().getScriptManager()->getGlobalScripts().run();
|
||||
bool paused = MWBase::Environment::get().getWindowManager()->isGuiMode();
|
||||
|
||||
bool changed = MWBase::Environment::get().getWorld()->hasCellChanged();
|
||||
// update game state
|
||||
MWBase::Environment::get().getStateManager()->update (frametime);
|
||||
|
||||
// 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 (MWBase::Environment::get().getStateManager()->getState()==
|
||||
MWBase::StateManager::State_Running)
|
||||
{
|
||||
// global scripts
|
||||
MWBase::Environment::get().getScriptManager()->getGlobalScripts().run();
|
||||
|
||||
// passing of time
|
||||
if (!MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||
MWBase::Environment::get().getWorld()->advanceTime(
|
||||
frametime*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/3600);
|
||||
bool changed = MWBase::Environment::get().getWorld()->hasCellChanged();
|
||||
|
||||
// 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
|
||||
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
|
||||
MWBase::Environment::get().getWorld()->update(frametime, MWBase::Environment::get().getWindowManager()->isGuiMode());
|
||||
MWBase::Environment::get().getWorld()->update(frametime, paused);
|
||||
|
||||
// update GUI
|
||||
Ogre::RenderWindow* window = mOgre->getWindow();
|
||||
|
@ -139,9 +152,10 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager)
|
|||
: mOgre (0)
|
||||
, mFpsLevel(0)
|
||||
, mVerboseScripts (false)
|
||||
, mNewGame (false)
|
||||
, mSkipMenu (false)
|
||||
, mUseSound (true)
|
||||
, mCompileAll (false)
|
||||
, mWarningsMode (1)
|
||||
, mScriptContext (0)
|
||||
, mFSStrict (false)
|
||||
, mScriptConsoleMode (false)
|
||||
|
@ -161,6 +175,7 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager)
|
|||
//kindly ask SDL not to trash our OGL context
|
||||
//might this be related to http://bugzilla.libsdl.org/show_bug.cgi?id=748 ?
|
||||
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software");
|
||||
SDL_SetMainReady();
|
||||
if(SDL_Init(flags) != 0)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (file.find_last_of(".") == std::string::npos)
|
||||
{
|
||||
throw std::runtime_error("Missing extension in content file!");
|
||||
}
|
||||
|
||||
mContentFiles.push_back(file);
|
||||
mContentFiles.push_back(file);
|
||||
}
|
||||
|
||||
void OMW::Engine::setScriptsVerbosity(bool scriptsVerbosity)
|
||||
|
@ -281,9 +291,9 @@ void OMW::Engine::setScriptsVerbosity(bool 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)
|
||||
|
@ -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.");
|
||||
|
||||
// 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))
|
||||
settings.loadUser(settingspath);
|
||||
else if (boost::filesystem::exists(localdefault))
|
||||
|
@ -313,18 +323,25 @@ std::string OMW::Engine::loadSettings (Settings::Manager & settings)
|
|||
|
||||
// load nif overrides
|
||||
NifOverrides::Overrides nifOverrides;
|
||||
if (boost::filesystem::exists(mCfgMgr.getLocalPath().string() + "/transparency-overrides.cfg"))
|
||||
nifOverrides.loadTransparencyOverrides(mCfgMgr.getLocalPath().string() + "/transparency-overrides.cfg");
|
||||
else if (boost::filesystem::exists(mCfgMgr.getGlobalPath().string() + "/transparency-overrides.cfg"))
|
||||
nifOverrides.loadTransparencyOverrides(mCfgMgr.getGlobalPath().string() + "/transparency-overrides.cfg");
|
||||
|
||||
settings.setBool("hardware cursors", "GUI", true);
|
||||
std::string transparencyOverrides = "/transparency-overrides.cfg";
|
||||
std::string materialOverrides = "/material-overrides.cfg";
|
||||
if (boost::filesystem::exists(mCfgMgr.getLocalPath().string() + transparencyOverrides))
|
||||
nifOverrides.loadTransparencyOverrides(mCfgMgr.getLocalPath().string() + transparencyOverrides);
|
||||
else if (boost::filesystem::exists(mCfgMgr.getGlobalPath().string() + transparencyOverrides))
|
||||
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;
|
||||
}
|
||||
|
||||
void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
||||
{
|
||||
mEnvironment.setStateManager (
|
||||
new MWState::StateManager (mCfgMgr.getUserDataPath() / "saves", mContentFiles.at (0)));
|
||||
|
||||
Nif::NIFFile::CacheLock cachelock;
|
||||
|
||||
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
|
||||
// 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);
|
||||
MWInput::InputManager* input = new MWInput::InputManager (*mOgre, *this, keybinderUser, keybinderUserExists, mGrab);
|
||||
mEnvironment.setInputManager (input);
|
||||
|
@ -391,10 +408,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
|||
input->setPlayer(&mEnvironment.getWorld()->getPlayer());
|
||||
|
||||
window->initUI();
|
||||
if (mNewGame)
|
||||
// still redundant work here: recreate CharacterCreation(),
|
||||
// double update visibility etc.
|
||||
window->setNewGame(true);
|
||||
window->renderWorldMap();
|
||||
|
||||
//Load translation data
|
||||
|
@ -402,7 +415,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
|||
for (size_t i = 0; i < mContentFiles.size(); i++)
|
||||
mTranslationDataStorage.loadTranslationData(mFileCollections, mContentFiles[i]);
|
||||
|
||||
Compiler::registerExtensions (mExtensions);
|
||||
Compiler::registerExtensions (mExtensions);
|
||||
|
||||
// Create sound system
|
||||
mEnvironment.setSoundManager (new MWSound::SoundManager(mUseSound));
|
||||
|
@ -412,7 +425,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
|||
mScriptContext->setExtensions (&mExtensions);
|
||||
|
||||
mEnvironment.setScriptManager (new MWScript::ScriptManager (MWBase::Environment::get().getWorld()->getStore(),
|
||||
mVerboseScripts, *mScriptContext));
|
||||
mVerboseScripts, *mScriptContext, mWarningsMode));
|
||||
|
||||
// Create game mechanics system
|
||||
MWMechanics::MechanicsManager* mechanics = new MWMechanics::MechanicsManager;
|
||||
|
@ -426,12 +439,12 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
|||
mechanics->buildPlayer();
|
||||
window->updatePlayer();
|
||||
|
||||
if (!mNewGame)
|
||||
{
|
||||
// load cell
|
||||
ESM::Position pos;
|
||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
// load cell
|
||||
ESM::Position pos;
|
||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
|
||||
if (!mCellName.empty())
|
||||
{
|
||||
if (world->findExteriorPosition(mCellName, pos)) {
|
||||
world->changeToExteriorCell (pos);
|
||||
}
|
||||
|
@ -441,7 +454,11 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
|||
}
|
||||
}
|
||||
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;
|
||||
event.timeSinceLastEvent = 0;
|
||||
|
@ -467,7 +484,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
|||
|
||||
void OMW::Engine::go()
|
||||
{
|
||||
assert (!mCellName.empty());
|
||||
assert (!mContentFiles.empty());
|
||||
assert (!mOgre);
|
||||
|
||||
|
@ -488,8 +504,14 @@ void OMW::Engine::go()
|
|||
if (!mStartupScript.empty())
|
||||
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
|
||||
while (!mEnvironment.getRequestExit())
|
||||
while (!mEnvironment.get().getStateManager()->hasQuitRequest())
|
||||
Ogre::Root::getSingleton().renderOneFrame();
|
||||
|
||||
// Save user settings
|
||||
|
@ -508,15 +530,20 @@ void OMW::Engine::activate()
|
|||
if (ptr.isEmpty())
|
||||
return;
|
||||
|
||||
if (ptr.getClass().getName(ptr) == "") // objects without name presented to user can never be activated
|
||||
return;
|
||||
|
||||
MWScript::InterpreterContext interpreterContext (&ptr.getRefData().getLocals(), ptr);
|
||||
|
||||
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);
|
||||
|
||||
std::string script = MWWorld::Class::get (ptr).getScript (ptr);
|
||||
|
||||
MWBase::Environment::get().getWorld()->breakInvisibility(MWBase::Environment::get().getWorld()->getPlayerPtr());
|
||||
|
||||
if (!script.empty())
|
||||
{
|
||||
MWBase::Environment::get().getWorld()->getLocalScripts().setIgnore (ptr);
|
||||
|
@ -534,7 +561,7 @@ void OMW::Engine::screenshot()
|
|||
// Count screenshots.
|
||||
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
|
||||
std::ostringstream stream;
|
||||
|
@ -586,8 +613,12 @@ void OMW::Engine::setStartupScript (const std::string& path)
|
|||
mStartupScript = path;
|
||||
}
|
||||
|
||||
|
||||
void OMW::Engine::setActivationDistanceOverride (int distance)
|
||||
{
|
||||
mActivationDistanceOverride = distance;
|
||||
}
|
||||
|
||||
void OMW::Engine::setWarningsMode (int mode)
|
||||
{
|
||||
mWarningsMode = mode;
|
||||
}
|
|
@ -71,9 +71,10 @@ namespace OMW
|
|||
std::vector<std::string> mContentFiles;
|
||||
int mFpsLevel;
|
||||
bool mVerboseScripts;
|
||||
bool mNewGame;
|
||||
bool mSkipMenu;
|
||||
bool mUseSound;
|
||||
bool mCompileAll;
|
||||
int mWarningsMode;
|
||||
std::string mFocusName;
|
||||
std::map<std::string,std::string> mFallbackMap;
|
||||
bool mScriptConsoleMode;
|
||||
|
@ -151,8 +152,7 @@ namespace OMW
|
|||
/// Disable or enable all sounds
|
||||
void setSoundUsage(bool soundUsage);
|
||||
|
||||
/// Start as a new game.
|
||||
void setNewGame(bool newGame);
|
||||
void setSkipMenu (bool skipMenu);
|
||||
|
||||
void setGrabMouse(bool grab) { mGrab = grab; }
|
||||
|
||||
|
@ -171,8 +171,6 @@ namespace OMW
|
|||
/// Font encoding
|
||||
void setEncoding(const ToUTF8::FromType& encoding);
|
||||
|
||||
void setAnimationVerbose(bool animverbose);
|
||||
|
||||
void setFallbackValues(std::map<std::string,std::string> map);
|
||||
|
||||
/// Enable console-only script functionality
|
||||
|
@ -184,6 +182,8 @@ namespace OMW
|
|||
/// Override the game setting specified activation distance.
|
||||
void setActivationDistanceOverride (int distance);
|
||||
|
||||
void setWarningsMode (int mode);
|
||||
|
||||
private:
|
||||
Files::ConfigurationManager& mCfgMgr;
|
||||
};
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
#include <iostream>
|
||||
#include <cstdio>
|
||||
|
||||
#include <components/version/version.hpp>
|
||||
#include <components/files/configurationmanager.hpp>
|
||||
|
||||
#include <SDL_messagebox.h>
|
||||
#include <SDL_main.h>
|
||||
#include <SDL.h>
|
||||
#include "engine.hpp"
|
||||
|
||||
#if defined(_WIN32) && !defined(_CONSOLE)
|
||||
|
@ -12,6 +12,7 @@
|
|||
#include <boost/iostreams/stream_buffer.hpp>
|
||||
|
||||
// For OutputDebugString
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
// makes __argc and __argv available on windows
|
||||
#include <cstdlib>
|
||||
|
@ -30,8 +31,6 @@ extern int is_debugger_attached(void);
|
|||
#include <OSX/macUtils.h>
|
||||
#endif
|
||||
|
||||
#include "config.hpp"
|
||||
|
||||
#include <boost/version.hpp>
|
||||
/**
|
||||
* 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"),
|
||||
"set resources directory")
|
||||
|
||||
("start", bpo::value<std::string>()->default_value("Beshara"),
|
||||
("start", bpo::value<std::string>()->default_value(""),
|
||||
"set initial cell")
|
||||
|
||||
("content", bpo::value<StringsVector>()->default_value(StringsVector(), "")
|
||||
->multitoken(), "content file(s): esm/esp, or omwgame/omwaddon")
|
||||
|
||||
("anim-verbose", bpo::value<bool>()->implicit_value(true)
|
||||
->default_value(false), "output animation indices files")
|
||||
|
||||
("nosound", bpo::value<bool>()->implicit_value(true)
|
||||
("no-sound", bpo::value<bool>()->implicit_value(true)
|
||||
->default_value(false), "disable all sounds")
|
||||
|
||||
("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(""),
|
||||
"select a file containing a list of console commands that is executed on startup")
|
||||
|
||||
("new-game", bpo::value<bool>()->implicit_value(true)
|
||||
->default_value(false), "activate char gen/new game mechanics")
|
||||
("script-warn", bpo::value<int>()->implicit_value (1)
|
||||
->default_value (1),
|
||||
"handling of warnings when compiling scripts\n"
|
||||
"\t0 - ignore warning\n"
|
||||
"\t1 - show warning but consider script as correctly compiled anyway\n"
|
||||
"\t2 - treat warnings as errors")
|
||||
|
||||
("skip-menu", bpo::value<bool>()->implicit_value(true)
|
||||
->default_value(false), "skip main menu on game startup")
|
||||
|
||||
("fs-strict", bpo::value<bool>()->implicit_value(true)
|
||||
->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::notify(variables);
|
||||
|
||||
cfgMgr.readConfiguration(variables, desc);
|
||||
|
||||
bool run = true;
|
||||
|
||||
if (variables.count ("help"))
|
||||
|
@ -188,6 +189,8 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
|||
if (!run)
|
||||
return false;
|
||||
|
||||
cfgMgr.readConfiguration(variables, desc);
|
||||
|
||||
engine.setGrabMouse(!variables.count("no-grab"));
|
||||
|
||||
// Font encoding settings
|
||||
|
@ -235,17 +238,17 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
|||
|
||||
// startup-settings
|
||||
engine.setCell(variables["start"].as<std::string>());
|
||||
engine.setNewGame(variables["new-game"].as<bool>());
|
||||
engine.setSkipMenu (variables["skip-menu"].as<bool>());
|
||||
|
||||
// other settings
|
||||
engine.setSoundUsage(!variables["nosound"].as<bool>());
|
||||
engine.setSoundUsage(!variables["no-sound"].as<bool>());
|
||||
engine.setScriptsVerbosity(variables["script-verbose"].as<bool>());
|
||||
engine.setCompileAll(variables["script-all"].as<bool>());
|
||||
engine.setAnimationVerbose(variables["anim-verbose"].as<bool>());
|
||||
engine.setFallbackValues(variables["fallback"].as<FallbackMap>().mMap);
|
||||
engine.setScriptConsoleMode (variables["script-console"].as<bool>());
|
||||
engine.setStartupScript (variables["script-run"].as<std::string>());
|
||||
engine.setActivationDistanceOverride (variables["activate-dist"].as<int>());
|
||||
engine.setWarningsMode (variables["script-warn"].as<int>());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -283,7 +286,7 @@ int main(int argc, char**argv)
|
|||
catch (std::exception &e)
|
||||
{
|
||||
#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;
|
||||
else
|
||||
#endif
|
||||
|
|
|
@ -3,6 +3,14 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
#include <libs/platform/stdint.h>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
class ESMReader;
|
||||
class ESMWriter;
|
||||
}
|
||||
|
||||
namespace MWWorld
|
||||
{
|
||||
class Ptr;
|
||||
|
@ -51,7 +59,13 @@ namespace MWBase
|
|||
|
||||
virtual void persuade (int type) = 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 "inputmanager.hpp"
|
||||
#include "windowmanager.hpp"
|
||||
#include "statemanager.hpp"
|
||||
|
||||
MWBase::Environment *MWBase::Environment::sThis = 0;
|
||||
bool MWBase::Environment::sExit = false;
|
||||
|
||||
MWBase::Environment::Environment()
|
||||
: 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);
|
||||
sThis = this;
|
||||
|
@ -69,6 +70,11 @@ void MWBase::Environment::setInputManager (InputManager *inputManager)
|
|||
mInputManager = inputManager;
|
||||
}
|
||||
|
||||
void MWBase::Environment::setStateManager (StateManager *stateManager)
|
||||
{
|
||||
mStateManager = stateManager;
|
||||
}
|
||||
|
||||
void MWBase::Environment::setFrameDuration (float duration)
|
||||
{
|
||||
mFrameDuration = duration;
|
||||
|
@ -122,6 +128,12 @@ MWBase::InputManager *MWBase::Environment::getInputManager() const
|
|||
return mInputManager;
|
||||
}
|
||||
|
||||
MWBase::StateManager *MWBase::Environment::getStateManager() const
|
||||
{
|
||||
assert (mStateManager);
|
||||
return mStateManager;
|
||||
}
|
||||
|
||||
float MWBase::Environment::getFrameDuration() const
|
||||
{
|
||||
return mFrameDuration;
|
||||
|
@ -141,17 +153,20 @@ void MWBase::Environment::cleanup()
|
|||
delete mScriptManager;
|
||||
mScriptManager = 0;
|
||||
|
||||
delete mWindowManager;
|
||||
mWindowManager = 0;
|
||||
|
||||
delete mWorld;
|
||||
mWorld = 0;
|
||||
|
||||
delete mSoundManager;
|
||||
mSoundManager = 0;
|
||||
|
||||
delete mWindowManager;
|
||||
mWindowManager = 0;
|
||||
|
||||
delete mInputManager;
|
||||
mInputManager = 0;
|
||||
|
||||
delete mStateManager;
|
||||
mStateManager = 0;
|
||||
}
|
||||
|
||||
const MWBase::Environment& MWBase::Environment::get()
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace MWBase
|
|||
class MechanicsManager;
|
||||
class InputManager;
|
||||
class WindowManager;
|
||||
class StateManager;
|
||||
|
||||
/// \brief Central hub for mw-subsystems
|
||||
///
|
||||
|
@ -30,10 +31,9 @@ namespace MWBase
|
|||
DialogueManager *mDialogueManager;
|
||||
Journal *mJournal;
|
||||
InputManager *mInputManager;
|
||||
StateManager *mStateManager;
|
||||
float mFrameDuration;
|
||||
|
||||
static bool sExit;
|
||||
|
||||
Environment (const Environment&);
|
||||
///< not implemented
|
||||
|
||||
|
@ -46,9 +46,6 @@ namespace MWBase
|
|||
|
||||
~Environment();
|
||||
|
||||
static void setRequestExit () { sExit = true; }
|
||||
static bool getRequestExit () { return sExit; }
|
||||
|
||||
void setWorld (World *world);
|
||||
|
||||
void setSoundManager (SoundManager *soundManager);
|
||||
|
@ -65,6 +62,8 @@ namespace MWBase
|
|||
|
||||
void setInputManager (InputManager *inputManager);
|
||||
|
||||
void setStateManager (StateManager *stateManager);
|
||||
|
||||
void setFrameDuration (float duration);
|
||||
///< Set length of current frame in seconds.
|
||||
|
||||
|
@ -84,6 +83,8 @@ namespace MWBase
|
|||
|
||||
InputManager *getInputManager() const;
|
||||
|
||||
StateManager *getStateManager() const;
|
||||
|
||||
float getFrameDuration() const;
|
||||
|
||||
void cleanup();
|
||||
|
|
|
@ -5,10 +5,18 @@
|
|||
#include <deque>
|
||||
#include <map>
|
||||
|
||||
#include <libs/platform/stdint.h>
|
||||
|
||||
#include "../mwdialogue/journalentry.hpp"
|
||||
#include "../mwdialogue/topic.hpp"
|
||||
#include "../mwdialogue/quest.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
class ESMReader;
|
||||
class ESMWriter;
|
||||
}
|
||||
|
||||
namespace MWBase
|
||||
{
|
||||
/// \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;
|
||||
///< 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;
|
||||
///< Iterator pointing to the begin of the main journal.
|
||||
|
@ -69,6 +77,12 @@ namespace MWBase
|
|||
|
||||
virtual TTopicIter topicEnd() const = 0;
|
||||
///< 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 <vector>
|
||||
#include <list>
|
||||
|
||||
namespace Ogre
|
||||
{
|
||||
|
@ -76,8 +77,12 @@ namespace MWBase
|
|||
virtual void setPlayerClass (const ESM::Class& class_) = 0;
|
||||
///< Set player class to custom class.
|
||||
|
||||
virtual void restoreDynamicStats() = 0;
|
||||
///< If the player is sleeping, this should be called every hour.
|
||||
virtual void rest(bool sleep) = 0;
|
||||
///< 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;
|
||||
///< 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;
|
||||
///< 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
|
||||
{
|
||||
PT_Admire,
|
||||
|
@ -101,28 +136,35 @@ namespace MWBase
|
|||
float currentTemporaryDispositionDelta, bool& success, float& tempChange, float& permChange) = 0;
|
||||
///< Perform a persuasion action on NPC
|
||||
|
||||
virtual void forceStateUpdate(const MWWorld::Ptr &ptr) = 0;
|
||||
///< Forces an object to refresh its animation state.
|
||||
virtual void forceStateUpdate(const MWWorld::Ptr &ptr) = 0;
|
||||
///< 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 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 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 bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName) = 0;
|
||||
|
||||
/// Update magic effects for an actor. Usually done automatically once per frame, but if we're currently
|
||||
/// paused we may want to do it manually (after equipping permanent enchantment)
|
||||
virtual void updateMagicEffects (const MWWorld::Ptr& ptr) = 0;
|
||||
/// Update magic effects for an actor. Usually done automatically once per frame, but if we're currently
|
||||
/// paused we may want to do it manually (after equipping permanent enchantment)
|
||||
virtual void updateMagicEffects (const MWWorld::Ptr& ptr) = 0;
|
||||
|
||||
virtual void toggleAI() = 0;
|
||||
virtual bool isAIActive() = 0;
|
||||
virtual void toggleAI() = 0;
|
||||
virtual bool isAIActive() = 0;
|
||||
|
||||
virtual void getObjectsInRange (const Ogre::Vector3& position, float radius, std::vector<MWWorld::Ptr>& objects) = 0;
|
||||
|
||||
///return the list of actors which are following the given actor (ie AiFollow is active and the target is the actor)
|
||||
virtual std::list<MWWorld::Ptr> getActorsFollowing(const MWWorld::Ptr& actor) = 0;
|
||||
|
||||
virtual void playerLoaded() = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -35,8 +35,6 @@ namespace MWBase
|
|||
|
||||
virtual ~ScriptManager() {}
|
||||
|
||||
virtual void resetGlobalScripts() = 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)
|
||||
|
||||
|
|
|
@ -147,6 +147,10 @@ namespace MWBase
|
|||
virtual void update(float duration) = 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;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
81
apps/openmw/mwbase/statemanager.hpp
Normal file
81
apps/openmw/mwbase/statemanager.hpp
Normal file
|
@ -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
|
||||
{
|
||||
struct Class;
|
||||
class ESMReader;
|
||||
class ESMWriter;
|
||||
}
|
||||
|
||||
namespace MWWorld
|
||||
|
@ -55,6 +57,12 @@ namespace MWGui
|
|||
class InventoryWindow;
|
||||
class ContainerWindow;
|
||||
class DialogueWindow;
|
||||
|
||||
enum ShowInDialogueMode {
|
||||
ShowInDialogueMode_IfPossible,
|
||||
ShowInDialogueMode_Only,
|
||||
ShowInDialogueMode_Never
|
||||
};
|
||||
}
|
||||
|
||||
namespace SFO
|
||||
|
@ -137,8 +145,8 @@ namespace MWBase
|
|||
virtual void wmUpdateFps(float fps, unsigned int triangleCount, unsigned int batchCount) = 0;
|
||||
|
||||
/// Set value for the given ID.
|
||||
virtual void setValue (const std::string& id, const MWMechanics::Stat<int>& value) = 0;
|
||||
virtual void setValue (int parSkill, const MWMechanics::Stat<float>& value) = 0;
|
||||
virtual void setValue (const std::string& id, const MWMechanics::AttributeValue& 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 std::string& 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 std::string getSelectedSpell() = 0;
|
||||
virtual void setSelectedSpell(const std::string& spellId, int successChancePercent) = 0;
|
||||
virtual void setSelectedEnchantItem(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;
|
||||
///< 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 removeStaticMessageBox() = 0;
|
||||
|
||||
virtual void enterPressed () = 0;
|
||||
virtual void activateKeyPressed () = 0;
|
||||
virtual int readPressedButton() = 0;
|
||||
///< returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox)
|
||||
|
||||
virtual void onFrame (float frameDuration) = 0;
|
||||
|
||||
/// \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::Stat<int> > getPlayerAttributeValues() = 0;
|
||||
virtual std::map<int, MWMechanics::SkillValue > getPlayerSkillValues() = 0;
|
||||
virtual std::map<int, MWMechanics::AttributeValue > getPlayerAttributeValues() = 0;
|
||||
virtual SkillList getPlayerMinorSkills() = 0;
|
||||
virtual SkillList getPlayerMajorSkills() = 0;
|
||||
|
||||
|
@ -281,12 +287,19 @@ namespace MWBase
|
|||
|
||||
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 Loading::Listener* getLoadingScreen() = 0;
|
||||
|
||||
/// Should the cursor be visible?
|
||||
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
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include <components/settings/settings.hpp>
|
||||
|
||||
|
@ -30,17 +31,18 @@ namespace OEngine
|
|||
namespace ESM
|
||||
{
|
||||
class ESMReader;
|
||||
class ESMWriter;
|
||||
struct Position;
|
||||
struct Cell;
|
||||
struct Class;
|
||||
struct Potion;
|
||||
struct Spell;
|
||||
struct NPC;
|
||||
struct CellId;
|
||||
}
|
||||
|
||||
namespace MWRender
|
||||
{
|
||||
class ExternalRendering;
|
||||
class Animation;
|
||||
}
|
||||
|
||||
|
@ -80,7 +82,6 @@ namespace MWBase
|
|||
Render_CollisionDebug,
|
||||
Render_Wireframe,
|
||||
Render_Pathgrid,
|
||||
Render_Compositors,
|
||||
Render_BoundingBoxes
|
||||
};
|
||||
|
||||
|
@ -96,13 +97,26 @@ namespace MWBase
|
|||
|
||||
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;
|
||||
///< \ŧ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 *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 toggleWater() = 0;
|
||||
|
@ -114,6 +128,7 @@ namespace MWBase
|
|||
virtual const MWWorld::Fallback *getFallback () const = 0;
|
||||
|
||||
virtual MWWorld::Player& getPlayer() = 0;
|
||||
virtual MWWorld::Ptr getPlayerPtr() = 0;
|
||||
|
||||
virtual const MWWorld::ESMStore& getStore() const = 0;
|
||||
|
||||
|
@ -131,7 +146,7 @@ namespace MWBase
|
|||
virtual Ogre::Vector2 getNorthVector (MWWorld::CellStore* cell) = 0;
|
||||
///< 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
|
||||
|
||||
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;
|
||||
///< 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 MWWorld::Globals::Data getGlobalVariable (const std::string& name) const = 0;
|
||||
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 float getGlobalFloat (const std::string& name) const = 0;
|
||||
///< Get value independently from real type.
|
||||
|
||||
virtual char getGlobalVariableType (const std::string& name) const = 0;
|
||||
///< Return ' ', if there is no global variable with this name.
|
||||
|
||||
virtual std::vector<std::string> getGlobals () const = 0;
|
||||
|
||||
virtual std::string getCurrentCellName() const = 0;
|
||||
virtual std::string getCellName (const MWWorld::CellStore *cell = 0) const = 0;
|
||||
///< Return name of the cell.
|
||||
///
|
||||
/// \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;
|
||||
//< Remove the script attached to ref from mLocalScripts
|
||||
|
@ -158,6 +183,10 @@ namespace MWBase
|
|||
///< Return a pointer to a liveCellRef with the given name.
|
||||
/// \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;
|
||||
///< Return a pointer to a liveCellRef with the given Ogre handle.
|
||||
|
||||
|
@ -182,8 +211,12 @@ namespace MWBase
|
|||
virtual void setDay (int day) = 0;
|
||||
///< Set in-game time day.
|
||||
|
||||
virtual int getDay() = 0;
|
||||
virtual int getMonth() = 0;
|
||||
virtual int getDay() const = 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;
|
||||
///< Return current in-game time stamp.
|
||||
|
@ -212,6 +245,8 @@ namespace MWBase
|
|||
virtual void changeToExteriorCell (const ESM::Position& position) = 0;
|
||||
///< 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;
|
||||
///< 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
|
||||
/// 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 void adjustPosition (const MWWorld::Ptr& ptr) = 0;
|
||||
|
@ -333,7 +368,7 @@ namespace MWBase
|
|||
virtual bool isSwimming(const MWWorld::Ptr &object) const = 0;
|
||||
///Is the head of the creature underwater?
|
||||
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 void togglePOV() = 0;
|
||||
|
@ -367,8 +402,6 @@ namespace MWBase
|
|||
|
||||
virtual void enableActorCollision(const MWWorld::Ptr& actor, bool enable) = 0;
|
||||
|
||||
virtual void setupExternalRendering (MWRender::ExternalRendering& rendering) = 0;
|
||||
|
||||
virtual int canRest() = 0;
|
||||
///< check if the player is allowed to rest \n
|
||||
/// 0 - yes \n
|
||||
|
@ -383,6 +416,7 @@ namespace MWBase
|
|||
virtual void playVideo(const std::string& name, bool allowSkipping) = 0;
|
||||
virtual void stopVideo() = 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
|
||||
/// \return false if exterior with given name not exists, true otherwise
|
||||
|
@ -415,10 +449,61 @@ namespace MWBase
|
|||
|
||||
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 launchProjectile (const std::string& id, bool stack, const ESM::EffectList& effects,
|
||||
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;
|
||||
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");
|
||||
}
|
||||
info.text = text;
|
||||
|
||||
return info;
|
||||
|
|
|
@ -124,10 +124,11 @@ namespace MWClass
|
|||
std::string text;
|
||||
text += "\n#{sQuality}: " + MWGui::ToolTips::toString(ref->mBase->mData.mQuality);
|
||||
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()) {
|
||||
text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner");
|
||||
text += MWGui::ToolTips::getMiscString(ref->mRef.mFaction, "Faction");
|
||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
|
||||
}
|
||||
info.text = text;
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include "../mwworld/physicssystem.hpp"
|
||||
#include "../mwworld/nullaction.hpp"
|
||||
#include "../mwworld/containerstore.hpp"
|
||||
#include "../mwworld/player.hpp"
|
||||
|
||||
#include "../mwrender/objects.hpp"
|
||||
#include "../mwrender/renderinginterface.hpp"
|
||||
|
@ -172,7 +171,7 @@ namespace MWClass
|
|||
if (ptr.getCellRef().mCharge == -1)
|
||||
return ref->mBase->mData.mValue;
|
||||
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()
|
||||
|
@ -248,10 +247,11 @@ namespace MWClass
|
|||
+ MWGui::ToolTips::toString(ref->mBase->mData.mHealth);
|
||||
|
||||
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()) {
|
||||
text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner");
|
||||
text += MWGui::ToolTips::getMiscString(ref->mRef.mFaction, "Faction");
|
||||
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
|
||||
{
|
||||
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
|
||||
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();
|
||||
slot!=slots_.first.end(); ++slot)
|
||||
if (npc.getClass().isNpc())
|
||||
{
|
||||
std::string npcRace = npc.get<ESM::NPC>()->mBase->mRace;
|
||||
|
||||
// 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);
|
||||
|
@ -306,29 +310,20 @@ namespace MWClass
|
|||
{
|
||||
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_LFoot || (*itr).mPart == ESM::PRT_RFoot)
|
||||
{
|
||||
return std::make_pair(0, "#{sNotifyMessage14}");
|
||||
}
|
||||
}
|
||||
if((*itr).mPart == ESM::PRT_Head)
|
||||
return std::make_pair(0, "#{sNotifyMessage13}");
|
||||
if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot)
|
||||
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)
|
||||
{
|
||||
MWWorld::ContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||
|
@ -371,12 +366,12 @@ namespace MWClass
|
|||
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 =
|
||||
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
|
||||
|
|
|
@ -79,7 +79,7 @@ namespace MWClass
|
|||
|
||||
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;
|
||||
};
|
||||
|
|
|
@ -136,10 +136,11 @@ namespace MWClass
|
|||
std::string text;
|
||||
|
||||
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()) {
|
||||
text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner");
|
||||
text += MWGui::ToolTips::getMiscString(ref->mRef.mFaction, "Faction");
|
||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
|
||||
}
|
||||
|
||||
|
@ -188,12 +189,12 @@ namespace MWClass
|
|||
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 =
|
||||
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
|
||||
|
|
|
@ -58,7 +58,7 @@ namespace MWClass
|
|||
|
||||
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;
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#include "../mwworld/cellstore.hpp"
|
||||
#include "../mwworld/physicssystem.hpp"
|
||||
#include "../mwworld/nullaction.hpp"
|
||||
#include "../mwworld/player.hpp"
|
||||
|
||||
#include "../mwgui/tooltips.hpp"
|
||||
|
||||
|
@ -191,10 +190,11 @@ namespace MWClass
|
|||
std::string text;
|
||||
|
||||
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()) {
|
||||
text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner");
|
||||
text += MWGui::ToolTips::getMiscString(ref->mRef.mFaction, "Faction");
|
||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script");
|
||||
}
|
||||
|
||||
|
@ -235,11 +235,12 @@ namespace MWClass
|
|||
// slots that this item can be equipped in
|
||||
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();
|
||||
slot!=slots_.first.end(); ++slot)
|
||||
if (npc.getClass().isNpc())
|
||||
{
|
||||
std::string npcRace = npc.get<ESM::NPC>()->mBase->mRace;
|
||||
|
||||
// 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);
|
||||
|
@ -247,25 +248,16 @@ namespace MWClass
|
|||
{
|
||||
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 (*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}");
|
||||
}
|
||||
if((*itr).mPart == ESM::PRT_Head)
|
||||
return std::make_pair(0, "#{sNotifyMessage13}");
|
||||
if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot)
|
||||
return std::make_pair(0, "#{sNotifyMessage15}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_pair (1, "");
|
||||
}
|
||||
|
||||
|
@ -287,12 +279,12 @@ namespace MWClass
|
|||
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 =
|
||||
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
|
||||
|
|
|
@ -71,7 +71,7 @@ namespace MWClass
|
|||
|
||||
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;
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "container.hpp"
|
||||
|
||||
#include <components/esm/loadcont.hpp>
|
||||
#include <components/esm/containerstate.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
@ -16,7 +17,6 @@
|
|||
#include "../mwworld/actionopen.hpp"
|
||||
#include "../mwworld/actiontrap.hpp"
|
||||
#include "../mwworld/physicssystem.hpp"
|
||||
#include "../mwworld/player.hpp"
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
|
||||
#include "../mwgui/tooltips.hpp"
|
||||
|
@ -53,7 +53,7 @@ namespace MWClass
|
|||
ptr.get<ESM::Container>();
|
||||
|
||||
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
|
||||
ptr.getRefData().setCustomData (data.release());
|
||||
|
@ -108,7 +108,7 @@ namespace MWClass
|
|||
const std::string lockedSound = "LockedChest";
|
||||
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);
|
||||
|
||||
bool needKey = ptr.getCellRef().mLockLevel>0;
|
||||
|
@ -216,6 +216,7 @@ namespace MWClass
|
|||
|
||||
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");
|
||||
}
|
||||
|
||||
|
@ -258,4 +259,26 @@ namespace MWClass
|
|||
|
||||
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;
|
||||
///< 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();
|
||||
|
||||
virtual std::string getModel(const MWWorld::Ptr &ptr) const;
|
||||
|
|
|
@ -2,10 +2,12 @@
|
|||
#include "creature.hpp"
|
||||
|
||||
#include <components/esm/loadcrea.hpp>
|
||||
#include <components/esm/creaturestate.hpp>
|
||||
|
||||
#include "../mwmechanics/creaturestats.hpp"
|
||||
#include "../mwmechanics/magiceffects.hpp"
|
||||
#include "../mwmechanics/movement.hpp"
|
||||
#include "../mwmechanics/spellcasting.hpp"
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
|
@ -26,22 +28,30 @@
|
|||
|
||||
#include "../mwgui/tooltips.hpp"
|
||||
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
|
||||
#include "../mwmechanics/npcstats.hpp"
|
||||
#include "../mwmechanics/combat.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
struct CustomData : public MWWorld::CustomData
|
||||
{
|
||||
MWMechanics::CreatureStats mCreatureStats;
|
||||
MWWorld::ContainerStore mContainerStore;
|
||||
MWWorld::ContainerStore* mContainerStore; // may be InventoryStore for some creatures
|
||||
MWMechanics::Movement mMovement;
|
||||
|
||||
virtual MWWorld::CustomData *clone() const;
|
||||
|
||||
CustomData() : mContainerStore(0) {}
|
||||
virtual ~CustomData() { delete mContainerStore; }
|
||||
};
|
||||
|
||||
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");
|
||||
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;
|
||||
}
|
||||
|
@ -68,14 +89,14 @@ namespace MWClass
|
|||
MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
|
||||
|
||||
// creature stats
|
||||
data->mCreatureStats.getAttribute(0).set (ref->mBase->mData.mStrength);
|
||||
data->mCreatureStats.getAttribute(1).set (ref->mBase->mData.mIntelligence);
|
||||
data->mCreatureStats.getAttribute(2).set (ref->mBase->mData.mWillpower);
|
||||
data->mCreatureStats.getAttribute(3).set (ref->mBase->mData.mAgility);
|
||||
data->mCreatureStats.getAttribute(4).set (ref->mBase->mData.mSpeed);
|
||||
data->mCreatureStats.getAttribute(5).set (ref->mBase->mData.mEndurance);
|
||||
data->mCreatureStats.getAttribute(6).set (ref->mBase->mData.mPersonality);
|
||||
data->mCreatureStats.getAttribute(7).set (ref->mBase->mData.mLuck);
|
||||
data->mCreatureStats.setAttribute(ESM::Attribute::Strength, ref->mBase->mData.mStrength);
|
||||
data->mCreatureStats.setAttribute(ESM::Attribute::Intelligence, ref->mBase->mData.mIntelligence);
|
||||
data->mCreatureStats.setAttribute(ESM::Attribute::Willpower, ref->mBase->mData.mWillpower);
|
||||
data->mCreatureStats.setAttribute(ESM::Attribute::Agility, ref->mBase->mData.mAgility);
|
||||
data->mCreatureStats.setAttribute(ESM::Attribute::Speed, ref->mBase->mData.mSpeed);
|
||||
data->mCreatureStats.setAttribute(ESM::Attribute::Endurance, ref->mBase->mData.mEndurance);
|
||||
data->mCreatureStats.setAttribute(ESM::Attribute::Personality, ref->mBase->mData.mPersonality);
|
||||
data->mCreatureStats.setAttribute(ESM::Attribute::Luck, ref->mBase->mData.mLuck);
|
||||
data->mCreatureStats.setHealth (ref->mBase->mData.mHealth);
|
||||
data->mCreatureStats.setMagicka (ref->mBase->mData.mMana);
|
||||
data->mCreatureStats.setFatigue (ref->mBase->mData.mFatigue);
|
||||
|
@ -84,10 +105,10 @@ namespace MWClass
|
|||
|
||||
data->mCreatureStats.getAiSequence().fill(ref->mBase->mAiPackage);
|
||||
|
||||
data->mCreatureStats.setAiSetting (0, ref->mBase->mAiData.mHello);
|
||||
data->mCreatureStats.setAiSetting (1, ref->mBase->mAiData.mFight);
|
||||
data->mCreatureStats.setAiSetting (2, ref->mBase->mAiData.mFlee);
|
||||
data->mCreatureStats.setAiSetting (3, ref->mBase->mAiData.mAlarm);
|
||||
data->mCreatureStats.setAiSetting (MWMechanics::CreatureStats::AI_Hello, ref->mBase->mAiData.mHello);
|
||||
data->mCreatureStats.setAiSetting (MWMechanics::CreatureStats::AI_Fight, ref->mBase->mAiData.mFight);
|
||||
data->mCreatureStats.setAiSetting (MWMechanics::CreatureStats::AI_Flee, ref->mBase->mAiData.mFlee);
|
||||
data->mCreatureStats.setAiSetting (MWMechanics::CreatureStats::AI_Alarm, ref->mBase->mAiData.mAlarm);
|
||||
|
||||
// spells
|
||||
for (std::vector<std::string>::const_iterator iter (ref->mBase->mSpells.mList.begin());
|
||||
|
@ -95,13 +116,23 @@ namespace MWClass
|
|||
data->mCreatureStats.getSpells().add (*iter);
|
||||
|
||||
// inventory
|
||||
data->mContainerStore.fill(ref->mBase->mInventory, getId(ptr),
|
||||
MWBase::Environment::get().getWorld()->getStore());
|
||||
|
||||
data->mContainerStore.add("gold_001", ref->mBase->mData.mGold, ptr);
|
||||
if (ref->mBase->mFlags & ESM::Creature::Weapon)
|
||||
data->mContainerStore = new MWWorld::InventoryStore();
|
||||
else
|
||||
data->mContainerStore = new MWWorld::ContainerStore();
|
||||
|
||||
// store
|
||||
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
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
|
||||
|
||||
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
|
||||
|
@ -163,6 +196,144 @@ namespace MWClass
|
|||
|
||||
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
|
||||
|
@ -189,18 +360,60 @@ namespace MWClass
|
|||
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);
|
||||
float health = getCreatureStats(ptr).getHealth().getCurrent() - damage;
|
||||
setActorHealth(ptr, health, attacker);
|
||||
float health = getCreatureStats(ptr).getHealth().getCurrent() - damage;
|
||||
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());
|
||||
fatigue.setCurrent(fatigue.getCurrent() - damage);
|
||||
getCreatureStats(ptr).setFatigue(fatigue);
|
||||
case ESM::Skill::LightArmor:
|
||||
sndMgr->playSound3D(ptr, "Light Armor Hit", 1.0f, 1.0f);
|
||||
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));
|
||||
}
|
||||
|
||||
MWWorld::ContainerStore& Creature::getContainerStore (const MWWorld::Ptr& ptr)
|
||||
const
|
||||
MWWorld::ContainerStore& Creature::getContainerStore (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
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
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::Creature> *ref =
|
||||
ptr.get<ESM::Creature>();
|
||||
MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
|
||||
|
||||
return ref->mBase->mScript;
|
||||
}
|
||||
|
@ -284,10 +512,51 @@ namespace MWClass
|
|||
float Creature::getSpeed(const MWWorld::Ptr &ptr) const
|
||||
{
|
||||
MWMechanics::CreatureStats& stats = getCreatureStats(ptr);
|
||||
|
||||
float walkSpeed = fMinWalkSpeedCreature->getFloat() + 0.01 * stats.getAttribute(ESM::Attribute::Speed).getModified()
|
||||
* (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
|
||||
|
@ -413,6 +682,14 @@ namespace MWClass
|
|||
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)
|
||||
{
|
||||
if(name == "left")
|
||||
|
@ -451,6 +728,76 @@ namespace MWClass
|
|||
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::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…
Reference in a new issue