Merge branch 'master' of https://github.com/OpenMW/openmw into osg

Conflicts:
	apps/opencs/model/doc/document.cpp
	apps/opencs/model/doc/documentmanager.cpp
	components/CMakeLists.txt
	components/bsa/resources.cpp
	components/nif/data.hpp
	components/nif/node.cpp
	components/nifogre/mesh.hpp
	components/nifogre/ogrenifloader.cpp
	components/nifogre/particles.cpp
c++11
scrawl 10 years ago
commit 236d628884

@ -21,6 +21,14 @@ addons:
build_command_prepend: "cmake ."
build_command: "make -j3"
branch_pattern: coverity_scan
matrix:
include:
- os: linux
env:
ANALYZE="scan-build-3.6 --use-cc clang-3.6 --use-c++ clang++-3.6 "
compiler: clang
allow_failures:
- env: ANALYZE="scan-build-3.6 --use-cc clang-3.6 --use-c++ clang++-3.6 "
before_install:
- if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./CI/before_install.linux.sh; fi
@ -30,8 +38,8 @@ before_script:
- if [ "${TRAVIS_OS_NAME}" = "osx" ]; then ./CI/before_script.osx.sh; fi
script:
- cd ./build
- if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then make -j4; fi
- if [ "$COVERITY_SCAN_BRANCH" != 1 ] && ["${TRAVIS_OS_NAME}" = "osx"]; then make package; fi
- if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then ${ANALYZE}make -j4; fi
- if [ "$COVERITY_SCAN_BRANCH" != 1 ] && [ "${TRAVIS_OS_NAME}" = "osx" ]; then make package; fi
after_script:
- if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi
notifications:

@ -39,6 +39,8 @@ Programmers
Eli2
Emanuel Guével (potatoesmaster)
eroen
escondida
Evgeniy Mineev (sandstranger)
Fil Krynicki (filkry)
Gašper Sedej
gugus/gus
@ -91,7 +93,6 @@ Programmers
Rohit Nirmal
Roman Melnik (Kromgart)
Roman Proskuryakov (humbug)
sandstranger
Sandy Carter (bwrsandman)
Scott Howard
Sebastian Wick (swick)

@ -1,3 +1,42 @@
0.35.1
------
Bug #781: incorrect trajectory of the sun
Bug #1079: Wrong starting position in "Character Stuff Wonderland"
Bug #1443: Repetitive taking of a stolen object is repetitively considered as a crime
Bug #1533: Divine Intervention goes to the wrong place.
Bug #1714: No visual indicator for time passed during training
Bug #1916: Telekinesis does not allow safe opening of traps
Bug #2227: Editor: addon file name inconsistency
Bug #2271: Player can melee enemies from water with impunity
Bug #2275: Objects with bigger scale move further using Move script
Bug #2285: Aryon's Dominator enchantment does not work properly
Bug #2290: No punishment for stealing gold from owned containers
Bug #2328: Launcher does not respond to Ctrl+C
Bug #2334: Drag-and-drop on a content file in the launcher creates duplicate items
Bug #2338: Arrows reclaimed from corpses do not stack sometimes
Bug #2344: Launcher - Settings importer running correctly?
Bug #2346: Launcher - Importing plugins into content list screws up the load order
Bug #2348: Mod: H.E.L.L.U.V.A. Handy Holdables does not appear in the content list
Bug #2353: Detect Animal detects dead creatures
Bug #2354: Cmake does not respect LIB_SUFFIX
Bug #2356: Active magic set inactive when switching magic items
Bug #2361: ERROR: ESM Error: Previous record contains unread bytes
Bug #2382: Switching spells with "next spell" or "previous spell" while holding shift promps delete spell dialog
Bug #2388: Regression: Can't toggle map on/off
Bug #2392: MOD Shrines - Restore Health and Cancel Options adds 100 health points
Bug #2394: List of Data Files tab in openmw-laucher needs to show all content files.
Bug #2402: Editor: skills saved incorrectly
Bug #2408: Equipping a constant effect Restore Health/Magicka/Fatigue item will permanently boost the stat it's restoring
Bug #2415: It is now possible to fall off the prison ship into the water when starting a new game
Bug #2419: MOD MCA crash to desktop
Bug #2420: Game crashes when character enters a certain area
Bug #2421: infinite loop when using cycle weapon without having a weapon
Feature #2221: Cannot dress dead NPCs
Feature #2349: Check CMake sets correct MSVC compiler settings for release build.
Feature #2397: Set default values for global mandatory records.
Feature #2412: Basic joystick support
0.35.0
------

@ -1,7 +1,12 @@
#!/bin/sh
export CXX=g++
export CC=gcc
if [ "${ANALYZE}" ]; then
if [ $(lsb_release -sc) = "precise" ]; then
echo "yes" | sudo apt-add-repository ppa:ubuntu-toolchain-r/test
fi
echo "yes" | sudo add-apt-repository "deb http://llvm.org/apt/`lsb_release -sc`/ llvm-toolchain-`lsb_release -sc`-3.6 main"
wget -O - http://llvm.org/apt/llvm-snapshot.gpg.key|sudo apt-key add -
fi
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
@ -10,6 +15,7 @@ sudo apt-get install -qq libgtest-dev google-mock
sudo apt-get install -qq libboost-filesystem-dev libboost-program-options-dev libboost-system-dev libboost-thread-dev libboost-wave-dev
sudo apt-get install -qq libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libavresample-dev
sudo apt-get install -qq libbullet-dev libogre-1.9-dev libmygui-dev libsdl2-dev libunshield-dev libtinyxml-dev libopenal-dev libqt4-dev
if [ "${ANALYZE}" ]; then sudo apt-get install -qq clang-3.6; fi
sudo mkdir /usr/src/gtest/build
cd /usr/src/gtest/build
sudo cmake .. -DBUILD_SHARED_LIBS=1

@ -2,4 +2,6 @@
mkdir build
cd build
cmake .. -DBUILD_WITH_CODE_COVERAGE=1 -DBUILD_UNITTESTS=1 -DCMAKE_INSTALL_PREFIX=/usr -DBINDIR=/usr/games -DCMAKE_BUILD_TYPE="RelWithDebInfo" -DUSE_SYSTEM_TINYXML=TRUE
export CODE_COVERAGE=1
if [ "${CC}" = "clang" ]; then export CODE_COVERAGE=0; fi
${ANALYZE}cmake .. -DBUILD_WITH_CODE_COVERAGE=${CODE_COVERAGE} -DBUILD_UNITTESTS=1 -DCMAKE_INSTALL_PREFIX=/usr -DBINDIR=/usr/games -DCMAKE_BUILD_TYPE="RelWithDebInfo" -DUSE_SYSTEM_TINYXML=TRUE

@ -20,7 +20,7 @@ message(STATUS "Configuring OpenMW...")
set(OPENMW_VERSION_MAJOR 0)
set(OPENMW_VERSION_MINOR 35)
set(OPENMW_VERSION_RELEASE 0)
set(OPENMW_VERSION_RELEASE 1)
set(OPENMW_VERSION_COMMITHASH "")
set(OPENMW_VERSION_TAGHASH "")
@ -98,43 +98,6 @@ endif()
# We probably support older versions than this.
cmake_minimum_required(VERSION 2.6)
# source directory: libs
set(LIBS_DIR ${CMAKE_SOURCE_DIR}/libs)
set(OENGINE_OGRE
${LIBS_DIR}/openengine/ogre/renderer.cpp
${LIBS_DIR}/openengine/ogre/lights.cpp
${LIBS_DIR}/openengine/ogre/selectionbuffer.cpp
${LIBS_DIR}/openengine/ogre/imagerotate.cpp
)
set(OENGINE_GUI
${LIBS_DIR}/openengine/gui/loglistener.cpp
${LIBS_DIR}/openengine/gui/manager.cpp
${LIBS_DIR}/openengine/gui/layout.cpp
)
set(OENGINE_BULLET
${LIBS_DIR}/openengine/bullet/BtOgre.cpp
${LIBS_DIR}/openengine/bullet/BtOgreExtras.h
${LIBS_DIR}/openengine/bullet/BtOgreGP.h
${LIBS_DIR}/openengine/bullet/BtOgrePG.h
${LIBS_DIR}/openengine/bullet/physic.cpp
${LIBS_DIR}/openengine/bullet/physic.hpp
${LIBS_DIR}/openengine/bullet/BulletShapeLoader.cpp
${LIBS_DIR}/openengine/bullet/BulletShapeLoader.h
${LIBS_DIR}/openengine/bullet/trace.cpp
${LIBS_DIR}/openengine/bullet/trace.h
)
set(OENGINE_ALL ${OENGINE_OGRE} ${OENGINE_GUI} ${OENGINE_BULLET})
source_group(libs\\openengine FILES ${OENGINE_ALL})
set(OPENMW_LIBS ${OENGINE_ALL})
set(OPENMW_LIBS_HEADER)
# Sound setup
set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE SWRESAMPLE AVRESAMPLE)
unset(FFMPEG_LIBRARIES CACHE)
@ -270,7 +233,8 @@ endif ()
endif(WIN32)
endif(OGRE_STATIC)
include_directories("."
include_directories("." ${LIBS_DIR}
SYSTEM
${OGRE_INCLUDE_DIR} ${OGRE_INCLUDE_DIR}/Ogre ${OGRE_INCLUDE_DIR}/OGRE ${OGRE_INCLUDE_DIRS} ${OGRE_PLUGIN_INCLUDE_DIRS}
${OGRE_INCLUDE_DIR}/Overlay ${OGRE_Overlay_INCLUDE_DIR}
${SDL2_INCLUDE_DIR}
@ -279,7 +243,7 @@ include_directories("."
${MYGUI_INCLUDE_DIRS}
${MYGUI_PLATFORM_INCLUDE_DIRS}
${OPENAL_INCLUDE_DIR}
${LIBS_DIR}
${BULLET_INCLUDE_DIRS}
)
link_directories(${SDL2_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR} ${MYGUI_LIB_DIR})
@ -379,6 +343,9 @@ configure_file(${OpenMW_SOURCE_DIR}/files/opencs.ini
configure_file(${OpenMW_SOURCE_DIR}/files/opencs/defaultfilters
"${OpenMW_BINARY_DIR}/resources/defaultfilters" COPYONLY)
configure_file(${OpenMW_SOURCE_DIR}/files/gamecontrollerdb.txt
"${OpenMW_BINARY_DIR}/gamecontrollerdb.txt")
if (NOT WIN32 AND NOT APPLE)
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.desktop
"${OpenMW_BINARY_DIR}/openmw.desktop")
@ -386,22 +353,22 @@ if (NOT WIN32 AND NOT APPLE)
"${OpenMW_BINARY_DIR}/openmw-cs.desktop")
endif()
# Compiler settings
if (CMAKE_COMPILER_IS_GNUCC)
SET(CMAKE_CXX_FLAGS "-Wall -Wextra -Wno-unused-parameter -Wno-reorder -std=c++98 -pedantic -Wno-long-long ${CMAKE_CXX_FLAGS}")
# CXX Compiler settings
if (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clang)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-unused-parameter -Wno-reorder -std=c++98 -pedantic -Wno-long-long")
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion
OUTPUT_VARIABLE GCC_VERSION)
if ("${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6)
SET(CMAKE_CXX_FLAGS "-Wno-unused-but-set-parameter ${CMAKE_CXX_FLAGS}")
endif("${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6)
if (CMAKE_CXX_COMPILER_ID STREQUAL GNU AND "${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-but-set-parameter")
endif(CMAKE_CXX_COMPILER_ID STREQUAL GNU AND "${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6)
elseif (MSVC)
# Enable link-time code generation globally for all linking
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /GL")
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG")
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG")
set(CMAKE_STATIC_LINKER_FLAGS_RELEASE "${CMAKE_STATIC_LINKER_FLAGS_RELEASE} /LTCG")
endif (CMAKE_COMPILER_IS_GNUCC)
endif (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clang)
IF(NOT WIN32 AND NOT APPLE)
# Linux building
@ -468,6 +435,8 @@ IF(NOT WIN32 AND NOT APPLE)
INSTALL(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw")
INSTALL(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw")
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "${SYSCONFDIR}" RENAME "openmw.cfg" COMPONENT "openmw")
INSTALL(FILES "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw")
IF(BUILD_OPENCS)
INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION "${SYSCONFDIR}" COMPONENT "opencs")
ENDIF(BUILD_OPENCS)
@ -488,6 +457,7 @@ if(WIN32)
"${OpenMW_SOURCE_DIR}/Docs/license/DejaVu Font License.txt"
"${OpenMW_BINARY_DIR}/settings-default.cfg"
"${OpenMW_BINARY_DIR}/transparency-overrides.cfg"
"${OpenMW_BINARY_DIR}/gamecontrollerdb.txt"
"${OpenMW_BINARY_DIR}/Release/openmw.exe"
DESTINATION ".")
@ -572,6 +542,10 @@ if(WIN32)
include(CPack)
endif(WIN32)
# Libs
include_directories(libs)
add_subdirectory(libs/openengine)
# Extern
#add_subdirectory (extern/shiny)
#add_subdirectory (extern/ogre-ffmpeg-videoplayer)
@ -682,6 +656,7 @@ if (WIN32)
4193 # #pragma warning(pop) : no matching '#pragma warning(push)'
4251 # class 'XXXX' needs to have dll-interface to be used by clients of class 'YYYY'
4275 # non dll-interface struct 'XXXX' used as base for dll-interface class 'YYYY'
4315 # undocumented, 'this' pointer for member might not be aligned (OgreMemoryStlAllocator.h)
# caused by boost
4191 # 'type cast' : unsafe conversion (1.56, thread_primitives.hpp, normally off)
@ -689,6 +664,7 @@ if (WIN32)
# OpenMW specific warnings
4099 # Type mismatch, declared class or struct is defined with other type
4100 # Unreferenced formal parameter (-Wunused-parameter)
4101 # Unreferenced local variable (-Wunused-variable)
4127 # Conditional expression is constant
4242 # Storing value in a variable of a smaller type, possible loss of data
4244 # Storing value of one type in variable of another (size_t in int, for example)
@ -707,56 +683,23 @@ if (WIN32)
set(WARNINGS "${WARNINGS} /wd${d}")
endforeach(d)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNINGS} ${MT_BUILD}")
# boost::wave has a few issues with signed / unsigned conversions, so we suppress those here
set(SHINY_WARNINGS "${WARNINGS} /wd4245")
set_target_properties(shiny PROPERTIES COMPILE_FLAGS "${SHINY_WARNINGS} ${MT_BUILD}")
# there's an unreferenced local variable in the ogre platform, suppress it
set(SHINY_OGRE_WARNINGS "${WARNINGS} /wd4101")
set_target_properties(shiny.OgrePlatform PROPERTIES COMPILE_FLAGS "${SHINY_OGRE_WARNINGS} ${MT_BUILD}")
set_target_properties(sdl4ogre PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
# oics uses tinyxml, which has an initialized but unused variable
set(OICS_WARNINGS "${WARNINGS} /wd4189")
set_target_properties(oics PROPERTIES COMPILE_FLAGS "${OICS_WARNINGS} ${MT_BUILD}")
set_target_properties(components PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
if (BUILD_LAUNCHER)
set_target_properties(openmw-launcher PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
endif (BUILD_LAUNCHER)
set_target_properties(openmw PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
if (BUILD_BSATOOL)
set_target_properties(bsatool PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
endif (BUILD_BSATOOL)
if (BUILD_ESMTOOL)
set_target_properties(esmtool PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
endif (BUILD_ESMTOOL)
if (BUILD_WIZARD)
set_target_properties(openmw-wizard PROPERTIES COMPILE_FLAGS ${WARNINGS})
endif (BUILD_WIZARD)
if (BUILD_OPENCS)
# QT triggers an informational warning that the object layout may differ when compiled with /vd2
set(OPENCS_WARNINGS "${WARNINGS} ${MT_BUILD} /wd4435")
set_target_properties(openmw-cs PROPERTIES COMPILE_FLAGS ${OPENCS_WARNINGS})
endif (BUILD_OPENCS)
if (BUILD_MWINIIMPORTER)
set_target_properties(openmw-iniimporter PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
endif (BUILD_MWINIIMPORTER)
endif(MSVC)
# Same for MinGW
if (MINGW)
if (USE_DEBUG_CONSOLE)
set_target_properties(openmw PROPERTIES LINK_FLAGS_DEBUG "-Wl,-subsystem,console")
set_target_properties(openmw PROPERTIES LINK_FLAGS_RELWITHDEBINFO "-Wl,-subsystem,console")
set_target_properties(openmw PROPERTIES COMPILE_DEFINITIONS_DEBUG "_CONSOLE")
else(USE_DEBUG_CONSOLE)
set_target_properties(openmw PROPERTIES LINK_FLAGS_DEBUG "-Wl,-subsystem,windows")
set_target_properties(openmw PROPERTIES LINK_FLAGS_RELWITHDEBINFO "-Wl,-subsystem,windows")
endif(USE_DEBUG_CONSOLE)
set_target_properties(openmw PROPERTIES LINK_FLAGS_RELEASE "-Wl,-subsystem,console")
set_target_properties(openmw PROPERTIES LINK_FLAGS_MINSIZEREL "-Wl,-subsystem,console")
set_target_properties(openmw PROPERTIES COMPILE_DEFINITIONS_RELEASE "_CONSOLE")
endif(MINGW)
# TODO: At some point release builds should not use the console but rather write to a log file
#set_target_properties(openmw PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS")
#set_target_properties(openmw PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:WINDOWS")
@ -770,6 +713,7 @@ if (APPLE)
install(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
install(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" RENAME "openmw.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
install(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
install(FILES "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
install(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
install(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)

@ -6,7 +6,7 @@ OpenMW
OpenMW is an attempt at recreating the engine for the popular role-playing game
Morrowind by Bethesda Softworks. You need to own and install the original game for OpenMW to work.
* Version: 0.35.0
* Version: 0.35.1
* License: GPL (see docs/license/GPL3.txt for more information)
* Website: http://www.openmw.org
* IRC: #openmw on irc.freenode.net
@ -23,7 +23,7 @@ Getting Started
* [Testing the game](https://wiki.openmw.org/index.php?title=Testing)
* [How to contribute](https://wiki.openmw.org/index.php?title=Contribution_Wanted)
* [Report a bug](http://bugs.openmw.org/projects/openmw) - read the [guidelines](https://wiki.openmw.org/index.php?title=Bug_Reporting_Guidelines) before submitting your first bug!
* [Known issues] (http://bugs.openmw.org/projects/openmw/issues?utf8=%E2%9C%93&set_filter=1&f%5B%5D=status_id&op%5Bstatus_id%5D=%3D&v%5Bstatus_id%5D%5B%5D=7&f%5B%5D=tracker_id&op%5Btracker_id%5D=%3D&v%5Btracker_id%5D%5B%5D=1&f%5B%5D=&c%5B%5D=project&c%5B%5D=tracker&c%5B%5D=status&c%5B%5D=priority&c%5B%5D=subject&c%5B%5D=assigned_to&c%5B%5D=updated_on&group_by=tracker)
* [Known issues](http://bugs.openmw.org/projects/openmw/issues?utf8=%E2%9C%93&set_filter=1&f%5B%5D=status_id&op%5Bstatus_id%5D=%3D&v%5Bstatus_id%5D%5B%5D=7&f%5B%5D=tracker_id&op%5Btracker_id%5D=%3D&v%5Btracker_id%5D%5B%5D=1&f%5B%5D=&c%5B%5D=project&c%5B%5D=tracker&c%5B%5D=status&c%5B%5D=priority&c%5B%5D=subject&c%5B%5D=assigned_to&c%5B%5D=updated_on&group_by=tracker)
The data path
-------------

@ -461,7 +461,7 @@ int clone(Arguments& info)
for (Stats::iterator it = stats.begin(); it != stats.end(); ++it)
{
name.val = it->first;
float amount = it->second;
int amount = it->second;
std::cout << std::setw(digitCount) << amount << " " << name.toString() << " ";
if (++i % 3 == 0)

@ -6,6 +6,9 @@
#include <boost/format.hpp>
namespace
{
void printAIPackage(ESM::AIPackage p)
{
std::cout << " AI Type: " << aiTypeLabel(p.mType)
@ -16,7 +19,7 @@ void printAIPackage(ESM::AIPackage p)
std::cout << " Duration: " << p.mWander.mDuration << std::endl;
std::cout << " Time of Day: " << (int)p.mWander.mTimeOfDay << std::endl;
if (p.mWander.mShouldRepeat != 1)
std::cout << " Should repeat: " << (bool)p.mWander.mShouldRepeat << std::endl;
std::cout << " Should repeat: " << (bool)(p.mWander.mShouldRepeat != 0) << std::endl;
std::cout << " Idle: ";
for (int i = 0; i != 8; i++)
@ -149,6 +152,26 @@ void printEffectList(ESM::EffectList effects)
}
}
void printTransport(const std::vector<ESM::Transport::Dest>& transport)
{
std::vector<ESM::Transport::Dest>::const_iterator dit;
for (dit = transport.begin(); dit != transport.end(); ++dit)
{
std::cout << " Destination Position: "
<< boost::format("%12.3f") % dit->mPos.pos[0] << ","
<< boost::format("%12.3f") % dit->mPos.pos[1] << ","
<< boost::format("%12.3f") % dit->mPos.pos[2] << ")" << std::endl;
std::cout << " Destination Rotation: "
<< boost::format("%9.6f") % dit->mPos.rot[0] << ","
<< boost::format("%9.6f") % dit->mPos.rot[1] << ","
<< boost::format("%9.6f") % dit->mPos.rot[2] << ")" << std::endl;
if (dit->mCellName != "")
std::cout << " Destination Cell: " << dit->mCellName << std::endl;
}
}
}
namespace EsmTool {
RecordBase *
@ -631,6 +654,8 @@ void Record<ESM::Creature>::print()
for (sit = mData.mSpells.mList.begin(); sit != mData.mSpells.mList.end(); ++sit)
std::cout << " Spell: " << *sit << std::endl;
printTransport(mData.getTransport());
std::cout << " Artifical Intelligence: " << mData.mHasAI << std::endl;
std::cout << " AI Hello:" << (int)mData.mAiData.mHello << std::endl;
std::cout << " AI Fight:" << (int)mData.mAiData.mFight << std::endl;
@ -1042,20 +1067,7 @@ void Record<ESM::NPC>::print()
for (sit = mData.mSpells.mList.begin(); sit != mData.mSpells.mList.end(); ++sit)
std::cout << " Spell: " << *sit << std::endl;
std::vector<ESM::NPC::Dest>::iterator dit;
for (dit = mData.mTransport.begin(); dit != mData.mTransport.end(); ++dit)
{
std::cout << " Destination Position: "
<< boost::format("%12.3f") % dit->mPos.pos[0] << ","
<< boost::format("%12.3f") % dit->mPos.pos[1] << ","
<< boost::format("%12.3f") % dit->mPos.pos[2] << ")" << std::endl;
std::cout << " Destination Rotation: "
<< boost::format("%9.6f") % dit->mPos.rot[0] << ","
<< boost::format("%9.6f") % dit->mPos.rot[1] << ","
<< boost::format("%9.6f") % dit->mPos.rot[2] << ")" << std::endl;
if (dit->mCellName != "")
std::cout << " Destination Cell: " << dit->mCellName << std::endl;
}
printTransport(mData.getTransport());
std::cout << " Artifical Intelligence: " << mData.mHasAI << std::endl;
std::cout << " AI Hello:" << (int)mData.mAiData.mHello << std::endl;
@ -1253,7 +1265,7 @@ void Record<ESM::Spell>::print()
template<>
void Record<ESM::StartScript>::print()
{
std::cout << "Start Script: " << mData.mScript << std::endl;
std::cout << "Start Script: " << mData.mId << std::endl;
std::cout << "Start Data: " << mData.mData << std::endl;
}

@ -23,18 +23,18 @@ namespace ESSImport
}
for (int i=0; i<8; ++i)
{
cStats.mAttributes[i].mBase = acdt.mAttributes[i][1];
cStats.mAttributes[i].mMod = acdt.mAttributes[i][0];
cStats.mAttributes[i].mCurrent = acdt.mAttributes[i][0];
cStats.mAttributes[i].mBase = static_cast<int>(acdt.mAttributes[i][1]);
cStats.mAttributes[i].mMod = static_cast<int>(acdt.mAttributes[i][0]);
cStats.mAttributes[i].mCurrent = static_cast<int>(acdt.mAttributes[i][0]);
}
cStats.mGoldPool = acdt.mGoldPool;
cStats.mTalkedTo = acdt.mFlags & TalkedToPlayer;
cStats.mAttacked = acdt.mFlags & Attacked;
cStats.mTalkedTo = (acdt.mFlags & TalkedToPlayer) != 0;
cStats.mAttacked = (acdt.mFlags & Attacked) != 0;
}
void convertACSC (const ACSC& acsc, ESM::CreatureStats& cStats)
{
cStats.mDead = acsc.mFlags & Dead;
cStats.mDead = (acsc.mFlags & Dead) != 0;
}
void convertNpcData (const ActorData& actorData, ESM::NpcStats& npcStats)

@ -553,7 +553,7 @@ public:
ESM::WeatherState weather;
weather.mCurrentWeather = toString(mGame.mGMDT.mCurrentWeather);
weather.mNextWeather = toString(mGame.mGMDT.mNextWeather);
weather.mRemainingTransitionTime = mGame.mGMDT.mWeatherTransition/100.f*(0.015*24*3600);
weather.mRemainingTransitionTime = mGame.mGMDT.mWeatherTransition/100.f*(0.015f*24*3600);
weather.mHour = mContext->mHour;
weather.mWindSpeed = 0.f;
weather.mTimePassed = 0.0;

@ -43,13 +43,17 @@ namespace ESSImport
float mMagicEffects[27]; // Effect attributes: https://wiki.openmw.org/index.php?title=Research:Magic#Effect_attributes
unsigned char mUnknown4[4];
unsigned int mGoldPool;
unsigned char mUnknown5[4];
unsigned char mCountDown; // seen the same value as in ACSC.mCorpseClearCountdown, maybe
// this one is for respawning?
unsigned char mUnknown5[3];
};
struct ACSC
{
unsigned char mUnknown1[17];
unsigned char mFlags; // ACSCFlags
unsigned char mUnknown2[94];
unsigned char mUnknown2[22];
unsigned char mCorpseClearCountdown; // hours?
unsigned char mUnknown3[71];
};
#pragma pack(pop)

@ -43,7 +43,7 @@ namespace ESSImport
{
unsigned int deleted;
esm.getHT(deleted);
mDeleted = (deleted >> 24) & 0x2; // the other 3 bytes seem to be uninitialized garbage
mDeleted = ((deleted >> 24) & 0x2) != 0; // the other 3 bytes seem to be uninitialized garbage
}
if (esm.isNextSub("MVRF"))

@ -14,10 +14,10 @@ namespace ESSImport
float scale;
esm.getHNOT(scale, "XSCL");
// FIXME: use AiPackageList, need to fix getSubName()
while (esm.isNextSub("AI_W") || esm.isNextSub("AI_E") || esm.isNextSub("AI_T") || esm.isNextSub("AI_F")
|| esm.isNextSub("AI_A"))
esm.skipHSub();
mAiPackages.add(esm);
mInventory.load(esm);
}

@ -2,6 +2,7 @@
#define OPENMW_ESSIMPORT_CREC_H
#include "importinventory.hpp"
#include <components/esm/aipackage.hpp>
namespace ESM
{
@ -17,6 +18,7 @@ namespace ESSImport
int mIndex;
Inventory mInventory;
ESM::AIPackageList mAiPackages;
void load(ESM::ESMReader& esm);
};

@ -9,10 +9,9 @@ namespace ESSImport
{
esm.getHNT(mNPDT, "NPDT");
// FIXME: use AiPackageList, need to fix getSubName()
while (esm.isNextSub("AI_W") || esm.isNextSub("AI_E") || esm.isNextSub("AI_T") || esm.isNextSub("AI_F")
|| esm.isNextSub("AI_A"))
esm.skipHSub();
mAiPackages.add(esm);
mInventory.load(esm);
}

@ -27,6 +27,7 @@ namespace ESSImport
} mNPDT;
Inventory mInventory;
ESM::AIPackageList mAiPackages;
void load(ESM::ESMReader &esm);
};

@ -61,6 +61,7 @@ Launcher::MainDialog::MainDialog(QWidget *parent)
QString revision(OPENMW_VERSION_COMMITHASH);
QString tag(OPENMW_VERSION_TAGHASH);
versionLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
if (!revision.isEmpty() && !tag.isEmpty())
{
if (revision == tag) {
@ -238,24 +239,8 @@ void Launcher::MainDialog::changePage(QListWidgetItem *current, QListWidgetItem
current = previous;
int currentIndex = iconWidget->row(current);
// int previousIndex = iconWidget->row(previous);
pagesWidget->setCurrentIndex(currentIndex);
// DataFilesPage *previousPage = dynamic_cast<DataFilesPage *>(pagesWidget->widget(previousIndex));
// DataFilesPage *currentPage = dynamic_cast<DataFilesPage *>(pagesWidget->widget(currentIndex));
// //special call to update/save data files page list view when it's displayed/hidden.
// if (previousPage)
// {
// if (previousPage->objectName() == "DataFilesPage")
// previousPage->saveSettings();
// }
// else if (currentPage)
// {
// if (currentPage->objectName() == "DataFilesPage")
// currentPage->loadSettings();
// }
mSettingsPage->resetProgressBar();
}
bool Launcher::MainDialog::setupLauncherSettings()

@ -39,6 +39,7 @@ Launcher::SettingsPage::SettingsPage(Files::ConfigurationManager &cfg,
mWizardInvoker = new ProcessInvoker();
mImporterInvoker = new ProcessInvoker();
resetProgressBar();
connect(mWizardInvoker->getProcess(), SIGNAL(started()),
this, SLOT(wizardStarted()));
@ -94,7 +95,7 @@ Launcher::SettingsPage::~SettingsPage()
void Launcher::SettingsPage::on_wizardButton_clicked()
{
saveSettings();
mMain->writeSettings();
if (!mWizardInvoker->startProcess(QLatin1String("openmw-wizard"), false))
return;
@ -102,7 +103,7 @@ void Launcher::SettingsPage::on_wizardButton_clicked()
void Launcher::SettingsPage::on_importerButton_clicked()
{
saveSettings();
mMain->writeSettings();
// Create the file if it doesn't already exist, else the importer will fail
QString path(QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()));
@ -141,8 +142,13 @@ void Launcher::SettingsPage::on_importerButton_clicked()
qDebug() << "arguments " << arguments;
// start the progress bar as a "bouncing ball"
progressBar->setMaximum(0);
progressBar->setValue(0);
if (!mImporterInvoker->startProcess(QLatin1String("openmw-iniimporter"), arguments, false))
return;
{
resetProgressBar();
}
}
void Launcher::SettingsPage::on_browseButton_clicked()
@ -197,38 +203,35 @@ void Launcher::SettingsPage::importerStarted()
void Launcher::SettingsPage::importerFinished(int exitCode, QProcess::ExitStatus exitStatus)
{
if (exitCode != 0 || exitStatus == QProcess::CrashExit)
return;
// Importer may have changed settings, so refresh
mMain->reloadSettings();
// Import selected data files from openmw.cfg
if (addonsCheckBox->isChecked())
{
// Because we've reloaded settings, the current content list matches content in OpenMW.cfg
QString oldContentListName = mLauncherSettings.getCurrentContentListName();
if (mProfileDialog->exec() == QDialog::Accepted)
{
// remove the current content list to prevent duplication
//... except, not allowed to delete the Default content list
if (oldContentListName.compare(DataFilesPage::mDefaultContentListName) != 0)
{
mLauncherSettings.removeContentList(oldContentListName);
}
resetProgressBar();
const QString newContentListName(mProfileDialog->lineEdit()->text());
const QStringList files(mGameSettings.getContentList());
mLauncherSettings.setCurrentContentListName(newContentListName);
mLauncherSettings.setContentList(newContentListName, files);
QMessageBox msgBox;
msgBox.setWindowTitle(tr("Importer finished"));
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setIcon(QMessageBox::Warning);
msgBox.setText(tr("Failed to import settings from INI file."));
msgBox.exec();
}
else
{
// indicate progress finished
progressBar->setMaximum(1);
progressBar->setValue(1);
// Make DataFiles Page load the new content list.
// Importer may have changed settings, so refresh
mMain->reloadSettings();
}
}
importerButton->setEnabled(true);
}
void Launcher::SettingsPage::resetProgressBar()
{
// set progress bar to 0 %
progressBar->reset();
}
void Launcher::SettingsPage::updateOkButton(const QString &text)
{
// We do this here because we need to access the profiles

@ -30,6 +30,9 @@ namespace Launcher
void saveSettings();
bool loadSettings();
/// set progress bar on page to 0%
void resetProgressBar();
private slots:
void on_wizardButton_clicked();
@ -57,7 +60,6 @@ namespace Launcher
MainDialog *mMain;
TextInputDialog *mProfileDialog;
};
}

@ -8,7 +8,8 @@
#include <sstream>
#include <components/misc/stringops.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/version.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
namespace bfs = boost::filesystem;
@ -660,7 +661,7 @@ std::string MwIniImporter::numberToString(int n) {
return str.str();
}
MwIniImporter::multistrmap MwIniImporter::loadIniFile(const std::string& filename) const {
MwIniImporter::multistrmap MwIniImporter::loadIniFile(const boost::filesystem::path& filename) const {
std::cout << "load ini file: " << filename << std::endl;
std::string section("");
@ -719,7 +720,7 @@ MwIniImporter::multistrmap MwIniImporter::loadIniFile(const std::string& filenam
return map;
}
MwIniImporter::multistrmap MwIniImporter::loadCfgFile(const std::string& filename) {
MwIniImporter::multistrmap MwIniImporter::loadCfgFile(const boost::filesystem::path& filename) {
std::cout << "load cfg file: " << filename << std::endl;
MwIniImporter::multistrmap map;
@ -825,10 +826,14 @@ void MwIniImporter::importArchives(multistrmap &cfg, const multistrmap &ini) con
}
}
void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini) const {
std::vector<std::string> contentFiles;
void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini, const boost::filesystem::path& iniFilename) const {
std::vector<std::pair<std::time_t, std::string> > contentFiles;
std::string baseGameFile("Game Files:GameFile");
std::string gameFile("");
std::time_t defaultTime = 0;
// assume the Game Files are all in a "Data Files" directory under the directory holding Morrowind.ini
const boost::filesystem::path gameFilesDir(iniFilename.parent_path() /= "Data Files");
multistrmap::const_iterator it = ini.begin();
for(int i=0; it != ini.end(); i++) {
@ -845,18 +850,20 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini) co
Misc::StringUtils::toLower(filetype);
if(filetype.compare("esm") == 0 || filetype.compare("esp") == 0) {
contentFiles.push_back(*entry);
boost::filesystem::path filepath(gameFilesDir);
filepath /= *entry;
contentFiles.push_back(std::make_pair(lastWriteTime(filepath, defaultTime), *entry));
}
}
gameFile = "";
}
cfg.erase("content");
cfg.insert( std::make_pair("content", std::vector<std::string>() ) );
for(std::vector<std::string>::const_iterator it=contentFiles.begin(); it!=contentFiles.end(); ++it) {
cfg["content"].push_back(*it);
// this will sort files by time order first, then alphabetical (maybe), I suspect non ASCII filenames will be stuffed.
sort(contentFiles.begin(), contentFiles.end());
for(std::vector<std::pair<std::time_t, std::string> >::const_iterator it=contentFiles.begin(); it!=contentFiles.end(); ++it) {
cfg["content"].push_back(it->second);
}
}
@ -873,3 +880,27 @@ void MwIniImporter::setInputEncoding(const ToUTF8::FromType &encoding)
{
mEncoding = encoding;
}
std::time_t MwIniImporter::lastWriteTime(const boost::filesystem::path& filename, std::time_t defaultTime)
{
std::time_t writeTime(defaultTime);
if (boost::filesystem::exists(filename))
{
// FixMe: remove #if when Boost dependency for Linux builds updated
// This allows Linux to build until then
#if (BOOST_VERSION >= 104800)
// need to resolve any symlinks so that we get time of file, not symlink
boost::filesystem::path resolved = boost::filesystem::canonical(filename);
#else
boost::filesystem::path resolved = filename;
#endif
writeTime = boost::filesystem::last_write_time(resolved);
std::cout << "content file: " << resolved << " timestamp = (" << writeTime <<
") " << asctime(localtime(&writeTime)) << std::endl;
}
else
{
std::cout << "content file: " << filename << " not found" << std::endl;
}
return writeTime;
}

@ -6,6 +6,7 @@
#include <vector>
#include <exception>
#include <iosfwd>
#include <boost/filesystem/path.hpp>
#include <components/to_utf8/to_utf8.hpp>
@ -17,17 +18,22 @@ class MwIniImporter {
MwIniImporter();
void setInputEncoding(const ToUTF8::FromType& encoding);
void setVerbose(bool verbose);
multistrmap loadIniFile(const std::string& filename) const;
static multistrmap loadCfgFile(const std::string& filename);
multistrmap loadIniFile(const boost::filesystem::path& filename) const;
static multistrmap loadCfgFile(const boost::filesystem::path& filename);
void merge(multistrmap &cfg, const multistrmap &ini) const;
void mergeFallback(multistrmap &cfg, const multistrmap &ini) const;
void importGameFiles(multistrmap &cfg, const multistrmap &ini) const;
void importGameFiles(multistrmap &cfg, const multistrmap &ini,
const boost::filesystem::path& iniFilename) const;
void importArchives(multistrmap &cfg, const multistrmap &ini) const;
static void writeToFile(std::ostream &out, const multistrmap &cfg);
private:
static void insertMultistrmap(multistrmap &cfg, const std::string& key, const std::string& value);
static std::string numberToString(int n);
/// \return file's "last modified time", used in original MW to determine plug-in load order
static std::time_t lastWriteTime(const boost::filesystem::path& filename, std::time_t defaultTime);
bool mVerbose;
strmap mMergeMap;
std::vector<std::string> mMergeFallback;

@ -93,8 +93,8 @@ int wmain(int argc, wchar_t *wargv[]) {
bpo::notify(vm);
std::string iniFile = vm["ini"].as<std::string>();
std::string cfgFile = vm["cfg"].as<std::string>();
boost::filesystem::path iniFile(vm["ini"].as<std::string>());
boost::filesystem::path cfgFile(vm["cfg"].as<std::string>());
// if no output is given, write back to cfg file
std::string outputFile(vm["output"].as<std::string>());
@ -110,7 +110,7 @@ int wmain(int argc, wchar_t *wargv[]) {
std::cerr << "cfg file does not exist" << std::endl;
MwIniImporter importer;
importer.setVerbose(vm.count("verbose"));
importer.setVerbose(vm.count("verbose") != 0);
// Font encoding settings
std::string encoding(vm["encoding"].as<std::string>());
@ -123,7 +123,7 @@ int wmain(int argc, wchar_t *wargv[]) {
importer.mergeFallback(cfg, ini);
if(vm.count("game-files")) {
importer.importGameFiles(cfg, ini);
importer.importGameFiles(cfg, ini, iniFile);
}
if(!vm.count("no-archives")) {

@ -5,7 +5,7 @@ set (OPENCS_SRC main.cpp
opencs_units (. editor)
opencs_units (model/doc
document operation saving documentmanager loader runner
document operation saving documentmanager loader runner operationholder
)
opencs_units_noqt (model/doc
@ -40,6 +40,7 @@ opencs_units (model/tools
opencs_units_noqt (model/tools
mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck
birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck
startscriptcheck
)
@ -164,7 +165,8 @@ qt4_wrap_ui(OPENCS_UI_HDR ${OPENCS_UI})
qt4_wrap_cpp(OPENCS_MOC_SRC ${OPENCS_HDR_QT})
qt4_add_resources(OPENCS_RES_SRC ${OPENCS_RES})
include_directories(${CMAKE_CURRENT_BINARY_DIR} ${BULLET_INCLUDE_DIRS})
# for compiled .ui files
include_directories(${CMAKE_CURRENT_BINARY_DIR})
if(APPLE)
set (OPENCS_MAC_ICON ${CMAKE_SOURCE_DIR}/files/mac/openmw-cs.icns)
@ -174,7 +176,6 @@ endif(APPLE)
add_executable(openmw-cs
MACOSX_BUNDLE
${OENGINE_BULLET}
${OPENCS_SRC}
${OPENCS_UI_HDR}
${OPENCS_MOC_SRC}
@ -198,6 +199,7 @@ if(APPLE)
endif(APPLE)
target_link_libraries(openmw-cs
${OENGINE_LIBRARY}
${OGRE_LIBRARIES}
${OGRE_Overlay_LIBRARIES}
${OGRE_STATIC_PLUGINS}

@ -2252,7 +2252,8 @@ CSMDoc::Document::Document (const VFS::Manager* vfs, const Files::ConfigurationM
mTools (*this), mResDir(resDir),
mProjectPath ((configuration.getUserDataPath() / "projects") /
(savePath.filename().string() + ".project")),
mSaving (*this, mProjectPath, encoding),
mSavingOperation (*this, mProjectPath, encoding),
mSaving (&mSavingOperation),
mRunner (mProjectPath)
{
if (mContentFiles.empty())

@ -20,6 +20,7 @@
#include "saving.hpp"
#include "blacklist.hpp"
#include "runner.hpp"
#include "operationholder.hpp"
class QAbstractItemModel;
@ -38,7 +39,7 @@ namespace ESM
namespace Files
{
class ConfigurationManager;
struct ConfigurationManager;
}
namespace CSMWorld
@ -61,7 +62,8 @@ namespace CSMDoc
CSMWorld::Data mData;
CSMTools::Tools mTools;
boost::filesystem::path mProjectPath;
Saving mSaving;
Saving mSavingOperation;
OperationHolder mSaving;
boost::filesystem::path mResDir;
Blacklist mBlacklist;
Runner mRunner;

@ -22,7 +22,7 @@ namespace VFS
namespace Files
{
class ConfigurationManager;
struct ConfigurationManager;
}
namespace CSMDoc

@ -29,9 +29,9 @@ void CSMDoc::Operation::prepareStages()
CSMDoc::Operation::Operation (int type, bool ordered, bool finalAlways)
: mType (type), mStages(std::vector<std::pair<Stage *, int> >()), mCurrentStage(mStages.begin()),
mCurrentStep(0), mCurrentStepTotal(0), mTotalSteps(0), mOrdered (ordered),
mFinalAlways (finalAlways), mError(false)
mFinalAlways (finalAlways), mError(false), mConnected (false)
{
connect (this, SIGNAL (finished()), this, SLOT (operationDone()));
mTimer = new QTimer (this);
}
CSMDoc::Operation::~Operation()
@ -42,15 +42,17 @@ CSMDoc::Operation::~Operation()
void CSMDoc::Operation::run()
{
prepareStages();
QTimer timer;
mTimer->stop();
timer.connect (&timer, SIGNAL (timeout()), this, SLOT (executeStage()));
if (!mConnected)
{
connect (mTimer, SIGNAL (timeout()), this, SLOT (executeStage()));
mConnected = true;
}
timer.start (0);
prepareStages();
exec();
mTimer->start (0);
}
void CSMDoc::Operation::appendStage (Stage *stage)
@ -65,7 +67,7 @@ bool CSMDoc::Operation::hasError() const
void CSMDoc::Operation::abort()
{
if (!isRunning())
if (!mTimer->isActive())
return;
mError = true;
@ -116,10 +118,11 @@ void CSMDoc::Operation::executeStage()
emit reportMessage (iter->mId, iter->mMessage, iter->mHint, mType);
if (mCurrentStage==mStages.end())
exit();
operationDone();
}
void CSMDoc::Operation::operationDone()
{
mTimer->stop();
emit done (mType, mError);
}

@ -3,7 +3,8 @@
#include <vector>
#include <QThread>
#include <QObject>
#include <QTimer>
namespace CSMWorld
{
@ -14,7 +15,7 @@ namespace CSMDoc
{
class Stage;
class Operation : public QThread
class Operation : public QObject
{
Q_OBJECT
@ -27,6 +28,8 @@ namespace CSMDoc
int mOrdered;
bool mFinalAlways;
bool mError;
bool mConnected;
QTimer *mTimer;
void prepareStages();
@ -38,8 +41,6 @@ namespace CSMDoc
virtual ~Operation();
virtual void run();
void appendStage (Stage *stage);
///< The ownership of \a stage is transferred to *this.
///
@ -60,6 +61,8 @@ namespace CSMDoc
void abort();
void run();
private slots:
void executeStage();

@ -0,0 +1,65 @@
#include "operationholder.hpp"
#include "operation.hpp"
CSMDoc::OperationHolder::OperationHolder (Operation *operation) : mRunning (false)
{
if (operation)
setOperation (operation);
}
void CSMDoc::OperationHolder::setOperation (Operation *operation)
{
mOperation = operation;
mOperation->moveToThread (&mThread);
connect (
mOperation, SIGNAL (progress (int, int, int)),
this, SIGNAL (progress (int, int, int)));
connect (
mOperation, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)),
this, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)));
connect (
mOperation, SIGNAL (done (int, bool)),
this, SLOT (doneSlot (int, bool)));
connect (this, SIGNAL (abortSignal()), mOperation, SLOT (abort()));
connect (&mThread, SIGNAL (started()), mOperation, SLOT (run()));
}
bool CSMDoc::OperationHolder::isRunning() const
{
return mRunning;
}
void CSMDoc::OperationHolder::start()
{
mRunning = true;
mThread.start();
}
void CSMDoc::OperationHolder::abort()
{
mRunning = false;
emit abortSignal();
}
void CSMDoc::OperationHolder::abortAndWait()
{
if (mRunning)
{
mThread.quit();
mThread.wait();
}
}
void CSMDoc::OperationHolder::doneSlot (int type, bool failed)
{
mRunning = false;
mThread.quit();
emit done (type, failed);
}

@ -0,0 +1,56 @@
#ifndef CSM_DOC_OPERATIONHOLDER_H
#define CSM_DOC_OPERATIONHOLDER_H
#include <QObject>
#include <QThread>
namespace CSMWorld
{
class UniversalId;
}
namespace CSMDoc
{
class Operation;
class OperationHolder : public QObject
{
Q_OBJECT
QThread mThread;
Operation *mOperation;
bool mRunning;
public:
OperationHolder (Operation *operation = 0);
void setOperation (Operation *operation);
bool isRunning() const;
void start();
void abort();
// Abort and wait until thread has finished.
void abortAndWait();
private slots:
void doneSlot (int type, bool failed);
signals:
void progress (int current, int max, int type);
void reportMessage (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint, int type);
void done (int type, bool failed);
void abortSignal();
};
}
#endif

@ -6,7 +6,7 @@
#include <QTemporaryFile>
#include <QTextStream>
#include "operation.hpp"
#include "operationholder.hpp"
CSMDoc::Runner::Runner (const boost::filesystem::path& projectPath)
: mRunning (false), mStartup (0), mProjectPath (projectPath)
@ -145,7 +145,7 @@ void CSMDoc::Runner::readyReadStandardOutput()
}
CSMDoc::SaveWatcher::SaveWatcher (Runner *runner, Operation *operation)
CSMDoc::SaveWatcher::SaveWatcher (Runner *runner, OperationHolder *operation)
: QObject (runner), mRunner (runner)
{
connect (operation, SIGNAL (done (int, bool)), this, SLOT (saveDone (int, bool)));

@ -16,6 +16,8 @@ class QTemporaryFile;
namespace CSMDoc
{
class OperationHolder;
class Runner : public QObject
{
Q_OBJECT
@ -74,7 +76,7 @@ namespace CSMDoc
public:
/// *this attaches itself to runner
SaveWatcher (Runner *runner, Operation *operation);
SaveWatcher (Runner *runner, OperationHolder *operation);
private slots:

@ -78,6 +78,9 @@ CSMDoc::Saving::Saving (Document& document, const boost::filesystem::path& proje
appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::MagicEffect> >
(mDocument.getData().getMagicEffects(), mState));
appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::StartScript> >
(mDocument.getData().getStartScripts(), mState));
appendStage (new WriteDialogueCollectionStage (mDocument, mState, false));
appendStage (new WriteDialogueCollectionStage (mDocument, mState, true));
@ -90,6 +93,10 @@ CSMDoc::Saving::Saving (Document& document, const boost::filesystem::path& proje
appendStage (new WritePathgridCollectionStage (mDocument, mState));
appendStage (new WriteLandCollectionStage (mDocument, mState));
appendStage (new WriteLandTextureCollectionStage (mDocument, mState));
// close file and clean up
appendStage (new CloseSaveStage (mState));

@ -90,7 +90,7 @@ void CSMDoc::WriteHeaderStage::perform (int stage, Messages& messages)
CSMDoc::WriteDialogueCollectionStage::WriteDialogueCollectionStage (Document& document,
SavingState& state, bool journal)
: mDocument (document), mState (state),
: mState (state),
mTopics (journal ? document.getData().getJournals() : document.getData().getTopics()),
mInfos (journal ? document.getData().getJournalInfos() : document.getData().getTopicInfos())
{}
@ -353,6 +353,74 @@ void CSMDoc::WritePathgridCollectionStage::perform (int stage, Messages& message
}
CSMDoc::WriteLandCollectionStage::WriteLandCollectionStage (Document& document,
SavingState& state)
: mDocument (document), mState (state)
{}
int CSMDoc::WriteLandCollectionStage::setup()
{
return mDocument.getData().getLand().getSize();
}
void CSMDoc::WriteLandCollectionStage::perform (int stage, Messages& messages)
{
const CSMWorld::Record<CSMWorld::Land>& land =
mDocument.getData().getLand().getRecord (stage);
if (land.mState==CSMWorld::RecordBase::State_Modified ||
land.mState==CSMWorld::RecordBase::State_ModifiedOnly)
{
CSMWorld::Land record = land.get();
mState.getWriter().startRecord (record.mLand->sRecordId);
record.mLand->save (mState.getWriter());
if(record.mLand->mLandData)
record.mLand->mLandData->save (mState.getWriter());
mState.getWriter().endRecord (record.mLand->sRecordId);
}
else if (land.mState==CSMWorld::RecordBase::State_Deleted)
{
/// \todo write record with delete flag
}
}
CSMDoc::WriteLandTextureCollectionStage::WriteLandTextureCollectionStage (Document& document,
SavingState& state)
: mDocument (document), mState (state)
{}
int CSMDoc::WriteLandTextureCollectionStage::setup()
{
return mDocument.getData().getLandTextures().getSize();
}
void CSMDoc::WriteLandTextureCollectionStage::perform (int stage, Messages& messages)
{
const CSMWorld::Record<CSMWorld::LandTexture>& landTexture =
mDocument.getData().getLandTextures().getRecord (stage);
if (landTexture.mState==CSMWorld::RecordBase::State_Modified ||
landTexture.mState==CSMWorld::RecordBase::State_ModifiedOnly)
{
CSMWorld::LandTexture record = landTexture.get();
mState.getWriter().startRecord (record.sRecordId);
record.save (mState.getWriter());
mState.getWriter().endRecord (record.sRecordId);
}
else if (landTexture.mState==CSMWorld::RecordBase::State_Deleted)
{
/// \todo write record with delete flag
}
}
CSMDoc::CloseSaveStage::CloseSaveStage (SavingState& state)
: mState (state)
{}

@ -7,6 +7,8 @@
#include "../world/idcollection.hpp"
#include "../world/scope.hpp"
#include <components/esm/defs.hpp>
#include "savingstate.hpp"
namespace ESM
@ -103,7 +105,14 @@ namespace CSMDoc
if (state==CSMWorld::RecordBase::State_Modified ||
state==CSMWorld::RecordBase::State_ModifiedOnly)
{
mState.getWriter().startRecord (mCollection.getRecord (stage).mModified.sRecordId);
// FIXME: A quick Workaround to support records which should not write
// NAME, including SKIL, MGEF and SCPT. If there are many more
// idcollection records that doesn't use NAME then a more generic
// solution may be required.
uint32_t name = mCollection.getRecord (stage).mModified.sRecordId;
mState.getWriter().startRecord (name);
if(name != ESM::REC_SKIL && name != ESM::REC_MGEF && name != ESM::REC_SCPT)
mState.getWriter().writeHNCString ("NAME", mCollection.getId (stage));
mCollection.getRecord (stage).mModified.save (mState.getWriter());
mState.getWriter().endRecord (mCollection.getRecord (stage).mModified.sRecordId);
@ -117,7 +126,6 @@ namespace CSMDoc
class WriteDialogueCollectionStage : public Stage
{
Document& mDocument;
SavingState& mState;
const CSMWorld::IdCollection<ESM::Dialogue>& mTopics;
CSMWorld::InfoCollection& mInfos;
@ -200,6 +208,40 @@ namespace CSMDoc
///< Messages resulting from this stage will be appended to \a messages.
};
class WriteLandCollectionStage : public Stage
{
Document& mDocument;
SavingState& mState;
public:
WriteLandCollectionStage (Document& document, SavingState& state);
virtual int setup();
///< \return number of steps
virtual void perform (int stage, Messages& messages);
///< Messages resulting from this stage will be appended to \a messages.
};
class WriteLandTextureCollectionStage : public Stage
{
Document& mDocument;
SavingState& mState;
public:
WriteLandTextureCollectionStage (Document& document, SavingState& state);
virtual int setup();
///< \return number of steps
virtual void perform (int stage, Messages& messages);
///< Messages resulting from this stage will be appended to \a messages.
};
class CloseSaveStage : public Stage
{
SavingState& mState;

@ -48,10 +48,6 @@ void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages &message
}
}
// Check if referenced object is in valid cell
if (mCells.searchId(cellRef.mCell) == -1)
messages.push_back(std::make_pair(id, " is referencing object from non existing cell " + cellRef.mCell));
// If object have owner, check if that owner reference is valid
if (!cellRef.mOwner.empty() && mReferencables.searchId(cellRef.mOwner) == -1)
messages.push_back(std::make_pair(id, " has non existing owner " + cellRef.mOwner));
@ -70,9 +66,9 @@ void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages &message
// Check item's faction rank
if (hasFaction && cellRef.mFactionRank < -1)
messages.push_back(std::make_pair(id, " has faction set but has invalid faction rank " + cellRef.mFactionRank));
messages.push_back(std::make_pair(id, " has faction set but has invalid faction rank " + boost::lexical_cast<std::string>(cellRef.mFactionRank)));
else if (!hasFaction && cellRef.mFactionRank != -2)
messages.push_back(std::make_pair(id, " has invalid faction rank " + cellRef.mFactionRank));
messages.push_back(std::make_pair(id, " has invalid faction rank " + boost::lexical_cast<std::string>(cellRef.mFactionRank)));
// If door have destination cell, check if that reference is valid
if (!cellRef.mDestCell.empty())

@ -0,0 +1,31 @@
#include "startscriptcheck.hpp"
#include <components/misc/stringops.hpp>
CSMTools::StartScriptCheckStage::StartScriptCheckStage (
const CSMWorld::IdCollection<ESM::StartScript>& startScripts,
const CSMWorld::IdCollection<ESM::Script>& scripts)
: mStartScripts (startScripts), mScripts (scripts)
{}
void CSMTools::StartScriptCheckStage::perform(int stage, CSMDoc::Messages& messages)
{
const CSMWorld::Record<ESM::StartScript>& record = mStartScripts.getRecord (stage);
if (record.isDeleted())
return;
std::string scriptId = record.get().mId;
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_StartScript, scriptId);
if (mScripts.searchId (Misc::StringUtils::lowerCase (scriptId))==-1)
messages.push_back (
std::make_pair (id, "Start script " + scriptId + " does not exist"));
}
int CSMTools::StartScriptCheckStage::setup()
{
return mStartScripts.getSize();
}

@ -0,0 +1,28 @@
#ifndef CSM_TOOLS_STARTSCRIPTCHECK_H
#define CSM_TOOLS_STARTSCRIPTCHECK_H
#include <components/esm/loadsscr.hpp>
#include <components/esm/loadscpt.hpp>
#include "../doc/stage.hpp"
#include "../world/idcollection.hpp"
namespace CSMTools
{
class StartScriptCheckStage : public CSMDoc::Stage
{
const CSMWorld::IdCollection<ESM::StartScript>& mStartScripts;
const CSMWorld::IdCollection<ESM::Script>& mScripts;
public:
StartScriptCheckStage (const CSMWorld::IdCollection<ESM::StartScript>& startScripts,
const CSMWorld::IdCollection<ESM::Script>& scripts);
virtual void perform(int stage, CSMDoc::Messages& messages);
virtual int setup();
};
}
#endif

@ -24,31 +24,32 @@
#include "scriptcheck.hpp"
#include "bodypartcheck.hpp"
#include "referencecheck.hpp"
#include "startscriptcheck.hpp"
CSMDoc::Operation *CSMTools::Tools::get (int type)
CSMDoc::OperationHolder *CSMTools::Tools::get (int type)
{
switch (type)
{
case CSMDoc::State_Verifying: return mVerifier;
case CSMDoc::State_Verifying: return &mVerifier;
}
return 0;
}
const CSMDoc::Operation *CSMTools::Tools::get (int type) const
const CSMDoc::OperationHolder *CSMTools::Tools::get (int type) const
{
return const_cast<Tools *> (this)->get (type);
}
CSMDoc::Operation *CSMTools::Tools::getVerifier()
CSMDoc::OperationHolder *CSMTools::Tools::getVerifier()
{
if (!mVerifier)
if (!mVerifierOperation)
{
mVerifier = new CSMDoc::Operation (CSMDoc::State_Verifying, false);
mVerifierOperation = new CSMDoc::Operation (CSMDoc::State_Verifying, false);
connect (mVerifier, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int)));
connect (mVerifier, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool)));
connect (mVerifier,
connect (&mVerifier, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int)));
connect (&mVerifier, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool)));
connect (&mVerifier,
SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)),
this, SLOT (verifierMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)));
@ -58,48 +59,49 @@ CSMDoc::Operation *CSMTools::Tools::getVerifier()
mandatoryIds.push_back ("GameHour");
mandatoryIds.push_back ("Month");
mandatoryIds.push_back ("PCRace");
mandatoryIds.push_back ("PCVampire");
mandatoryIds.push_back ("PCWerewolf");
mandatoryIds.push_back ("PCYear");
mVerifier->appendStage (new MandatoryIdStage (mData.getGlobals(),
mVerifierOperation->appendStage (new MandatoryIdStage (mData.getGlobals(),
CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Globals), mandatoryIds));
mVerifier->appendStage (new SkillCheckStage (mData.getSkills()));
mVerifierOperation->appendStage (new SkillCheckStage (mData.getSkills()));
mVerifier->appendStage (new ClassCheckStage (mData.getClasses()));
mVerifierOperation->appendStage (new ClassCheckStage (mData.getClasses()));
mVerifier->appendStage (new FactionCheckStage (mData.getFactions()));
mVerifierOperation->appendStage (new FactionCheckStage (mData.getFactions()));
mVerifier->appendStage (new RaceCheckStage (mData.getRaces()));
mVerifierOperation->appendStage (new RaceCheckStage (mData.getRaces()));
mVerifier->appendStage (new SoundCheckStage (mData.getSounds()));
mVerifierOperation->appendStage (new SoundCheckStage (mData.getSounds()));
mVerifier->appendStage (new RegionCheckStage (mData.getRegions()));
mVerifierOperation->appendStage (new RegionCheckStage (mData.getRegions()));
mVerifier->appendStage (new BirthsignCheckStage (mData.getBirthsigns()));
mVerifierOperation->appendStage (new BirthsignCheckStage (mData.getBirthsigns()));
mVerifier->appendStage (new SpellCheckStage (mData.getSpells()));
mVerifierOperation->appendStage (new SpellCheckStage (mData.getSpells()));
mVerifier->appendStage (new ReferenceableCheckStage (mData.getReferenceables().getDataSet(), mData.getRaces(), mData.getClasses(), mData.getFactions()));
mVerifierOperation->appendStage (new ReferenceableCheckStage (mData.getReferenceables().getDataSet(), mData.getRaces(), mData.getClasses(), mData.getFactions()));
mVerifier->appendStage (new ReferenceCheckStage(mData.getReferences(), mData.getReferenceables(), mData.getCells(), mData.getFactions()));
mVerifierOperation->appendStage (new ReferenceCheckStage(mData.getReferences(), mData.getReferenceables(), mData.getCells(), mData.getFactions()));
mVerifier->appendStage (new ScriptCheckStage (mDocument));
mVerifierOperation->appendStage (new ScriptCheckStage (mDocument));
mVerifier->appendStage(
mVerifierOperation->appendStage (new StartScriptCheckStage (mData.getStartScripts(), mData.getScripts()));
mVerifierOperation->appendStage(
new BodyPartCheckStage(
mData.getBodyParts(),
mData.getResources(
CSMWorld::UniversalId( CSMWorld::UniversalId::Type_Meshes )),
mData.getRaces() ));
mVerifier.setOperation (mVerifierOperation);
}
return mVerifier;
return &mVerifier;
}
CSMTools::Tools::Tools (CSMDoc::Document& document)
: mDocument (document), mData (document.getData()), mVerifier (0), mNextReportNumber (0)
: mDocument (document), mData (document.getData()), mVerifierOperation (0), mNextReportNumber (0)
{
// index 0: load error log
mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel));
@ -108,7 +110,11 @@ CSMTools::Tools::Tools (CSMDoc::Document& document)
CSMTools::Tools::~Tools()
{
delete mVerifier;
if (mVerifierOperation)
{
mVerifier.abortAndWait();
delete mVerifierOperation;
}
for (std::map<int, ReportModel *>::iterator iter (mReports.begin()); iter!=mReports.end(); ++iter)
delete iter->second;
@ -126,7 +132,7 @@ CSMWorld::UniversalId CSMTools::Tools::runVerifier()
void CSMTools::Tools::abortOperation (int type)
{
if (CSMDoc::Operation *operation = get (type))
if (CSMDoc::OperationHolder *operation = get (type))
operation->abort();
}
@ -141,7 +147,7 @@ int CSMTools::Tools::getRunningOperations() const
int result = 0;
for (int i=0; sOperations[i]!=-1; ++i)
if (const CSMDoc::Operation *operation = get (sOperations[i]))
if (const CSMDoc::OperationHolder *operation = get (sOperations[i]))
if (operation->isRunning())
result |= sOperations[i];

@ -5,6 +5,8 @@
#include <map>
#include "../doc/operationholder.hpp"
namespace CSMWorld
{
class Data;
@ -27,7 +29,8 @@ namespace CSMTools
CSMDoc::Document& mDocument;
CSMWorld::Data& mData;
CSMDoc::Operation *mVerifier;
CSMDoc::Operation *mVerifierOperation;
CSMDoc::OperationHolder mVerifier;
std::map<int, ReportModel *> mReports;
int mNextReportNumber;
std::map<int, int> mActiveReports; // type, report number
@ -36,12 +39,12 @@ namespace CSMTools
Tools (const Tools&);
Tools& operator= (const Tools&);
CSMDoc::Operation *getVerifier();
CSMDoc::OperationHolder *getVerifier();
CSMDoc::Operation *get (int type);
CSMDoc::OperationHolder *get (int type);
///< Returns a 0-pointer, if operation hasn't been used yet.
const CSMDoc::Operation *get (int type) const;
const CSMDoc::OperationHolder *get (int type) const;
///< Returns a 0-pointer, if operation hasn't been used yet.
public:

@ -20,7 +20,7 @@ namespace CSMWorld
{
class IdTable;
class IdTable;
class RecordBase;
struct RecordBase;
class ModifyCommand : public QUndoCommand
{

@ -254,6 +254,10 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
mPathgrids.addColumn (new RecordStateColumn<Pathgrid>);
mPathgrids.addColumn (new FixedRecordTypeColumn<Pathgrid> (UniversalId::Type_Pathgrid));
mStartScripts.addColumn (new StringIdColumn<ESM::StartScript>);
mStartScripts.addColumn (new RecordStateColumn<ESM::StartScript>);
mStartScripts.addColumn (new FixedRecordTypeColumn<ESM::StartScript> (UniversalId::Type_StartScript));
mRefs.addColumn (new StringIdColumn<CellRef> (true));
mRefs.addColumn (new RecordStateColumn<CellRef>);
mRefs.addColumn (new FixedRecordTypeColumn<CellRef> (UniversalId::Type_Reference));
@ -327,6 +331,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
addModel (new IdTable (&mSoundGens), UniversalId::Type_SoundGen);
addModel (new IdTable (&mMagicEffects), UniversalId::Type_MagicEffect);
addModel (new IdTable (&mPathgrids), UniversalId::Type_Pathgrid);
addModel (new IdTable (&mStartScripts), UniversalId::Type_StartScript);
addModel (new IdTable (&mReferenceables, IdTable::Feature_Preview),
UniversalId::Type_Referenceable);
addModel (new IdTable (&mRefs, IdTable::Feature_ViewCell | IdTable::Feature_Preview), UniversalId::Type_Reference);
@ -620,6 +625,16 @@ CSMWorld::SubCellCollection<CSMWorld::Pathgrid>& CSMWorld::Data::getPathgrids()
return mPathgrids;
}
const CSMWorld::IdCollection<ESM::StartScript>& CSMWorld::Data::getStartScripts() const
{
return mStartScripts;
}
CSMWorld::IdCollection<ESM::StartScript>& CSMWorld::Data::getStartScripts()
{
return mStartScripts;
}
const CSMWorld::Resources& CSMWorld::Data::getResources (const UniversalId& id) const
{
return mResourcesManager.get (id.getType());
@ -724,6 +739,7 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages)
case ESM::REC_SNDG: mSoundGens.load (*mReader, mBase); break;
case ESM::REC_MGEF: mMagicEffects.load (*mReader, mBase); break;
case ESM::REC_PGRD: mPathgrids.load (*mReader, mBase); break;
case ESM::REC_SSCR: mStartScripts.load (*mReader, mBase); break;
case ESM::REC_LTEX: mLandTextures.load (*mReader, mBase); break;
@ -734,7 +750,7 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages)
if (index!=-1 && !mBase)
mLand.getRecord (index).mModified.mLand->loadData (
ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | ESM::Land::DATA_VCLR |
ESM::Land::DATA_VTEX);
ESM::Land::DATA_VTEX | ESM::Land::DATA_WNAM);
break;
}

@ -25,6 +25,7 @@
#include <components/esm/loadbody.hpp>
#include <components/esm/loadsndg.hpp>
#include <components/esm/loadmgef.hpp>
#include <components/esm/loadsscr.hpp>
#include <components/esm/debugprofile.hpp>
#include <components/esm/filter.hpp>
@ -87,6 +88,7 @@ namespace CSMWorld
SubCellCollection<Pathgrid> mPathgrids;
IdCollection<ESM::DebugProfile> mDebugProfiles;
IdCollection<ESM::SoundGenerator> mSoundGens;
IdCollection<ESM::StartScript> mStartScripts;
InfoCollection mTopicInfos;
InfoCollection mJournalInfos;
IdCollection<Cell> mCells;
@ -238,6 +240,10 @@ namespace CSMWorld
SubCellCollection<Pathgrid>& getPathgrids();
const IdCollection<ESM::StartScript>& getStartScripts() const;
IdCollection<ESM::StartScript>& getStartScripts();
/// Throws an exception, if \a id does not match a resources list.
const Resources& getResources (const UniversalId& id) const;

@ -10,7 +10,7 @@
namespace CSMWorld
{
class CollectionBase;
class RecordBase;
struct RecordBase;
class IdTable : public IdTableBase
{

@ -26,7 +26,7 @@ void CSMWorld::InfoCollection::load (const Info& record, bool base)
if (!record2.get().mPrev.empty())
{
index = getIndex (record2.get().mPrev, topic);
index = getInfoIndex (record2.get().mPrev, topic);
if (index!=-1)
++index;
@ -34,7 +34,7 @@ void CSMWorld::InfoCollection::load (const Info& record, bool base)
if (index==-1 && !record2.get().mNext.empty())
{
index = getIndex (record2.get().mNext, topic);
index = getInfoIndex (record2.get().mNext, topic);
}
if (index==-1)
@ -60,7 +60,7 @@ void CSMWorld::InfoCollection::load (const Info& record, bool base)
}
}
int CSMWorld::InfoCollection::getIndex (const std::string& id, const std::string& topic) const
int CSMWorld::InfoCollection::getInfoIndex (const std::string& id, const std::string& topic) const
{
std::string fullId = Misc::StringUtils::lowerCase (topic) + "#" + id;

@ -6,7 +6,7 @@
namespace ESM
{
class Dialogue;
struct Dialogue;
}
namespace CSMWorld
@ -22,7 +22,7 @@ namespace CSMWorld
void load (const Info& record, bool base);
int getIndex (const std::string& id, const std::string& topic) const;
int getInfoIndex (const std::string& id, const std::string& topic) const;
///< Return index for record \a id or -1 (if not present; deleted records are considered)
///
/// \param id info ID without topic prefix

@ -22,6 +22,8 @@ namespace CSMWorld
virtual RecordBase *clone() const = 0;
virtual RecordBase *modifiedCopy() const = 0;
virtual void assign (const RecordBase& record) = 0;
///< Will throw an exception if the types don't match.
@ -38,8 +40,15 @@ namespace CSMWorld
ESXRecordT mBase;
ESXRecordT mModified;
Record();
Record(State state,
const ESXRecordT *base = 0, const ESXRecordT *modified = 0);
virtual RecordBase *clone() const;
virtual RecordBase *modifiedCopy() const;
virtual void assign (const RecordBase& record);
const ESXRecordT& get() const;
@ -58,6 +67,29 @@ namespace CSMWorld
///< Merge modified into base.
};
template <typename ESXRecordT>
Record<ESXRecordT>::Record()
: mBase(), mModified()
{ }
template <typename ESXRecordT>
Record<ESXRecordT>::Record(State state, const ESXRecordT *base, const ESXRecordT *modified)
{
if(base)
mBase = *base;
if(modified)
mModified = *modified;
this->mState = state;
}
template <typename ESXRecordT>
RecordBase *Record<ESXRecordT>::modifiedCopy() const
{
return new Record<ESXRecordT> (State_ModifiedOnly, 0, &(this->get()));
}
template <typename ESXRecordT>
RecordBase *Record<ESXRecordT>::clone() const
{

@ -5,8 +5,6 @@
namespace CSMWorld
{
class Cell;
/// \brief Wrapper for CellRef sub record
struct CellRef : public ESM::CellRef
{

@ -12,7 +12,7 @@
namespace CSMWorld
{
struct Cell;
struct UniversalId;
class UniversalId;
/// \brief References in cells
class RefCollection : public Collection<CellRef>

@ -9,7 +9,7 @@ namespace CSMWorld
{
class RefIdColumn;
class RefIdData;
class RecordBase;
struct RecordBase;
class RefIdAdapter
{

@ -156,10 +156,16 @@ namespace CSMWorld
Record<RecordT>& record = static_cast<Record<RecordT>&> (
data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType())));
RecordT record2 = record.get();
if (column==mModel.mModel)
record.get().mModel = value.toString().toUtf8().constData();
record2.mModel = value.toString().toUtf8().constData();
else
{
BaseRefIdAdapter<RecordT>::setData (column, data, index, value);
return;
}
record.setModified(record2);
}
struct NameColumns : public ModelColumns
@ -216,12 +222,18 @@ namespace CSMWorld
Record<RecordT>& record = static_cast<Record<RecordT>&> (
data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType())));
RecordT record2 = record.get();
if (column==mName.mName)
record.get().mName = value.toString().toUtf8().constData();
record2.mName = value.toString().toUtf8().constData();
else if (column==mName.mScript)
record.get().mScript = value.toString().toUtf8().constData();
record2.mScript = value.toString().toUtf8().constData();
else
{
ModelRefIdAdapter<RecordT>::setData (column, data, index, value);
return;
}
record.setModified(record2);
}
struct InventoryColumns : public NameColumns
@ -283,14 +295,20 @@ namespace CSMWorld
Record<RecordT>& record = static_cast<Record<RecordT>&> (
data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType())));
RecordT record2 = record.get();
if (column==mInventory.mIcon)
record.get().mIcon = value.toString().toUtf8().constData();
record2.mIcon = value.toString().toUtf8().constData();
else if (column==mInventory.mWeight)
record.get().mData.mWeight = value.toFloat();
record2.mData.mWeight = value.toFloat();
else if (column==mInventory.mValue)
record.get().mData.mValue = value.toInt();
record2.mData.mValue = value.toInt();
else
{
NameRefIdAdapter<RecordT>::setData (column, data, index, value);
return;
}
record.setModified(record2);
}
class PotionRefIdAdapter : public InventoryRefIdAdapter<ESM::Potion>
@ -364,12 +382,18 @@ namespace CSMWorld
Record<RecordT>& record = static_cast<Record<RecordT>&> (
data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType())));
RecordT record2 = record.get();
if (column==mEnchantable.mEnchantment)
record.get().mEnchant = value.toString().toUtf8().constData();
record2.mEnchant = value.toString().toUtf8().constData();
else if (column==mEnchantable.mEnchantmentPoints)
record.get().mData.mEnchant = value.toInt();
record2.mData.mEnchant = value.toInt();
else
{
InventoryRefIdAdapter<RecordT>::setData (column, data, index, value);
return;
}
record.setModified(record2);
}
struct ToolColumns : public InventoryColumns
@ -426,12 +450,18 @@ namespace CSMWorld
Record<RecordT>& record = static_cast<Record<RecordT>&> (
data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType())));
RecordT record2 = record.get();
if (column==mTools.mQuality)
record.get().mData.mQuality = value.toFloat();
record2.mData.mQuality = value.toFloat();
else if (column==mTools.mUses)
record.get().mData.mUses = value.toInt();
record2.mData.mUses = value.toInt();
else
{
InventoryRefIdAdapter<RecordT>::setData (column, data, index, value);
return;
}
record.setModified(record2);
}
struct ActorColumns : public NameColumns
@ -508,16 +538,17 @@ namespace CSMWorld
Record<RecordT>& record = static_cast<Record<RecordT>&> (
data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType())));
RecordT record2 = record.get();
if (column==mActors.mHasAi)
record.get().mHasAI = value.toInt();
record2.mHasAI = value.toInt();
else if (column==mActors.mHello)
record.get().mAiData.mHello = value.toInt();
record2.mAiData.mHello = value.toInt();
else if (column==mActors.mFlee)
record.get().mAiData.mFlee = value.toInt();
record2.mAiData.mFlee = value.toInt();
else if (column==mActors.mFight)
record.get().mAiData.mFight = value.toInt();
record2.mAiData.mFight = value.toInt();
else if (column==mActors.mAlarm)
record.get().mAiData.mAlarm = value.toInt();
record2.mAiData.mAlarm = value.toInt();
else
{
typename std::map<const RefIdColumn *, unsigned int>::const_iterator iter =
@ -525,15 +556,20 @@ namespace CSMWorld
if (iter!=mActors.mServices.end())
{
if (value.toInt()!=0)
record.get().mAiData.mServices |= iter->second;
record2.mAiData.mServices |= iter->second;
else
record.get().mAiData.mServices &= ~iter->second;
record2.mAiData.mServices &= ~iter->second;
}
else
{
NameRefIdAdapter<RecordT>::setData (column, data, index, value);
return;
}
}
record.setModified(record2);
}
class ApparatusRefIdAdapter : public InventoryRefIdAdapter<ESM::Apparatus>
{
const RefIdColumn *mType;

@ -470,8 +470,7 @@ 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;
std::auto_ptr<RecordBase> newRecord(mData.getRecord(mData.searchId(origin)).modifiedCopy());
mAdapters.find(type)->second->setId(*newRecord, destination);
mData.insertRecord(*newRecord, type, destination);
}

@ -55,6 +55,7 @@ namespace
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_SoundGens, "Sound Generators", 0 },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_MagicEffects, "Magic Effects", 0 },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Pathgrids, "Pathgrids", 0 },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_StartScripts, "Start Scripts", 0 },
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker
};
@ -118,6 +119,7 @@ namespace
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_SoundGen, "Sound Generator", 0 },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MagicEffect, "Magic Effect", 0 },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Pathgrid, "Pathgrid", 0 },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_StartScript, "Start Script", 0 },
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker
};

@ -128,6 +128,8 @@ namespace CSMWorld
Type_MagicEffect,
Type_Pathgrids,
Type_Pathgrid,
Type_StartScripts,
Type_StartScript,
Type_RunLog
};

@ -5,6 +5,7 @@
#include <string>
#include <boost/filesystem.hpp>
#include <boost/algorithm/string/case_conv.hpp>
#include <QHBoxLayout>
#include <QLabel>
@ -72,8 +73,11 @@ void CSVDoc::AdjusterWidget::setName (const QString& name, bool addon)
{
boost::filesystem::path path (name.toUtf8().data());
bool isLegacyPath = (path.extension() == ".esm" ||
path.extension() == ".esp");
std::string extension = path.extension().string();
boost::algorithm::to_lower(extension);
bool isLegacyPath = (extension == ".esm" ||
extension == ".esp");
bool isFilePathChanged = (path.parent_path().string() != mLocalData.string());

@ -147,17 +147,19 @@ void CSVDoc::FileDialog::slotUpdateAcceptButton(int)
void CSVDoc::FileDialog::slotUpdateAcceptButton(const QString &name, bool)
{
bool success = (mSelector->selectedFiles().size() > 0);
bool success = !mSelector->selectedFiles().empty();
bool isNew = (mAction == ContentAction_New);
if (isNew)
success = success && !(name.isEmpty());
else
else if (success)
{
ContentSelectorModel::EsmFile *file = mSelector->selectedFiles().back();
mAdjusterWidget->setName (file->filePath(), !file->isGameFile());
}
else
mAdjusterWidget->setName ("", true);
ui.projectButtonBox->button (QDialogButtonBox::Ok)->setEnabled (success);
}

@ -20,7 +20,7 @@ void CSVDoc::LoadingDocument::closeEvent (QCloseEvent *event)
CSVDoc::LoadingDocument::LoadingDocument (CSMDoc::Document *document)
: mDocument (document), mAborted (false), mMessages (0), mTotalRecords (0)
{
setWindowTitle (("Opening " + document->getSavePath().filename().string()).c_str());
setWindowTitle (QString::fromUtf8((std::string("Opening ") + document->getSavePath().filename().string()).c_str()));
setMinimumWidth (400);

@ -96,7 +96,7 @@ QWidget *CSVDoc::StartupDialogue::createTools()
CSVDoc::StartupDialogue::StartupDialogue() : mWidth (0), mColumn (2)
{
setWindowTitle ("Open CS");
setWindowTitle ("OpenMW-CS");
QVBoxLayout *layout = new QVBoxLayout (this);

@ -26,7 +26,7 @@ void CSVDoc::SubView::updateUserSetting (const QString &, const QStringList &)
void CSVDoc::SubView::setUniversalId (const CSMWorld::UniversalId& id)
{
mUniversalId = id;
setWindowTitle (mUniversalId.toString().c_str());
setWindowTitle (QString::fromUtf8(mUniversalId.toString().c_str()));
}
void CSVDoc::SubView::closeEvent (QCloseEvent *event)

@ -173,6 +173,10 @@ void CSVDoc::View::setupMechanicsMenu()
QAction *effects = new QAction (tr ("Magic Effects"), this);
connect (effects, SIGNAL (triggered()), this, SLOT (addMagicEffectsSubView()));
mechanics->addAction (effects);
QAction *startScripts = new QAction (tr ("Start Scripts"), this);
connect (startScripts, SIGNAL (triggered()), this, SLOT (addStartScriptsSubView()));
mechanics->addAction (startScripts);
}
void CSVDoc::View::setupCharacterMenu()
@ -320,7 +324,7 @@ void CSVDoc::View::updateTitle()
if (hideTitle)
stream << " - " << mSubViews.at (0)->getTitle();
setWindowTitle (stream.str().c_str());
setWindowTitle (QString::fromUtf8(stream.str().c_str()));
}
void CSVDoc::View::updateSubViewIndicies(SubView *view)
@ -481,6 +485,8 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin
(!isReferenceable && id == sb->getUniversalId()))
{
sb->setFocus();
if (!hint.empty())
sb->useHint (hint);
return;
}
}
@ -511,8 +517,6 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin
assert(view);
view->setParent(this);
mSubViews.append(view); // only after assert
if (!hint.empty())
view->useHint (hint);
int minWidth = userSettings.setting ("window/minimum-width", QString("325")).toInt();
view->setMinimumWidth(minWidth);
@ -534,6 +538,9 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin
this, SLOT (updateSubViewIndicies (SubView *)));
view->show();
if (!hint.empty())
view->useHint (hint);
}
void CSVDoc::View::newView()
@ -716,6 +723,11 @@ void CSVDoc::View::addPathgridSubView()
addSubView (CSMWorld::UniversalId::Type_Pathgrids);
}
void CSVDoc::View::addStartScriptsSubView()
{
addSubView (CSMWorld::UniversalId::Type_StartScripts);
}
void CSVDoc::View::abortOperation (int type)
{
mDocument->abortOperation (type);

@ -215,6 +215,8 @@ namespace CSVDoc
void addPathgridSubView();
void addStartScriptsSubView();
void toggleShowStatusBar (bool show);
void loadErrorLog();

@ -248,7 +248,7 @@ bool CSVDoc::ViewManager::showModifiedDocumentMessageBox (CSVDoc::View *view)
QMessageBox messageBox(view);
CSMDoc::Document *document = view->getDocument();
messageBox.setWindowTitle (document->getSavePath().filename().string().c_str());
messageBox.setWindowTitle (QString::fromUtf8(document->getSavePath().filename().string().c_str()));
messageBox.setText ("The document has been modified.");
messageBox.setInformativeText ("Do you want to save your changes?");
messageBox.setStandardButtons (QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);

@ -76,7 +76,7 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st
if (landIndex != -1)
{
const ESM::Land* esmLand = land.getRecord(mId).get().mLand.get();
if(esmLand)
if(esmLand && esmLand->mDataTypes&ESM::Land::DATA_VHGT)
{
mTerrain.reset(new Terrain::TerrainGrid(sceneManager, new TerrainStorage(mData), Element_Terrain, true,
Terrain::Align_XY));

@ -22,7 +22,7 @@ namespace Resource
namespace CSMWorld
{
class Data;
class CellRef;
struct CellRef;
}
namespace CSVWorld

@ -30,7 +30,7 @@ void CSVTools::ReportTable::contextMenuEvent (QContextMenuEvent *event)
void CSVTools::ReportTable::mouseMoveEvent (QMouseEvent *event)
{
if (event->buttons() & Qt::LeftButton)
startDrag (*this);
startDragFromTable (*this);
}
void CSVTools::ReportTable::mouseDoubleClickEvent (QMouseEvent *event)

@ -2,6 +2,7 @@
#include <utility>
#include <memory>
#include <stdexcept>
#include <QGridLayout>
#include <QLabel>
@ -39,8 +40,12 @@ QAbstractItemDelegate(parent),
mTable(table)
{}
void CSVWorld::NotEditableSubDelegate::setEditorData (QLabel* editor, const QModelIndex& index) const
void CSVWorld::NotEditableSubDelegate::setEditorData (QWidget* editor, const QModelIndex& index) const
{
QLabel* label = qobject_cast<QLabel*>(editor);
if(!label)
return;
QVariant v = index.data(Qt::EditRole);
if (!v.isValid())
{
@ -53,16 +58,17 @@ void CSVWorld::NotEditableSubDelegate::setEditorData (QLabel* editor, const QMod
if (QVariant::String == v.type())
{
editor->setText(v.toString());
} else //else we are facing enums
label->setText(v.toString());
}
else //else we are facing enums
{
int data = v.toInt();
std::vector<std::string> enumNames (CSMWorld::Columns::getEnums (static_cast<CSMWorld::Columns::ColumnId> (mTable->getColumnId (index.column()))));
editor->setText(QString::fromUtf8(enumNames.at(data).c_str()));
label->setText(QString::fromUtf8(enumNames.at(data).c_str()));
}
}
void CSVWorld::NotEditableSubDelegate::setModelData (QWidget* editor, QAbstractItemModel* model, const QModelIndex& index, CSMWorld::ColumnBase::Display display) const
void CSVWorld::NotEditableSubDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const
{
//not editable widgets will not save model data
}
@ -79,8 +85,7 @@ QSize CSVWorld::NotEditableSubDelegate::sizeHint (const QStyleOptionViewItem& op
QWidget* CSVWorld::NotEditableSubDelegate::createEditor (QWidget *parent,
const QStyleOptionViewItem& option,
const QModelIndex& index,
CSMWorld::ColumnBase::Display display) const
const QModelIndex& index) const
{
return new QLabel(parent);
}
@ -223,6 +228,11 @@ void CSVWorld::DialogueDelegateDispatcher::setEditorData (QWidget* editor, const
}
}
void CSVWorld::DialogueDelegateDispatcher::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const
{
setModelData(editor, model, index, CSMWorld::ColumnBase::Display_None);
}
void CSVWorld::DialogueDelegateDispatcher::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index, CSMWorld::ColumnBase::Display display) const
{
std::map<int, CommandDelegate*>::const_iterator delegateIt(mDelegates.find(display));
@ -257,7 +267,7 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase::
QWidget* editor = NULL;
if (! (mTable->flags (index) & Qt::ItemIsEditable))
{
return mNotEditableDelegate.createEditor(qobject_cast<QWidget*>(mParent), QStyleOptionViewItem(), index, display);
return mNotEditableDelegate.createEditor(qobject_cast<QWidget*>(mParent), QStyleOptionViewItem(), index);
}
std::map<int, CommandDelegate*>::iterator delegateIt(mDelegates.find(display));
@ -266,6 +276,8 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase::
editor = delegateIt->second->createEditor(qobject_cast<QWidget*>(mParent), QStyleOptionViewItem(), index, display);
DialogueDelegateDispatcherProxy* proxy = new DialogueDelegateDispatcherProxy(editor, display);
// NOTE: For each entry in CSVWorld::CommandDelegate::createEditor() a corresponding entry
// is required here
if (qobject_cast<DropLineEdit*>(editor))
{
connect(editor, SIGNAL(editingFinished()), proxy, SLOT(editorDataCommited()));
@ -286,10 +298,12 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase::
{
connect(editor, SIGNAL(currentIndexChanged (int)), proxy, SLOT(editorDataCommited()));
}
else if (qobject_cast<QAbstractSpinBox*>(editor))
else if (qobject_cast<QAbstractSpinBox*>(editor) || qobject_cast<QLineEdit*>(editor))
{
connect(editor, SIGNAL(editingFinished()), proxy, SLOT(editorDataCommited()));
}
else // throw an exception because this is a coding error
throw std::logic_error ("Dialogue editor type missing");
connect(proxy, SIGNAL(editorDataCommited(QWidget*, const QModelIndex&, CSMWorld::ColumnBase::Display)), this, SLOT(editorDataCommited(QWidget*, const QModelIndex&, CSMWorld::ColumnBase::Display)));
mProxys.push_back(proxy); //deleted in the destructor

@ -40,9 +40,9 @@ namespace CSVWorld
public:
NotEditableSubDelegate(const CSMWorld::IdTable* table, QObject * parent = 0);
virtual void setEditorData (QLabel* editor, const QModelIndex& index) const;
virtual void setEditorData (QWidget* editor, const QModelIndex& index) const;
virtual void setModelData (QWidget* editor, QAbstractItemModel* model, const QModelIndex& index, CSMWorld::ColumnBase::Display display) const;
virtual void setModelData (QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const;
virtual void paint (QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const;
///< does nothing
@ -52,8 +52,7 @@ namespace CSVWorld
virtual QWidget *createEditor (QWidget *parent,
const QStyleOptionViewItem& option,
const QModelIndex& index,
CSMWorld::ColumnBase::Display display = CSMWorld::ColumnBase::Display_None) const;
const QModelIndex& index) const;
};
//this can't be nested into the DialogueDelegateDispatcher, because it needs to emit signals
@ -119,6 +118,8 @@ namespace CSVWorld
virtual void setEditorData (QWidget* editor, const QModelIndex& index) const;
virtual void setModelData (QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const;
virtual void setModelData (QWidget* editor, QAbstractItemModel* model, const QModelIndex& index, CSMWorld::ColumnBase::Display display) const;
virtual void paint (QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const;

@ -3,7 +3,7 @@
#include "../../model/world/tablemimedata.hpp"
#include "dragrecordtable.hpp"
void CSVWorld::DragRecordTable::startDrag (const CSVWorld::DragRecordTable& table)
void CSVWorld::DragRecordTable::startDragFromTable (const CSVWorld::DragRecordTable& table)
{
CSMWorld::TableMimeData* mime = new CSMWorld::TableMimeData (table.getDraggedRecords(), mDocument);

@ -33,7 +33,7 @@ namespace CSVWorld
void setEditLock(bool locked);
protected:
void startDrag(const DragRecordTable& table);
void startDragFromTable(const DragRecordTable& table);
void dragEnterEvent(QDragEnterEvent *event);

@ -46,7 +46,6 @@ QWidget *CSVWorld::EnumDelegate::createEditor(QWidget *parent,
const QModelIndex& index) const
{
return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_None);
//overloading virtual functions is HARD
}
QWidget *CSVWorld::EnumDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem& option,

@ -345,7 +345,7 @@ void CSVWorld::RegionMap::viewInTable()
void CSVWorld::RegionMap::mouseMoveEvent (QMouseEvent* event)
{
startDrag(*this);
startDragFromTable(*this);
}
std::vector< CSMWorld::UniversalId > CSVWorld::RegionMap::getDraggedRecords() const

@ -68,6 +68,7 @@ void CSVWorld::ScriptSubView::useHint (const std::string& hint)
if (cursor.movePosition (QTextCursor::Down, QTextCursor::MoveAnchor, line))
cursor.movePosition (QTextCursor::Right, QTextCursor::MoveAnchor, column);
mEditor->setFocus();
mEditor->setTextCursor (cursor);
}
}

@ -43,6 +43,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
CSMWorld::UniversalId::Type_BodyParts,
CSMWorld::UniversalId::Type_SoundGens,
CSMWorld::UniversalId::Type_Pathgrids,
CSMWorld::UniversalId::Type_StartScripts,
CSMWorld::UniversalId::Type_None // end marker
};
@ -123,6 +124,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
CSMWorld::UniversalId::Type_BodyPart,
CSMWorld::UniversalId::Type_SoundGen,
CSMWorld::UniversalId::Type_Pathgrid,
CSMWorld::UniversalId::Type_StartScript,
CSMWorld::UniversalId::Type_None // end marker
};

@ -635,7 +635,7 @@ void CSVWorld::Table::mouseMoveEvent (QMouseEvent* event)
{
if (event->buttons() & Qt::LeftButton)
{
startDrag(*this);
startDragFromTable(*this);
}
}

@ -139,6 +139,12 @@ void CSVWorld::CommandDelegate::setModelData (QWidget *editor, QAbstractItemMode
///< \todo provide some kind of feedback to the user, indicating that editing is currently not possible.
}
QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleOptionViewItem& option,
const QModelIndex& index) const
{
return createEditor (parent, option, index, CSMWorld::ColumnBase::Display_None);
}
QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleOptionViewItem& option,
const QModelIndex& index, CSMWorld::ColumnBase::Display display) const
{
@ -152,6 +158,8 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO
}
}
// NOTE: for each editor type (e.g. QLineEdit) there needs to be a corresponding
// entry in CSVWorld::DialogueDelegateDispatcher::makeEditor()
switch (display)
{
case CSMWorld::ColumnBase::Display_Colour:
@ -228,6 +236,11 @@ bool CSVWorld::CommandDelegate::isEditLocked() const
return mEditLock;
}
void CSVWorld::CommandDelegate::setEditorData (QWidget *editor, const QModelIndex& index) const
{
setEditorData (editor, index, false);
}
void CSVWorld::CommandDelegate::setEditorData (QWidget *editor, const QModelIndex& index, bool tryDisplay) const
{
QVariant v = index.data(Qt::EditRole);

@ -130,10 +130,14 @@ namespace CSVWorld
virtual void setModelData (QWidget *editor, QAbstractItemModel *model,
const QModelIndex& index) const;
virtual QWidget *createEditor (QWidget *parent,
const QStyleOptionViewItem& option,
const QModelIndex& index) const;
virtual QWidget *createEditor (QWidget *parent,
const QStyleOptionViewItem& option,
const QModelIndex& index,
CSMWorld::ColumnBase::Display display = CSMWorld::ColumnBase::Display_None) const;
CSMWorld::ColumnBase::Display display) const;
void setEditLock (bool locked);
@ -141,8 +145,9 @@ namespace CSVWorld
///< \return Does column require update?
virtual void setEditorData (QWidget *editor, const QModelIndex& index, bool tryDisplay = false) const;
virtual void setEditorData (QWidget *editor, const QModelIndex& index) const;
virtual void setEditorData (QWidget *editor, const QModelIndex& index, bool tryDisplay) const;
public slots:

@ -7,6 +7,7 @@ set(GAME
)
if (ANDROID)
set(GAME ${GAME} android_commandLine.cpp)
set(GAME ${GAME} android_main.c)
endif()
@ -104,7 +105,6 @@ find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS})
if (NOT ANDROID)
add_executable(openmw
${OPENMW_LIBS} ${OPENMW_LIBS_HEADER}
${OPENMW_FILES}
${GAME} ${GAME_HEADER}
${APPLE_BUNDLE_RESOURCES}
@ -112,7 +112,6 @@ if (NOT ANDROID)
else ()
add_library(openmw
SHARED
${OPENMW_LIBS} ${OPENMW_LIBS_HEADER}
${OPENMW_FILES}
${GAME} ${GAME_HEADER}
)
@ -120,9 +119,10 @@ endif ()
# Sound stuff - here so CMake doesn't stupidly recompile EVERYTHING
# when we change the backend.
include_directories(${SOUND_INPUT_INCLUDES} ${BULLET_INCLUDE_DIRS})
include_directories(${SOUND_INPUT_INCLUDES})
target_link_libraries(openmw
${OENGINE_LIBRARY}
${OGRE_LIBRARIES}
${OGRE_STATIC_PLUGINS}
${SHINY_LIBRARIES}

@ -0,0 +1,27 @@
#include "android_commandLine.h"
#include "string.h"
const char **argvData;
int argcData;
extern "C" void releaseArgv();
void releaseArgv() {
delete[] argvData;
}
JNIEXPORT void JNICALL Java_ui_activity_GameActivity_commandLine(JNIEnv *env,
jobject obj, jint argc, jobjectArray stringArray) {
jboolean iscopy;
argcData = (int) argc;
argvData = new const char *[argcData + 1];
argvData[0] = "openmw";
for (int i = 1; i < argcData + 1; i++) {
jstring string = (jstring) (env)->GetObjectArrayElement(stringArray,
i - 1);
argvData[i] = (env)->GetStringUTFChars(string, &iscopy);
(env)->DeleteLocalRef(string);
}
(env)->DeleteLocalRef(stringArray);
}

@ -0,0 +1,16 @@
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
#ifndef _Included_ui_activity_GameActivity_commandLine
#define _Included_ui_activity_GameActivity_commandLine
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT void JNICALL Java_ui_activity_GameActivity_commandLine(JNIEnv *env, jobject obj,jint argcData, jobjectArray stringArray);
#ifdef __cplusplus
}
#endif
#endif

@ -1,38 +1,33 @@
#include "../../SDL_internal.h"
#ifdef __ANDROID__
#include "SDL_main.h"
/*******************************************************************************
Functions called by JNI
*******************************************************************************/
*******************************************************************************/
#include <jni.h>
/* Called before to initialize JNI bindings */
extern void SDL_Android_Init(JNIEnv* env, jclass cls);
extern int argcData;
extern const char **argvData;
void releaseArgv();
int Java_org_libsdl_app_SDLActivity_nativeInit(JNIEnv* env, jclass cls, jobject obj)
{
int Java_org_libsdl_app_SDLActivity_nativeInit(JNIEnv* env, jclass cls,
jobject obj) {
SDL_Android_Init(env, cls);
SDL_SetMainReady();
/* Run the application code! */
/* Run the application code! */
int status;
char *argv[2];
argv[0] = SDL_strdup("openmw");
argv[1] = NULL;
status = main(1, argv);
status = main(argcData+1, argvData);
releaseArgv();
/* Do not issue an exit or the whole application will terminate instead of just the SDL thread */
/* exit(status); */

@ -10,6 +10,8 @@
#include <SDL.h>
#include <openengine/misc/rng.hpp>
#include <components/compiler/extensions0.hpp>
#include <components/bsa/resources.hpp>
@ -191,15 +193,13 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager)
, mExportFonts(false)
, mNewGame (false)
{
std::srand ( std::time(NULL) );
OEngine::Misc::Rng::init();
std::srand ( static_cast<unsigned int>(std::time(NULL)) );
MWClass::registerClasses();
Uint32 flags = SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE;
Uint32 flags = SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE|SDL_INIT_GAMECONTROLLER|SDL_INIT_JOYSTICK;
if(SDL_WasInit(flags) == 0)
{
//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)
{
@ -368,9 +368,29 @@ 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.getUserConfigPath() / "input_v2.xml").string();
std::string keybinderUser = (mCfgMgr.getUserConfigPath() / "input_v3.xml").string();
bool keybinderUserExists = boost::filesystem::exists(keybinderUser);
MWInput::InputManager* input = new MWInput::InputManager (*mOgre, *this, keybinderUser, keybinderUserExists, mGrab);
if(!keybinderUserExists)
{
std::string input2 = (mCfgMgr.getUserConfigPath() / "input_v2.xml").string();
if(boost::filesystem::exists(input2)) {
boost::filesystem::copy_file(input2, keybinderUser);
keybinderUserExists = boost::filesystem::exists(keybinderUser);
}
}
// find correct path to the game controller bindings
const std::string localdefault = mCfgMgr.getLocalPath().string() + "/gamecontrollerdb.cfg";
const std::string globaldefault = mCfgMgr.getGlobalPath().string() + "/gamecontrollerdb.cfg";
std::string gameControllerdb;
if (boost::filesystem::exists(localdefault))
gameControllerdb = localdefault;
else if (boost::filesystem::exists(globaldefault))
gameControllerdb = globaldefault;
else
gameControllerdb = ""; //if it doesn't exist, pass in an empty string
MWInput::InputManager* input = new MWInput::InputManager (*mOgre, *this, keybinderUser, keybinderUserExists, gameControllerdb, mGrab);
mEnvironment.setInputManager (input);
MWGui::WindowManager* window = new MWGui::WindowManager(

@ -290,7 +290,7 @@ public:
std::streamsize write(const char *str, std::streamsize size)
{
// Make a copy for null termination
std::string tmp (str, size);
std::string tmp (str, static_cast<unsigned int>(size));
// Write string to Visual Studio Debug output
OutputDebugString (tmp.c_str ());
return size;

@ -37,11 +37,23 @@ namespace MWBase
virtual bool getControlSwitch (const std::string& sw) = 0;
virtual std::string getActionDescription (int action) = 0;
virtual std::string getActionBindingName (int action) = 0;
virtual std::vector<int> getActionSorting () = 0;
virtual std::string getActionKeyBindingName (int action) = 0;
virtual std::string getActionControllerBindingName (int action) = 0;
virtual std::string sdlControllerAxisToString(int axis) = 0;
virtual std::string sdlControllerButtonToString(int button) = 0;
///Actions available for binding to keyboard buttons
virtual std::vector<int> getActionKeySorting() = 0;
///Actions available for binding to controller buttons
virtual std::vector<int> getActionControllerSorting() = 0;
virtual int getNumActions() = 0;
virtual void enableDetectingBindingMode (int action) = 0;
virtual void resetToDefaultBindings() = 0;
///If keyboard is true, only pay attention to keyboard events. If false, only pay attention to controller events (excluding esc)
virtual void enableDetectingBindingMode (int action, bool keyboard) = 0;
virtual void resetToDefaultKeyBindings() = 0;
virtual void resetToDefaultControllerBindings() = 0;
/// Returns if the last used input device was a joystick or a keyboard
/// @return true if joystick, false otherwise
virtual bool joystickLastUsed() = 0;
};
}

@ -20,7 +20,7 @@ namespace MWWorld
namespace MWSound
{
class Sound;
class Sound_Decoder;
struct Sound_Decoder;
typedef boost::shared_ptr<Sound_Decoder> DecoderPtr;
}

@ -149,17 +149,14 @@ namespace MWBase
/// \todo investigate, if we really need to expose every single lousy UI element to the outside world
virtual MWGui::DialogueWindow* getDialogueWindow() = 0;
virtual MWGui::ContainerWindow* getContainerWindow() = 0;
virtual MWGui::InventoryWindow* getInventoryWindow() = 0;
virtual MWGui::BookWindow* getBookWindow() = 0;
virtual MWGui::ScrollWindow* getScrollWindow() = 0;
virtual MWGui::CountDialog* getCountDialog() = 0;
virtual MWGui::ConfirmationDialog* getConfirmationDialog() = 0;
virtual MWGui::TradeWindow* getTradeWindow() = 0;
virtual MWGui::SpellBuyingWindow* getSpellBuyingWindow() = 0;
virtual MWGui::TravelWindow* getTravelWindow() = 0;
virtual MWGui::SpellWindow* getSpellWindow() = 0;
virtual MWGui::Console* getConsole() = 0;
virtual void updateSpellWindow() = 0;
virtual void setConsoleSelectedObject(const MWWorld::Ptr& object) = 0;
virtual void wmUpdateFps(float fps, unsigned int triangleCount, unsigned int batchCount) = 0;
@ -181,12 +178,6 @@ namespace MWBase
virtual void configureSkills (const SkillList& major, const SkillList& minor) = 0;
///< configure skill groups, each set contains the skill ID for that group.
virtual void setReputation (int reputation) = 0;
///< set the current reputation value
virtual void setBounty (int bounty) = 0;
///< set the current bounty value
virtual void updateSkillArea() = 0;
///< update display of skills, factions, birth sign, reputation and bounty
@ -303,6 +294,12 @@ namespace MWBase
virtual void startTraining(MWWorld::Ptr actor) = 0;
virtual void startRepair(MWWorld::Ptr actor) = 0;
virtual void startRepairItem(MWWorld::Ptr item) = 0;
virtual void startTravel(const MWWorld::Ptr& actor) = 0;
virtual void startSpellBuying(const MWWorld::Ptr& actor) = 0;
virtual void startTrade(const MWWorld::Ptr& actor) = 0;
virtual void openContainer(const MWWorld::Ptr& container, bool loot) = 0;
virtual void showBook(const MWWorld::Ptr& item, bool showTakeButton) = 0;
virtual void showScroll(const MWWorld::Ptr& item, bool showTakeButton) = 0;
virtual void showSoulgemDialog (MWWorld::Ptr item) = 0;
@ -332,9 +329,8 @@ namespace MWBase
/// Does the current stack of GUI-windows permit saving?
virtual bool isSavingAllowed() const = 0;
/// Returns the current Modal
/** Used to send exit command to active Modal when Esc is pressed **/
virtual MWGui::WindowModal* getCurrentModal() const = 0;
/// Send exit command to active Modal window
virtual void exitCurrentModal() = 0;
/// Sets the current Modal
/** Used to send exit command to active Modal when Esc is pressed **/

@ -49,7 +49,7 @@ namespace MWRender
namespace MWMechanics
{
class Movement;
struct Movement;
}
namespace MWWorld
@ -205,10 +205,8 @@ namespace MWBase
///< Return a pointer to a liveCellRef which contains \a ptr.
/// \note Search is limited to the active cells.
/// \todo enable reference in the OGRE scene
virtual void enable (const MWWorld::Ptr& ptr) = 0;
/// \todo disable reference in the OGRE scene
virtual void disable (const MWWorld::Ptr& ptr) = 0;
virtual void advanceTime (double hours) = 0;
@ -268,6 +266,8 @@ namespace MWBase
virtual MWWorld::Ptr getFacedObject() = 0;
///< Return pointer to the object the player is looking at, if it is within activation range
virtual float getMaxActivationDistance() = 0;
/// 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, or alternatively the "Bip01 Head" node as a basis.
@ -551,7 +551,7 @@ namespace MWBase
virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const Ogre::Vector3& worldPos) = 0;
virtual void explodeSpell (const Ogre::Vector3& origin, const ESM::EffectList& effects,
const MWWorld::Ptr& caster, int rangeType, const std::string& id, const std::string& sourceName) = 0;
const MWWorld::Ptr& caster, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName) = 0;
virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor) = 0;

@ -155,7 +155,7 @@ namespace MWClass
bool Apparatus::canSell (const MWWorld::Ptr& item, int npcServices) const
{
return npcServices & ESM::NPC::Apparatus;
return (npcServices & ESM::NPC::Apparatus) != 0;
}
float Apparatus::getWeight(const MWWorld::Ptr &ptr) const

@ -154,9 +154,9 @@ namespace MWClass
const MWWorld::Store<ESM::GameSetting> &gmst =
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
float iWeight = gmst.find (typeGmst)->getInt();
float iWeight = floor(gmst.find(typeGmst)->getFloat());
float epsilon = 5e-4;
float epsilon = 0.0005f;
if (ref->mBase->mData.mWeight == 0)
return ESM::Skill::Unarmored;
@ -245,7 +245,8 @@ namespace MWClass
else
typeText = "#{sHeavy}";
text += "\n#{sArmorRating}: " + MWGui::ToolTips::toString(ref->mBase->mData.mArmor);
text += "\n#{sArmorRating}: " + MWGui::ToolTips::toString(getEffectiveArmorRating(ptr,
MWBase::Environment::get().getWorld()->getPlayerPtr()));
int remainingHealth = getItemHealth(ptr);
text += "\n#{sCondition}: " + MWGui::ToolTips::toString(remainingHealth) + "/"
@ -261,7 +262,7 @@ namespace MWClass
info.enchant = ref->mBase->mEnchant;
if (!info.enchant.empty())
info.remainingEnchantCharge = ptr.getCellRef().getEnchantmentCharge();
info.remainingEnchantCharge = static_cast<int>(ptr.getCellRef().getEnchantmentCharge());
info.text = text;
@ -290,6 +291,22 @@ namespace MWClass
return record->mId;
}
int Armor::getEffectiveArmorRating(const MWWorld::Ptr &ptr, const MWWorld::Ptr &actor) const
{
MWWorld::LiveCellRef<ESM::Armor> *ref = ptr.get<ESM::Armor>();
int armorSkillType = getEquipmentSkill(ptr);
int armorSkill = actor.getClass().getSkill(actor, armorSkillType);
const MWBase::World *world = MWBase::Environment::get().getWorld();
int iBaseArmorSkill = world->getStore().get<ESM::GameSetting>().find("iBaseArmorSkill")->getInt();
if(ref->mBase->mData.mWeight == 0)
return ref->mBase->mData.mArmor;
else
return ref->mBase->mData.mArmor * armorSkill / iBaseArmorSkill;
}
std::pair<int, std::string> Armor::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const
{
MWWorld::InventoryStore& invStore = npc.getClass().getInventoryStore(npc);

@ -86,6 +86,9 @@ namespace MWClass
virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const;
virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const;
/// Get the effective armor rating, factoring in the actor's skills, for the given armor.
virtual int getEffectiveArmorRating(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const;
};
}

@ -203,7 +203,7 @@ namespace MWClass
info.enchant = ref->mBase->mEnchant;
if (!info.enchant.empty())
info.remainingEnchantCharge = ptr.getCellRef().getEnchantmentCharge();
info.remainingEnchantCharge = static_cast<int>(ptr.getCellRef().getEnchantmentCharge());
info.text = text;

@ -1,6 +1,8 @@
#include "creature.hpp"
#include <openengine/misc/rng.hpp>
#include <components/esm/loadcrea.hpp>
#include <components/esm/creaturestate.hpp>
@ -103,9 +105,9 @@ namespace MWClass
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);
data->mCreatureStats.setHealth(static_cast<float>(ref->mBase->mData.mHealth));
data->mCreatureStats.setMagicka(static_cast<float>(ref->mBase->mData.mMana));
data->mCreatureStats.setFatigue(static_cast<float>(ref->mBase->mData.mFatigue));
data->mCreatureStats.setLevel(ref->mBase->mData.mLevel);
@ -164,7 +166,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
MWRender::Actors& actors = renderingInterface.getActors();
actors.insertCreature(ptr, model, ref->mBase->mFlags & ESM::Creature::Weapon);
actors.insertCreature(ptr, model, (ref->mBase->mFlags & ESM::Creature::Weapon) != 0);
}
void Creature::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const
@ -249,7 +251,7 @@ namespace MWClass
float hitchance = MWMechanics::getHitChance(ptr, victim, ref->mBase->mData.mCombat);
if((::rand()/(RAND_MAX+1.0)) > hitchance/100.0f)
if(OEngine::Misc::Rng::rollProbability() >= hitchance/100.0f)
{
victim.getClass().onHit(victim, 0.0f, false, MWWorld::Ptr(), ptr, false);
MWMechanics::reduceWeaponCondition(0.f, false, weapon, ptr);
@ -288,9 +290,7 @@ namespace MWClass
if(attack)
{
damage = attack[0] + ((attack[1]-attack[0])*stats.getAttackStrength());
damage *= gmst.find("fDamageStrengthBase")->getFloat() +
(stats.getAttribute(ESM::Attribute::Strength).getModified() * gmst.find("fDamageStrengthMult")->getFloat() * 0.1);
MWMechanics::adjustWeaponDamage(damage, weapon);
MWMechanics::adjustWeaponDamage(damage, weapon, ptr);
MWMechanics::reduceWeaponCondition(damage, true, weapon, ptr);
}
@ -355,7 +355,7 @@ namespace MWClass
if(!object.isEmpty())
getCreatureStats(ptr).setLastHitObject(object.getClass().getId(object));
if(setOnPcHitMe && !attacker.isEmpty() && attacker.getRefData().getHandle() == "player")
if(setOnPcHitMe && !attacker.isEmpty() && attacker == MWBase::Environment::get().getWorld()->getPlayerPtr())
{
const std::string &script = ptr.get<ESM::Creature>()->mBase->mScript;
/* Set the OnPCHitMe script variable. The script is responsible for clearing it. */
@ -376,9 +376,8 @@ namespace MWClass
// Check for knockdown
float agilityTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * getGmst().fKnockDownMult->getFloat();
float knockdownTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified()
* getGmst().iKnockDownOddsMult->getInt() * 0.01 + getGmst().iKnockDownOddsBase->getInt();
int roll = std::rand()/ (static_cast<double> (RAND_MAX) + 1) * 100; // [0, 99]
if (ishealth && agilityTerm <= damage && knockdownTerm <= roll)
* getGmst().iKnockDownOddsMult->getInt() * 0.01f + getGmst().iKnockDownOddsBase->getInt();
if (ishealth && agilityTerm <= damage && knockdownTerm <= OEngine::Misc::Rng::roll0to99())
{
getCreatureStats(ptr).setKnockedDown(true);
@ -493,7 +492,7 @@ namespace MWClass
{
MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
return (ref->mBase->mFlags & ESM::Creature::Weapon);
return (ref->mBase->mFlags & ESM::Creature::Weapon) != 0;
}
std::string Creature::getScript (const MWWorld::Ptr& ptr) const
@ -508,7 +507,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Creature> *ref =
ptr.get<ESM::Creature>();
return ref->mBase->mFlags & ESM::Creature::Essential;
return (ref->mBase->mFlags & ESM::Creature::Essential) != 0;
}
void Creature::registerSelf()
@ -528,7 +527,7 @@ namespace MWClass
MWMechanics::CreatureStats& stats = getCreatureStats(ptr);
const GMST& gmst = getGmst();
float walkSpeed = gmst.fMinWalkSpeedCreature->getFloat() + 0.01 * stats.getAttribute(ESM::Attribute::Speed).getModified()
float walkSpeed = gmst.fMinWalkSpeedCreature->getFloat() + 0.01f * stats.getAttribute(ESM::Attribute::Speed).getModified()
* (gmst.fMaxWalkSpeedCreature->getFloat() - gmst.fMinWalkSpeedCreature->getFloat());
const MWBase::World *world = MWBase::Environment::get().getWorld();
@ -626,7 +625,7 @@ namespace MWClass
float Creature::getCapacity (const MWWorld::Ptr& ptr) const
{
const MWMechanics::CreatureStats& stats = getCreatureStats (ptr);
return stats.getAttribute(0).getModified()*5;
return static_cast<float>(stats.getAttribute(0).getModified() * 5);
}
float Creature::getEncumbrance (const MWWorld::Ptr& ptr) const
@ -682,7 +681,7 @@ namespace MWClass
++sound;
}
if(!sounds.empty())
return sounds[(int)(rand()/(RAND_MAX+1.0)*sounds.size())]->mSound;
return sounds[OEngine::Misc::Rng::rollDice(sounds.size())]->mSound;
}
if (type == ESM::SoundGenerator::Land)
@ -713,7 +712,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Creature> *ref =
ptr.get<ESM::Creature>();
return ref->mBase->mFlags & ESM::Creature::Flies;
return (ref->mBase->mFlags & ESM::Creature::Flies) != 0;
}
bool Creature::canSwim(const MWWorld::Ptr &ptr) const

@ -167,19 +167,19 @@ namespace MWClass
if (opening)
{
MWBase::Environment::get().getSoundManager()->fadeOutSound3D(ptr,
closeSound, 0.5);
float offset = ptr.getRefData().getLocalRotation().rot[2]/ 3.14159265 * 2.0;
closeSound, 0.5f);
float offset = ptr.getRefData().getLocalRotation().rot[2]/ 3.14159265f * 2.0f;
action->setSoundOffset(offset);
action->setSound(openSound);
}
else
{
MWBase::Environment::get().getSoundManager()->fadeOutSound3D(ptr,
openSound, 0.5);
float offset = 1.0 - ptr.getRefData().getLocalRotation().rot[2]/ 3.14159265 * 2.0;
openSound, 0.5f);
float offset = 1.0f - ptr.getRefData().getLocalRotation().rot[2]/ 3.14159265f * 2.0f;
//most if not all door have closing bang somewhere in the middle of the sound,
//so we divide offset by two
action->setSoundOffset(offset * 0.5);
action->setSoundOffset(offset * 0.5f);
action->setSound(closeSound);
}

@ -192,7 +192,7 @@ namespace MWClass
bool Ingredient::canSell (const MWWorld::Ptr& item, int npcServices) const
{
return npcServices & ESM::NPC::Ingredients;
return (npcServices & ESM::NPC::Ingredients) != 0;
}

@ -50,7 +50,7 @@ namespace MWClass
assert (ref->mBase != NULL);
if(!model.empty())
physics.addObject(ptr, model, ref->mBase->mData.mFlags & ESM::Light::Carry);
physics.addObject(ptr, model, (ref->mBase->mData.mFlags & ESM::Light::Carry) != 0);
if (!ref->mBase->mSound.empty() && !(ref->mBase->mData.mFlags & ESM::Light::OffDefault))
MWBase::Environment::get().getSoundManager()->playSound3D(ptr, ref->mBase->mSound, 1.0, 1.0,
@ -205,7 +205,7 @@ namespace MWClass
{
MWWorld::LiveCellRef<ESM::Light> *ref = ptr.get<ESM::Light>();
if (ptr.getCellRef().getCharge() == -1)
return ref->mBase->mData.mTime;
return static_cast<float>(ref->mBase->mData.mTime);
else
return ptr.getCellRef().getChargeFloat();
}
@ -221,7 +221,7 @@ namespace MWClass
bool Light::canSell (const MWWorld::Ptr& item, int npcServices) const
{
return npcServices & ESM::NPC::Lights;
return (npcServices & ESM::NPC::Lights) != 0;
}
float Light::getWeight(const MWWorld::Ptr &ptr) const

@ -173,7 +173,7 @@ namespace MWClass
bool Lockpick::canSell (const MWWorld::Ptr& item, int npcServices) const
{
return npcServices & ESM::NPC::Picks;
return (npcServices & ESM::NPC::Picks) != 0;
}
int Lockpick::getItemMaxHealth (const MWWorld::Ptr& ptr) const

@ -259,7 +259,7 @@ namespace MWClass
{
MWWorld::LiveCellRef<ESM::Miscellaneous> *ref =
ptr.get<ESM::Miscellaneous>();
return ref->mBase->mData.mIsKey;
return ref->mBase->mData.mIsKey != 0;
}
}

@ -5,6 +5,8 @@
#include <OgreSceneNode.h>
#include <openengine/misc/rng.hpp>
#include <components/esm/loadmgef.hpp>
#include <components/esm/loadnpc.hpp>
#include <components/esm/npcstate.hpp>
@ -66,12 +68,12 @@ namespace
double i = floor(d);
d -= i;
if(d < 0.5)
return i;
return static_cast<int>(i);
if(d > 0.5)
return i + 1.0;
return static_cast<int>(i) + 1;
if(is_even(i))
return i;
return i + 1.0;
return static_cast<int>(i);
return static_cast<int>(i) + 1;
}
void autoCalculateAttributes (const ESM::NPC* npc, MWMechanics::CreatureStats& creatureStats)
@ -116,7 +118,7 @@ namespace
continue;
// is this a minor or major skill?
float add=0.2;
float add=0.2f;
for (int k=0; k<5; ++k)
{
if (class_->mData.mSkills[k][0] == j)
@ -149,7 +151,7 @@ namespace
|| class_->mData.mAttribute[1] == ESM::Attribute::Endurance)
multiplier += 1;
creatureStats.setHealth(static_cast<int> (0.5 * (strength + endurance)) + multiplier * (creatureStats.getLevel() - 1));
creatureStats.setHealth(floor(0.5f * (strength + endurance)) + multiplier * (creatureStats.getLevel() - 1));
}
/**
@ -279,8 +281,6 @@ namespace MWClass
gmst.fKnockDownMult = store.find("fKnockDownMult");
gmst.iKnockDownOddsMult = store.find("iKnockDownOddsMult");
gmst.iKnockDownOddsBase = store.find("iKnockDownOddsBase");
gmst.fDamageStrengthBase = store.find("fDamageStrengthBase");
gmst.fDamageStrengthMult = store.find("fDamageStrengthMult");
gmst.fCombatArmorMinMult = store.find("fCombatArmorMinMult");
inited = true;
@ -475,7 +475,6 @@ namespace MWClass
void Npc::hit(const MWWorld::Ptr& ptr, int type) const
{
MWBase::World *world = MWBase::Environment::get().getWorld();
const GMST& gmst = getGmst();
const MWWorld::Store<ESM::GameSetting> &store = world->getStore().get<ESM::GameSetting>();
@ -507,7 +506,7 @@ namespace MWClass
if(otherstats.isDead()) // Can't hit dead actors
return;
if(ptr.getRefData().getHandle() == "player")
if(ptr == MWBase::Environment::get().getWorld()->getPlayerPtr())
MWBase::Environment::get().getWindowManager()->setEnemy(victim);
int weapskill = ESM::Skill::HandToHand;
@ -516,7 +515,7 @@ namespace MWClass
float hitchance = MWMechanics::getHitChance(ptr, victim, ptr.getClass().getSkill(ptr, weapskill));
if((::rand()/(RAND_MAX+1.0)) > hitchance/100.0f)
if (OEngine::Misc::Rng::rollProbability() >= hitchance / 100.0f)
{
othercls.onHit(victim, 0.0f, false, weapon, ptr, false);
MWMechanics::reduceWeaponCondition(0.f, false, weapon, ptr);
@ -538,10 +537,8 @@ namespace MWClass
if(attack)
{
damage = attack[0] + ((attack[1]-attack[0])*stats.getAttackStrength());
damage *= gmst.fDamageStrengthBase->getFloat() +
(stats.getAttribute(ESM::Attribute::Strength).getModified() * gmst.fDamageStrengthMult->getFloat() * 0.1);
}
MWMechanics::adjustWeaponDamage(damage, weapon);
MWMechanics::adjustWeaponDamage(damage, weapon, ptr);
MWMechanics::reduceWeaponCondition(damage, true, weapon, ptr);
healthdmg = true;
}
@ -549,7 +546,7 @@ namespace MWClass
{
MWMechanics::getHandToHandDamage(ptr, victim, damage, healthdmg);
}
if(ptr.getRefData().getHandle() == "player")
if(ptr == MWBase::Environment::get().getWorld()->getPlayerPtr())
{
skillUsageSucceeded(ptr, weapskill, 0);
@ -625,7 +622,7 @@ namespace MWClass
if(!object.isEmpty())
getCreatureStats(ptr).setLastHitObject(object.getClass().getId(object));
if(setOnPcHitMe && !attacker.isEmpty() && attacker.getRefData().getHandle() == "player")
if(setOnPcHitMe && !attacker.isEmpty() && attacker == MWBase::Environment::get().getWorld()->getPlayerPtr())
{
const std::string &script = ptr.getClass().getScript(ptr);
/* Set the OnPCHitMe script variable. The script is responsible for clearing it. */
@ -648,8 +645,7 @@ namespace MWClass
const GMST& gmst = getGmst();
int chance = store.get<ESM::GameSetting>().find("iVoiceHitOdds")->getInt();
int roll = std::rand()/ (static_cast<double> (RAND_MAX) + 1) * 100; // [0, 99]
if (roll < chance)
if (OEngine::Misc::Rng::roll0to99() < chance)
{
MWBase::Environment::get().getDialogueManager()->say(ptr, "hit");
}
@ -657,9 +653,8 @@ namespace MWClass
// Check for knockdown
float agilityTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * gmst.fKnockDownMult->getFloat();
float knockdownTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified()
* gmst.iKnockDownOddsMult->getInt() * 0.01 + gmst.iKnockDownOddsBase->getInt();
roll = std::rand()/ (static_cast<double> (RAND_MAX) + 1) * 100; // [0, 99]
if (ishealth && agilityTerm <= damage && knockdownTerm <= roll)
* gmst.iKnockDownOddsMult->getInt() * 0.01f + gmst.iKnockDownOddsBase->getInt();
if (ishealth && agilityTerm <= damage && knockdownTerm <= OEngine::Misc::Rng::roll0to99())
{
getCreatureStats(ptr).setKnockedDown(true);
@ -685,12 +680,12 @@ namespace MWClass
MWWorld::InventoryStore::Slot_RightPauldron, MWWorld::InventoryStore::Slot_RightPauldron,
MWWorld::InventoryStore::Slot_LeftGauntlet, MWWorld::InventoryStore::Slot_RightGauntlet
};
int hitslot = hitslots[(int)(::rand()/(RAND_MAX+1.0)*20.0)];
int hitslot = hitslots[OEngine::Misc::Rng::rollDice(20)];
float unmitigatedDamage = damage;
float x = damage / (damage + getArmorRating(ptr));
damage *= std::max(gmst.fCombatArmorMinMult->getFloat(), x);
int damageDiff = unmitigatedDamage - damage;
int damageDiff = static_cast<int>(unmitigatedDamage - damage);
if (damage < 1)
damage = 1;
@ -708,7 +703,7 @@ namespace MWClass
if (armorhealth == 0)
armor = *inv.unequipItem(armor, ptr);
if (ptr.getRefData().getHandle() == "player")
if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr())
skillUsageSucceeded(ptr, armor.getClass().getEquipmentSkill(armor), 0);
switch(armor.getClass().getEquipmentSkill(armor))
@ -724,7 +719,7 @@ namespace MWClass
break;
}
}
else if(ptr.getRefData().getHandle() == "player")
else if(ptr == MWBase::Environment::get().getWorld()->getPlayerPtr())
skillUsageSucceeded(ptr, ESM::Skill::Unarmored, 0);
}
}
@ -737,7 +732,7 @@ namespace MWClass
if(damage > 0.0f)
{
sndMgr->playSound3D(ptr, "Health Damage", 1.0f, 1.0f);
if (ptr.getRefData().getHandle() == "player")
if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr())
MWBase::Environment::get().getWindowManager()->activateHitOverlay();
}
float health = getCreatureStats(ptr).getHealth().getCurrent() - damage;
@ -815,7 +810,7 @@ namespace MWClass
const MWWorld::Ptr& actor) const
{
// player got activated by another NPC
if(ptr.getRefData().getHandle() == "player")
if(ptr == MWBase::Environment::get().getWorld()->getPlayerPtr())
return boost::shared_ptr<MWWorld::Action>(new MWWorld::ActionTalk(actor));
// Werewolfs can't activate NPCs
@ -938,7 +933,7 @@ namespace MWClass
gmst.fJumpEncumbranceMultiplier->getFloat() *
(1.0f - Npc::getEncumbrance(ptr)/Npc::getCapacity(ptr));
float a = npcdata->mNpcStats.getSkill(ESM::Skill::Acrobatics).getModified();
float a = static_cast<float>(npcdata->mNpcStats.getSkill(ESM::Skill::Acrobatics).getModified());
float b = 0.0f;
if(a > 50.0f)
{
@ -993,7 +988,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::NPC> *ref =
ptr.get<ESM::NPC>();
return ref->mBase->mFlags & ESM::NPC::Essential;
return (ref->mBase->mFlags & ESM::NPC::Essential) != 0;
}
void Npc::registerSelf()
@ -1086,7 +1081,6 @@ namespace MWClass
MWMechanics::NpcStats &stats = getNpcStats(ptr);
MWWorld::InventoryStore &invStore = getInventoryStore(ptr);
int iBaseArmorSkill = store.find("iBaseArmorSkill")->getInt();
float fUnarmoredBase1 = store.find("fUnarmoredBase1")->getFloat();
float fUnarmoredBase2 = store.find("fUnarmoredBase2")->getFloat();
int unarmoredSkill = stats.getSkill(ESM::Skill::Unarmored).getModified();
@ -1098,19 +1092,11 @@ namespace MWClass
if (it == invStore.end() || it->getTypeName() != typeid(ESM::Armor).name())
{
// unarmored
ratings[i] = (fUnarmoredBase1 * unarmoredSkill) * (fUnarmoredBase2 * unarmoredSkill);
ratings[i] = static_cast<int>((fUnarmoredBase1 * unarmoredSkill) * (fUnarmoredBase2 * unarmoredSkill));
}
else
{
MWWorld::LiveCellRef<ESM::Armor> *ref = it->get<ESM::Armor>();
int armorSkillType = it->getClass().getEquipmentSkill(*it);
int armorSkill = stats.getSkill(armorSkillType).getModified();
if(ref->mBase->mData.mWeight == 0)
ratings[i] = ref->mBase->mData.mArmor;
else
ratings[i] = ref->mBase->mData.mArmor * armorSkill / iBaseArmorSkill;
ratings[i] = it->getClass().getEffectiveArmorRating(*it, ptr);
}
}

@ -5,7 +5,7 @@
namespace ESM
{
class GameSetting;
struct GameSetting;
}
namespace MWClass
@ -38,8 +38,6 @@ namespace MWClass
const ESM::GameSetting *fKnockDownMult;
const ESM::GameSetting *iKnockDownOddsMult;
const ESM::GameSetting *iKnockDownOddsBase;
const ESM::GameSetting *fDamageStrengthBase;
const ESM::GameSetting *fDamageStrengthMult;
const ESM::GameSetting *fCombatArmorMinMult;
};

@ -185,7 +185,7 @@ namespace MWClass
bool Potion::canSell (const MWWorld::Ptr& item, int npcServices) const
{
return npcServices & ESM::NPC::Potions;
return (npcServices & ESM::NPC::Potions) != 0;
}
float Potion::getWeight(const MWWorld::Ptr &ptr) const

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

Loading…
Cancel
Save