mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-16 19:19:56 +00:00
Merge branch 'master' of https://github.com/OpenMW/openmw
# Conflicts: # docs/source/openmw-mods/index.rst
This commit is contained in:
commit
bf805813e5
145 changed files with 2968 additions and 933 deletions
|
@ -1,6 +1,6 @@
|
||||||
os:
|
os:
|
||||||
- linux
|
- linux
|
||||||
- osx
|
# - osx
|
||||||
osx_image: xcode7.2
|
osx_image: xcode7.2
|
||||||
language: cpp
|
language: cpp
|
||||||
sudo: required
|
sudo: required
|
||||||
|
|
|
@ -23,10 +23,12 @@ Programmers
|
||||||
Alexander Olofsson (Ace)
|
Alexander Olofsson (Ace)
|
||||||
Allofich
|
Allofich
|
||||||
AnyOldName3
|
AnyOldName3
|
||||||
|
Aussiemon
|
||||||
Austin Salgat (Salgat)
|
Austin Salgat (Salgat)
|
||||||
Artem Kotsynyak (greye)
|
Artem Kotsynyak (greye)
|
||||||
artemutin
|
artemutin
|
||||||
Arthur Moore (EmperorArthur)
|
Arthur Moore (EmperorArthur)
|
||||||
|
Assumeru
|
||||||
athile
|
athile
|
||||||
Ben Shealy (bentsherman)
|
Ben Shealy (bentsherman)
|
||||||
Bret Curtis (psi29a)
|
Bret Curtis (psi29a)
|
||||||
|
@ -73,6 +75,7 @@ Programmers
|
||||||
Karl-Felix Glatzer (k1ll)
|
Karl-Felix Glatzer (k1ll)
|
||||||
Kevin Poitra (PuppyKevin)
|
Kevin Poitra (PuppyKevin)
|
||||||
Koncord
|
Koncord
|
||||||
|
Kurnevsky Evgeny (kurnevsky)
|
||||||
Lars Söderberg (Lazaroth)
|
Lars Söderberg (Lazaroth)
|
||||||
lazydev
|
lazydev
|
||||||
Leon Saunders (emoose)
|
Leon Saunders (emoose)
|
||||||
|
@ -119,6 +122,7 @@ Programmers
|
||||||
Scott Howard
|
Scott Howard
|
||||||
Sebastian Wick (swick)
|
Sebastian Wick (swick)
|
||||||
Sergey Shambir
|
Sergey Shambir
|
||||||
|
ShadowRadiance
|
||||||
sir_herrbatka
|
sir_herrbatka
|
||||||
smbas
|
smbas
|
||||||
Stefan Galowicz (bogglez)
|
Stefan Galowicz (bogglez)
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
brew update
|
brew update
|
||||||
|
|
||||||
brew rm cmake || true
|
brew rm cmake || true
|
||||||
brew rm pkgconfig || true
|
brew rm pkgconfig || true
|
||||||
brew rm qt5 || true
|
brew rm qt5 || true
|
||||||
brew install cmake pkgconfig qt5
|
brew install cmake pkgconfig qt55
|
||||||
|
|
||||||
curl http://downloads.openmw.org/osx/dependencies/openmw-deps-263d4a8.zip -o ~/openmw-deps.zip
|
curl http://downloads.openmw.org/osx/dependencies/openmw-deps-263d4a8.zip -o ~/openmw-deps.zip
|
||||||
unzip ~/openmw-deps.zip -d /private/tmp/openmw-deps > /dev/null
|
unzip ~/openmw-deps.zip -d /private/tmp/openmw-deps > /dev/null
|
||||||
|
|
|
@ -4,13 +4,12 @@ export CXX=clang++
|
||||||
export CC=clang
|
export CC=clang
|
||||||
|
|
||||||
DEPENDENCIES_ROOT="/private/tmp/openmw-deps/openmw-deps"
|
DEPENDENCIES_ROOT="/private/tmp/openmw-deps/openmw-deps"
|
||||||
QT_PATH="/usr/local/opt/qt5"
|
QT_PATH="/usr/local/opt/qt55"
|
||||||
|
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
|
|
||||||
cmake \
|
cmake \
|
||||||
-D CMAKE_EXE_LINKER_FLAGS="-lz" \
|
|
||||||
-D CMAKE_PREFIX_PATH="$DEPENDENCIES_ROOT;$QT_PATH" \
|
-D CMAKE_PREFIX_PATH="$DEPENDENCIES_ROOT;$QT_PATH" \
|
||||||
-D CMAKE_OSX_DEPLOYMENT_TARGET="10.8" \
|
-D CMAKE_OSX_DEPLOYMENT_TARGET="10.8" \
|
||||||
-D CMAKE_OSX_SYSROOT="macosx10.11" \
|
-D CMAKE_OSX_SYSROOT="macosx10.11" \
|
||||||
|
|
|
@ -46,7 +46,7 @@ if(EXISTS ${PROJECT_SOURCE_DIR}/.git)
|
||||||
else(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/shallow)
|
else(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/shallow)
|
||||||
message(STATUS "Shallow Git clone detected, not attempting to retrieve version info")
|
message(STATUS "Shallow Git clone detected, not attempting to retrieve version info")
|
||||||
endif(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/shallow)
|
endif(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/shallow)
|
||||||
endif(EXISTS ${PROJECT_SOURCE_DIR}/.git)
|
endif(EXISTS ${PROJECT_SOURCE_DIR}/.git)
|
||||||
|
|
||||||
# Macros
|
# Macros
|
||||||
include(OpenMWMacros)
|
include(OpenMWMacros)
|
||||||
|
@ -96,7 +96,7 @@ endif()
|
||||||
# Set up common paths
|
# Set up common paths
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
set(MORROWIND_DATA_FILES "./data" CACHE PATH "location of Morrowind data files")
|
set(MORROWIND_DATA_FILES "./data" CACHE PATH "location of Morrowind data files")
|
||||||
set(OPENMW_RESOURCE_FILES "./resources" CACHE PATH "location of OpenMW resources files")
|
set(OPENMW_RESOURCE_FILES "../Resources/resources" CACHE PATH "location of OpenMW resources files")
|
||||||
elseif(UNIX)
|
elseif(UNIX)
|
||||||
# Paths
|
# Paths
|
||||||
SET(BINDIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Where to install binaries")
|
SET(BINDIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Where to install binaries")
|
||||||
|
@ -286,6 +286,11 @@ endif (APPLE)
|
||||||
# Set up DEBUG define
|
# Set up DEBUG define
|
||||||
set_directory_properties(PROPERTIES COMPILE_DEFINITIONS_DEBUG DEBUG=1)
|
set_directory_properties(PROPERTIES COMPILE_DEFINITIONS_DEBUG DEBUG=1)
|
||||||
|
|
||||||
|
if (NOT APPLE)
|
||||||
|
set(OPENMW_MYGUI_FILES_ROOT ${OpenMW_BINARY_DIR})
|
||||||
|
set(OPENMW_SHADERS_ROOT ${OpenMW_BINARY_DIR})
|
||||||
|
endif ()
|
||||||
|
|
||||||
add_subdirectory(files/)
|
add_subdirectory(files/)
|
||||||
|
|
||||||
# Specify build paths
|
# Specify build paths
|
||||||
|
@ -307,11 +312,15 @@ endif (APPLE)
|
||||||
configure_file(${OpenMW_SOURCE_DIR}/files/settings-default.cfg
|
configure_file(${OpenMW_SOURCE_DIR}/files/settings-default.cfg
|
||||||
"${OpenMW_BINARY_DIR}/settings-default.cfg")
|
"${OpenMW_BINARY_DIR}/settings-default.cfg")
|
||||||
|
|
||||||
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg.local
|
if (NOT APPLE)
|
||||||
"${OpenMW_BINARY_DIR}/openmw.cfg")
|
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg.local
|
||||||
|
"${OpenMW_BINARY_DIR}/openmw.cfg")
|
||||||
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg
|
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg
|
||||||
"${OpenMW_BINARY_DIR}/openmw.cfg.install")
|
"${OpenMW_BINARY_DIR}/openmw.cfg.install")
|
||||||
|
else ()
|
||||||
|
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg
|
||||||
|
"${OpenMW_BINARY_DIR}/openmw.cfg")
|
||||||
|
endif ()
|
||||||
|
|
||||||
configure_file(${OpenMW_SOURCE_DIR}/files/openmw-cs.cfg
|
configure_file(${OpenMW_SOURCE_DIR}/files/openmw-cs.cfg
|
||||||
"${OpenMW_BINARY_DIR}/openmw-cs.cfg")
|
"${OpenMW_BINARY_DIR}/openmw-cs.cfg")
|
||||||
|
@ -419,8 +428,10 @@ IF(NOT WIN32 AND NOT APPLE)
|
||||||
ENDIF(NOT WIN32 AND NOT APPLE)
|
ENDIF(NOT WIN32 AND NOT APPLE)
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
FILE(GLOB dll_files "${OpenMW_BINARY_DIR}/Release/*.dll")
|
FILE(GLOB dll_files_debug "${OpenMW_BINARY_DIR}/Debug/*.dll")
|
||||||
INSTALL(FILES ${dll_files} DESTINATION ".")
|
FILE(GLOB dll_files_release "${OpenMW_BINARY_DIR}/Release/*.dll")
|
||||||
|
INSTALL(FILES ${dll_files_debug} DESTINATION "." CONFIGURATIONS Debug)
|
||||||
|
INSTALL(FILES ${dll_files_release} DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel)
|
||||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg")
|
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg")
|
||||||
INSTALL(FILES "${OpenMW_SOURCE_DIR}/CHANGELOG.md" DESTINATION "." RENAME "CHANGELOG.txt")
|
INSTALL(FILES "${OpenMW_SOURCE_DIR}/CHANGELOG.md" DESTINATION "." RENAME "CHANGELOG.txt")
|
||||||
INSTALL(FILES "${OpenMW_SOURCE_DIR}/README.md" DESTINATION "." RENAME "README.txt")
|
INSTALL(FILES "${OpenMW_SOURCE_DIR}/README.md" DESTINATION "." RENAME "README.txt")
|
||||||
|
@ -429,36 +440,23 @@ if(WIN32)
|
||||||
"${OpenMW_SOURCE_DIR}/Docs/license/DejaVu Font License.txt"
|
"${OpenMW_SOURCE_DIR}/Docs/license/DejaVu Font License.txt"
|
||||||
"${OpenMW_BINARY_DIR}/settings-default.cfg"
|
"${OpenMW_BINARY_DIR}/settings-default.cfg"
|
||||||
"${OpenMW_BINARY_DIR}/gamecontrollerdb.txt"
|
"${OpenMW_BINARY_DIR}/gamecontrollerdb.txt"
|
||||||
"${OpenMW_BINARY_DIR}/Release/openmw.exe"
|
|
||||||
DESTINATION ".")
|
DESTINATION ".")
|
||||||
|
|
||||||
IF(BUILD_LAUNCHER)
|
|
||||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-launcher.exe" DESTINATION ".")
|
|
||||||
ENDIF(BUILD_LAUNCHER)
|
|
||||||
IF(BUILD_MWINIIMPORTER)
|
|
||||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-iniimporter.exe" DESTINATION ".")
|
|
||||||
ENDIF(BUILD_MWINIIMPORTER)
|
|
||||||
IF(BUILD_ESSIMPORTER)
|
|
||||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-essimporter.exe" DESTINATION ".")
|
|
||||||
ENDIF(BUILD_ESSIMPORTER)
|
|
||||||
IF(BUILD_OPENCS)
|
|
||||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-cs.exe" DESTINATION ".")
|
|
||||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.cfg" DESTINATION ".")
|
|
||||||
ENDIF(BUILD_OPENCS)
|
|
||||||
IF(BUILD_WIZARD)
|
|
||||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-wizard.exe" DESTINATION ".")
|
|
||||||
ENDIF(BUILD_WIZARD)
|
|
||||||
if(BUILD_MYGUI_PLUGIN)
|
if(BUILD_MYGUI_PLUGIN)
|
||||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/Plugin_MyGUI_OpenMW_Resources.dll" DESTINATION ".")
|
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Debug/Plugin_MyGUI_OpenMW_Resources.dll" DESTINATION "." CONFIGURATIONS Debug)
|
||||||
|
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/Plugin_MyGUI_OpenMW_Resources.dll" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel)
|
||||||
ENDIF(BUILD_MYGUI_PLUGIN)
|
ENDIF(BUILD_MYGUI_PLUGIN)
|
||||||
|
|
||||||
IF(DESIRED_QT_VERSION MATCHES 5)
|
IF(DESIRED_QT_VERSION MATCHES 5)
|
||||||
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/Release/platforms" DESTINATION ".")
|
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/Debug/platforms" DESTINATION "." CONFIGURATIONS Debug)
|
||||||
|
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/Release/platforms" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel)
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
|
||||||
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ".")
|
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ".")
|
||||||
FILE(GLOB plugin_dir "${OpenMW_BINARY_DIR}/Release/osgPlugins-*")
|
FILE(GLOB plugin_dir_debug "${OpenMW_BINARY_DIR}/Debug/osgPlugins-*")
|
||||||
INSTALL(DIRECTORY ${plugin_dir} DESTINATION ".")
|
FILE(GLOB plugin_dir_release "${OpenMW_BINARY_DIR}/Release/osgPlugins-*")
|
||||||
|
INSTALL(DIRECTORY ${plugin_dir_debug} DESTINATION "." CONFIGURATIONS Debug)
|
||||||
|
INSTALL(DIRECTORY ${plugin_dir_release} DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel)
|
||||||
|
|
||||||
SET(CPACK_GENERATOR "NSIS")
|
SET(CPACK_GENERATOR "NSIS")
|
||||||
SET(CPACK_PACKAGE_NAME "OpenMW")
|
SET(CPACK_PACKAGE_NAME "OpenMW")
|
||||||
|
@ -725,14 +723,7 @@ if (APPLE)
|
||||||
configure_file("${QT_COCOA_PLUGIN_PATH}" "${OPENCS_BUNDLE_NAME}/Contents/MacOS/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}" COPYONLY)
|
configure_file("${QT_COCOA_PLUGIN_PATH}" "${OPENCS_BUNDLE_NAME}/Contents/MacOS/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}" COPYONLY)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
set(INSTALL_SUBDIR OpenMW)
|
install(DIRECTORY "${APP_BUNDLE_DIR}" USE_SOURCE_PERMISSIONS DESTINATION "." COMPONENT Runtime)
|
||||||
|
|
||||||
install(DIRECTORY "${APP_BUNDLE_DIR}" USE_SOURCE_PERMISSIONS DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
|
|
||||||
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}/openmw-cs.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
|
|
||||||
|
|
||||||
set(CPACK_GENERATOR "DragNDrop")
|
set(CPACK_GENERATOR "DragNDrop")
|
||||||
set(CPACK_PACKAGE_VERSION ${OPENMW_VERSION})
|
set(CPACK_PACKAGE_VERSION ${OPENMW_VERSION})
|
||||||
|
@ -740,8 +731,8 @@ if (APPLE)
|
||||||
set(CPACK_PACKAGE_VERSION_MINOR ${OPENMW_VERSION_MINOR})
|
set(CPACK_PACKAGE_VERSION_MINOR ${OPENMW_VERSION_MINOR})
|
||||||
set(CPACK_PACKAGE_VERSION_PATCH ${OPENMW_VERSION_RELEASE})
|
set(CPACK_PACKAGE_VERSION_PATCH ${OPENMW_VERSION_RELEASE})
|
||||||
|
|
||||||
set(INSTALLED_OPENMW_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}")
|
set(INSTALLED_OPENMW_APP "\${CMAKE_INSTALL_PREFIX}/${APP_BUNDLE_NAME}")
|
||||||
set(INSTALLED_OPENCS_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}")
|
set(INSTALLED_OPENCS_APP "\${CMAKE_INSTALL_PREFIX}/${OPENCS_BUNDLE_NAME}")
|
||||||
|
|
||||||
install(CODE "
|
install(CODE "
|
||||||
set(BU_CHMOD_BUNDLE_ITEMS ON)
|
set(BU_CHMOD_BUNDLE_ITEMS ON)
|
||||||
|
@ -785,8 +776,8 @@ if (APPLE)
|
||||||
set(${plugins_var} ${PLUGINS} PARENT_SCOPE)
|
set(${plugins_var} ${PLUGINS} PARENT_SCOPE)
|
||||||
endfunction (install_plugins_for_bundle)
|
endfunction (install_plugins_for_bundle)
|
||||||
|
|
||||||
install_plugins_for_bundle("${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}" PLUGINS)
|
install_plugins_for_bundle("${APP_BUNDLE_NAME}" PLUGINS)
|
||||||
install_plugins_for_bundle("${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}" OPENCS_PLUGINS)
|
install_plugins_for_bundle("${OPENCS_BUNDLE_NAME}" OPENCS_PLUGINS)
|
||||||
|
|
||||||
set(PLUGINS ${PLUGINS} "${INSTALLED_OPENMW_APP}/Contents/MacOS/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}")
|
set(PLUGINS ${PLUGINS} "${INSTALLED_OPENMW_APP}/Contents/MacOS/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}")
|
||||||
set(OPENCS_PLUGINS ${OPENCS_PLUGINS} "${INSTALLED_OPENCS_APP}/Contents/MacOS/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}")
|
set(OPENCS_PLUGINS ${OPENCS_PLUGINS} "${INSTALLED_OPENCS_APP}/Contents/MacOS/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}")
|
||||||
|
@ -828,3 +819,4 @@ if (DOXYGEN_FOUND)
|
||||||
WORKING_DIRECTORY ${OpenMW_BINARY_DIR}
|
WORKING_DIRECTORY ${OpenMW_BINARY_DIR}
|
||||||
COMMENT "Generating documentation for the github-pages at ${DOXYGEN_PAGES_OUTPUT_DIR}" VERBATIM)
|
COMMENT "Generating documentation for the github-pages at ${DOXYGEN_PAGES_OUTPUT_DIR}" VERBATIM)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
|
|
@ -42,3 +42,7 @@ if (BUILD_WITH_CODE_COVERAGE)
|
||||||
add_definitions (--coverage)
|
add_definitions (--coverage)
|
||||||
target_link_libraries(openmw-essimporter gcov)
|
target_link_libraries(openmw-essimporter gcov)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (WIN32)
|
||||||
|
INSTALL(TARGETS openmw-essimporter RUNTIME DESTINATION ".")
|
||||||
|
endif(WIN32)
|
||||||
|
|
|
@ -271,23 +271,34 @@ private:
|
||||||
class ConvertPCDT : public Converter
|
class ConvertPCDT : public Converter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ConvertPCDT() : mFirstPersonCam(true) {}
|
ConvertPCDT()
|
||||||
|
: mFirstPersonCam(true),
|
||||||
|
mTeleportingEnabled(true),
|
||||||
|
mLevitationEnabled(true)
|
||||||
|
{}
|
||||||
|
|
||||||
virtual void read(ESM::ESMReader &esm)
|
virtual void read(ESM::ESMReader &esm)
|
||||||
{
|
{
|
||||||
PCDT pcdt;
|
PCDT pcdt;
|
||||||
pcdt.load(esm);
|
pcdt.load(esm);
|
||||||
|
|
||||||
convertPCDT(pcdt, mContext->mPlayer, mContext->mDialogueState.mKnownTopics, mFirstPersonCam);
|
convertPCDT(pcdt, mContext->mPlayer, mContext->mDialogueState.mKnownTopics, mFirstPersonCam, mTeleportingEnabled, mLevitationEnabled, mContext->mControlsState);
|
||||||
}
|
}
|
||||||
virtual void write(ESM::ESMWriter &esm)
|
virtual void write(ESM::ESMWriter &esm)
|
||||||
{
|
{
|
||||||
|
esm.startRecord(ESM::REC_ENAB);
|
||||||
|
esm.writeHNT("TELE", mTeleportingEnabled);
|
||||||
|
esm.writeHNT("LEVT", mLevitationEnabled);
|
||||||
|
esm.endRecord(ESM::REC_ENAB);
|
||||||
|
|
||||||
esm.startRecord(ESM::REC_CAM_);
|
esm.startRecord(ESM::REC_CAM_);
|
||||||
esm.writeHNT("FIRS", mFirstPersonCam);
|
esm.writeHNT("FIRS", mFirstPersonCam);
|
||||||
esm.endRecord(ESM::REC_CAM_);
|
esm.endRecord(ESM::REC_CAM_);
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
bool mFirstPersonCam;
|
bool mFirstPersonCam;
|
||||||
|
bool mTeleportingEnabled;
|
||||||
|
bool mLevitationEnabled;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ConvertCNTC : public Converter
|
class ConvertCNTC : public Converter
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
namespace ESSImport
|
namespace ESSImport
|
||||||
{
|
{
|
||||||
|
|
||||||
void convertPCDT(const PCDT& pcdt, ESM::Player& out, std::vector<std::string>& outDialogueTopics, bool& firstPersonCam)
|
void convertPCDT(const PCDT& pcdt, ESM::Player& out, std::vector<std::string>& outDialogueTopics, bool& firstPersonCam, bool& teleportingEnabled, bool& levitationEnabled, ESM::ControlsState& controls)
|
||||||
{
|
{
|
||||||
out.mBirthsign = pcdt.mBirthsign;
|
out.mBirthsign = pcdt.mBirthsign;
|
||||||
out.mObject.mNpcStats.mBounty = pcdt.mBounty;
|
out.mObject.mNpcStats.mBounty = pcdt.mBounty;
|
||||||
|
@ -25,18 +25,28 @@ namespace ESSImport
|
||||||
out.mObject.mNpcStats.mSkills[i].mProgress = pcdt.mPNAM.mSkillProgress[i];
|
out.mObject.mNpcStats.mSkills[i].mProgress = pcdt.mPNAM.mSkillProgress[i];
|
||||||
out.mObject.mNpcStats.mLevelProgress = pcdt.mPNAM.mLevelProgress;
|
out.mObject.mNpcStats.mLevelProgress = pcdt.mPNAM.mLevelProgress;
|
||||||
|
|
||||||
if (pcdt.mPNAM.mDrawState & PCDT::DrawState_Weapon)
|
if (pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_WeaponDrawn)
|
||||||
out.mObject.mCreatureStats.mDrawState = 1;
|
out.mObject.mCreatureStats.mDrawState = 1;
|
||||||
if (pcdt.mPNAM.mDrawState & PCDT::DrawState_Spell)
|
if (pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_SpellDrawn)
|
||||||
out.mObject.mCreatureStats.mDrawState = 2;
|
out.mObject.mCreatureStats.mDrawState = 2;
|
||||||
|
|
||||||
firstPersonCam = !(pcdt.mPNAM.mCameraFlags & PCDT::CameraFlag_ThirdPerson);
|
firstPersonCam = !(pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_ThirdPerson);
|
||||||
|
teleportingEnabled = !(pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_TeleportingDisabled);
|
||||||
|
levitationEnabled = !(pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_LevitationDisabled);
|
||||||
|
|
||||||
for (std::vector<std::string>::const_iterator it = pcdt.mKnownDialogueTopics.begin();
|
for (std::vector<std::string>::const_iterator it = pcdt.mKnownDialogueTopics.begin();
|
||||||
it != pcdt.mKnownDialogueTopics.end(); ++it)
|
it != pcdt.mKnownDialogueTopics.end(); ++it)
|
||||||
{
|
{
|
||||||
outDialogueTopics.push_back(Misc::StringUtils::lowerCase(*it));
|
outDialogueTopics.push_back(Misc::StringUtils::lowerCase(*it));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
controls.mViewSwitchDisabled = pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_ViewSwitchDisabled;
|
||||||
|
controls.mControlsDisabled = pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_ControlsDisabled;
|
||||||
|
controls.mJumpingDisabled = pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_JumpingDisabled;
|
||||||
|
controls.mLookingDisabled = pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_LookingDisabled;
|
||||||
|
controls.mVanityModeDisabled = pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_VanityModeDisabled;
|
||||||
|
controls.mWeaponDrawingDisabled = pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_WeaponDrawingDisabled;
|
||||||
|
controls.mSpellDrawingDisabled = pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_SpellDrawingDisabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,12 @@
|
||||||
#include "importplayer.hpp"
|
#include "importplayer.hpp"
|
||||||
|
|
||||||
#include <components/esm/player.hpp>
|
#include <components/esm/player.hpp>
|
||||||
|
#include <components/esm/controlsstate.hpp>
|
||||||
|
|
||||||
namespace ESSImport
|
namespace ESSImport
|
||||||
{
|
{
|
||||||
|
|
||||||
void convertPCDT(const PCDT& pcdt, ESM::Player& out, std::vector<std::string>& outDialogueTopics, bool& firstPersonCam);
|
void convertPCDT(const PCDT& pcdt, ESM::Player& out, std::vector<std::string>& outDialogueTopics, bool& firstPersonCam, bool& teleportingEnabled, bool& levitationEnabled, ESM::ControlsState& controls);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,7 @@ namespace
|
||||||
{
|
{
|
||||||
for (int x=0; x<128; ++x)
|
for (int x=0; x<128; ++x)
|
||||||
{
|
{
|
||||||
|
assert(image->data(x,y));
|
||||||
*(image->data(x,y)+2) = *it++;
|
*(image->data(x,y)+2) = *it++;
|
||||||
*(image->data(x,y)+1) = *it++;
|
*(image->data(x,y)+1) = *it++;
|
||||||
*image->data(x,y) = *it++;
|
*image->data(x,y) = *it++;
|
||||||
|
@ -422,6 +423,10 @@ namespace ESSImport
|
||||||
writer.startRecord (ESM::REC_DIAS);
|
writer.startRecord (ESM::REC_DIAS);
|
||||||
context.mDialogueState.save(writer);
|
context.mDialogueState.save(writer);
|
||||||
writer.endRecord(ESM::REC_DIAS);
|
writer.endRecord(ESM::REC_DIAS);
|
||||||
|
|
||||||
|
writer.startRecord(ESM::REC_INPU);
|
||||||
|
context.mControlsState.save(writer);
|
||||||
|
writer.endRecord(ESM::REC_INPU);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <components/esm/globalmap.hpp>
|
#include <components/esm/globalmap.hpp>
|
||||||
#include <components/esm/loadcrea.hpp>
|
#include <components/esm/loadcrea.hpp>
|
||||||
#include <components/esm/loadnpc.hpp>
|
#include <components/esm/loadnpc.hpp>
|
||||||
|
#include <components/esm/controlsstate.hpp>
|
||||||
|
|
||||||
#include "importnpcc.hpp"
|
#include "importnpcc.hpp"
|
||||||
#include "importcrec.hpp"
|
#include "importcrec.hpp"
|
||||||
|
@ -32,6 +33,8 @@ namespace ESSImport
|
||||||
|
|
||||||
ESM::DialogueState mDialogueState;
|
ESM::DialogueState mDialogueState;
|
||||||
|
|
||||||
|
ESM::ControlsState mControlsState;
|
||||||
|
|
||||||
// cells which should show an explored overlay on the global map
|
// cells which should show an explored overlay on the global map
|
||||||
std::set<std::pair<int, int> > mExploredCells;
|
std::set<std::pair<int, int> > mExploredCells;
|
||||||
|
|
||||||
|
|
|
@ -38,14 +38,20 @@ struct PCDT
|
||||||
|
|
||||||
std::vector<std::string> mKnownDialogueTopics;
|
std::vector<std::string> mKnownDialogueTopics;
|
||||||
|
|
||||||
enum DrawState_
|
enum PlayerFlags
|
||||||
{
|
{
|
||||||
DrawState_Weapon = 0x80,
|
PlayerFlags_ViewSwitchDisabled = 0x1,
|
||||||
DrawState_Spell = 0x100
|
PlayerFlags_ControlsDisabled = 0x4,
|
||||||
};
|
PlayerFlags_WeaponDrawn = 0x80,
|
||||||
enum CameraFlags
|
PlayerFlags_SpellDrawn = 0x100,
|
||||||
{
|
PlayerFlags_JumpingDisabled = 0x1000,
|
||||||
CameraFlag_ThirdPerson = 0x2
|
PlayerFlags_LookingDisabled = 0x2000,
|
||||||
|
PlayerFlags_VanityModeDisabled = 0x4000,
|
||||||
|
PlayerFlags_WeaponDrawingDisabled = 0x8000,
|
||||||
|
PlayerFlags_SpellDrawingDisabled = 0x10000,
|
||||||
|
PlayerFlags_ThirdPerson = 0x20000,
|
||||||
|
PlayerFlags_TeleportingDisabled = 0x40000,
|
||||||
|
PlayerFlags_LevitationDisabled = 0x80000
|
||||||
};
|
};
|
||||||
|
|
||||||
#pragma pack(push)
|
#pragma pack(push)
|
||||||
|
@ -62,8 +68,7 @@ struct PCDT
|
||||||
|
|
||||||
struct PNAM
|
struct PNAM
|
||||||
{
|
{
|
||||||
short mDrawState; // DrawState
|
int mPlayerFlags; // controls, camera and draw state
|
||||||
short mCameraFlags; // CameraFlags
|
|
||||||
unsigned int mLevelProgress;
|
unsigned int mLevelProgress;
|
||||||
float mSkillProgress[27]; // skill progress, non-uniform scaled
|
float mSkillProgress[27]; // skill progress, non-uniform scaled
|
||||||
unsigned char mSkillIncreases[8]; // number of skill increases for each attribute
|
unsigned char mSkillIncreases[8]; // number of skill increases for each attribute
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace ESM
|
||||||
namespace ESSImport
|
namespace ESSImport
|
||||||
{
|
{
|
||||||
|
|
||||||
/// Local variable assigments for a running script
|
/// Local variable assignments for a running script
|
||||||
struct SCRI
|
struct SCRI
|
||||||
{
|
{
|
||||||
std::string mScript;
|
std::string mScript;
|
||||||
|
|
|
@ -87,6 +87,10 @@ add_executable(openmw-launcher
|
||||||
${UI_HDRS}
|
${UI_HDRS}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (WIN32)
|
||||||
|
INSTALL(TARGETS openmw-launcher RUNTIME DESTINATION ".")
|
||||||
|
endif (WIN32)
|
||||||
|
|
||||||
target_link_libraries(openmw-launcher
|
target_link_libraries(openmw-launcher
|
||||||
${SDL2_LIBRARY_ONLY}
|
${SDL2_LIBRARY_ONLY}
|
||||||
components
|
components
|
||||||
|
|
|
@ -35,14 +35,6 @@ int main(int argc, char *argv[])
|
||||||
// Now we make sure the current dir is set to application path
|
// Now we make sure the current dir is set to application path
|
||||||
QDir dir(QCoreApplication::applicationDirPath());
|
QDir dir(QCoreApplication::applicationDirPath());
|
||||||
|
|
||||||
#ifdef Q_OS_MAC
|
|
||||||
if (dir.dirName() == "MacOS") {
|
|
||||||
dir.cdUp();
|
|
||||||
dir.cdUp();
|
|
||||||
dir.cdUp();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QDir::setCurrent(dir.absolutePath());
|
QDir::setCurrent(dir.absolutePath());
|
||||||
|
|
||||||
Launcher::MainDialog mainWin;
|
Launcher::MainDialog mainWin;
|
||||||
|
|
|
@ -293,6 +293,7 @@ bool Launcher::MainDialog::setupGameSettings()
|
||||||
{
|
{
|
||||||
mGameSettings.clear();
|
mGameSettings.clear();
|
||||||
|
|
||||||
|
QString localPath = QString::fromUtf8(mCfgMgr.getLocalPath().string().c_str());
|
||||||
QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str());
|
QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str());
|
||||||
QString globalPath = QString::fromUtf8(mCfgMgr.getGlobalPath().string().c_str());
|
QString globalPath = QString::fromUtf8(mCfgMgr.getGlobalPath().string().c_str());
|
||||||
|
|
||||||
|
@ -320,13 +321,13 @@ bool Launcher::MainDialog::setupGameSettings()
|
||||||
// Now the rest - priority: user > local > global
|
// Now the rest - priority: user > local > global
|
||||||
QStringList paths;
|
QStringList paths;
|
||||||
paths.append(globalPath + QString("openmw.cfg"));
|
paths.append(globalPath + QString("openmw.cfg"));
|
||||||
paths.append(QString("openmw.cfg"));
|
paths.append(localPath + QString("openmw.cfg"));
|
||||||
paths.append(userPath + QString("openmw.cfg"));
|
paths.append(userPath + QString("openmw.cfg"));
|
||||||
|
|
||||||
foreach (const QString &path, paths) {
|
foreach (const QString &path2, paths) {
|
||||||
qDebug() << "Loading config file:" << path.toUtf8().constData();
|
qDebug() << "Loading config file:" << path2.toUtf8().constData();
|
||||||
|
|
||||||
QFile file(path);
|
file.setFileName(path2);
|
||||||
if (file.exists()) {
|
if (file.exists()) {
|
||||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
cfgError(tr("Error opening OpenMW configuration file"),
|
cfgError(tr("Error opening OpenMW configuration file"),
|
||||||
|
@ -346,13 +347,13 @@ bool Launcher::MainDialog::setupGameSettings()
|
||||||
QStringList dataDirs;
|
QStringList dataDirs;
|
||||||
|
|
||||||
// Check if the paths actually contain data files
|
// Check if the paths actually contain data files
|
||||||
foreach (const QString path, mGameSettings.getDataDirs()) {
|
foreach (const QString path3, mGameSettings.getDataDirs()) {
|
||||||
QDir dir(path);
|
QDir dir(path3);
|
||||||
QStringList filters;
|
QStringList filters;
|
||||||
filters << "*.esp" << "*.esm" << "*.omwgame" << "*.omwaddon";
|
filters << "*.esp" << "*.esm" << "*.omwgame" << "*.omwaddon";
|
||||||
|
|
||||||
if (!dir.entryList(filters).isEmpty())
|
if (!dir.entryList(filters).isEmpty())
|
||||||
dataDirs.append(path);
|
dataDirs.append(path3);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dataDirs.isEmpty())
|
if (dataDirs.isEmpty())
|
||||||
|
|
|
@ -22,7 +22,8 @@ target_link_libraries(openmw-iniimporter
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
target_link_libraries(openmw-iniimporter
|
target_link_libraries(openmw-iniimporter
|
||||||
${Boost_LOCALE_LIBRARY})
|
${Boost_LOCALE_LIBRARY})
|
||||||
endif()
|
INSTALL(TARGETS openmw-iniimporter RUNTIME DESTINATION ".")
|
||||||
|
endif(WIN32)
|
||||||
|
|
||||||
if (MINGW)
|
if (MINGW)
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -municode")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -municode")
|
||||||
|
|
|
@ -162,9 +162,15 @@ endif()
|
||||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
set (OPENCS_MAC_ICON ${CMAKE_SOURCE_DIR}/files/mac/openmw-cs.icns)
|
set (OPENCS_MAC_ICON "${CMAKE_SOURCE_DIR}/files/mac/openmw-cs.icns")
|
||||||
|
set (OPENCS_CFG "${OpenMW_BINARY_DIR}/openmw-cs.cfg")
|
||||||
|
set (OPENCS_DEFAULT_FILTERS_FILE "${OpenMW_BINARY_DIR}/resources/defaultfilters")
|
||||||
|
set (OPENCS_OPENMW_CFG "${OpenMW_BINARY_DIR}/openmw.cfg")
|
||||||
else()
|
else()
|
||||||
set (OPENCS_MAC_ICON "")
|
set (OPENCS_MAC_ICON "")
|
||||||
|
set (OPENCS_CFG "")
|
||||||
|
set (OPENCS_DEFAULT_FILTERS_FILE "")
|
||||||
|
set (OPENCS_OPENMW_CFG "")
|
||||||
endif(APPLE)
|
endif(APPLE)
|
||||||
|
|
||||||
add_executable(openmw-cs
|
add_executable(openmw-cs
|
||||||
|
@ -174,12 +180,23 @@ add_executable(openmw-cs
|
||||||
${OPENCS_MOC_SRC}
|
${OPENCS_MOC_SRC}
|
||||||
${OPENCS_RES_SRC}
|
${OPENCS_RES_SRC}
|
||||||
${OPENCS_MAC_ICON}
|
${OPENCS_MAC_ICON}
|
||||||
|
${OPENCS_CFG}
|
||||||
|
${OPENCS_DEFAULT_FILTERS_FILE}
|
||||||
|
${OPENCS_OPENMW_CFG}
|
||||||
)
|
)
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
|
set(OPENCS_BUNDLE_NAME "OpenMW-CS")
|
||||||
|
set(OPENCS_BUNDLE_RESOURCES_DIR "${OpenMW_BINARY_DIR}/${OPENCS_BUNDLE_NAME}.app/Contents/Resources")
|
||||||
|
|
||||||
|
set(OPENMW_MYGUI_FILES_ROOT ${OPENCS_BUNDLE_RESOURCES_DIR})
|
||||||
|
set(OPENMW_SHADERS_ROOT ${OPENCS_BUNDLE_RESOURCES_DIR})
|
||||||
|
|
||||||
|
add_subdirectory(../../files/ ${CMAKE_CURRENT_BINARY_DIR}/files)
|
||||||
|
|
||||||
set_target_properties(openmw-cs PROPERTIES
|
set_target_properties(openmw-cs PROPERTIES
|
||||||
RUNTIME_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}"
|
RUNTIME_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}"
|
||||||
OUTPUT_NAME "OpenMW-CS"
|
OUTPUT_NAME ${OPENCS_BUNDLE_NAME}
|
||||||
MACOSX_BUNDLE_ICON_FILE "openmw-cs.icns"
|
MACOSX_BUNDLE_ICON_FILE "openmw-cs.icns"
|
||||||
MACOSX_BUNDLE_BUNDLE_NAME "OpenCS"
|
MACOSX_BUNDLE_BUNDLE_NAME "OpenCS"
|
||||||
MACOSX_BUNDLE_GUI_IDENTIFIER "org.openmw.opencs"
|
MACOSX_BUNDLE_GUI_IDENTIFIER "org.openmw.opencs"
|
||||||
|
@ -190,6 +207,16 @@ if(APPLE)
|
||||||
|
|
||||||
set_source_files_properties(${OPENCS_MAC_ICON} PROPERTIES
|
set_source_files_properties(${OPENCS_MAC_ICON} PROPERTIES
|
||||||
MACOSX_PACKAGE_LOCATION Resources)
|
MACOSX_PACKAGE_LOCATION Resources)
|
||||||
|
set_source_files_properties(${OPENCS_CFG} PROPERTIES
|
||||||
|
MACOSX_PACKAGE_LOCATION Resources)
|
||||||
|
set_source_files_properties(${OPENCS_DEFAULT_FILTERS_FILE} PROPERTIES
|
||||||
|
MACOSX_PACKAGE_LOCATION Resources/resources)
|
||||||
|
set_source_files_properties(${OPENCS_OPENMW_CFG} PROPERTIES
|
||||||
|
MACOSX_PACKAGE_LOCATION Resources)
|
||||||
|
|
||||||
|
add_custom_command(TARGET openmw-cs
|
||||||
|
POST_BUILD
|
||||||
|
COMMAND cp "${OpenMW_BINARY_DIR}/resources/version" "${OPENCS_BUNDLE_RESOURCES_DIR}/resources")
|
||||||
endif(APPLE)
|
endif(APPLE)
|
||||||
|
|
||||||
target_link_libraries(openmw-cs
|
target_link_libraries(openmw-cs
|
||||||
|
@ -223,9 +250,18 @@ endif()
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
target_link_libraries(openmw-cs ${Boost_LOCALE_LIBRARY})
|
target_link_libraries(openmw-cs ${Boost_LOCALE_LIBRARY})
|
||||||
|
INSTALL(TARGETS openmw-cs RUNTIME DESTINATION ".")
|
||||||
|
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.cfg" DESTINATION ".")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (MSVC)
|
||||||
|
# Debug version needs increased number of sections beyond 2^16
|
||||||
|
if (CMAKE_CL_64)
|
||||||
|
set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj")
|
||||||
|
endif (CMAKE_CL_64)
|
||||||
|
endif (MSVC)
|
||||||
|
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
INSTALL(TARGETS openmw-cs BUNDLE DESTINATION OpenMW COMPONENT BUNDLE)
|
INSTALL(TARGETS openmw-cs BUNDLE DESTINATION "." COMPONENT BUNDLE)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -62,11 +62,6 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
#ifdef Q_OS_MAC
|
#ifdef Q_OS_MAC
|
||||||
QDir dir(QCoreApplication::applicationDirPath());
|
QDir dir(QCoreApplication::applicationDirPath());
|
||||||
if (dir.dirName() == "MacOS") {
|
|
||||||
dir.cdUp();
|
|
||||||
dir.cdUp();
|
|
||||||
dir.cdUp();
|
|
||||||
}
|
|
||||||
QDir::setCurrent(dir.absolutePath());
|
QDir::setCurrent(dir.absolutePath());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ namespace CSMPrefs
|
||||||
enum SecondaryMode
|
enum SecondaryMode
|
||||||
{
|
{
|
||||||
SM_Replace, ///< The secondary signal replaces the regular signal when the modifier is active
|
SM_Replace, ///< The secondary signal replaces the regular signal when the modifier is active
|
||||||
SM_Detach, ///< The secondary signal is emitted independant of the regular signal, even if not active
|
SM_Detach, ///< The secondary signal is emitted independent of the regular signal, even if not active
|
||||||
SM_Ignore ///< The secondary signal will not ever be emitted
|
SM_Ignore ///< The secondary signal will not ever be emitted
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -184,7 +184,7 @@ void CSMTools::MergeLandTexturesStage::perform (int stage, CSMDoc::Messages& mes
|
||||||
CSMWorld::LandTexture texture =
|
CSMWorld::LandTexture texture =
|
||||||
mState.mSource.getData().getLandTextures().getRecord (index).get();
|
mState.mSource.getData().getLandTextures().getRecord (index).get();
|
||||||
|
|
||||||
std::ostringstream stream;
|
stream.clear();
|
||||||
stream << mNext->second-1 << "_0";
|
stream << mNext->second-1 << "_0";
|
||||||
|
|
||||||
texture.mIndex = mNext->second-1;
|
texture.mIndex = mNext->second-1;
|
||||||
|
|
|
@ -659,7 +659,7 @@ void CSMTools::ReferenceableCheckStage::npcCheck (
|
||||||
{
|
{
|
||||||
if ((npc.mFlags & ESM::NPC::Autocalc) == 0) //0x0010 = autocalculated flag
|
if ((npc.mFlags & ESM::NPC::Autocalc) == 0) //0x0010 = autocalculated flag
|
||||||
{
|
{
|
||||||
messages.push_back (std::make_pair (id, npc.mId + " mNpdtType or flags mismatch!")); //should not happend?
|
messages.push_back (std::make_pair (id, npc.mId + " mNpdtType or flags mismatch!")); //should not happen?
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -915,7 +915,7 @@ void CSMTools::ReferenceableCheckStage::inventoryListCheck(
|
||||||
id + " contains non-existing item (" + itemName + ")"));
|
id + " contains non-existing item (" + itemName + ")"));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Needs to accomodate Containers, Creatures, and NPCs
|
// Needs to accommodate containers, creatures, and NPCs
|
||||||
switch (localIndex.second)
|
switch (localIndex.second)
|
||||||
{
|
{
|
||||||
case CSMWorld::UniversalId::Type_Potion:
|
case CSMWorld::UniversalId::Type_Potion:
|
||||||
|
|
|
@ -1627,264 +1627,264 @@ const char * CSMWorld::DefaultGmsts::OptionalStrings[CSMWorld::DefaultGmsts::Opt
|
||||||
|
|
||||||
const float CSMWorld::DefaultGmsts::FloatsDefaultValues[CSMWorld::DefaultGmsts::FloatCount] =
|
const float CSMWorld::DefaultGmsts::FloatsDefaultValues[CSMWorld::DefaultGmsts::FloatCount] =
|
||||||
{
|
{
|
||||||
0.3, // fAIFleeFleeMult
|
0.3f, // fAIFleeFleeMult
|
||||||
7.0, // fAIFleeHealthMult
|
7.0f, // fAIFleeHealthMult
|
||||||
3.0, // fAIMagicSpellMult
|
3.0f, // fAIMagicSpellMult
|
||||||
1.0, // fAIMeleeArmorMult
|
1.0f, // fAIMeleeArmorMult
|
||||||
1.0, // fAIMeleeSummWeaponMult
|
1.0f, // fAIMeleeSummWeaponMult
|
||||||
2.0, // fAIMeleeWeaponMult
|
2.0f, // fAIMeleeWeaponMult
|
||||||
5.0, // fAIRangeMagicSpellMult
|
5.0f, // fAIRangeMagicSpellMult
|
||||||
5.0, // fAIRangeMeleeWeaponMult
|
5.0f, // fAIRangeMeleeWeaponMult
|
||||||
2000.0, // fAlarmRadius
|
2000.0f, // fAlarmRadius
|
||||||
1.0, // fAthleticsRunBonus
|
1.0f, // fAthleticsRunBonus
|
||||||
40.0, // fAudioDefaultMaxDistance
|
40.0f, // fAudioDefaultMaxDistance
|
||||||
5.0, // fAudioDefaultMinDistance
|
5.0f, // fAudioDefaultMinDistance
|
||||||
50.0, // fAudioMaxDistanceMult
|
50.0f, // fAudioMaxDistanceMult
|
||||||
20.0, // fAudioMinDistanceMult
|
20.0f, // fAudioMinDistanceMult
|
||||||
60.0, // fAudioVoiceDefaultMaxDistance
|
60.0f, // fAudioVoiceDefaultMaxDistance
|
||||||
10.0, // fAudioVoiceDefaultMinDistance
|
10.0f, // fAudioVoiceDefaultMinDistance
|
||||||
50.0, // fAutoPCSpellChance
|
50.0f, // fAutoPCSpellChance
|
||||||
80.0, // fAutoSpellChance
|
80.0f, // fAutoSpellChance
|
||||||
50.0, // fBargainOfferBase
|
50.0f, // fBargainOfferBase
|
||||||
-4.0, // fBargainOfferMulti
|
-4.0f, // fBargainOfferMulti
|
||||||
24.0, // fBarterGoldResetDelay
|
24.0f, // fBarterGoldResetDelay
|
||||||
1.75, // fBaseRunMultiplier
|
1.75f, // fBaseRunMultiplier
|
||||||
1.25, // fBlockStillBonus
|
1.25f, // fBlockStillBonus
|
||||||
150.0, // fBribe1000Mod
|
150.0f, // fBribe1000Mod
|
||||||
75.0, // fBribe100Mod
|
75.0f, // fBribe100Mod
|
||||||
35.0, // fBribe10Mod
|
35.0f, // fBribe10Mod
|
||||||
60.0, // fCombatAngleXY
|
60.0f, // fCombatAngleXY
|
||||||
60.0, // fCombatAngleZ
|
60.0f, // fCombatAngleZ
|
||||||
0.25, // fCombatArmorMinMult
|
0.25f, // fCombatArmorMinMult
|
||||||
-90.0, // fCombatBlockLeftAngle
|
-90.0f, // fCombatBlockLeftAngle
|
||||||
30.0, // fCombatBlockRightAngle
|
30.0f, // fCombatBlockRightAngle
|
||||||
4.0, // fCombatCriticalStrikeMult
|
4.0f, // fCombatCriticalStrikeMult
|
||||||
0.1, // fCombatDelayCreature
|
0.1f, // fCombatDelayCreature
|
||||||
0.1, // fCombatDelayNPC
|
0.1f, // fCombatDelayNPC
|
||||||
128.0, // fCombatDistance
|
128.0f, // fCombatDistance
|
||||||
0.3, // fCombatDistanceWerewolfMod
|
0.3f, // fCombatDistanceWerewolfMod
|
||||||
30.0, // fCombatForceSideAngle
|
30.0f, // fCombatForceSideAngle
|
||||||
0.2, // fCombatInvisoMult
|
0.2f, // fCombatInvisoMult
|
||||||
1.5, // fCombatKODamageMult
|
1.5f, // fCombatKODamageMult
|
||||||
45.0, // fCombatTorsoSideAngle
|
45.0f, // fCombatTorsoSideAngle
|
||||||
0.3, // fCombatTorsoStartPercent
|
0.3f, // fCombatTorsoStartPercent
|
||||||
0.8, // fCombatTorsoStopPercent
|
0.8f, // fCombatTorsoStopPercent
|
||||||
15.0, // fConstantEffectMult
|
15.0f, // fConstantEffectMult
|
||||||
72.0, // fCorpseClearDelay
|
72.0f, // fCorpseClearDelay
|
||||||
72.0, // fCorpseRespawnDelay
|
72.0f, // fCorpseRespawnDelay
|
||||||
0.5, // fCrimeGoldDiscountMult
|
0.5f, // fCrimeGoldDiscountMult
|
||||||
0.9, // fCrimeGoldTurnInMult
|
0.9f, // fCrimeGoldTurnInMult
|
||||||
1.0, // fCrimeStealing
|
1.0f, // fCrimeStealing
|
||||||
0.5, // fDamageStrengthBase
|
0.5f, // fDamageStrengthBase
|
||||||
0.1, // fDamageStrengthMult
|
0.1f, // fDamageStrengthMult
|
||||||
5.0, // fDifficultyMult
|
5.0f, // fDifficultyMult
|
||||||
2.5, // fDiseaseXferChance
|
2.5f, // fDiseaseXferChance
|
||||||
-10.0, // fDispAttacking
|
-10.0f, // fDispAttacking
|
||||||
-1.0, // fDispBargainFailMod
|
-1.0f, // fDispBargainFailMod
|
||||||
1.0, // fDispBargainSuccessMod
|
1.0f, // fDispBargainSuccessMod
|
||||||
0.0, // fDispCrimeMod
|
0.0f, // fDispCrimeMod
|
||||||
-10.0, // fDispDiseaseMod
|
-10.0f, // fDispDiseaseMod
|
||||||
3.0, // fDispFactionMod
|
3.0f, // fDispFactionMod
|
||||||
1.0, // fDispFactionRankBase
|
1.0f, // fDispFactionRankBase
|
||||||
0.5, // fDispFactionRankMult
|
0.5f, // fDispFactionRankMult
|
||||||
1.0, // fDispositionMod
|
1.0f, // fDispositionMod
|
||||||
50.0, // fDispPersonalityBase
|
50.0f, // fDispPersonalityBase
|
||||||
0.5, // fDispPersonalityMult
|
0.5f, // fDispPersonalityMult
|
||||||
-25.0, // fDispPickPocketMod
|
-25.0f, // fDispPickPocketMod
|
||||||
5.0, // fDispRaceMod
|
5.0f, // fDispRaceMod
|
||||||
-0.5, // fDispStealing
|
-0.5f, // fDispStealing
|
||||||
-5.0, // fDispWeaponDrawn
|
-5.0f, // fDispWeaponDrawn
|
||||||
0.5, // fEffectCostMult
|
0.5f, // fEffectCostMult
|
||||||
0.1, // fElementalShieldMult
|
0.1f, // fElementalShieldMult
|
||||||
3.0, // fEnchantmentChanceMult
|
3.0f, // fEnchantmentChanceMult
|
||||||
0.5, // fEnchantmentConstantChanceMult
|
0.5f, // fEnchantmentConstantChanceMult
|
||||||
100.0, // fEnchantmentConstantDurationMult
|
100.0f, // fEnchantmentConstantDurationMult
|
||||||
0.1, // fEnchantmentMult
|
0.1f, // fEnchantmentMult
|
||||||
1000.0, // fEnchantmentValueMult
|
1000.0f, // fEnchantmentValueMult
|
||||||
0.3, // fEncumberedMoveEffect
|
0.3f, // fEncumberedMoveEffect
|
||||||
5.0, // fEncumbranceStrMult
|
5.0f, // fEncumbranceStrMult
|
||||||
0.04, // fEndFatigueMult
|
0.04f, // fEndFatigueMult
|
||||||
0.25, // fFallAcroBase
|
0.25f, // fFallAcroBase
|
||||||
0.01, // fFallAcroMult
|
0.01f, // fFallAcroMult
|
||||||
400.0, // fFallDamageDistanceMin
|
400.0f, // fFallDamageDistanceMin
|
||||||
0.0, // fFallDistanceBase
|
0.0f, // fFallDistanceBase
|
||||||
0.07, // fFallDistanceMult
|
0.07f, // fFallDistanceMult
|
||||||
2.0, // fFatigueAttackBase
|
2.0f, // fFatigueAttackBase
|
||||||
0.0, // fFatigueAttackMult
|
0.0f, // fFatigueAttackMult
|
||||||
1.25, // fFatigueBase
|
1.25f, // fFatigueBase
|
||||||
4.0, // fFatigueBlockBase
|
4.0f, // fFatigueBlockBase
|
||||||
0.0, // fFatigueBlockMult
|
0.0f, // fFatigueBlockMult
|
||||||
5.0, // fFatigueJumpBase
|
5.0f, // fFatigueJumpBase
|
||||||
0.0, // fFatigueJumpMult
|
0.0f, // fFatigueJumpMult
|
||||||
0.5, // fFatigueMult
|
0.5f, // fFatigueMult
|
||||||
2.5, // fFatigueReturnBase
|
2.5f, // fFatigueReturnBase
|
||||||
0.02, // fFatigueReturnMult
|
0.02f, // fFatigueReturnMult
|
||||||
5.0, // fFatigueRunBase
|
5.0f, // fFatigueRunBase
|
||||||
2.0, // fFatigueRunMult
|
2.0f, // fFatigueRunMult
|
||||||
1.5, // fFatigueSneakBase
|
1.5f, // fFatigueSneakBase
|
||||||
1.5, // fFatigueSneakMult
|
1.5f, // fFatigueSneakMult
|
||||||
0.0, // fFatigueSpellBase
|
0.0f, // fFatigueSpellBase
|
||||||
0.0, // fFatigueSpellCostMult
|
0.0f, // fFatigueSpellCostMult
|
||||||
0.0, // fFatigueSpellMult
|
0.0f, // fFatigueSpellMult
|
||||||
7.0, // fFatigueSwimRunBase
|
7.0f, // fFatigueSwimRunBase
|
||||||
0.0, // fFatigueSwimRunMult
|
0.0f, // fFatigueSwimRunMult
|
||||||
2.5, // fFatigueSwimWalkBase
|
2.5f, // fFatigueSwimWalkBase
|
||||||
0.0, // fFatigueSwimWalkMult
|
0.0f, // fFatigueSwimWalkMult
|
||||||
0.2, // fFightDispMult
|
0.2f, // fFightDispMult
|
||||||
0.005, // fFightDistanceMultiplier
|
0.005f, // fFightDistanceMultiplier
|
||||||
50.0, // fFightStealing
|
50.0f, // fFightStealing
|
||||||
3000.0, // fFleeDistance
|
3000.0f, // fFleeDistance
|
||||||
512.0, // fGreetDistanceReset
|
512.0f, // fGreetDistanceReset
|
||||||
0.1, // fHandtoHandHealthPer
|
0.1f, // fHandtoHandHealthPer
|
||||||
1.0, // fHandToHandReach
|
1.0f, // fHandToHandReach
|
||||||
0.5, // fHoldBreathEndMult
|
0.5f, // fHoldBreathEndMult
|
||||||
20.0, // fHoldBreathTime
|
20.0f, // fHoldBreathTime
|
||||||
0.75, // fIdleChanceMultiplier
|
0.75f, // fIdleChanceMultiplier
|
||||||
1.0, // fIngredientMult
|
1.0f, // fIngredientMult
|
||||||
0.5, // fInteriorHeadTrackMult
|
0.5f, // fInteriorHeadTrackMult
|
||||||
128.0, // fJumpAcrobaticsBase
|
128.0f, // fJumpAcrobaticsBase
|
||||||
4.0, // fJumpAcroMultiplier
|
4.0f, // fJumpAcroMultiplier
|
||||||
0.5, // fJumpEncumbranceBase
|
0.5f, // fJumpEncumbranceBase
|
||||||
1.0, // fJumpEncumbranceMultiplier
|
1.0f, // fJumpEncumbranceMultiplier
|
||||||
0.5, // fJumpMoveBase
|
0.5f, // fJumpMoveBase
|
||||||
0.5, // fJumpMoveMult
|
0.5f, // fJumpMoveMult
|
||||||
1.0, // fJumpRunMultiplier
|
1.0f, // fJumpRunMultiplier
|
||||||
0.5, // fKnockDownMult
|
0.5f, // fKnockDownMult
|
||||||
5.0, // fLevelMod
|
5.0f, // fLevelMod
|
||||||
0.1, // fLevelUpHealthEndMult
|
0.1f, // fLevelUpHealthEndMult
|
||||||
0.6, // fLightMaxMod
|
0.6f, // fLightMaxMod
|
||||||
10.0, // fLuckMod
|
10.0f, // fLuckMod
|
||||||
10.0, // fMagesGuildTravel
|
10.0f, // fMagesGuildTravel
|
||||||
1.5, // fMagicCreatureCastDelay
|
1.5f, // fMagicCreatureCastDelay
|
||||||
0.0167, // fMagicDetectRefreshRate
|
0.0167f, // fMagicDetectRefreshRate
|
||||||
1.0, // fMagicItemConstantMult
|
1.0f, // fMagicItemConstantMult
|
||||||
1.0, // fMagicItemCostMult
|
1.0f, // fMagicItemCostMult
|
||||||
1.0, // fMagicItemOnceMult
|
1.0f, // fMagicItemOnceMult
|
||||||
1.0, // fMagicItemPriceMult
|
1.0f, // fMagicItemPriceMult
|
||||||
0.05, // fMagicItemRechargePerSecond
|
0.05f, // fMagicItemRechargePerSecond
|
||||||
1.0, // fMagicItemStrikeMult
|
1.0f, // fMagicItemStrikeMult
|
||||||
1.0, // fMagicItemUsedMult
|
1.0f, // fMagicItemUsedMult
|
||||||
3.0, // fMagicStartIconBlink
|
3.0f, // fMagicStartIconBlink
|
||||||
0.5, // fMagicSunBlockedMult
|
0.5f, // fMagicSunBlockedMult
|
||||||
0.75, // fMajorSkillBonus
|
0.75f, // fMajorSkillBonus
|
||||||
300.0, // fMaxFlySpeed
|
300.0f, // fMaxFlySpeed
|
||||||
0.5, // fMaxHandToHandMult
|
0.5f, // fMaxHandToHandMult
|
||||||
400.0, // fMaxHeadTrackDistance
|
400.0f, // fMaxHeadTrackDistance
|
||||||
200.0, // fMaxWalkSpeed
|
200.0f, // fMaxWalkSpeed
|
||||||
300.0, // fMaxWalkSpeedCreature
|
300.0f, // fMaxWalkSpeedCreature
|
||||||
0.9, // fMedMaxMod
|
0.9f, // fMedMaxMod
|
||||||
0.1, // fMessageTimePerChar
|
0.1f, // fMessageTimePerChar
|
||||||
5.0, // fMinFlySpeed
|
5.0f, // fMinFlySpeed
|
||||||
0.1, // fMinHandToHandMult
|
0.1f, // fMinHandToHandMult
|
||||||
1.0, // fMinorSkillBonus
|
1.0f, // fMinorSkillBonus
|
||||||
100.0, // fMinWalkSpeed
|
100.0f, // fMinWalkSpeed
|
||||||
5.0, // fMinWalkSpeedCreature
|
5.0f, // fMinWalkSpeedCreature
|
||||||
1.25, // fMiscSkillBonus
|
1.25f, // fMiscSkillBonus
|
||||||
2.0, // fNPCbaseMagickaMult
|
2.0f, // fNPCbaseMagickaMult
|
||||||
0.5, // fNPCHealthBarFade
|
0.5f, // fNPCHealthBarFade
|
||||||
3.0, // fNPCHealthBarTime
|
3.0f, // fNPCHealthBarTime
|
||||||
1.0, // fPCbaseMagickaMult
|
1.0f, // fPCbaseMagickaMult
|
||||||
0.3, // fPerDieRollMult
|
0.3f, // fPerDieRollMult
|
||||||
5.0, // fPersonalityMod
|
5.0f, // fPersonalityMod
|
||||||
1.0, // fPerTempMult
|
1.0f, // fPerTempMult
|
||||||
-1.0, // fPickLockMult
|
-1.0f, // fPickLockMult
|
||||||
0.3, // fPickPocketMod
|
0.3f, // fPickPocketMod
|
||||||
20.0, // fPotionMinUsefulDuration
|
20.0f, // fPotionMinUsefulDuration
|
||||||
0.5, // fPotionStrengthMult
|
0.5f, // fPotionStrengthMult
|
||||||
0.5, // fPotionT1DurMult
|
0.5f, // fPotionT1DurMult
|
||||||
1.5, // fPotionT1MagMult
|
1.5f, // fPotionT1MagMult
|
||||||
20.0, // fPotionT4BaseStrengthMult
|
20.0f, // fPotionT4BaseStrengthMult
|
||||||
12.0, // fPotionT4EquipStrengthMult
|
12.0f, // fPotionT4EquipStrengthMult
|
||||||
3000.0, // fProjectileMaxSpeed
|
3000.0f, // fProjectileMaxSpeed
|
||||||
400.0, // fProjectileMinSpeed
|
400.0f, // fProjectileMinSpeed
|
||||||
25.0, // fProjectileThrownStoreChance
|
25.0f, // fProjectileThrownStoreChance
|
||||||
3.0, // fRepairAmountMult
|
3.0f, // fRepairAmountMult
|
||||||
1.0, // fRepairMult
|
1.0f, // fRepairMult
|
||||||
1.0, // fReputationMod
|
1.0f, // fReputationMod
|
||||||
0.15, // fRestMagicMult
|
0.15f, // fRestMagicMult
|
||||||
0.0, // fSeriousWoundMult
|
0.0f, // fSeriousWoundMult
|
||||||
0.25, // fSleepRandMod
|
0.25f, // fSleepRandMod
|
||||||
0.3, // fSleepRestMod
|
0.3f, // fSleepRestMod
|
||||||
-1.0, // fSneakBootMult
|
-1.0f, // fSneakBootMult
|
||||||
0.5, // fSneakDistanceBase
|
0.5f, // fSneakDistanceBase
|
||||||
0.002, // fSneakDistanceMultiplier
|
0.002f, // fSneakDistanceMultiplier
|
||||||
0.5, // fSneakNoViewMult
|
0.5f, // fSneakNoViewMult
|
||||||
1.0, // fSneakSkillMult
|
1.0f, // fSneakSkillMult
|
||||||
0.75, // fSneakSpeedMultiplier
|
0.75f, // fSneakSpeedMultiplier
|
||||||
1.0, // fSneakUseDelay
|
1.0f, // fSneakUseDelay
|
||||||
500.0, // fSneakUseDist
|
500.0f, // fSneakUseDist
|
||||||
1.5, // fSneakViewMult
|
1.5f, // fSneakViewMult
|
||||||
3.0, // fSoulGemMult
|
3.0f, // fSoulGemMult
|
||||||
0.8, // fSpecialSkillBonus
|
0.8f, // fSpecialSkillBonus
|
||||||
7.0, // fSpellMakingValueMult
|
7.0f, // fSpellMakingValueMult
|
||||||
2.0, // fSpellPriceMult
|
2.0f, // fSpellPriceMult
|
||||||
10.0, // fSpellValueMult
|
10.0f, // fSpellValueMult
|
||||||
0.25, // fStromWalkMult
|
0.25f, // fStromWalkMult
|
||||||
0.7, // fStromWindSpeed
|
0.7f, // fStromWindSpeed
|
||||||
3.0, // fSuffocationDamage
|
3.0f, // fSuffocationDamage
|
||||||
0.9, // fSwimHeightScale
|
0.9f, // fSwimHeightScale
|
||||||
0.1, // fSwimRunAthleticsMult
|
0.1f, // fSwimRunAthleticsMult
|
||||||
0.5, // fSwimRunBase
|
0.5f, // fSwimRunBase
|
||||||
0.02, // fSwimWalkAthleticsMult
|
0.02f, // fSwimWalkAthleticsMult
|
||||||
0.5, // fSwimWalkBase
|
0.5f, // fSwimWalkBase
|
||||||
1.0, // fSwingBlockBase
|
1.0f, // fSwingBlockBase
|
||||||
1.0, // fSwingBlockMult
|
1.0f, // fSwingBlockMult
|
||||||
1000.0, // fTargetSpellMaxSpeed
|
1000.0f, // fTargetSpellMaxSpeed
|
||||||
1000.0, // fThrownWeaponMaxSpeed
|
1000.0f, // fThrownWeaponMaxSpeed
|
||||||
300.0, // fThrownWeaponMinSpeed
|
300.0f, // fThrownWeaponMinSpeed
|
||||||
0.0, // fTrapCostMult
|
0.0f, // fTrapCostMult
|
||||||
4000.0, // fTravelMult
|
4000.0f, // fTravelMult
|
||||||
16000.0,// fTravelTimeMult
|
16000.0f,// fTravelTimeMult
|
||||||
0.1, // fUnarmoredBase1
|
0.1f, // fUnarmoredBase1
|
||||||
0.065, // fUnarmoredBase2
|
0.065f, // fUnarmoredBase2
|
||||||
30.0, // fVanityDelay
|
30.0f, // fVanityDelay
|
||||||
10.0, // fVoiceIdleOdds
|
10.0f, // fVoiceIdleOdds
|
||||||
0.0, // fWaterReflectUpdateAlways
|
0.0f, // fWaterReflectUpdateAlways
|
||||||
10.0, // fWaterReflectUpdateSeldom
|
10.0f, // fWaterReflectUpdateSeldom
|
||||||
0.1, // fWeaponDamageMult
|
0.1f, // fWeaponDamageMult
|
||||||
1.0, // fWeaponFatigueBlockMult
|
1.0f, // fWeaponFatigueBlockMult
|
||||||
0.25, // fWeaponFatigueMult
|
0.25f, // fWeaponFatigueMult
|
||||||
150.0, // fWereWolfAcrobatics
|
150.0f, // fWereWolfAcrobatics
|
||||||
150.0, // fWereWolfAgility
|
150.0f, // fWereWolfAgility
|
||||||
1.0, // fWereWolfAlchemy
|
1.0f, // fWereWolfAlchemy
|
||||||
1.0, // fWereWolfAlteration
|
1.0f, // fWereWolfAlteration
|
||||||
1.0, // fWereWolfArmorer
|
1.0f, // fWereWolfArmorer
|
||||||
150.0, // fWereWolfAthletics
|
150.0f, // fWereWolfAthletics
|
||||||
1.0, // fWereWolfAxe
|
1.0f, // fWereWolfAxe
|
||||||
1.0, // fWereWolfBlock
|
1.0f, // fWereWolfBlock
|
||||||
1.0, // fWereWolfBluntWeapon
|
1.0f, // fWereWolfBluntWeapon
|
||||||
1.0, // fWereWolfConjuration
|
1.0f, // fWereWolfConjuration
|
||||||
1.0, // fWereWolfDestruction
|
1.0f, // fWereWolfDestruction
|
||||||
1.0, // fWereWolfEnchant
|
1.0f, // fWereWolfEnchant
|
||||||
150.0, // fWereWolfEndurance
|
150.0f, // fWereWolfEndurance
|
||||||
400.0, // fWereWolfFatigue
|
400.0f, // fWereWolfFatigue
|
||||||
100.0, // fWereWolfHandtoHand
|
100.0f, // fWereWolfHandtoHand
|
||||||
2.0, // fWereWolfHealth
|
2.0f, // fWereWolfHealth
|
||||||
1.0, // fWereWolfHeavyArmor
|
1.0f, // fWereWolfHeavyArmor
|
||||||
1.0, // fWereWolfIllusion
|
1.0f, // fWereWolfIllusion
|
||||||
1.0, // fWereWolfIntellegence
|
1.0f, // fWereWolfIntellegence
|
||||||
1.0, // fWereWolfLightArmor
|
1.0f, // fWereWolfLightArmor
|
||||||
1.0, // fWereWolfLongBlade
|
1.0f, // fWereWolfLongBlade
|
||||||
1.0, // fWereWolfLuck
|
1.0f, // fWereWolfLuck
|
||||||
100.0, // fWereWolfMagicka
|
100.0f, // fWereWolfMagicka
|
||||||
1.0, // fWereWolfMarksman
|
1.0f, // fWereWolfMarksman
|
||||||
1.0, // fWereWolfMediumArmor
|
1.0f, // fWereWolfMediumArmor
|
||||||
1.0, // fWereWolfMerchantile
|
1.0f, // fWereWolfMerchantile
|
||||||
1.0, // fWereWolfMysticism
|
1.0f, // fWereWolfMysticism
|
||||||
1.0, // fWereWolfPersonality
|
1.0f, // fWereWolfPersonality
|
||||||
1.0, // fWereWolfRestoration
|
1.0f, // fWereWolfRestoration
|
||||||
1.5, // fWereWolfRunMult
|
1.5f, // fWereWolfRunMult
|
||||||
1.0, // fWereWolfSecurity
|
1.0f, // fWereWolfSecurity
|
||||||
1.0, // fWereWolfShortBlade
|
1.0f, // fWereWolfShortBlade
|
||||||
1.5, // fWereWolfSilverWeaponDamageMult
|
1.5f, // fWereWolfSilverWeaponDamageMult
|
||||||
1.0, // fWereWolfSneak
|
1.0f, // fWereWolfSneak
|
||||||
1.0, // fWereWolfSpear
|
1.0f, // fWereWolfSpear
|
||||||
1.0, // fWereWolfSpeechcraft
|
1.0f, // fWereWolfSpeechcraft
|
||||||
150.0, // fWereWolfSpeed
|
150.0f, // fWereWolfSpeed
|
||||||
150.0, // fWereWolfStrength
|
150.0f, // fWereWolfStrength
|
||||||
100.0, // fWereWolfUnarmored
|
100.0f, // fWereWolfUnarmored
|
||||||
1.0, // fWereWolfWillPower
|
1.0f, // fWereWolfWillPower
|
||||||
15.0 // fWortChanceValue
|
15.0f // fWortChanceValue
|
||||||
};
|
};
|
||||||
|
|
||||||
const int CSMWorld::DefaultGmsts::IntsDefaultValues[CSMWorld::DefaultGmsts::IntCount] =
|
const int CSMWorld::DefaultGmsts::IntsDefaultValues[CSMWorld::DefaultGmsts::IntCount] =
|
||||||
|
|
|
@ -191,7 +191,7 @@ void CSMWorld::IdTable::setRecord (const std::string& id, const RecordBase& reco
|
||||||
|
|
||||||
if (index==-1)
|
if (index==-1)
|
||||||
{
|
{
|
||||||
int index = mIdCollection->getAppendIndex (id, type);
|
index = mIdCollection->getAppendIndex (id, type);
|
||||||
|
|
||||||
beginInsertRows (QModelIndex(), index, index);
|
beginInsertRows (QModelIndex(), index, index);
|
||||||
|
|
||||||
|
|
|
@ -198,12 +198,12 @@ QModelIndex CSMWorld::IdTree::parent (const QModelIndex& index) const
|
||||||
return QModelIndex();
|
return QModelIndex();
|
||||||
|
|
||||||
unsigned int id = index.internalId();
|
unsigned int id = index.internalId();
|
||||||
const std::pair<int, int>& adress(unfoldIndexAddress(id));
|
const std::pair<int, int>& address(unfoldIndexAddress(id));
|
||||||
|
|
||||||
if (adress.first >= this->rowCount() || adress.second >= this->columnCount())
|
if (address.first >= this->rowCount() || address.second >= this->columnCount())
|
||||||
throw "Parent index is not present in the model";
|
throw "Parent index is not present in the model";
|
||||||
|
|
||||||
return createIndex(adress.first, adress.second);
|
return createIndex(address.first, address.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int CSMWorld::IdTree::foldIndexAddress (const QModelIndex& index) const
|
unsigned int CSMWorld::IdTree::foldIndexAddress (const QModelIndex& index) const
|
||||||
|
|
|
@ -63,7 +63,7 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool
|
||||||
std::cerr << "Position: #" << index.first << " " << index.second
|
std::cerr << "Position: #" << index.first << " " << index.second
|
||||||
<<", Target #"<< mref.mTarget[0] << " " << mref.mTarget[1] << std::endl;
|
<<", Target #"<< mref.mTarget[0] << " " << mref.mTarget[1] << std::endl;
|
||||||
|
|
||||||
std::ostringstream stream;
|
stream.clear();
|
||||||
stream << "#" << mref.mTarget[0] << " " << mref.mTarget[1];
|
stream << "#" << mref.mTarget[0] << " " << mref.mTarget[1];
|
||||||
ref.mCell = stream.str(); // overwrite
|
ref.mCell = stream.str(); // overwrite
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@ namespace CSVRender
|
||||||
updateCellData(mData.getCells().getRecord(cellIndex));
|
updateCellData(mData.getCells().getRecord(cellIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keep water existance/height up to date
|
// Keep water existence/height up to date
|
||||||
QAbstractItemModel* cells = mData.getTableModel(CSMWorld::UniversalId::Type_Cells);
|
QAbstractItemModel* cells = mData.getTableModel(CSMWorld::UniversalId::Type_Cells);
|
||||||
connect(cells, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)),
|
connect(cells, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)),
|
||||||
this, SLOT(cellDataChanged(const QModelIndex&, const QModelIndex&)));
|
this, SLOT(cellDataChanged(const QModelIndex&, const QModelIndex&)));
|
||||||
|
|
|
@ -516,7 +516,7 @@ void CSVRender::PagedWorldspaceWidget::useViewHint (const std::string& hint)
|
||||||
// Current coordinate
|
// Current coordinate
|
||||||
int x, y;
|
int x, y;
|
||||||
|
|
||||||
// Loop throught all the coordinates to add them to selection
|
// Loop through all the coordinates to add them to selection
|
||||||
while (stream >> ignore1 >> ignore2 >> x >> y)
|
while (stream >> ignore1 >> ignore2 >> x >> y)
|
||||||
selection.add (CSMWorld::CellCoordinates (x, y));
|
selection.add (CSMWorld::CellCoordinates (x, y));
|
||||||
|
|
||||||
|
|
|
@ -214,7 +214,7 @@ SceneWidget::SceneWidget(boost::shared_ptr<Resource::ResourceSystem> resourceSys
|
||||||
|
|
||||||
SceneWidget::~SceneWidget()
|
SceneWidget::~SceneWidget()
|
||||||
{
|
{
|
||||||
// Since we're holding on to the scene templates past the existance of this graphics context, we'll need to manually release the created objects
|
// Since we're holding on to the scene templates past the existence of this graphics context, we'll need to manually release the created objects
|
||||||
mResourceSystem->getSceneManager()->releaseGLObjects(mView->getCamera()->getGraphicsContext()->getState());
|
mResourceSystem->getSceneManager()->releaseGLObjects(mView->getCamera()->getGraphicsContext()->getState());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,8 +45,8 @@ namespace CSVWorld
|
||||||
///< \note Non-existent cells are not listed.
|
///< \note Non-existent cells are not listed.
|
||||||
|
|
||||||
QModelIndexList getSelectedCells (bool existent = true, bool nonExistent = false) const;
|
QModelIndexList getSelectedCells (bool existent = true, bool nonExistent = false) const;
|
||||||
///< \param existant Include existant cells.
|
///< \param existent Include existent cells.
|
||||||
/// \param nonExistant Include non-existant cells.
|
/// \param nonExistent Include non-existent cells.
|
||||||
|
|
||||||
QModelIndexList getMissingRegionCells() const;
|
QModelIndexList getMissingRegionCells() const;
|
||||||
///< Unselected cells within all regions that have at least one selected cell.
|
///< Unselected cells within all regions that have at least one selected cell.
|
||||||
|
|
|
@ -42,7 +42,7 @@ add_openmw_dir (mwgui
|
||||||
itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview
|
itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview
|
||||||
tradeitemmodel companionitemmodel pickpocketitemmodel controllers savegamedialog
|
tradeitemmodel companionitemmodel pickpocketitemmodel controllers savegamedialog
|
||||||
recharge mode videowidget backgroundimage itemwidget screenfader debugwindow spellmodel spellview
|
recharge mode videowidget backgroundimage itemwidget screenfader debugwindow spellmodel spellview
|
||||||
draganddrop timeadvancer jailscreen
|
draganddrop timeadvancer jailscreen itemchargeview
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwdialogue
|
add_openmw_dir (mwdialogue
|
||||||
|
@ -179,6 +179,21 @@ target_link_libraries(openmw ${CMAKE_THREAD_LIBS_INIT})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
|
set(BUNDLE_RESOURCES_DIR "${APP_BUNDLE_DIR}/Contents/Resources")
|
||||||
|
|
||||||
|
set(OPENMW_MYGUI_FILES_ROOT ${BUNDLE_RESOURCES_DIR})
|
||||||
|
set(OPENMW_SHADERS_ROOT ${BUNDLE_RESOURCES_DIR})
|
||||||
|
|
||||||
|
add_subdirectory(../../files/ ${CMAKE_CURRENT_BINARY_DIR}/files)
|
||||||
|
|
||||||
|
configure_file("${OpenMW_BINARY_DIR}/settings-default.cfg" ${BUNDLE_RESOURCES_DIR} COPYONLY)
|
||||||
|
configure_file("${OpenMW_BINARY_DIR}/openmw.cfg" ${BUNDLE_RESOURCES_DIR} COPYONLY)
|
||||||
|
configure_file("${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" ${BUNDLE_RESOURCES_DIR} COPYONLY)
|
||||||
|
|
||||||
|
add_custom_command(TARGET openmw
|
||||||
|
POST_BUILD
|
||||||
|
COMMAND cp "${OpenMW_BINARY_DIR}/resources/version" "${BUNDLE_RESOURCES_DIR}/resources")
|
||||||
|
|
||||||
find_library(COCOA_FRAMEWORK Cocoa)
|
find_library(COCOA_FRAMEWORK Cocoa)
|
||||||
find_library(IOKIT_FRAMEWORK IOKit)
|
find_library(IOKIT_FRAMEWORK IOKit)
|
||||||
target_link_libraries(openmw ${COCOA_FRAMEWORK} ${IOKIT_FRAMEWORK})
|
target_link_libraries(openmw ${COCOA_FRAMEWORK} ${IOKIT_FRAMEWORK})
|
||||||
|
@ -186,7 +201,7 @@ if(APPLE)
|
||||||
if (FFmpeg_FOUND)
|
if (FFmpeg_FOUND)
|
||||||
find_library(COREVIDEO_FRAMEWORK CoreVideo)
|
find_library(COREVIDEO_FRAMEWORK CoreVideo)
|
||||||
find_library(VDA_FRAMEWORK VideoDecodeAcceleration)
|
find_library(VDA_FRAMEWORK VideoDecodeAcceleration)
|
||||||
target_link_libraries(openmw ${COREVIDEO_FRAMEWORK} ${VDA_FRAMEWORK})
|
target_link_libraries(openmw z ${COREVIDEO_FRAMEWORK} ${VDA_FRAMEWORK})
|
||||||
endif()
|
endif()
|
||||||
endif(APPLE)
|
endif(APPLE)
|
||||||
|
|
||||||
|
@ -202,3 +217,8 @@ if (MSVC)
|
||||||
endif (CMAKE_CL_64)
|
endif (CMAKE_CL_64)
|
||||||
add_definitions("-D_USE_MATH_DEFINES")
|
add_definitions("-D_USE_MATH_DEFINES")
|
||||||
endif (MSVC)
|
endif (MSVC)
|
||||||
|
|
||||||
|
if (WIN32)
|
||||||
|
INSTALL(TARGETS openmw RUNTIME DESTINATION ".")
|
||||||
|
endif (WIN32)
|
||||||
|
|
||||||
|
|
|
@ -493,7 +493,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
||||||
mEnvironment.setWindowManager (window);
|
mEnvironment.setWindowManager (window);
|
||||||
|
|
||||||
// Create sound system
|
// Create sound system
|
||||||
mEnvironment.setSoundManager (new MWSound::SoundManager(mVFS.get(), mUseSound));
|
mEnvironment.setSoundManager (new MWSound::SoundManager(mVFS.get(), mFallbackMap, mUseSound));
|
||||||
|
|
||||||
if (!mSkipMenu)
|
if (!mSkipMenu)
|
||||||
{
|
{
|
||||||
|
|
|
@ -352,9 +352,8 @@ int main(int argc, char**argv)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
// FIXME: set current dir to bundle path
|
boost::filesystem::path binary_path = boost::filesystem::system_complete(boost::filesystem::path(argv[0]));
|
||||||
//boost::filesystem::path bundlePath = boost::filesystem::path(Ogre::macBundlePath()).parent_path();
|
boost::filesystem::current_path(binary_path.parent_path());
|
||||||
//boost::filesystem::current_path(bundlePath);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
engine.reset(new OMW::Engine(cfgMgr));
|
engine.reset(new OMW::Engine(cfgMgr));
|
||||||
|
|
|
@ -5,6 +5,19 @@
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace Loading
|
||||||
|
{
|
||||||
|
class Listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
class ESMReader;
|
||||||
|
class ESMWriter;
|
||||||
|
}
|
||||||
|
|
||||||
namespace MWBase
|
namespace MWBase
|
||||||
{
|
{
|
||||||
/// \brief Interface for input manager (implemented in MWInput)
|
/// \brief Interface for input manager (implemented in MWInput)
|
||||||
|
@ -56,6 +69,10 @@ namespace MWBase
|
||||||
/// Returns if the last used input device was a joystick or a keyboard
|
/// Returns if the last used input device was a joystick or a keyboard
|
||||||
/// @return true if joystick, false otherwise
|
/// @return true if joystick, false otherwise
|
||||||
virtual bool joystickLastUsed() = 0;
|
virtual bool joystickLastUsed() = 0;
|
||||||
|
|
||||||
|
virtual int countSavedGameRecords() const = 0;
|
||||||
|
virtual void write(ESM::ESMWriter& writer, Loading::Listener& progress) = 0;
|
||||||
|
virtual void readRecord(ESM::ESMReader& reader, uint32_t type) = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -233,7 +233,7 @@ namespace MWBase
|
||||||
virtual void removeDialog(MWGui::Layout* dialog) = 0;
|
virtual void removeDialog(MWGui::Layout* dialog) = 0;
|
||||||
|
|
||||||
///Gracefully attempts to exit the topmost GUI mode
|
///Gracefully attempts to exit the topmost GUI mode
|
||||||
/** No guarentee of actually closing the window **/
|
/** No guarantee of actually closing the window **/
|
||||||
virtual void exitCurrentGuiMode() = 0;
|
virtual void exitCurrentGuiMode() = 0;
|
||||||
|
|
||||||
virtual void messageBox (const std::string& message, enum MWGui::ShowInDialogueMode showInDialogueMode = MWGui::ShowInDialogueMode_IfPossible) = 0;
|
virtual void messageBox (const std::string& message, enum MWGui::ShowInDialogueMode showInDialogueMode = MWGui::ShowInDialogueMode_IfPossible) = 0;
|
||||||
|
|
|
@ -548,7 +548,7 @@ namespace MWBase
|
||||||
/// Resets all actors in the current active cells to their original location within that cell.
|
/// Resets all actors in the current active cells to their original location within that cell.
|
||||||
virtual void resetActors() = 0;
|
virtual void resetActors() = 0;
|
||||||
|
|
||||||
virtual bool isWalkingOnWater (const MWWorld::ConstPtr& actor) = 0;
|
virtual bool isWalkingOnWater (const MWWorld::ConstPtr& actor) const = 0;
|
||||||
|
|
||||||
/// Return a vector aiming the actor's weapon towards a target.
|
/// Return a vector aiming the actor's weapon towards a target.
|
||||||
/// @note The length of the vector is the distance between actor and target.
|
/// @note The length of the vector is the distance between actor and target.
|
||||||
|
@ -560,6 +560,12 @@ namespace MWBase
|
||||||
virtual void removeContainerScripts(const MWWorld::Ptr& reference) = 0;
|
virtual void removeContainerScripts(const MWWorld::Ptr& reference) = 0;
|
||||||
|
|
||||||
virtual bool isPlayerInJail() const = 0;
|
virtual bool isPlayerInJail() const = 0;
|
||||||
|
|
||||||
|
/// Return terrain height at \a worldPos position.
|
||||||
|
virtual float getTerrainHeightAt(const osg::Vec3f& worldPos) const = 0;
|
||||||
|
|
||||||
|
/// Return physical or rendering half extents of the given actor.
|
||||||
|
virtual osg::Vec3f getHalfExtents(const MWWorld::ConstPtr& actor, bool rendering=false) const = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -118,9 +118,9 @@ namespace MWClass
|
||||||
}
|
}
|
||||||
|
|
||||||
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
|
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
|
||||||
MWWorld::ManualRef ref(store, id);
|
MWWorld::ManualRef manualRef(store, id);
|
||||||
ref.getPtr().getCellRef().setPosition(ptr.getCellRef().getPosition());
|
manualRef.getPtr().getCellRef().setPosition(ptr.getCellRef().getPosition());
|
||||||
MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->placeObject(ref.getPtr(), ptr.getCell() , ptr.getCellRef().getPosition());
|
MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->placeObject(manualRef.getPtr(), ptr.getCell() , ptr.getCellRef().getPosition());
|
||||||
customData.mSpawnActorId = placed.getClass().getCreatureStats(placed).getActorId();
|
customData.mSpawnActorId = placed.getClass().getCreatureStats(placed).getActorId();
|
||||||
customData.mSpawn = false;
|
customData.mSpawn = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -174,7 +174,7 @@ namespace MWDialogue
|
||||||
executeScript (info->mResultScript);
|
executeScript (info->mResultScript);
|
||||||
mLastTopic = Misc::StringUtils::lowerCase(it->mId);
|
mLastTopic = Misc::StringUtils::lowerCase(it->mId);
|
||||||
|
|
||||||
// update topics again to accomodate changes resulting from executeScript
|
// update topics again to accommodate changes resulting from executeScript
|
||||||
updateTopics();
|
updateTopics();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -200,15 +200,15 @@ namespace MWGui
|
||||||
std::set<MWMechanics::EffectKey> effectIds = mAlchemy->listEffects();
|
std::set<MWMechanics::EffectKey> effectIds = mAlchemy->listEffects();
|
||||||
Widgets::SpellEffectList list;
|
Widgets::SpellEffectList list;
|
||||||
unsigned int effectIndex=0;
|
unsigned int effectIndex=0;
|
||||||
for (std::set<MWMechanics::EffectKey>::iterator it = effectIds.begin(); it != effectIds.end(); ++it)
|
for (std::set<MWMechanics::EffectKey>::iterator it2 = effectIds.begin(); it2 != effectIds.end(); ++it2)
|
||||||
{
|
{
|
||||||
Widgets::SpellEffectParams params;
|
Widgets::SpellEffectParams params;
|
||||||
params.mEffectID = it->mId;
|
params.mEffectID = it2->mId;
|
||||||
const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(it->mId);
|
const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(it2->mId);
|
||||||
if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill)
|
if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill)
|
||||||
params.mSkill = it->mArg;
|
params.mSkill = it2->mArg;
|
||||||
else if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetAttribute)
|
else if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetAttribute)
|
||||||
params.mAttribute = it->mArg;
|
params.mAttribute = it2->mArg;
|
||||||
params.mIsConstant = true;
|
params.mIsConstant = true;
|
||||||
params.mNoTarget = true;
|
params.mNoTarget = true;
|
||||||
|
|
||||||
|
|
|
@ -226,7 +226,7 @@ namespace MWGui
|
||||||
coord.top += lineHeight;
|
coord.top += lineHeight;
|
||||||
|
|
||||||
end = categories[category].spells.end();
|
end = categories[category].spells.end();
|
||||||
for (std::vector<std::string>::const_iterator it = categories[category].spells.begin(); it != end; ++it)
|
for (it = categories[category].spells.begin(); it != end; ++it)
|
||||||
{
|
{
|
||||||
const std::string &spellId = *it;
|
const std::string &spellId = *it;
|
||||||
spellWidget = mSpellArea->createWidget<Widgets::MWSpell>("MW_StatName", coord, MyGUI::Align::Default, std::string("Spell") + MyGUI::utility::toString(i));
|
spellWidget = mSpellArea->createWidget<Widgets::MWSpell>("MW_StatName", coord, MyGUI::Align::Default, std::string("Spell") + MyGUI::utility::toString(i));
|
||||||
|
|
|
@ -132,6 +132,12 @@ namespace MWGui
|
||||||
mReviewDialog->configureSkills(major, minor);
|
mReviewDialog->configureSkills(major, minor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CharacterCreation::onFrame(float duration)
|
||||||
|
{
|
||||||
|
if (mReviewDialog)
|
||||||
|
mReviewDialog->onFrame(duration);
|
||||||
|
}
|
||||||
|
|
||||||
void CharacterCreation::spawnDialog(const char id)
|
void CharacterCreation::spawnDialog(const char id)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|
|
@ -50,6 +50,8 @@ namespace MWGui
|
||||||
void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value);
|
void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value);
|
||||||
void configureSkills (const SkillList& major, const SkillList& minor);
|
void configureSkills (const SkillList& major, const SkillList& minor);
|
||||||
|
|
||||||
|
void onFrame(float duration);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
osg::Group* mParent;
|
osg::Group* mParent;
|
||||||
Resource::ResourceSystem* mResourceSystem;
|
Resource::ResourceSystem* mResourceSystem;
|
||||||
|
|
|
@ -85,8 +85,8 @@ void InventoryItemModel::update()
|
||||||
|
|
||||||
if (mActor.getClass().hasInventoryStore(mActor))
|
if (mActor.getClass().hasInventoryStore(mActor))
|
||||||
{
|
{
|
||||||
MWWorld::InventoryStore& store = mActor.getClass().getInventoryStore(mActor);
|
MWWorld::InventoryStore& invStore = mActor.getClass().getInventoryStore(mActor);
|
||||||
if (store.isEquipped(newItem.mBase))
|
if (invStore.isEquipped(newItem.mBase))
|
||||||
newItem.mType = ItemStack::Type_Equipped;
|
newItem.mType = ItemStack::Type_Equipped;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
212
apps/openmw/mwgui/itemchargeview.cpp
Normal file
212
apps/openmw/mwgui/itemchargeview.cpp
Normal file
|
@ -0,0 +1,212 @@
|
||||||
|
#include "itemchargeview.hpp"
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
#include <MyGUI_Gui.h>
|
||||||
|
#include <MyGUI_TextBox.h>
|
||||||
|
#include <MyGUI_ScrollView.h>
|
||||||
|
#include <MyGUI_FactoryManager.h>
|
||||||
|
|
||||||
|
#include <components/esm/loadench.hpp>
|
||||||
|
|
||||||
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwbase/world.hpp"
|
||||||
|
|
||||||
|
#include "../mwworld/class.hpp"
|
||||||
|
#include "../mwworld/esmstore.hpp"
|
||||||
|
|
||||||
|
#include "itemmodel.hpp"
|
||||||
|
#include "itemwidget.hpp"
|
||||||
|
|
||||||
|
namespace MWGui
|
||||||
|
{
|
||||||
|
ItemChargeView::ItemChargeView()
|
||||||
|
: mScrollView(NULL),
|
||||||
|
mDisplayMode(DisplayMode_Health)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemChargeView::registerComponents()
|
||||||
|
{
|
||||||
|
MyGUI::FactoryManager::getInstance().registerFactory<ItemChargeView>("Widget");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemChargeView::initialiseOverride()
|
||||||
|
{
|
||||||
|
Base::initialiseOverride();
|
||||||
|
|
||||||
|
assignWidget(mScrollView, "ScrollView");
|
||||||
|
if (mScrollView == NULL)
|
||||||
|
throw std::runtime_error("Item charge view needs a scroll view");
|
||||||
|
|
||||||
|
mScrollView->setCanvasAlign(MyGUI::Align::Left | MyGUI::Align::Top);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemChargeView::setModel(ItemModel* model)
|
||||||
|
{
|
||||||
|
mModel.reset(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemChargeView::setDisplayMode(ItemChargeView::DisplayMode type)
|
||||||
|
{
|
||||||
|
mDisplayMode = type;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemChargeView::update()
|
||||||
|
{
|
||||||
|
if (!mModel.get())
|
||||||
|
{
|
||||||
|
layoutWidgets();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mModel->update();
|
||||||
|
|
||||||
|
Lines lines;
|
||||||
|
std::set<Lines::const_iterator> visitedLines;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < mModel->getItemCount(); ++i)
|
||||||
|
{
|
||||||
|
ItemStack stack = mModel->getItem(static_cast<ItemModel::ModelIndex>(i));
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
for (Lines::const_iterator iter = mLines.begin(); iter != mLines.end(); ++iter)
|
||||||
|
{
|
||||||
|
if (iter->mItemPtr == stack.mBase)
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
visitedLines.insert(iter);
|
||||||
|
|
||||||
|
// update line widgets
|
||||||
|
updateLine(*iter);
|
||||||
|
lines.push_back(*iter);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
{
|
||||||
|
// add line widgets
|
||||||
|
Line line;
|
||||||
|
line.mItemPtr = stack.mBase;
|
||||||
|
|
||||||
|
line.mText = mScrollView->createWidget<MyGUI::TextBox>("SandText", MyGUI::IntCoord(), MyGUI::Align::Default);
|
||||||
|
line.mText->setNeedMouseFocus(false);
|
||||||
|
|
||||||
|
line.mIcon = mScrollView->createWidget<ItemWidget>("MW_ItemIconSmall", MyGUI::IntCoord(), MyGUI::Align::Default);
|
||||||
|
line.mIcon->setItem(line.mItemPtr);
|
||||||
|
line.mIcon->setUserString("ToolTipType", "ItemPtr");
|
||||||
|
line.mIcon->setUserData(line.mItemPtr);
|
||||||
|
line.mIcon->eventMouseButtonClick += MyGUI::newDelegate(this, &ItemChargeView::onIconClicked);
|
||||||
|
line.mIcon->eventMouseWheel += MyGUI::newDelegate(this, &ItemChargeView::onMouseWheelMoved);
|
||||||
|
|
||||||
|
line.mCharge = mScrollView->createWidget<Widgets::MWDynamicStat>("MW_ChargeBar", MyGUI::IntCoord(), MyGUI::Align::Default);
|
||||||
|
line.mCharge->setNeedMouseFocus(false);
|
||||||
|
|
||||||
|
updateLine(line);
|
||||||
|
|
||||||
|
lines.push_back(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Lines::iterator iter = mLines.begin(); iter != mLines.end(); ++iter)
|
||||||
|
{
|
||||||
|
if (visitedLines.count(iter))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// remove line widgets
|
||||||
|
MyGUI::Gui::getInstance().destroyWidget(iter->mText);
|
||||||
|
MyGUI::Gui::getInstance().destroyWidget(iter->mIcon);
|
||||||
|
MyGUI::Gui::getInstance().destroyWidget(iter->mCharge);
|
||||||
|
}
|
||||||
|
|
||||||
|
mLines.swap(lines);
|
||||||
|
|
||||||
|
layoutWidgets();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemChargeView::layoutWidgets()
|
||||||
|
{
|
||||||
|
int currentY = 0;
|
||||||
|
|
||||||
|
for (Lines::const_iterator iter = mLines.begin(); iter != mLines.end(); ++iter)
|
||||||
|
{
|
||||||
|
iter->mText->setCoord(8, currentY, mScrollView->getWidth()-8, 18);
|
||||||
|
currentY += 19;
|
||||||
|
|
||||||
|
iter->mIcon->setCoord(16, currentY, 32, 32);
|
||||||
|
iter->mCharge->setCoord(72, currentY+2, std::max(199, mScrollView->getWidth()-72-38), 20);
|
||||||
|
currentY += 32 + 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the scrollbar is hidden
|
||||||
|
mScrollView->setVisibleVScroll(false);
|
||||||
|
mScrollView->setCanvasSize(MyGUI::IntSize(mScrollView->getWidth(), std::max(mScrollView->getHeight(), currentY)));
|
||||||
|
mScrollView->setVisibleVScroll(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemChargeView::resetScrollbars()
|
||||||
|
{
|
||||||
|
mScrollView->setViewOffset(MyGUI::IntPoint(0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemChargeView::setSize(const MyGUI::IntSize& value)
|
||||||
|
{
|
||||||
|
bool changed = (value.width != getWidth() || value.height != getHeight());
|
||||||
|
Base::setSize(value);
|
||||||
|
if (changed)
|
||||||
|
layoutWidgets();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemChargeView::setCoord(const MyGUI::IntCoord& value)
|
||||||
|
{
|
||||||
|
bool changed = (value.width != getWidth() || value.height != getHeight());
|
||||||
|
Base::setCoord(value);
|
||||||
|
if (changed)
|
||||||
|
layoutWidgets();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemChargeView::updateLine(const ItemChargeView::Line& line)
|
||||||
|
{
|
||||||
|
line.mText->setCaption(line.mItemPtr.getClass().getName(line.mItemPtr));
|
||||||
|
|
||||||
|
line.mCharge->setVisible(false);
|
||||||
|
switch (mDisplayMode)
|
||||||
|
{
|
||||||
|
case DisplayMode_Health:
|
||||||
|
if (!line.mItemPtr.getClass().hasItemHealth(line.mItemPtr))
|
||||||
|
break;
|
||||||
|
|
||||||
|
line.mCharge->setVisible(true);
|
||||||
|
line.mCharge->setValue(line.mItemPtr.getClass().getItemHealth(line.mItemPtr),
|
||||||
|
line.mItemPtr.getClass().getItemMaxHealth(line.mItemPtr));
|
||||||
|
break;
|
||||||
|
case DisplayMode_EnchantmentCharge:
|
||||||
|
std::string enchId = line.mItemPtr.getClass().getEnchantment(line.mItemPtr);
|
||||||
|
if (enchId.empty())
|
||||||
|
break;
|
||||||
|
const ESM::Enchantment* ench = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().search(enchId);
|
||||||
|
if (!ench)
|
||||||
|
break;
|
||||||
|
|
||||||
|
line.mCharge->setVisible(true);
|
||||||
|
line.mCharge->setValue(static_cast<int>(line.mItemPtr.getCellRef().getEnchantmentCharge()),
|
||||||
|
ench->mData.mCharge);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemChargeView::onIconClicked(MyGUI::Widget* sender)
|
||||||
|
{
|
||||||
|
eventItemClicked(this, *sender->getUserData<MWWorld::Ptr>());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemChargeView::onMouseWheelMoved(MyGUI::Widget* /*sender*/, int rel)
|
||||||
|
{
|
||||||
|
if (mScrollView->getViewOffset().top + rel*0.3f > 0)
|
||||||
|
mScrollView->setViewOffset(MyGUI::IntPoint(0, 0));
|
||||||
|
else
|
||||||
|
mScrollView->setViewOffset(MyGUI::IntPoint(0, static_cast<int>(mScrollView->getViewOffset().top + rel*0.3f)));
|
||||||
|
}
|
||||||
|
}
|
78
apps/openmw/mwgui/itemchargeview.hpp
Normal file
78
apps/openmw/mwgui/itemchargeview.hpp
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
#ifndef MWGUI_ITEMCHARGEVIEW_H
|
||||||
|
#define MWGUI_ITEMCHARGEVIEW_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <MyGUI_Widget.h>
|
||||||
|
|
||||||
|
#include "../mwworld/ptr.hpp"
|
||||||
|
|
||||||
|
#include "widgets.hpp"
|
||||||
|
|
||||||
|
namespace MyGUI
|
||||||
|
{
|
||||||
|
class TextBox;
|
||||||
|
class ScrollView;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MWGui
|
||||||
|
{
|
||||||
|
class ItemModel;
|
||||||
|
class ItemWidget;
|
||||||
|
|
||||||
|
class ItemChargeView : public MyGUI::Widget
|
||||||
|
{
|
||||||
|
MYGUI_RTTI_DERIVED(ItemChargeView)
|
||||||
|
public:
|
||||||
|
enum DisplayMode
|
||||||
|
{
|
||||||
|
DisplayMode_Health,
|
||||||
|
DisplayMode_EnchantmentCharge
|
||||||
|
};
|
||||||
|
|
||||||
|
ItemChargeView();
|
||||||
|
|
||||||
|
/// Register needed components with MyGUI's factory manager
|
||||||
|
static void registerComponents();
|
||||||
|
|
||||||
|
virtual void initialiseOverride();
|
||||||
|
|
||||||
|
/// Takes ownership of \a model
|
||||||
|
void setModel(ItemModel* model);
|
||||||
|
|
||||||
|
void setDisplayMode(DisplayMode type);
|
||||||
|
|
||||||
|
void update();
|
||||||
|
void layoutWidgets();
|
||||||
|
void resetScrollbars();
|
||||||
|
|
||||||
|
virtual void setSize(const MyGUI::IntSize& value);
|
||||||
|
virtual void setCoord(const MyGUI::IntCoord& value);
|
||||||
|
|
||||||
|
MyGUI::delegates::CMultiDelegate2<MyGUI::Widget*, const MWWorld::Ptr&> eventItemClicked;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Line
|
||||||
|
{
|
||||||
|
MWWorld::Ptr mItemPtr;
|
||||||
|
MyGUI::TextBox* mText;
|
||||||
|
ItemWidget* mIcon;
|
||||||
|
Widgets::MWDynamicStatPtr mCharge;
|
||||||
|
};
|
||||||
|
|
||||||
|
void updateLine(const Line& line);
|
||||||
|
|
||||||
|
void onIconClicked(MyGUI::Widget* sender);
|
||||||
|
void onMouseWheelMoved(MyGUI::Widget* sender, int rel);
|
||||||
|
|
||||||
|
typedef std::vector<Line> Lines;
|
||||||
|
Lines mLines;
|
||||||
|
|
||||||
|
std::auto_ptr<ItemModel> mModel;
|
||||||
|
MyGUI::ScrollView* mScrollView;
|
||||||
|
DisplayMode mDisplayMode;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -101,6 +101,8 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
if (mFrame)
|
if (mFrame)
|
||||||
mFrame->setImageTexture("");
|
mFrame->setImageTexture("");
|
||||||
|
if (mItemShadow)
|
||||||
|
mItemShadow->setImageTexture("");
|
||||||
mItem->setImageTexture("");
|
mItem->setImageTexture("");
|
||||||
mText->setCaption("");
|
mText->setCaption("");
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
#include <MyGUI_ScrollView.h>
|
#include <MyGUI_ScrollView.h>
|
||||||
#include <MyGUI_Gui.h>
|
#include <MyGUI_Gui.h>
|
||||||
|
|
||||||
|
#include <components/widgets/box.hpp>
|
||||||
|
|
||||||
#include <components/misc/rng.hpp>
|
#include <components/misc/rng.hpp>
|
||||||
|
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
@ -21,6 +23,9 @@
|
||||||
|
|
||||||
#include "widgets.hpp"
|
#include "widgets.hpp"
|
||||||
#include "itemwidget.hpp"
|
#include "itemwidget.hpp"
|
||||||
|
#include "itemchargeview.hpp"
|
||||||
|
#include "sortfilteritemmodel.hpp"
|
||||||
|
#include "inventoryitemmodel.hpp"
|
||||||
|
|
||||||
namespace MWGui
|
namespace MWGui
|
||||||
{
|
{
|
||||||
|
@ -29,13 +34,15 @@ Recharge::Recharge()
|
||||||
: WindowBase("openmw_recharge_dialog.layout")
|
: WindowBase("openmw_recharge_dialog.layout")
|
||||||
{
|
{
|
||||||
getWidget(mBox, "Box");
|
getWidget(mBox, "Box");
|
||||||
getWidget(mView, "View");
|
|
||||||
getWidget(mGemBox, "GemBox");
|
getWidget(mGemBox, "GemBox");
|
||||||
getWidget(mGemIcon, "GemIcon");
|
getWidget(mGemIcon, "GemIcon");
|
||||||
getWidget(mChargeLabel, "ChargeLabel");
|
getWidget(mChargeLabel, "ChargeLabel");
|
||||||
getWidget(mCancelButton, "CancelButton");
|
getWidget(mCancelButton, "CancelButton");
|
||||||
|
|
||||||
mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &Recharge::onCancel);
|
mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &Recharge::onCancel);
|
||||||
|
mBox->eventItemClicked += MyGUI::newDelegate(this, &Recharge::onItemClicked);
|
||||||
|
|
||||||
|
mBox->setDisplayMode(ItemChargeView::DisplayMode_EnchantmentCharge);
|
||||||
|
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
}
|
}
|
||||||
|
@ -43,8 +50,13 @@ Recharge::Recharge()
|
||||||
void Recharge::open()
|
void Recharge::open()
|
||||||
{
|
{
|
||||||
center();
|
center();
|
||||||
|
|
||||||
|
SortFilterItemModel * model = new SortFilterItemModel(new InventoryItemModel(MWMechanics::getPlayer()));
|
||||||
|
model->setFilter(SortFilterItemModel::Filter_OnlyRechargable);
|
||||||
|
mBox->setModel(model);
|
||||||
|
|
||||||
// Reset scrollbars
|
// Reset scrollbars
|
||||||
mView->setViewOffset(MyGUI::IntPoint(0, 0));
|
mBox->resetScrollbars();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Recharge::exit()
|
void Recharge::exit()
|
||||||
|
@ -72,66 +84,16 @@ void Recharge::updateView()
|
||||||
|
|
||||||
bool toolBoxVisible = (gem.getRefData().getCount() != 0);
|
bool toolBoxVisible = (gem.getRefData().getCount() != 0);
|
||||||
mGemBox->setVisible(toolBoxVisible);
|
mGemBox->setVisible(toolBoxVisible);
|
||||||
|
mGemBox->setUserString("Hidden", toolBoxVisible ? "false" : "true");
|
||||||
|
|
||||||
bool toolBoxWasVisible = (mBox->getPosition().top != mGemBox->getPosition().top);
|
mBox->update();
|
||||||
|
|
||||||
if (toolBoxVisible && !toolBoxWasVisible)
|
Gui::Box* box = dynamic_cast<Gui::Box*>(mMainWidget);
|
||||||
{
|
if (box == NULL)
|
||||||
// shrink
|
throw std::runtime_error("main widget must be a box");
|
||||||
mBox->setPosition(mBox->getPosition() + MyGUI::IntPoint(0, mGemBox->getSize().height));
|
|
||||||
mBox->setSize(mBox->getSize() - MyGUI::IntSize(0,mGemBox->getSize().height));
|
|
||||||
}
|
|
||||||
else if (!toolBoxVisible && toolBoxWasVisible)
|
|
||||||
{
|
|
||||||
// expand
|
|
||||||
mBox->setPosition(MyGUI::IntPoint (mBox->getPosition().left, mGemBox->getPosition().top));
|
|
||||||
mBox->setSize(mBox->getSize() + MyGUI::IntSize(0,mGemBox->getSize().height));
|
|
||||||
}
|
|
||||||
|
|
||||||
while (mView->getChildCount())
|
box->notifyChildrenSizeChanged();
|
||||||
MyGUI::Gui::getInstance().destroyWidget(mView->getChildAt(0));
|
center();
|
||||||
|
|
||||||
int currentY = 0;
|
|
||||||
|
|
||||||
MWWorld::Ptr player = MWMechanics::getPlayer();
|
|
||||||
MWWorld::ContainerStore& store = player.getClass().getContainerStore(player);
|
|
||||||
for (MWWorld::ContainerStoreIterator iter (store.begin());
|
|
||||||
iter!=store.end(); ++iter)
|
|
||||||
{
|
|
||||||
std::string enchantmentName = iter->getClass().getEnchantment(*iter);
|
|
||||||
if (enchantmentName.empty())
|
|
||||||
continue;
|
|
||||||
const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().find(enchantmentName);
|
|
||||||
if (iter->getCellRef().getEnchantmentCharge() >= enchantment->mData.mCharge
|
|
||||||
|| iter->getCellRef().getEnchantmentCharge() == -1)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
MyGUI::TextBox* text = mView->createWidget<MyGUI::TextBox> (
|
|
||||||
"SandText", MyGUI::IntCoord(8, currentY, mView->getWidth()-8, 18), MyGUI::Align::Default);
|
|
||||||
text->setCaption(iter->getClass().getName(*iter));
|
|
||||||
text->setNeedMouseFocus(false);
|
|
||||||
currentY += 19;
|
|
||||||
|
|
||||||
ItemWidget* icon = mView->createWidget<ItemWidget> (
|
|
||||||
"MW_ItemIconSmall", MyGUI::IntCoord(16, currentY, 32, 32), MyGUI::Align::Default);
|
|
||||||
icon->setItem(*iter);
|
|
||||||
icon->setUserString("ToolTipType", "ItemPtr");
|
|
||||||
icon->setUserData(*iter);
|
|
||||||
icon->eventMouseButtonClick += MyGUI::newDelegate(this, &Recharge::onItemClicked);
|
|
||||||
icon->eventMouseWheel += MyGUI::newDelegate(this, &Recharge::onMouseWheel);
|
|
||||||
|
|
||||||
Widgets::MWDynamicStatPtr chargeWidget = mView->createWidget<Widgets::MWDynamicStat>
|
|
||||||
("MW_ChargeBar", MyGUI::IntCoord(72, currentY+2, 199, 20), MyGUI::Align::Default);
|
|
||||||
chargeWidget->setValue(static_cast<int>(iter->getCellRef().getEnchantmentCharge()), enchantment->mData.mCharge);
|
|
||||||
chargeWidget->setNeedMouseFocus(false);
|
|
||||||
|
|
||||||
currentY += 32 + 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the scrollbar is hidden
|
|
||||||
mView->setVisibleVScroll(false);
|
|
||||||
mView->setCanvasSize (MyGUI::IntSize(mView->getWidth(), std::max(mView->getHeight(), currentY)));
|
|
||||||
mView->setVisibleVScroll(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Recharge::onCancel(MyGUI::Widget *sender)
|
void Recharge::onCancel(MyGUI::Widget *sender)
|
||||||
|
@ -139,15 +101,13 @@ void Recharge::onCancel(MyGUI::Widget *sender)
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Recharge::onItemClicked(MyGUI::Widget *sender)
|
void Recharge::onItemClicked(MyGUI::Widget *sender, const MWWorld::Ptr& item)
|
||||||
{
|
{
|
||||||
MWWorld::Ptr gem = *mGemIcon->getUserData<MWWorld::Ptr>();
|
MWWorld::Ptr gem = *mGemIcon->getUserData<MWWorld::Ptr>();
|
||||||
|
|
||||||
if (!gem.getRefData().getCount())
|
if (!gem.getRefData().getCount())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
MWWorld::Ptr item = *sender->getUserData<MWWorld::Ptr>();
|
|
||||||
|
|
||||||
MWWorld::Ptr player = MWMechanics::getPlayer();
|
MWWorld::Ptr player = MWMechanics::getPlayer();
|
||||||
MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player);
|
MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player);
|
||||||
MWMechanics::NpcStats& npcStats = player.getClass().getNpcStats(player);
|
MWMechanics::NpcStats& npcStats = player.getClass().getNpcStats(player);
|
||||||
|
@ -198,12 +158,4 @@ void Recharge::onItemClicked(MyGUI::Widget *sender)
|
||||||
updateView();
|
updateView();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Recharge::onMouseWheel(MyGUI::Widget* _sender, int _rel)
|
|
||||||
{
|
|
||||||
if (mView->getViewOffset().top + _rel*0.3f > 0)
|
|
||||||
mView->setViewOffset(MyGUI::IntPoint(0, 0));
|
|
||||||
else
|
|
||||||
mView->setViewOffset(MyGUI::IntPoint(0, static_cast<int>(mView->getViewOffset().top + _rel*0.3f)));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
|
|
||||||
class ItemWidget;
|
class ItemWidget;
|
||||||
|
class ItemChargeView;
|
||||||
|
|
||||||
class Recharge : public WindowBase
|
class Recharge : public WindowBase
|
||||||
{
|
{
|
||||||
|
@ -25,8 +26,7 @@ public:
|
||||||
void start (const MWWorld::Ptr& gem);
|
void start (const MWWorld::Ptr& gem);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
MyGUI::Widget* mBox;
|
ItemChargeView* mBox;
|
||||||
MyGUI::ScrollView* mView;
|
|
||||||
|
|
||||||
MyGUI::Widget* mGemBox;
|
MyGUI::Widget* mGemBox;
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ protected:
|
||||||
|
|
||||||
void updateView();
|
void updateView();
|
||||||
|
|
||||||
void onItemClicked (MyGUI::Widget* sender);
|
void onItemClicked (MyGUI::Widget* sender, const MWWorld::Ptr& item);
|
||||||
void onCancel (MyGUI::Widget* sender);
|
void onCancel (MyGUI::Widget* sender);
|
||||||
void onMouseWheel(MyGUI::Widget* _sender, int _rel);
|
void onMouseWheel(MyGUI::Widget* _sender, int _rel);
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,9 @@
|
||||||
|
|
||||||
#include <MyGUI_ScrollView.h>
|
#include <MyGUI_ScrollView.h>
|
||||||
#include <MyGUI_Gui.h>
|
#include <MyGUI_Gui.h>
|
||||||
|
#include <MyGUI_ItemBox.h>
|
||||||
|
|
||||||
|
#include <components/widgets/box.hpp>
|
||||||
|
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
|
@ -17,6 +20,9 @@
|
||||||
#include "widgets.hpp"
|
#include "widgets.hpp"
|
||||||
|
|
||||||
#include "itemwidget.hpp"
|
#include "itemwidget.hpp"
|
||||||
|
#include "itemchargeview.hpp"
|
||||||
|
#include "sortfilteritemmodel.hpp"
|
||||||
|
#include "inventoryitemmodel.hpp"
|
||||||
|
|
||||||
namespace MWGui
|
namespace MWGui
|
||||||
{
|
{
|
||||||
|
@ -25,7 +31,6 @@ Repair::Repair()
|
||||||
: WindowBase("openmw_repair.layout")
|
: WindowBase("openmw_repair.layout")
|
||||||
{
|
{
|
||||||
getWidget(mRepairBox, "RepairBox");
|
getWidget(mRepairBox, "RepairBox");
|
||||||
getWidget(mRepairView, "RepairView");
|
|
||||||
getWidget(mToolBox, "ToolBox");
|
getWidget(mToolBox, "ToolBox");
|
||||||
getWidget(mToolIcon, "ToolIcon");
|
getWidget(mToolIcon, "ToolIcon");
|
||||||
getWidget(mUsesLabel, "UsesLabel");
|
getWidget(mUsesLabel, "UsesLabel");
|
||||||
|
@ -33,13 +38,21 @@ Repair::Repair()
|
||||||
getWidget(mCancelButton, "CancelButton");
|
getWidget(mCancelButton, "CancelButton");
|
||||||
|
|
||||||
mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &Repair::onCancel);
|
mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &Repair::onCancel);
|
||||||
|
mRepairBox->eventItemClicked += MyGUI::newDelegate(this, &Repair::onRepairItem);
|
||||||
|
|
||||||
|
mRepairBox->setDisplayMode(ItemChargeView::DisplayMode_Health);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Repair::open()
|
void Repair::open()
|
||||||
{
|
{
|
||||||
center();
|
center();
|
||||||
|
|
||||||
|
SortFilterItemModel * model = new SortFilterItemModel(new InventoryItemModel(MWMechanics::getPlayer()));
|
||||||
|
model->setFilter(SortFilterItemModel::Filter_OnlyRepairable);
|
||||||
|
mRepairBox->setModel(model);
|
||||||
|
|
||||||
// Reset scrollbars
|
// Reset scrollbars
|
||||||
mRepairView->setViewOffset(MyGUI::IntPoint(0, 0));
|
mRepairBox->resetScrollbars();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Repair::exit()
|
void Repair::exit()
|
||||||
|
@ -75,89 +88,31 @@ void Repair::updateRepairView()
|
||||||
|
|
||||||
bool toolBoxVisible = (mRepair.getTool().getRefData().getCount() != 0);
|
bool toolBoxVisible = (mRepair.getTool().getRefData().getCount() != 0);
|
||||||
mToolBox->setVisible(toolBoxVisible);
|
mToolBox->setVisible(toolBoxVisible);
|
||||||
|
mToolBox->setUserString("Hidden", toolBoxVisible ? "false" : "true");
|
||||||
|
|
||||||
bool toolBoxWasVisible = (mRepairBox->getPosition().top != mToolBox->getPosition().top);
|
mRepairBox->update();
|
||||||
|
|
||||||
if (toolBoxVisible && !toolBoxWasVisible)
|
Gui::Box* box = dynamic_cast<Gui::Box*>(mMainWidget);
|
||||||
{
|
if (box == NULL)
|
||||||
// shrink
|
throw std::runtime_error("main widget must be a box");
|
||||||
mRepairBox->setPosition(mRepairBox->getPosition() + MyGUI::IntPoint(0,mToolBox->getSize().height));
|
|
||||||
mRepairBox->setSize(mRepairBox->getSize() - MyGUI::IntSize(0,mToolBox->getSize().height));
|
|
||||||
}
|
|
||||||
else if (!toolBoxVisible && toolBoxWasVisible)
|
|
||||||
{
|
|
||||||
// expand
|
|
||||||
mRepairBox->setPosition(MyGUI::IntPoint (mRepairBox->getPosition().left, mToolBox->getPosition().top));
|
|
||||||
mRepairBox->setSize(mRepairBox->getSize() + MyGUI::IntSize(0,mToolBox->getSize().height));
|
|
||||||
}
|
|
||||||
|
|
||||||
while (mRepairView->getChildCount())
|
box->notifyChildrenSizeChanged();
|
||||||
MyGUI::Gui::getInstance().destroyWidget(mRepairView->getChildAt(0));
|
center();
|
||||||
|
|
||||||
int currentY = 0;
|
|
||||||
|
|
||||||
MWWorld::Ptr player = MWMechanics::getPlayer();
|
|
||||||
MWWorld::ContainerStore& store = player.getClass().getContainerStore(player);
|
|
||||||
int categories = MWWorld::ContainerStore::Type_Weapon | MWWorld::ContainerStore::Type_Armor;
|
|
||||||
for (MWWorld::ContainerStoreIterator iter (store.begin(categories));
|
|
||||||
iter!=store.end(); ++iter)
|
|
||||||
{
|
|
||||||
if (iter->getClass().hasItemHealth(*iter))
|
|
||||||
{
|
|
||||||
int maxDurability = iter->getClass().getItemMaxHealth(*iter);
|
|
||||||
int durability = iter->getClass().getItemHealth(*iter);
|
|
||||||
if (maxDurability == durability)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
MyGUI::TextBox* text = mRepairView->createWidget<MyGUI::TextBox> (
|
|
||||||
"SandText", MyGUI::IntCoord(8, currentY, mRepairView->getWidth()-8, 18), MyGUI::Align::Default);
|
|
||||||
text->setCaption(iter->getClass().getName(*iter));
|
|
||||||
text->setNeedMouseFocus(false);
|
|
||||||
currentY += 19;
|
|
||||||
|
|
||||||
ItemWidget* icon = mRepairView->createWidget<ItemWidget> (
|
|
||||||
"MW_ItemIconSmall", MyGUI::IntCoord(16, currentY, 32, 32), MyGUI::Align::Default);
|
|
||||||
icon->setItem(*iter);
|
|
||||||
icon->setUserString("ToolTipType", "ItemPtr");
|
|
||||||
icon->setUserData(*iter);
|
|
||||||
icon->eventMouseButtonClick += MyGUI::newDelegate(this, &Repair::onRepairItem);
|
|
||||||
icon->eventMouseWheel += MyGUI::newDelegate(this, &Repair::onMouseWheel);
|
|
||||||
|
|
||||||
Widgets::MWDynamicStatPtr chargeWidget = mRepairView->createWidget<Widgets::MWDynamicStat>
|
|
||||||
("MW_ChargeBar", MyGUI::IntCoord(72, currentY+2, 199, 20), MyGUI::Align::Default);
|
|
||||||
chargeWidget->setValue(durability, maxDurability);
|
|
||||||
chargeWidget->setNeedMouseFocus(false);
|
|
||||||
|
|
||||||
currentY += 32 + 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the scrollbar is hidden
|
|
||||||
mRepairView->setVisibleVScroll(false);
|
|
||||||
mRepairView->setCanvasSize (MyGUI::IntSize(mRepairView->getWidth(), std::max(mRepairView->getHeight(), currentY)));
|
|
||||||
mRepairView->setVisibleVScroll(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Repair::onCancel(MyGUI::Widget *sender)
|
void Repair::onCancel(MyGUI::Widget* /*sender*/)
|
||||||
{
|
{
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Repair::onRepairItem(MyGUI::Widget *sender)
|
void Repair::onRepairItem(MyGUI::Widget* /*sender*/, const MWWorld::Ptr& ptr)
|
||||||
{
|
{
|
||||||
if (!mRepair.getTool().getRefData().getCount())
|
if (!mRepair.getTool().getRefData().getCount())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mRepair.repair(*sender->getUserData<MWWorld::Ptr>());
|
mRepair.repair(ptr);
|
||||||
|
|
||||||
updateRepairView();
|
updateRepairView();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Repair::onMouseWheel(MyGUI::Widget* _sender, int _rel)
|
|
||||||
{
|
|
||||||
if (mRepairView->getViewOffset().top + _rel*0.3f > 0)
|
|
||||||
mRepairView->setViewOffset(MyGUI::IntPoint(0, 0));
|
|
||||||
else
|
|
||||||
mRepairView->setViewOffset(MyGUI::IntPoint(0, static_cast<int>(mRepairView->getViewOffset().top + _rel*0.3f)));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
|
|
||||||
class ItemWidget;
|
class ItemWidget;
|
||||||
|
class ItemChargeView;
|
||||||
|
|
||||||
class Repair : public WindowBase
|
class Repair : public WindowBase
|
||||||
{
|
{
|
||||||
|
@ -22,8 +23,7 @@ public:
|
||||||
void startRepairItem (const MWWorld::Ptr& item);
|
void startRepairItem (const MWWorld::Ptr& item);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
MyGUI::Widget* mRepairBox;
|
ItemChargeView* mRepairBox;
|
||||||
MyGUI::ScrollView* mRepairView;
|
|
||||||
|
|
||||||
MyGUI::Widget* mToolBox;
|
MyGUI::Widget* mToolBox;
|
||||||
|
|
||||||
|
@ -38,9 +38,8 @@ protected:
|
||||||
|
|
||||||
void updateRepairView();
|
void updateRepairView();
|
||||||
|
|
||||||
void onRepairItem (MyGUI::Widget* sender);
|
void onRepairItem(MyGUI::Widget* sender, const MWWorld::Ptr& ptr);
|
||||||
void onCancel (MyGUI::Widget* sender);
|
void onCancel(MyGUI::Widget* sender);
|
||||||
void onMouseWheel(MyGUI::Widget* _sender, int _rel);
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
#include "../mwworld/esmstore.hpp"
|
#include "../mwworld/esmstore.hpp"
|
||||||
|
#include "../mwmechanics/autocalcspell.hpp"
|
||||||
|
|
||||||
#include "tooltips.hpp"
|
#include "tooltips.hpp"
|
||||||
|
|
||||||
|
@ -29,7 +30,8 @@ namespace MWGui
|
||||||
const int ReviewDialog::sLineHeight = 18;
|
const int ReviewDialog::sLineHeight = 18;
|
||||||
|
|
||||||
ReviewDialog::ReviewDialog()
|
ReviewDialog::ReviewDialog()
|
||||||
: WindowModal("openmw_chargen_review.layout")
|
: WindowModal("openmw_chargen_review.layout"),
|
||||||
|
mUpdateSkillArea(false)
|
||||||
{
|
{
|
||||||
// Centre dialog
|
// Centre dialog
|
||||||
center();
|
center();
|
||||||
|
@ -102,7 +104,16 @@ namespace MWGui
|
||||||
void ReviewDialog::open()
|
void ReviewDialog::open()
|
||||||
{
|
{
|
||||||
WindowModal::open();
|
WindowModal::open();
|
||||||
updateSkillArea();
|
mUpdateSkillArea = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReviewDialog::onFrame(float /*duration*/)
|
||||||
|
{
|
||||||
|
if (mUpdateSkillArea)
|
||||||
|
{
|
||||||
|
updateSkillArea();
|
||||||
|
mUpdateSkillArea = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReviewDialog::setPlayerName(const std::string &name)
|
void ReviewDialog::setPlayerName(const std::string &name)
|
||||||
|
@ -121,6 +132,8 @@ namespace MWGui
|
||||||
ToolTips::createRaceToolTip(mRaceWidget, race);
|
ToolTips::createRaceToolTip(mRaceWidget, race);
|
||||||
mRaceWidget->setCaption(race->mName);
|
mRaceWidget->setCaption(race->mName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mUpdateSkillArea = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReviewDialog::setClass(const ESM::Class& class_)
|
void ReviewDialog::setClass(const ESM::Class& class_)
|
||||||
|
@ -141,6 +154,8 @@ namespace MWGui
|
||||||
mBirthSignWidget->setCaption(sign->mName);
|
mBirthSignWidget->setCaption(sign->mName);
|
||||||
ToolTips::createBirthsignToolTip(mBirthSignWidget, mBirthSignId);
|
ToolTips::createBirthsignToolTip(mBirthSignWidget, mBirthSignId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mUpdateSkillArea = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReviewDialog::setHealth(const MWMechanics::DynamicStat<float>& value)
|
void ReviewDialog::setHealth(const MWMechanics::DynamicStat<float>& value)
|
||||||
|
@ -170,7 +185,11 @@ namespace MWGui
|
||||||
if (attr == mAttributeWidgets.end())
|
if (attr == mAttributeWidgets.end())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
attr->second->setAttributeValue(value);
|
if (attr->second->getAttributeValue() != value)
|
||||||
|
{
|
||||||
|
attr->second->setAttributeValue(value);
|
||||||
|
mUpdateSkillArea = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReviewDialog::setSkillValue(ESM::Skill::SkillEnum skillId, const MWMechanics::SkillValue& value)
|
void ReviewDialog::setSkillValue(ESM::Skill::SkillEnum skillId, const MWMechanics::SkillValue& value)
|
||||||
|
@ -191,6 +210,7 @@ namespace MWGui
|
||||||
widget->_setWidgetState(state);
|
widget->_setWidgetState(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mUpdateSkillArea = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReviewDialog::configureSkills(const std::vector<int>& major, const std::vector<int>& minor)
|
void ReviewDialog::configureSkills(const std::vector<int>& major, const std::vector<int>& minor)
|
||||||
|
@ -211,7 +231,7 @@ namespace MWGui
|
||||||
mMiscSkills.push_back(skill);
|
mMiscSkills.push_back(skill);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateSkillArea();
|
mUpdateSkillArea = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReviewDialog::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2)
|
void ReviewDialog::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2)
|
||||||
|
@ -245,7 +265,7 @@ namespace MWGui
|
||||||
skillNameWidget->setCaption(text);
|
skillNameWidget->setCaption(text);
|
||||||
skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel);
|
skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel);
|
||||||
|
|
||||||
skillValueWidget = mSkillView->createWidget<MyGUI::TextBox>("SandTextRight", coord2, MyGUI::Align::Top | MyGUI::Align::Right);
|
skillValueWidget = mSkillView->createWidget<MyGUI::TextBox>("SandTextRight", coord2, MyGUI::Align::Default);
|
||||||
skillValueWidget->setCaption(value);
|
skillValueWidget->setCaption(value);
|
||||||
skillValueWidget->_setWidgetState(state);
|
skillValueWidget->_setWidgetState(state);
|
||||||
skillValueWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel);
|
skillValueWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel);
|
||||||
|
@ -273,6 +293,20 @@ namespace MWGui
|
||||||
coord2.top += sLineHeight;
|
coord2.top += sLineHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ReviewDialog::addItem(const ESM::Spell* spell, MyGUI::IntCoord& coord1, MyGUI::IntCoord& coord2)
|
||||||
|
{
|
||||||
|
Widgets::MWSpellPtr widget = mSkillView->createWidget<Widgets::MWSpell>("MW_StatName", coord1 + MyGUI::IntSize(coord2.width, 0), MyGUI::Align::Default);
|
||||||
|
widget->setSpellId(spell->mId);
|
||||||
|
widget->setUserString("ToolTipType", "Spell");
|
||||||
|
widget->setUserString("Spell", spell->mId);
|
||||||
|
widget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel);
|
||||||
|
|
||||||
|
mSkillWidgets.push_back(widget);
|
||||||
|
|
||||||
|
coord1.top += sLineHeight;
|
||||||
|
coord2.top += sLineHeight;
|
||||||
|
}
|
||||||
|
|
||||||
void ReviewDialog::addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2)
|
void ReviewDialog::addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2)
|
||||||
{
|
{
|
||||||
// Add a line separator if there are items above
|
// Add a line separator if there are items above
|
||||||
|
@ -332,6 +366,80 @@ namespace MWGui
|
||||||
if (!mMiscSkills.empty())
|
if (!mMiscSkills.empty())
|
||||||
addSkills(mMiscSkills, "sSkillClassMisc", "Misc Skills", coord1, coord2);
|
addSkills(mMiscSkills, "sSkillClassMisc", "Misc Skills", coord1, coord2);
|
||||||
|
|
||||||
|
// starting spells
|
||||||
|
std::vector<std::string> spells;
|
||||||
|
|
||||||
|
const ESM::Race* race = NULL;
|
||||||
|
if (!mRaceId.empty())
|
||||||
|
race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(mRaceId);
|
||||||
|
|
||||||
|
int skills[ESM::Skill::Length];
|
||||||
|
for (int i=0; i<ESM::Skill::Length; ++i)
|
||||||
|
skills[i] = mSkillValues.find(i)->second.getBase();
|
||||||
|
|
||||||
|
int attributes[ESM::Attribute::Length];
|
||||||
|
for (int i=0; i<ESM::Attribute::Length; ++i)
|
||||||
|
attributes[i] = mAttributeWidgets[i]->getAttributeValue().getBase();
|
||||||
|
|
||||||
|
std::vector<std::string> selectedSpells = MWMechanics::autoCalcPlayerSpells(skills, attributes, race);
|
||||||
|
for (std::vector<std::string>::iterator iter = selectedSpells.begin(); iter != selectedSpells.end(); ++iter)
|
||||||
|
{
|
||||||
|
std::string lower = Misc::StringUtils::lowerCase(*iter);
|
||||||
|
if (std::find(spells.begin(), spells.end(), lower) == spells.end())
|
||||||
|
spells.push_back(lower);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (race)
|
||||||
|
{
|
||||||
|
for (std::vector<std::string>::const_iterator iter = race->mPowers.mList.begin();
|
||||||
|
iter != race->mPowers.mList.end(); ++iter)
|
||||||
|
{
|
||||||
|
std::string lower = Misc::StringUtils::lowerCase(*iter);
|
||||||
|
if (std::find(spells.begin(), spells.end(), lower) == spells.end())
|
||||||
|
spells.push_back(lower);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mBirthSignId.empty())
|
||||||
|
{
|
||||||
|
const ESM::BirthSign* sign = MWBase::Environment::get().getWorld()->getStore().get<ESM::BirthSign>().find(mBirthSignId);
|
||||||
|
for (std::vector<std::string>::const_iterator iter = sign->mPowers.mList.begin();
|
||||||
|
iter != sign->mPowers.mList.end(); ++iter)
|
||||||
|
{
|
||||||
|
std::string lower = Misc::StringUtils::lowerCase(*iter);
|
||||||
|
if (std::find(spells.begin(), spells.end(), lower) == spells.end())
|
||||||
|
spells.push_back(lower);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mSkillWidgets.empty())
|
||||||
|
addSeparator(coord1, coord2);
|
||||||
|
addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString("sTypeAbility", "Abilities"), coord1, coord2);
|
||||||
|
for (std::vector<std::string>::const_iterator iter = spells.begin(); iter != spells.end(); ++iter)
|
||||||
|
{
|
||||||
|
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(*iter);
|
||||||
|
if (spell->mData.mType == ESM::Spell::ST_Ability)
|
||||||
|
addItem(spell, coord1, coord2);
|
||||||
|
}
|
||||||
|
|
||||||
|
addSeparator(coord1, coord2);
|
||||||
|
addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString("sTypePower", "Powers"), coord1, coord2);
|
||||||
|
for (std::vector<std::string>::const_iterator iter = spells.begin(); iter != spells.end(); ++iter)
|
||||||
|
{
|
||||||
|
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(*iter);
|
||||||
|
if (spell->mData.mType == ESM::Spell::ST_Power)
|
||||||
|
addItem(spell, coord1, coord2);
|
||||||
|
}
|
||||||
|
|
||||||
|
addSeparator(coord1, coord2);
|
||||||
|
addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString("sTypeSpell", "Spells"), coord1, coord2);
|
||||||
|
for (std::vector<std::string>::const_iterator iter = spells.begin(); iter != spells.end(); ++iter)
|
||||||
|
{
|
||||||
|
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(*iter);
|
||||||
|
if (spell->mData.mType == ESM::Spell::ST_Spell)
|
||||||
|
addItem(spell, coord1, coord2);
|
||||||
|
}
|
||||||
|
|
||||||
// Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the scrollbar is hidden
|
// Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the scrollbar is hidden
|
||||||
mSkillView->setVisibleVScroll(false);
|
mSkillView->setVisibleVScroll(false);
|
||||||
mSkillView->setCanvasSize (mSkillView->getWidth(), std::max(mSkillView->getHeight(), coord1.top));
|
mSkillView->setCanvasSize (mSkillView->getWidth(), std::max(mSkillView->getHeight(), coord1.top));
|
||||||
|
|
|
@ -6,6 +6,11 @@
|
||||||
#include "windowbase.hpp"
|
#include "windowbase.hpp"
|
||||||
#include "widgets.hpp"
|
#include "widgets.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
struct Spell;
|
||||||
|
}
|
||||||
|
|
||||||
namespace MWGui
|
namespace MWGui
|
||||||
{
|
{
|
||||||
class WindowManager;
|
class WindowManager;
|
||||||
|
@ -42,6 +47,8 @@ namespace MWGui
|
||||||
|
|
||||||
virtual void open();
|
virtual void open();
|
||||||
|
|
||||||
|
void onFrame(float duration);
|
||||||
|
|
||||||
// Events
|
// Events
|
||||||
typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void;
|
typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void;
|
||||||
typedef MyGUI::delegates::CMultiDelegate1<int> EventHandle_Int;
|
typedef MyGUI::delegates::CMultiDelegate1<int> EventHandle_Int;
|
||||||
|
@ -75,6 +82,7 @@ namespace MWGui
|
||||||
void addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
|
void addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
|
||||||
MyGUI::TextBox* addValueItem(const std::string& text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
|
MyGUI::TextBox* addValueItem(const std::string& text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
|
||||||
void addItem(const std::string& text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
|
void addItem(const std::string& text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
|
||||||
|
void addItem(const ESM::Spell* spell, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
|
||||||
void updateSkillArea();
|
void updateSkillArea();
|
||||||
|
|
||||||
static const int sLineHeight;
|
static const int sLineHeight;
|
||||||
|
@ -92,6 +100,8 @@ namespace MWGui
|
||||||
std::string mName, mRaceId, mBirthSignId;
|
std::string mName, mRaceId, mBirthSignId;
|
||||||
ESM::Class mKlass;
|
ESM::Class mKlass;
|
||||||
std::vector<MyGUI::Widget*> mSkillWidgets; //< Skills and other information
|
std::vector<MyGUI::Widget*> mSkillWidgets; //< Skills and other information
|
||||||
|
|
||||||
|
bool mUpdateSkillArea;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -466,9 +466,6 @@ namespace MWGui
|
||||||
else
|
else
|
||||||
actions = MWBase::Environment::get().getInputManager()->getActionControllerSorting();
|
actions = MWBase::Environment::get().getInputManager()->getActionControllerSorting();
|
||||||
|
|
||||||
const int h = 18;
|
|
||||||
const int w = mControlsBox->getWidth() - 28;
|
|
||||||
int curH = 0;
|
|
||||||
for (std::vector<int>::const_iterator it = actions.begin(); it != actions.end(); ++it)
|
for (std::vector<int>::const_iterator it = actions.begin(); it != actions.end(); ++it)
|
||||||
{
|
{
|
||||||
std::string desc = MWBase::Environment::get().getInputManager()->getActionDescription (*it);
|
std::string desc = MWBase::Environment::get().getInputManager()->getActionDescription (*it);
|
||||||
|
@ -481,16 +478,15 @@ namespace MWGui
|
||||||
else
|
else
|
||||||
binding = MWBase::Environment::get().getInputManager()->getActionControllerBindingName(*it);
|
binding = MWBase::Environment::get().getInputManager()->getActionControllerBindingName(*it);
|
||||||
|
|
||||||
Gui::SharedStateButton* leftText = mControlsBox->createWidget<Gui::SharedStateButton>("SandTextButton", MyGUI::IntCoord(0,curH,w,h), MyGUI::Align::Default);
|
Gui::SharedStateButton* leftText = mControlsBox->createWidget<Gui::SharedStateButton>("SandTextButton", MyGUI::IntCoord(), MyGUI::Align::Default);
|
||||||
leftText->setCaptionWithReplacing(desc);
|
leftText->setCaptionWithReplacing(desc);
|
||||||
|
|
||||||
Gui::SharedStateButton* rightText = mControlsBox->createWidget<Gui::SharedStateButton>("SandTextButton", MyGUI::IntCoord(0,curH,w,h), MyGUI::Align::Default);
|
Gui::SharedStateButton* rightText = mControlsBox->createWidget<Gui::SharedStateButton>("SandTextButton", MyGUI::IntCoord(), MyGUI::Align::Default);
|
||||||
rightText->setCaptionWithReplacing(binding);
|
rightText->setCaptionWithReplacing(binding);
|
||||||
rightText->setTextAlign (MyGUI::Align::Right);
|
rightText->setTextAlign (MyGUI::Align::Right);
|
||||||
rightText->setUserData(*it); // save the action id for callbacks
|
rightText->setUserData(*it); // save the action id for callbacks
|
||||||
rightText->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onRebindAction);
|
rightText->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onRebindAction);
|
||||||
rightText->eventMouseWheel += MyGUI::newDelegate(this, &SettingsWindow::onInputTabMouseWheel);
|
rightText->eventMouseWheel += MyGUI::newDelegate(this, &SettingsWindow::onInputTabMouseWheel);
|
||||||
curH += h;
|
|
||||||
|
|
||||||
Gui::ButtonGroup group;
|
Gui::ButtonGroup group;
|
||||||
group.push_back(leftText);
|
group.push_back(leftText);
|
||||||
|
@ -498,9 +494,25 @@ namespace MWGui
|
||||||
Gui::SharedStateButton::createButtonGroup(group);
|
Gui::SharedStateButton::createButtonGroup(group);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
layoutControlsBox();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SettingsWindow::layoutControlsBox()
|
||||||
|
{
|
||||||
|
const int h = 18;
|
||||||
|
const int w = mControlsBox->getWidth() - 28;
|
||||||
|
const int noWidgetsInRow = 2;
|
||||||
|
const int totalH = mControlsBox->getChildCount() / noWidgetsInRow * h;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < mControlsBox->getChildCount(); i++)
|
||||||
|
{
|
||||||
|
MyGUI::Widget * widget = mControlsBox->getChildAt(i);
|
||||||
|
widget->setCoord(0, i / noWidgetsInRow * h, w, h);
|
||||||
|
}
|
||||||
|
|
||||||
// Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the scrollbar is hidden
|
// Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the scrollbar is hidden
|
||||||
mControlsBox->setVisibleVScroll(false);
|
mControlsBox->setVisibleVScroll(false);
|
||||||
mControlsBox->setCanvasSize (mControlsBox->getWidth(), std::max(curH, mControlsBox->getHeight()));
|
mControlsBox->setCanvasSize (mControlsBox->getWidth(), std::max(totalH, mControlsBox->getHeight()));
|
||||||
mControlsBox->setVisibleVScroll(true);
|
mControlsBox->setVisibleVScroll(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -556,7 +568,7 @@ namespace MWGui
|
||||||
|
|
||||||
void SettingsWindow::onWindowResize(MyGUI::Window *_sender)
|
void SettingsWindow::onWindowResize(MyGUI::Window *_sender)
|
||||||
{
|
{
|
||||||
updateControlsBox();
|
layoutControlsBox();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SettingsWindow::resetScrollbars()
|
void SettingsWindow::resetScrollbars()
|
||||||
|
|
|
@ -66,6 +66,8 @@ namespace MWGui
|
||||||
|
|
||||||
void configureWidgets(MyGUI::Widget* widget);
|
void configureWidgets(MyGUI::Widget* widget);
|
||||||
void updateSliderLabel(MyGUI::ScrollBar* scroller, const std::string& value);
|
void updateSliderLabel(MyGUI::ScrollBar* scroller, const std::string& value);
|
||||||
|
|
||||||
|
void layoutControlsBox();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void resetScrollbars();
|
void resetScrollbars();
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "sortfilteritemmodel.hpp"
|
#include "sortfilteritemmodel.hpp"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
#include <components/misc/stringops.hpp>
|
#include <components/misc/stringops.hpp>
|
||||||
|
|
||||||
#include <components/esm/loadalch.hpp>
|
#include <components/esm/loadalch.hpp>
|
||||||
|
@ -14,9 +16,14 @@
|
||||||
#include <components/esm/loadprob.hpp>
|
#include <components/esm/loadprob.hpp>
|
||||||
#include <components/esm/loadrepa.hpp>
|
#include <components/esm/loadrepa.hpp>
|
||||||
#include <components/esm/loadweap.hpp>
|
#include <components/esm/loadweap.hpp>
|
||||||
|
#include <components/esm/loadench.hpp>
|
||||||
|
|
||||||
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwbase/world.hpp"
|
||||||
|
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
#include "../mwworld/nullaction.hpp"
|
#include "../mwworld/nullaction.hpp"
|
||||||
|
#include "../mwworld/esmstore.hpp"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
@ -139,6 +146,31 @@ namespace MWGui
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((mFilter & Filter_OnlyRepairable) && (
|
||||||
|
!base.getClass().hasItemHealth(base)
|
||||||
|
|| (base.getClass().getItemHealth(base) == base.getClass().getItemMaxHealth(base))
|
||||||
|
|| (base.getTypeName() != typeid(ESM::Weapon).name()
|
||||||
|
&& base.getTypeName() != typeid(ESM::Armor).name())))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (mFilter & Filter_OnlyRechargable)
|
||||||
|
{
|
||||||
|
if (!(item.mFlags & ItemStack::Flag_Enchanted))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
std::string enchId = base.getClass().getEnchantment(base);
|
||||||
|
const ESM::Enchantment* ench = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().search(enchId);
|
||||||
|
if (!ench)
|
||||||
|
{
|
||||||
|
std::cerr << "Can't find enchantment '" << enchId << "' on item " << base.getCellRef().getRefId() << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (base.getCellRef().getEnchantmentCharge() >= ench->mData.mCharge
|
||||||
|
|| base.getCellRef().getEnchantmentCharge() == -1)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,8 @@ namespace MWGui
|
||||||
static const int Filter_OnlyEnchantable = (1<<2);
|
static const int Filter_OnlyEnchantable = (1<<2);
|
||||||
static const int Filter_OnlyChargedSoulstones = (1<<3);
|
static const int Filter_OnlyChargedSoulstones = (1<<3);
|
||||||
static const int Filter_OnlyUsableItems = (1<<4); // Only items with a Use action
|
static const int Filter_OnlyUsableItems = (1<<4); // Only items with a Use action
|
||||||
|
static const int Filter_OnlyRepairable = (1<<5);
|
||||||
|
static const int Filter_OnlyRechargable = (1<<6);
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "../mwworld/inventorystore.hpp"
|
#include "../mwworld/inventorystore.hpp"
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
#include "../mwworld/esmstore.hpp"
|
#include "../mwworld/esmstore.hpp"
|
||||||
|
#include "../mwworld/player.hpp"
|
||||||
|
|
||||||
#include "../mwmechanics/spellcasting.hpp"
|
#include "../mwmechanics/spellcasting.hpp"
|
||||||
#include "../mwmechanics/spells.hpp"
|
#include "../mwmechanics/spells.hpp"
|
||||||
|
@ -122,8 +123,15 @@ namespace MWGui
|
||||||
const ESM::Spell* spell =
|
const ESM::Spell* spell =
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(spellId);
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(spellId);
|
||||||
|
|
||||||
if (spell->mData.mFlags & ESM::Spell::F_Always
|
MWWorld::Ptr player = MWMechanics::getPlayer();
|
||||||
|| spell->mData.mType == ESM::Spell::ST_Power)
|
std::string raceId = player.get<ESM::NPC>()->mBase->mRace;
|
||||||
|
const std::string& signId =
|
||||||
|
MWBase::Environment::get().getWorld()->getPlayer().getBirthSign();
|
||||||
|
const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(raceId);
|
||||||
|
const ESM::BirthSign* birthsign = MWBase::Environment::get().getWorld()->getStore().get<ESM::BirthSign>().find(signId);
|
||||||
|
|
||||||
|
// can't delete racial spells, birthsign spells or powers
|
||||||
|
if (race->mPowers.exists(spell->mId) || birthsign->mPowers.exists(spell->mId) || spell->mData.mType == ESM::Spell::ST_Power)
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sDeleteSpellError}");
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sDeleteSpellError}");
|
||||||
}
|
}
|
||||||
|
|
|
@ -256,7 +256,7 @@ namespace MWGui
|
||||||
std::string key = it->first.substr(0, underscorePos);
|
std::string key = it->first.substr(0, underscorePos);
|
||||||
std::string widgetName = it->first.substr(underscorePos+1, it->first.size()-(underscorePos+1));
|
std::string widgetName = it->first.substr(underscorePos+1, it->first.size()-(underscorePos+1));
|
||||||
|
|
||||||
std::string type = "Property";
|
type = "Property";
|
||||||
size_t caretPos = key.find("^");
|
size_t caretPos = key.find("^");
|
||||||
if (caretPos != std::string::npos)
|
if (caretPos != std::string::npos)
|
||||||
{
|
{
|
||||||
|
|
|
@ -109,6 +109,7 @@
|
||||||
#include "container.hpp"
|
#include "container.hpp"
|
||||||
#include "controllers.hpp"
|
#include "controllers.hpp"
|
||||||
#include "jailscreen.hpp"
|
#include "jailscreen.hpp"
|
||||||
|
#include "itemchargeview.hpp"
|
||||||
|
|
||||||
namespace MWGui
|
namespace MWGui
|
||||||
{
|
{
|
||||||
|
@ -223,6 +224,7 @@ namespace MWGui
|
||||||
MyGUI::FactoryManager::getInstance().registerFactory<osgMyGUI::ScalingLayer>("Layer");
|
MyGUI::FactoryManager::getInstance().registerFactory<osgMyGUI::ScalingLayer>("Layer");
|
||||||
BookPage::registerMyGUIComponents ();
|
BookPage::registerMyGUIComponents ();
|
||||||
ItemView::registerComponents();
|
ItemView::registerComponents();
|
||||||
|
ItemChargeView::registerComponents();
|
||||||
ItemWidget::registerComponents();
|
ItemWidget::registerComponents();
|
||||||
SpellView::registerComponents();
|
SpellView::registerComponents();
|
||||||
Gui::registerAllWidgets();
|
Gui::registerAllWidgets();
|
||||||
|
@ -1004,6 +1006,9 @@ namespace MWGui
|
||||||
mScreenFader->update(frameDuration);
|
mScreenFader->update(frameDuration);
|
||||||
|
|
||||||
mDebugWindow->onFrame(frameDuration);
|
mDebugWindow->onFrame(frameDuration);
|
||||||
|
|
||||||
|
if (mCharGen)
|
||||||
|
mCharGen->onFrame(frameDuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowManager::changeCell(const MWWorld::CellStore* cell)
|
void WindowManager::changeCell(const MWWorld::CellStore* cell)
|
||||||
|
|
|
@ -16,6 +16,9 @@
|
||||||
|
|
||||||
#include <components/sdlutil/sdlinputwrapper.hpp>
|
#include <components/sdlutil/sdlinputwrapper.hpp>
|
||||||
#include <components/sdlutil/sdlvideowrapper.hpp>
|
#include <components/sdlutil/sdlvideowrapper.hpp>
|
||||||
|
#include <components/esm/esmwriter.hpp>
|
||||||
|
#include <components/esm/esmreader.hpp>
|
||||||
|
#include <components/esm/controlsstate.hpp>
|
||||||
|
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
@ -1574,6 +1577,44 @@ namespace MWInput
|
||||||
mInputBinder->removeJoystickButtonBinding (mFakeDeviceID, mInputBinder->getJoystickButtonBinding (control, mFakeDeviceID, ICS::Control::INCREASE));
|
mInputBinder->removeJoystickButtonBinding (mFakeDeviceID, mInputBinder->getJoystickButtonBinding (control, mFakeDeviceID, ICS::Control::INCREASE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int InputManager::countSavedGameRecords() const
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputManager::write(ESM::ESMWriter& writer, Loading::Listener& /*progress*/)
|
||||||
|
{
|
||||||
|
ESM::ControlsState controls;
|
||||||
|
controls.mViewSwitchDisabled = !getControlSwitch("playerviewswitch");
|
||||||
|
controls.mControlsDisabled = !getControlSwitch("playercontrols");
|
||||||
|
controls.mJumpingDisabled = !getControlSwitch("playerjumping");
|
||||||
|
controls.mLookingDisabled = !getControlSwitch("playerlooking");
|
||||||
|
controls.mVanityModeDisabled = !getControlSwitch("vanitymode");
|
||||||
|
controls.mWeaponDrawingDisabled = !getControlSwitch("playerfighting");
|
||||||
|
controls.mSpellDrawingDisabled = !getControlSwitch("playermagic");
|
||||||
|
|
||||||
|
writer.startRecord (ESM::REC_INPU);
|
||||||
|
controls.save(writer);
|
||||||
|
writer.endRecord (ESM::REC_INPU);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputManager::readRecord(ESM::ESMReader& reader, uint32_t type)
|
||||||
|
{
|
||||||
|
if (type == ESM::REC_INPU)
|
||||||
|
{
|
||||||
|
ESM::ControlsState controls;
|
||||||
|
controls.load(reader);
|
||||||
|
|
||||||
|
toggleControlSwitch("playerviewswitch", !controls.mViewSwitchDisabled);
|
||||||
|
toggleControlSwitch("playercontrols", !controls.mControlsDisabled);
|
||||||
|
toggleControlSwitch("playerjumping", !controls.mJumpingDisabled);
|
||||||
|
toggleControlSwitch("playerlooking", !controls.mLookingDisabled);
|
||||||
|
toggleControlSwitch("vanitymode", !controls.mVanityModeDisabled);
|
||||||
|
toggleControlSwitch("playerfighting", !controls.mWeaponDrawingDisabled);
|
||||||
|
toggleControlSwitch("playermagic", !controls.mSpellDrawingDisabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void InputManager::resetToDefaultKeyBindings()
|
void InputManager::resetToDefaultKeyBindings()
|
||||||
{
|
{
|
||||||
loadKeyDefaults(true);
|
loadKeyDefaults(true);
|
||||||
|
|
|
@ -149,6 +149,10 @@ namespace MWInput
|
||||||
void clearAllKeyBindings (ICS::Control* control);
|
void clearAllKeyBindings (ICS::Control* control);
|
||||||
void clearAllControllerBindings (ICS::Control* control);
|
void clearAllControllerBindings (ICS::Control* control);
|
||||||
|
|
||||||
|
virtual int countSavedGameRecords() const;
|
||||||
|
virtual void write(ESM::ESMWriter& writer, Loading::Listener& progress);
|
||||||
|
virtual void readRecord(ESM::ESMReader& reader, uint32_t type);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SDL_Window* mWindow;
|
SDL_Window* mWindow;
|
||||||
bool mWindowVisible;
|
bool mWindowVisible;
|
||||||
|
|
|
@ -512,8 +512,8 @@ namespace MWMechanics
|
||||||
if (magnitude > 0 && remainingTime > 0 && remainingTime < mDuration)
|
if (magnitude > 0 && remainingTime > 0 && remainingTime < mDuration)
|
||||||
{
|
{
|
||||||
CreatureStats& creatureStats = mActor.getClass().getCreatureStats(mActor);
|
CreatureStats& creatureStats = mActor.getClass().getCreatureStats(mActor);
|
||||||
effectTick(creatureStats, mActor, key, magnitude * remainingTime);
|
if (effectTick(creatureStats, mActor, key, magnitude * remainingTime))
|
||||||
creatureStats.getMagicEffects().add(key, -magnitude);
|
creatureStats.getMagicEffects().add(key, -magnitude);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -527,8 +527,10 @@ namespace MWMechanics
|
||||||
|
|
||||||
if (duration > 0)
|
if (duration > 0)
|
||||||
{
|
{
|
||||||
// apply correct magnitude for tickable effects that have just expired,
|
// Apply correct magnitude for tickable effects that have just expired,
|
||||||
// in case duration > remaining time of effect
|
// in case duration > remaining time of effect.
|
||||||
|
// One case where this will happen is when the player uses the rest/wait command
|
||||||
|
// while there is a tickable effect active that should expire before the end of the rest/wait.
|
||||||
ExpiryVisitor visitor(ptr, duration);
|
ExpiryVisitor visitor(ptr, duration);
|
||||||
creatureStats.getActiveSpells().visitEffectSources(visitor);
|
creatureStats.getActiveSpells().visitEffectSources(visitor);
|
||||||
|
|
||||||
|
|
|
@ -41,9 +41,7 @@ namespace MWMechanics
|
||||||
if (pathTo(actor, dest, duration, MWBase::Environment::get().getWorld()->getMaxActivationDistance())) //Stop when you get in activation range
|
if (pathTo(actor, dest, duration, MWBase::Environment::get().getWorld()->getMaxActivationDistance())) //Stop when you get in activation range
|
||||||
{
|
{
|
||||||
// activate when reached
|
// activate when reached
|
||||||
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr(mObjectId,false);
|
|
||||||
MWBase::Environment::get().getWorld()->activate(target, actor);
|
MWBase::Environment::get().getWorld()->activate(target, actor);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "character.hpp"
|
#include "character.hpp"
|
||||||
#include "aicombataction.hpp"
|
#include "aicombataction.hpp"
|
||||||
#include "combat.hpp"
|
#include "combat.hpp"
|
||||||
|
#include "coordinateconverter.hpp"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
@ -50,23 +51,40 @@ namespace MWMechanics
|
||||||
bool mForceNoShortcut;
|
bool mForceNoShortcut;
|
||||||
ESM::Position mShortcutFailPos;
|
ESM::Position mShortcutFailPos;
|
||||||
MWMechanics::Movement mMovement;
|
MWMechanics::Movement mMovement;
|
||||||
|
|
||||||
|
enum FleeState
|
||||||
|
{
|
||||||
|
FleeState_None,
|
||||||
|
FleeState_Idle,
|
||||||
|
FleeState_RunBlindly,
|
||||||
|
FleeState_RunToDestination
|
||||||
|
};
|
||||||
|
FleeState mFleeState;
|
||||||
|
bool mLOS;
|
||||||
|
float mUpdateLOSTimer;
|
||||||
|
float mFleeBlindRunTimer;
|
||||||
|
ESM::Pathgrid::Point mFleeDest;
|
||||||
|
|
||||||
AiCombatStorage():
|
AiCombatStorage():
|
||||||
mAttackCooldown(0),
|
mAttackCooldown(0.0f),
|
||||||
mTimerReact(AI_REACTION_TIME),
|
mTimerReact(AI_REACTION_TIME),
|
||||||
mTimerCombatMove(0),
|
mTimerCombatMove(0.0f),
|
||||||
mReadyToAttack(false),
|
mReadyToAttack(false),
|
||||||
mAttack(false),
|
mAttack(false),
|
||||||
mAttackRange(0),
|
mAttackRange(0.0f),
|
||||||
mCombatMove(false),
|
mCombatMove(false),
|
||||||
mLastTargetPos(0,0,0),
|
mLastTargetPos(0,0,0),
|
||||||
mCell(NULL),
|
mCell(NULL),
|
||||||
mCurrentAction(),
|
mCurrentAction(),
|
||||||
mActionCooldown(0),
|
mActionCooldown(0.0f),
|
||||||
mStrength(),
|
mStrength(),
|
||||||
mForceNoShortcut(false),
|
mForceNoShortcut(false),
|
||||||
mShortcutFailPos(),
|
mShortcutFailPos(),
|
||||||
mMovement()
|
mMovement(),
|
||||||
|
mFleeState(FleeState_None),
|
||||||
|
mLOS(false),
|
||||||
|
mUpdateLOSTimer(0.0f),
|
||||||
|
mFleeBlindRunTimer(0.0f)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void startCombatMove(bool isDistantCombat, float distToTarget, float rangeAttack, const MWWorld::Ptr& actor, const MWWorld::Ptr& target);
|
void startCombatMove(bool isDistantCombat, float distToTarget, float rangeAttack, const MWWorld::Ptr& actor, const MWWorld::Ptr& target);
|
||||||
|
@ -76,6 +94,10 @@ namespace MWMechanics
|
||||||
const ESM::Weapon* weapon, bool distantCombat);
|
const ESM::Weapon* weapon, bool distantCombat);
|
||||||
void updateAttack(CharacterController& characterController);
|
void updateAttack(CharacterController& characterController);
|
||||||
void stopAttack();
|
void stopAttack();
|
||||||
|
|
||||||
|
void startFleeing();
|
||||||
|
void stopFleeing();
|
||||||
|
bool isFleeing();
|
||||||
};
|
};
|
||||||
|
|
||||||
AiCombat::AiCombat(const MWWorld::Ptr& actor) :
|
AiCombat::AiCombat(const MWWorld::Ptr& actor) :
|
||||||
|
@ -157,16 +179,27 @@ namespace MWMechanics
|
||||||
|| target.getClass().getCreatureStats(target).isDead())
|
|| target.getClass().getCreatureStats(target).isDead())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (storage.mCurrentAction.get()) // need to wait to init action with it's attack range
|
if (!storage.isFleeing())
|
||||||
{
|
{
|
||||||
//Update every frame
|
if (storage.mCurrentAction.get()) // need to wait to init action with its attack range
|
||||||
bool is_target_reached = pathTo(actor, target.getRefData().getPosition().pos, duration, storage.mAttackRange);
|
{
|
||||||
if (is_target_reached) storage.mReadyToAttack = true;
|
//Update every frame. UpdateLOS uses a timer, so the LOS check does not happen every frame.
|
||||||
}
|
updateLOS(actor, target, duration, storage);
|
||||||
|
float targetReachedTolerance = 0.0f;
|
||||||
|
if (storage.mLOS)
|
||||||
|
targetReachedTolerance = storage.mAttackRange;
|
||||||
|
bool is_target_reached = pathTo(actor, target.getRefData().getPosition().pos, duration, targetReachedTolerance);
|
||||||
|
if (is_target_reached) storage.mReadyToAttack = true;
|
||||||
|
}
|
||||||
|
|
||||||
storage.updateCombatMove(duration);
|
storage.updateCombatMove(duration);
|
||||||
if (storage.mReadyToAttack) updateActorsMovement(actor, duration, storage);
|
if (storage.mReadyToAttack) updateActorsMovement(actor, duration, storage);
|
||||||
storage.updateAttack(characterController);
|
storage.updateAttack(characterController);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
updateFleeing(actor, target, duration, storage);
|
||||||
|
}
|
||||||
storage.mActionCooldown -= duration;
|
storage.mActionCooldown -= duration;
|
||||||
|
|
||||||
float& timerReact = storage.mTimerReact;
|
float& timerReact = storage.mTimerReact;
|
||||||
|
@ -185,12 +218,6 @@ namespace MWMechanics
|
||||||
|
|
||||||
void AiCombat::attack(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, AiCombatStorage& storage, CharacterController& characterController)
|
void AiCombat::attack(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, AiCombatStorage& storage, CharacterController& characterController)
|
||||||
{
|
{
|
||||||
if (isTargetMagicallyHidden(target))
|
|
||||||
{
|
|
||||||
storage.stopAttack();
|
|
||||||
return; // TODO: run away instead of doing nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
const MWWorld::CellStore*& currentCell = storage.mCell;
|
const MWWorld::CellStore*& currentCell = storage.mCell;
|
||||||
bool cellChange = currentCell && (actor.getCell() != currentCell);
|
bool cellChange = currentCell && (actor.getCell() != currentCell);
|
||||||
if(!currentCell || cellChange)
|
if(!currentCell || cellChange)
|
||||||
|
@ -198,30 +225,61 @@ namespace MWMechanics
|
||||||
currentCell = actor.getCell();
|
currentCell = actor.getCell();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool forceFlee = false;
|
||||||
|
if (!canFight(actor, target))
|
||||||
|
{
|
||||||
|
storage.stopAttack();
|
||||||
|
characterController.setAttackingOrSpell(false);
|
||||||
|
storage.mActionCooldown = 0.f;
|
||||||
|
forceFlee = true;
|
||||||
|
}
|
||||||
|
|
||||||
const MWWorld::Class& actorClass = actor.getClass();
|
const MWWorld::Class& actorClass = actor.getClass();
|
||||||
actorClass.getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true);
|
actorClass.getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true);
|
||||||
|
|
||||||
float& actionCooldown = storage.mActionCooldown;
|
float& actionCooldown = storage.mActionCooldown;
|
||||||
if (actionCooldown > 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
float &rangeAttack = storage.mAttackRange;
|
|
||||||
boost::shared_ptr<Action>& currentAction = storage.mCurrentAction;
|
boost::shared_ptr<Action>& currentAction = storage.mCurrentAction;
|
||||||
if (characterController.readyToPrepareAttack())
|
|
||||||
|
if (!forceFlee)
|
||||||
{
|
{
|
||||||
currentAction = prepareNextAction(actor, target);
|
if (actionCooldown > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (characterController.readyToPrepareAttack())
|
||||||
|
{
|
||||||
|
currentAction = prepareNextAction(actor, target);
|
||||||
|
actionCooldown = currentAction->getActionCooldown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
currentAction.reset(new ActionFlee());
|
||||||
actionCooldown = currentAction->getActionCooldown();
|
actionCooldown = currentAction->getActionCooldown();
|
||||||
}
|
}
|
||||||
|
|
||||||
const ESM::Weapon *weapon = NULL;
|
if (!currentAction)
|
||||||
bool isRangedCombat = false;
|
return;
|
||||||
if (currentAction.get())
|
|
||||||
|
if (storage.isFleeing() != currentAction->isFleeing())
|
||||||
{
|
{
|
||||||
rangeAttack = currentAction->getCombatRange(isRangedCombat);
|
if (currentAction->isFleeing())
|
||||||
// Get weapon characteristics
|
{
|
||||||
weapon = currentAction->getWeapon();
|
storage.startFleeing();
|
||||||
|
MWBase::Environment::get().getDialogueManager()->say(actor, "flee");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
storage.stopFleeing();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isRangedCombat = false;
|
||||||
|
float &rangeAttack = storage.mAttackRange;
|
||||||
|
|
||||||
|
rangeAttack = currentAction->getCombatRange(isRangedCombat);
|
||||||
|
|
||||||
|
// Get weapon characteristics
|
||||||
|
const ESM::Weapon* weapon = currentAction->getWeapon();
|
||||||
|
|
||||||
ESM::Position pos = actor.getRefData().getPosition();
|
ESM::Position pos = actor.getRefData().getPosition();
|
||||||
osg::Vec3f vActorPos(pos.asVec3());
|
osg::Vec3f vActorPos(pos.asVec3());
|
||||||
osg::Vec3f vTargetPos(target.getRefData().getPosition().asVec3());
|
osg::Vec3f vTargetPos(target.getRefData().getPosition().asVec3());
|
||||||
|
@ -229,19 +287,7 @@ namespace MWMechanics
|
||||||
osg::Vec3f vAimDir = MWBase::Environment::get().getWorld()->aimToTarget(actor, target);
|
osg::Vec3f vAimDir = MWBase::Environment::get().getWorld()->aimToTarget(actor, target);
|
||||||
float distToTarget = MWBase::Environment::get().getWorld()->getHitDistance(actor, target);
|
float distToTarget = MWBase::Environment::get().getWorld()->getHitDistance(actor, target);
|
||||||
|
|
||||||
if (!currentAction)
|
storage.mReadyToAttack = (currentAction->isAttackingOrSpell() && distToTarget <= rangeAttack && storage.mLOS);
|
||||||
return;
|
|
||||||
|
|
||||||
storage.mReadyToAttack = (currentAction->isAttackingOrSpell() && distToTarget <= rangeAttack);
|
|
||||||
|
|
||||||
// can't fight if attacker can't go where target is. E.g. A fish can't attack person on land.
|
|
||||||
if (distToTarget > rangeAttack
|
|
||||||
&& !actorClass.isNpc() && !MWMechanics::isEnvironmentCompatible(actor, target))
|
|
||||||
{
|
|
||||||
// TODO: start fleeing?
|
|
||||||
storage.stopAttack();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (storage.mReadyToAttack)
|
if (storage.mReadyToAttack)
|
||||||
{
|
{
|
||||||
|
@ -267,6 +313,111 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MWMechanics::AiCombat::updateLOS(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, float duration, MWMechanics::AiCombatStorage& storage)
|
||||||
|
{
|
||||||
|
static const float LOS_UPDATE_DURATION = 0.5f;
|
||||||
|
if (storage.mUpdateLOSTimer <= 0.f)
|
||||||
|
{
|
||||||
|
storage.mLOS = MWBase::Environment::get().getWorld()->getLOS(actor, target);
|
||||||
|
storage.mUpdateLOSTimer = LOS_UPDATE_DURATION;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
storage.mUpdateLOSTimer -= duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MWMechanics::AiCombat::updateFleeing(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, float duration, MWMechanics::AiCombatStorage& storage)
|
||||||
|
{
|
||||||
|
static const float BLIND_RUN_DURATION = 1.0f;
|
||||||
|
|
||||||
|
updateLOS(actor, target, duration, storage);
|
||||||
|
|
||||||
|
AiCombatStorage::FleeState& state = storage.mFleeState;
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case AiCombatStorage::FleeState_None:
|
||||||
|
return;
|
||||||
|
|
||||||
|
case AiCombatStorage::FleeState_Idle:
|
||||||
|
{
|
||||||
|
float triggerDist = getMaxAttackDistance(target);
|
||||||
|
|
||||||
|
if (storage.mLOS &&
|
||||||
|
(triggerDist >= 1000 || getDistanceMinusHalfExtents(actor, target) <= triggerDist))
|
||||||
|
{
|
||||||
|
const ESM::Pathgrid* pathgrid =
|
||||||
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*storage.mCell->getCell());
|
||||||
|
|
||||||
|
bool runFallback = true;
|
||||||
|
|
||||||
|
if (pathgrid && !actor.getClass().isPureWaterCreature(actor))
|
||||||
|
{
|
||||||
|
ESM::Pathgrid::PointList points;
|
||||||
|
CoordinateConverter coords(storage.mCell->getCell());
|
||||||
|
|
||||||
|
osg::Vec3f localPos = actor.getRefData().getPosition().asVec3();
|
||||||
|
coords.toLocal(localPos);
|
||||||
|
|
||||||
|
int closestPointIndex = PathFinder::GetClosestPoint(pathgrid, localPos);
|
||||||
|
for (int i = 0; i < static_cast<int>(pathgrid->mPoints.size()); i++)
|
||||||
|
{
|
||||||
|
if (i != closestPointIndex && storage.mCell->isPointConnected(closestPointIndex, i))
|
||||||
|
{
|
||||||
|
points.push_back(pathgrid->mPoints[static_cast<size_t>(i)]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!points.empty())
|
||||||
|
{
|
||||||
|
ESM::Pathgrid::Point dest = points[Misc::Rng::rollDice(points.size())];
|
||||||
|
coords.toWorld(dest);
|
||||||
|
|
||||||
|
state = AiCombatStorage::FleeState_RunToDestination;
|
||||||
|
storage.mFleeDest = ESM::Pathgrid::Point(dest.mX, dest.mY, dest.mZ);
|
||||||
|
|
||||||
|
runFallback = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (runFallback)
|
||||||
|
{
|
||||||
|
state = AiCombatStorage::FleeState_RunBlindly;
|
||||||
|
storage.mFleeBlindRunTimer = 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AiCombatStorage::FleeState_RunBlindly:
|
||||||
|
{
|
||||||
|
// timer to prevent twitchy movement that can be observed in vanilla MW
|
||||||
|
if (storage.mFleeBlindRunTimer < BLIND_RUN_DURATION)
|
||||||
|
{
|
||||||
|
storage.mFleeBlindRunTimer += duration;
|
||||||
|
|
||||||
|
storage.mMovement.mRotation[2] = osg::PI + getZAngleToDir(target.getRefData().getPosition().asVec3()-actor.getRefData().getPosition().asVec3());
|
||||||
|
storage.mMovement.mPosition[1] = 1;
|
||||||
|
updateActorsMovement(actor, duration, storage);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
state = AiCombatStorage::FleeState_Idle;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AiCombatStorage::FleeState_RunToDestination:
|
||||||
|
{
|
||||||
|
static const float fFleeDistance = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fFleeDistance")->getFloat();
|
||||||
|
|
||||||
|
float dist = (actor.getRefData().getPosition().asVec3() - target.getRefData().getPosition().asVec3()).length();
|
||||||
|
if ((dist > fFleeDistance && !storage.mLOS)
|
||||||
|
|| pathTo(actor, storage.mFleeDest, duration))
|
||||||
|
{
|
||||||
|
state = AiCombatStorage::FleeState_Idle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
void AiCombat::updateActorsMovement(const MWWorld::Ptr& actor, float duration, AiCombatStorage& storage)
|
void AiCombat::updateActorsMovement(const MWWorld::Ptr& actor, float duration, AiCombatStorage& storage)
|
||||||
{
|
{
|
||||||
// apply combat movement
|
// apply combat movement
|
||||||
|
@ -446,6 +597,26 @@ namespace MWMechanics
|
||||||
mReadyToAttack = false;
|
mReadyToAttack = false;
|
||||||
mAttack = false;
|
mAttack = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AiCombatStorage::startFleeing()
|
||||||
|
{
|
||||||
|
stopFleeing();
|
||||||
|
mFleeState = FleeState_Idle;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AiCombatStorage::stopFleeing()
|
||||||
|
{
|
||||||
|
mMovement.mPosition[0] = 0;
|
||||||
|
mMovement.mPosition[1] = 0;
|
||||||
|
mMovement.mPosition[2] = 0;
|
||||||
|
mFleeState = FleeState_None;
|
||||||
|
mFleeDest = ESM::Pathgrid::Point(0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AiCombatStorage::isFleeing()
|
||||||
|
{
|
||||||
|
return mFleeState != FleeState_None;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,10 @@ namespace MWMechanics
|
||||||
|
|
||||||
void attack(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, AiCombatStorage& storage, CharacterController& characterController);
|
void attack(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, AiCombatStorage& storage, CharacterController& characterController);
|
||||||
|
|
||||||
|
void updateLOS(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, float duration, AiCombatStorage& storage);
|
||||||
|
|
||||||
|
void updateFleeing(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, float duration, AiCombatStorage& storage);
|
||||||
|
|
||||||
/// Transfer desired movement (from AiCombatStorage) to Actor
|
/// Transfer desired movement (from AiCombatStorage) to Actor
|
||||||
void updateActorsMovement(const MWWorld::Ptr& actor, float duration, AiCombatStorage& storage);
|
void updateActorsMovement(const MWWorld::Ptr& actor, float duration, AiCombatStorage& storage);
|
||||||
void rotateActorOnAxis(const MWWorld::Ptr& actor, int axis,
|
void rotateActorOnAxis(const MWWorld::Ptr& actor, int axis,
|
||||||
|
|
|
@ -5,14 +5,17 @@
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
#include "../mwbase/mechanicsmanager.hpp"
|
||||||
|
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
#include "../mwworld/esmstore.hpp"
|
#include "../mwworld/esmstore.hpp"
|
||||||
#include "../mwworld/inventorystore.hpp"
|
#include "../mwworld/inventorystore.hpp"
|
||||||
#include "../mwworld/actionequip.hpp"
|
#include "../mwworld/actionequip.hpp"
|
||||||
|
#include "../mwworld/cellstore.hpp"
|
||||||
|
|
||||||
#include "npcstats.hpp"
|
#include "npcstats.hpp"
|
||||||
#include "spellcasting.hpp"
|
#include "spellcasting.hpp"
|
||||||
|
#include "combat.hpp"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
@ -517,6 +520,7 @@ namespace MWMechanics
|
||||||
Spells& spells = actor.getClass().getCreatureStats(actor).getSpells();
|
Spells& spells = actor.getClass().getCreatureStats(actor).getSpells();
|
||||||
|
|
||||||
float bestActionRating = 0.f;
|
float bestActionRating = 0.f;
|
||||||
|
float antiFleeRating = 0.f;
|
||||||
// Default to hand-to-hand combat
|
// Default to hand-to-hand combat
|
||||||
boost::shared_ptr<Action> bestAction (new ActionWeapon(MWWorld::Ptr()));
|
boost::shared_ptr<Action> bestAction (new ActionWeapon(MWWorld::Ptr()));
|
||||||
if (actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf())
|
if (actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf())
|
||||||
|
@ -536,6 +540,7 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
bestActionRating = rating;
|
bestActionRating = rating;
|
||||||
bestAction.reset(new ActionPotion(*it));
|
bestAction.reset(new ActionPotion(*it));
|
||||||
|
antiFleeRating = std::numeric_limits<float>::max();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -546,6 +551,7 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
bestActionRating = rating;
|
bestActionRating = rating;
|
||||||
bestAction.reset(new ActionEnchantedItem(it));
|
bestAction.reset(new ActionEnchantedItem(it));
|
||||||
|
antiFleeRating = std::numeric_limits<float>::max();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -593,6 +599,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
bestActionRating = rating;
|
bestActionRating = rating;
|
||||||
bestAction.reset(new ActionWeapon(*it, ammo));
|
bestAction.reset(new ActionWeapon(*it, ammo));
|
||||||
|
antiFleeRating = vanillaRateWeaponAndAmmo(*it, ammo, actor, enemy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -606,13 +613,308 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
bestActionRating = rating;
|
bestActionRating = rating;
|
||||||
bestAction.reset(new ActionSpell(spell->mId));
|
bestAction.reset(new ActionSpell(spell->mId));
|
||||||
|
antiFleeRating = vanillaRateSpell(spell, actor, enemy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (makeFleeDecision(actor, enemy, antiFleeRating))
|
||||||
|
bestAction.reset(new ActionFlee());
|
||||||
|
|
||||||
if (bestAction.get())
|
if (bestAction.get())
|
||||||
bestAction->prepare(actor);
|
bestAction->prepare(actor);
|
||||||
|
|
||||||
return bestAction;
|
return bestAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float getDistanceMinusHalfExtents(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, bool minusZDist)
|
||||||
|
{
|
||||||
|
osg::Vec3f actor1Pos = actor1.getRefData().getPosition().asVec3();
|
||||||
|
osg::Vec3f actor2Pos = actor2.getRefData().getPosition().asVec3();
|
||||||
|
|
||||||
|
float dist = (actor1Pos - actor2Pos).length();
|
||||||
|
|
||||||
|
if (minusZDist)
|
||||||
|
dist -= std::abs(actor1Pos.z() - actor2Pos.z());
|
||||||
|
|
||||||
|
return (dist
|
||||||
|
- MWBase::Environment::get().getWorld()->getHalfExtents(actor1).y()
|
||||||
|
- MWBase::Environment::get().getWorld()->getHalfExtents(actor2).y());
|
||||||
|
}
|
||||||
|
|
||||||
|
float getMaxAttackDistance(const MWWorld::Ptr& actor)
|
||||||
|
{
|
||||||
|
const CreatureStats& stats = actor.getClass().getCreatureStats(actor);
|
||||||
|
const MWWorld::Store<ESM::GameSetting>& gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||||
|
|
||||||
|
std::string selectedSpellId = stats.getSpells().getSelectedSpell();
|
||||||
|
MWWorld::Ptr selectedEnchItem;
|
||||||
|
|
||||||
|
MWWorld::Ptr activeWeapon, activeAmmo;
|
||||||
|
if (actor.getClass().hasInventoryStore(actor))
|
||||||
|
{
|
||||||
|
MWWorld::InventoryStore& invStore = actor.getClass().getInventoryStore(actor);
|
||||||
|
|
||||||
|
MWWorld::ContainerStoreIterator item = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||||
|
if (item != invStore.end() && item.getType() == MWWorld::ContainerStore::Type_Weapon)
|
||||||
|
activeWeapon = *item;
|
||||||
|
|
||||||
|
item = invStore.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
|
||||||
|
if (item != invStore.end() && item.getType() == MWWorld::ContainerStore::Type_Weapon)
|
||||||
|
activeAmmo = *item;
|
||||||
|
|
||||||
|
if (invStore.getSelectedEnchantItem() != invStore.end())
|
||||||
|
selectedEnchItem = *invStore.getSelectedEnchantItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
float dist = 1.0f;
|
||||||
|
if (activeWeapon.isEmpty() && !selectedSpellId.empty() && !selectedEnchItem.isEmpty())
|
||||||
|
{
|
||||||
|
static const float fHandToHandReach = gmst.find("fHandToHandReach")->getFloat();
|
||||||
|
dist = fHandToHandReach;
|
||||||
|
}
|
||||||
|
else if (stats.getDrawState() == MWMechanics::DrawState_Spell)
|
||||||
|
{
|
||||||
|
dist = 1.0f;
|
||||||
|
if (!selectedSpellId.empty())
|
||||||
|
{
|
||||||
|
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(selectedSpellId);
|
||||||
|
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt =
|
||||||
|
spell->mEffects.mList.begin(); effectIt != spell->mEffects.mList.end(); ++effectIt)
|
||||||
|
{
|
||||||
|
if (effectIt->mArea == ESM::RT_Target)
|
||||||
|
{
|
||||||
|
const ESM::MagicEffect* effect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(effectIt->mEffectID);
|
||||||
|
dist = effect->mData.mSpeed;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!selectedEnchItem.isEmpty())
|
||||||
|
{
|
||||||
|
std::string enchId = selectedEnchItem.getClass().getEnchantment(selectedEnchItem);
|
||||||
|
if (!enchId.empty())
|
||||||
|
{
|
||||||
|
const ESM::Enchantment* ench = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().find(enchId);
|
||||||
|
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt =
|
||||||
|
ench->mEffects.mList.begin(); effectIt != ench->mEffects.mList.end(); ++effectIt)
|
||||||
|
{
|
||||||
|
if (effectIt->mArea == ESM::RT_Target)
|
||||||
|
{
|
||||||
|
const ESM::MagicEffect* effect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(effectIt->mEffectID);
|
||||||
|
dist = effect->mData.mSpeed;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const float fTargetSpellMaxSpeed = gmst.find("fTargetSpellMaxSpeed")->getFloat();
|
||||||
|
dist *= std::max(1000.0f, fTargetSpellMaxSpeed);
|
||||||
|
}
|
||||||
|
else if (!activeWeapon.isEmpty())
|
||||||
|
{
|
||||||
|
const ESM::Weapon* esmWeap = activeWeapon.get<ESM::Weapon>()->mBase;
|
||||||
|
if (esmWeap->mData.mType >= ESM::Weapon::MarksmanBow)
|
||||||
|
{
|
||||||
|
static const float fTargetSpellMaxSpeed = gmst.find("fProjectileMaxSpeed")->getFloat();
|
||||||
|
dist = fTargetSpellMaxSpeed;
|
||||||
|
if (!activeAmmo.isEmpty())
|
||||||
|
{
|
||||||
|
const ESM::Weapon* esmAmmo = activeAmmo.get<ESM::Weapon>()->mBase;
|
||||||
|
dist *= esmAmmo->mData.mSpeed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (esmWeap->mData.mReach > 1)
|
||||||
|
{
|
||||||
|
dist = esmWeap->mData.mReach;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dist = (dist > 0.f) ? dist : 1.0f;
|
||||||
|
|
||||||
|
static const float fCombatDistance = gmst.find("fCombatDistance")->getFloat();
|
||||||
|
static const float fCombatDistanceWerewolfMod = gmst.find("fCombatDistanceWerewolfMod")->getFloat();
|
||||||
|
|
||||||
|
float combatDistance = fCombatDistance;
|
||||||
|
if (actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf())
|
||||||
|
combatDistance *= (fCombatDistanceWerewolfMod + 1.0f);
|
||||||
|
|
||||||
|
if (dist < combatDistance)
|
||||||
|
dist *= combatDistance;
|
||||||
|
|
||||||
|
return dist;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool canFight(const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy)
|
||||||
|
{
|
||||||
|
ESM::Position actorPos = actor.getRefData().getPosition();
|
||||||
|
ESM::Position enemyPos = enemy.getRefData().getPosition();
|
||||||
|
|
||||||
|
const CreatureStats& enemyStats = enemy.getClass().getCreatureStats(enemy);
|
||||||
|
if (enemyStats.getMagicEffects().get(ESM::MagicEffect::Invisibility).getMagnitude() > 0
|
||||||
|
|| enemyStats.getMagicEffects().get(ESM::MagicEffect::Chameleon).getMagnitude() > 0)
|
||||||
|
{
|
||||||
|
if (!MWBase::Environment::get().getMechanicsManager()->awarenessCheck(enemy, actor))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actor.getClass().isPureWaterCreature(actor))
|
||||||
|
{
|
||||||
|
if (!MWBase::Environment::get().getWorld()->isWading(enemy))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
float atDist = getMaxAttackDistance(actor);
|
||||||
|
if (atDist > getDistanceMinusHalfExtents(actor, enemy)
|
||||||
|
&& atDist > std::abs(actorPos.pos[2] - enemyPos.pos[2]))
|
||||||
|
{
|
||||||
|
if (MWBase::Environment::get().getWorld()->getLOS(actor, enemy))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actor.getClass().isPureFlyingCreature(actor) || actor.getClass().isPureLandCreature(actor))
|
||||||
|
{
|
||||||
|
if (MWBase::Environment::get().getWorld()->isSwimming(enemy))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actor.getClass().isBipedal(actor) || !actor.getClass().canFly(actor))
|
||||||
|
{
|
||||||
|
if (enemy.getClass().getCreatureStats(enemy).getMagicEffects().get(ESM::MagicEffect::Levitate).getMagnitude() > 0)
|
||||||
|
{
|
||||||
|
float attackDistance = getMaxAttackDistance(actor);
|
||||||
|
if ((attackDistance + actorPos.pos[2]) < enemyPos.pos[2])
|
||||||
|
{
|
||||||
|
if (enemy.getCell()->isExterior())
|
||||||
|
{
|
||||||
|
if (attackDistance < (enemyPos.pos[2] - MWBase::Environment::get().getWorld()->getTerrainHeightAt(enemyPos.asVec3())))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!actor.getClass().canWalk(actor) && !actor.getClass().isBipedal(actor))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (actor.getClass().getCreatureStats(actor).getMagicEffects().get(ESM::MagicEffect::Levitate).getMagnitude() > 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (MWBase::Environment::get().getWorld()->isSwimming(actor))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (getDistanceMinusHalfExtents(actor, enemy, true) <= 0.0f)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
float vanillaRateSpell(const ESM::Spell* spell, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy)
|
||||||
|
{
|
||||||
|
const MWWorld::Store<ESM::GameSetting>& gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||||
|
|
||||||
|
static const float fAIMagicSpellMult = gmst.find("fAIMagicSpellMult")->getFloat();
|
||||||
|
static const float fAIRangeMagicSpellMult = gmst.find("fAIRangeMagicSpellMult")->getFloat();
|
||||||
|
|
||||||
|
float mult = fAIMagicSpellMult;
|
||||||
|
|
||||||
|
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt =
|
||||||
|
spell->mEffects.mList.begin(); effectIt != spell->mEffects.mList.end(); ++effectIt)
|
||||||
|
{
|
||||||
|
if (effectIt->mArea == ESM::RT_Target)
|
||||||
|
{
|
||||||
|
if (!MWBase::Environment::get().getWorld()->isSwimming(enemy))
|
||||||
|
mult = fAIRangeMagicSpellMult;
|
||||||
|
else
|
||||||
|
mult = 0.0f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return MWMechanics::getSpellSuccessChance(spell, actor) * mult;
|
||||||
|
}
|
||||||
|
|
||||||
|
float vanillaRateWeaponAndAmmo(const MWWorld::Ptr& weapon, const MWWorld::Ptr& ammo, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy)
|
||||||
|
{
|
||||||
|
const MWWorld::Store<ESM::GameSetting>& gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||||
|
|
||||||
|
static const float fAIMeleeWeaponMult = gmst.find("fAIMeleeWeaponMult")->getFloat();
|
||||||
|
static const float fAIMeleeArmorMult = gmst.find("fAIMeleeArmorMult")->getFloat();
|
||||||
|
static const float fAIRangeMeleeWeaponMult = gmst.find("fAIRangeMeleeWeaponMult")->getFloat();
|
||||||
|
|
||||||
|
if (weapon.isEmpty())
|
||||||
|
return 0.f;
|
||||||
|
|
||||||
|
float skillMult = actor.getClass().getSkill(actor, weapon.getClass().getEquipmentSkill(weapon)) * 0.01f;
|
||||||
|
float chopMult = fAIMeleeWeaponMult;
|
||||||
|
float bonusDamage = 0.f;
|
||||||
|
|
||||||
|
const ESM::Weapon* esmWeap = weapon.get<ESM::Weapon>()->mBase;
|
||||||
|
|
||||||
|
if (esmWeap->mData.mType >= ESM::Weapon::MarksmanBow)
|
||||||
|
{
|
||||||
|
if (!ammo.isEmpty() && !MWBase::Environment::get().getWorld()->isSwimming(enemy))
|
||||||
|
{
|
||||||
|
bonusDamage = ammo.get<ESM::Weapon>()->mBase->mData.mChop[1];
|
||||||
|
chopMult = fAIRangeMeleeWeaponMult;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
chopMult = 0.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float chopRating = (esmWeap->mData.mChop[1] + bonusDamage) * skillMult * chopMult;
|
||||||
|
float slashRating = esmWeap->mData.mSlash[1] * skillMult * fAIMeleeWeaponMult;
|
||||||
|
float thrustRating = esmWeap->mData.mThrust[1] * skillMult * fAIMeleeWeaponMult;
|
||||||
|
|
||||||
|
return actor.getClass().getArmorRating(actor) * fAIMeleeArmorMult
|
||||||
|
+ std::max(std::max(chopRating, slashRating), thrustRating);
|
||||||
|
}
|
||||||
|
|
||||||
|
float vanillaRateFlee(const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy)
|
||||||
|
{
|
||||||
|
const CreatureStats& stats = actor.getClass().getCreatureStats(actor);
|
||||||
|
const MWWorld::Store<ESM::GameSetting>& gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||||
|
|
||||||
|
int flee = stats.getAiSetting(CreatureStats::AI_Flee).getModified();
|
||||||
|
if (flee >= 100)
|
||||||
|
return flee;
|
||||||
|
|
||||||
|
static const float fAIFleeHealthMult = gmst.find("fAIFleeHealthMult")->getFloat();
|
||||||
|
static const float fAIFleeFleeMult = gmst.find("fAIFleeFleeMult")->getFloat();
|
||||||
|
|
||||||
|
float healthPercentage = (stats.getHealth().getModified() == 0.0f)
|
||||||
|
? 1.0f : stats.getHealth().getCurrent() / stats.getHealth().getModified();
|
||||||
|
float rating = (1.0f - healthPercentage) * fAIFleeHealthMult + flee * fAIFleeFleeMult;
|
||||||
|
|
||||||
|
static const int iWereWolfLevelToAttack = gmst.find("iWereWolfLevelToAttack")->getInt();
|
||||||
|
|
||||||
|
if (enemy.getClass().isNpc() && enemy.getClass().getNpcStats(enemy).isWerewolf() && stats.getLevel() < iWereWolfLevelToAttack)
|
||||||
|
{
|
||||||
|
static const int iWereWolfFleeMod = gmst.find("iWereWolfFleeMod")->getInt();
|
||||||
|
rating = iWereWolfFleeMod;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rating != 0.0f)
|
||||||
|
rating += getFightDistanceBias(actor, enemy);
|
||||||
|
|
||||||
|
return rating;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool makeFleeDecision(const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy, float antiFleeRating)
|
||||||
|
{
|
||||||
|
float fleeRating = vanillaRateFlee(actor, enemy);
|
||||||
|
if (fleeRating < 100.0f)
|
||||||
|
fleeRating = 0.0f;
|
||||||
|
|
||||||
|
if (fleeRating > antiFleeRating)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Run away after summoning a creature if we have nothing to use but fists.
|
||||||
|
if (antiFleeRating == 0.0f && !actor.getClass().getCreatureStats(actor).getSummonedCreatureMap().empty())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,18 @@ namespace MWMechanics
|
||||||
virtual float getActionCooldown() { return 0.f; }
|
virtual float getActionCooldown() { return 0.f; }
|
||||||
virtual const ESM::Weapon* getWeapon() const { return NULL; };
|
virtual const ESM::Weapon* getWeapon() const { return NULL; };
|
||||||
virtual bool isAttackingOrSpell() const { return true; }
|
virtual bool isAttackingOrSpell() const { return true; }
|
||||||
|
virtual bool isFleeing() const { return false; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class ActionFlee : public Action
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ActionFlee() {}
|
||||||
|
virtual void prepare(const MWWorld::Ptr& actor) {}
|
||||||
|
virtual float getCombatRange (bool& isRanged) const { return 0.0f; }
|
||||||
|
virtual float getActionCooldown() { return 3.0f; }
|
||||||
|
virtual bool isAttackingOrSpell() const { return false; }
|
||||||
|
virtual bool isFleeing() const { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class ActionSpell : public Action
|
class ActionSpell : public Action
|
||||||
|
@ -89,6 +101,15 @@ namespace MWMechanics
|
||||||
float rateEffects (const ESM::EffectList& list, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy);
|
float rateEffects (const ESM::EffectList& list, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy);
|
||||||
|
|
||||||
boost::shared_ptr<Action> prepareNextAction (const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy);
|
boost::shared_ptr<Action> prepareNextAction (const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy);
|
||||||
|
|
||||||
|
float getDistanceMinusHalfExtents(const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy, bool minusZDist=false);
|
||||||
|
float getMaxAttackDistance(const MWWorld::Ptr& actor);
|
||||||
|
bool canFight(const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy);
|
||||||
|
|
||||||
|
float vanillaRateSpell(const ESM::Spell* spell, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy);
|
||||||
|
float vanillaRateWeaponAndAmmo(const MWWorld::Ptr& weapon, const MWWorld::Ptr& ammo, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy);
|
||||||
|
float vanillaRateFlee(const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy);
|
||||||
|
bool makeFleeDecision(const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy, float antiFleeRating);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -152,7 +152,7 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characte
|
||||||
|
|
||||||
if (dist > 450)
|
if (dist > 450)
|
||||||
actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, true); //Make NPC run
|
actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, true); //Make NPC run
|
||||||
else if (dist < 325) //Have a bit of a dead zone, otherwise npc will constantly flip between running and not when right on the edge of the running threshhold
|
else if (dist < 325) //Have a bit of a dead zone, otherwise npc will constantly flip between running and not when right on the edge of the running threshold
|
||||||
actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, false); //make NPC walk
|
actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, false); //make NPC walk
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -141,6 +141,79 @@ namespace MWMechanics
|
||||||
return selectedSpells;
|
return selectedSpells;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> autoCalcPlayerSpells(const int* actorSkills, const int* actorAttributes, const ESM::Race* race)
|
||||||
|
{
|
||||||
|
const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore();
|
||||||
|
|
||||||
|
static const float fPCbaseMagickaMult = esmStore.get<ESM::GameSetting>().find("fPCbaseMagickaMult")->getFloat();
|
||||||
|
|
||||||
|
float baseMagicka = fPCbaseMagickaMult * actorAttributes[ESM::Attribute::Intelligence];
|
||||||
|
bool reachedLimit = false;
|
||||||
|
const ESM::Spell* weakestSpell = NULL;
|
||||||
|
int minCost = INT_MAX;
|
||||||
|
|
||||||
|
std::vector<std::string> selectedSpells;
|
||||||
|
|
||||||
|
|
||||||
|
const MWWorld::Store<ESM::Spell> &spells =
|
||||||
|
esmStore.get<ESM::Spell>();
|
||||||
|
for (MWWorld::Store<ESM::Spell>::iterator iter = spells.begin(); iter != spells.end(); ++iter)
|
||||||
|
{
|
||||||
|
const ESM::Spell* spell = &*iter;
|
||||||
|
|
||||||
|
if (spell->mData.mType != ESM::Spell::ST_Spell)
|
||||||
|
continue;
|
||||||
|
if (!(spell->mData.mFlags & ESM::Spell::F_PCStart))
|
||||||
|
continue;
|
||||||
|
if (reachedLimit && spell->mData.mCost <= minCost)
|
||||||
|
continue;
|
||||||
|
if (race && std::find(race->mPowers.mList.begin(), race->mPowers.mList.end(), spell->mId) != race->mPowers.mList.end())
|
||||||
|
continue;
|
||||||
|
if (baseMagicka < spell->mData.mCost)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
static const float fAutoPCSpellChance = esmStore.get<ESM::GameSetting>().find("fAutoPCSpellChance")->getFloat();
|
||||||
|
if (calcAutoCastChance(spell, actorSkills, actorAttributes, -1) < fAutoPCSpellChance)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!attrSkillCheck(spell, actorSkills, actorAttributes))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
selectedSpells.push_back(spell->mId);
|
||||||
|
|
||||||
|
if (reachedLimit)
|
||||||
|
{
|
||||||
|
std::vector<std::string>::iterator it = std::find(selectedSpells.begin(), selectedSpells.end(), weakestSpell->mId);
|
||||||
|
if (it != selectedSpells.end())
|
||||||
|
selectedSpells.erase(it);
|
||||||
|
|
||||||
|
minCost = INT_MAX;
|
||||||
|
for (std::vector<std::string>::iterator weakIt = selectedSpells.begin(); weakIt != selectedSpells.end(); ++weakIt)
|
||||||
|
{
|
||||||
|
const ESM::Spell* testSpell = esmStore.get<ESM::Spell>().find(*weakIt);
|
||||||
|
if (testSpell->mData.mCost < minCost)
|
||||||
|
{
|
||||||
|
minCost = testSpell->mData.mCost;
|
||||||
|
weakestSpell = testSpell;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (spell->mData.mCost < minCost)
|
||||||
|
{
|
||||||
|
weakestSpell = spell;
|
||||||
|
minCost = weakestSpell->mData.mCost;
|
||||||
|
}
|
||||||
|
static const unsigned int iAutoPCSpellMax = esmStore.get<ESM::GameSetting>().find("iAutoPCSpellMax")->getInt();
|
||||||
|
if (selectedSpells.size() == iAutoPCSpellMax)
|
||||||
|
reachedLimit = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return selectedSpells;
|
||||||
|
}
|
||||||
|
|
||||||
bool attrSkillCheck (const ESM::Spell* spell, const int* actorSkills, const int* actorAttributes)
|
bool attrSkillCheck (const ESM::Spell* spell, const int* actorSkills, const int* actorAttributes)
|
||||||
{
|
{
|
||||||
const std::vector<ESM::ENAMstruct>& effects = spell->mEffects.mList;
|
const std::vector<ESM::ENAMstruct>& effects = spell->mEffects.mList;
|
||||||
|
|
|
@ -16,6 +16,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
std::vector<std::string> autoCalcNpcSpells(const int* actorSkills, const int* actorAttributes, const ESM::Race* race);
|
std::vector<std::string> autoCalcNpcSpells(const int* actorSkills, const int* actorAttributes, const ESM::Race* race);
|
||||||
|
|
||||||
|
std::vector<std::string> autoCalcPlayerSpells(const int* actorSkills, const int* actorAttributes, const ESM::Race* race);
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
|
|
||||||
bool attrSkillCheck (const ESM::Spell* spell, const int* actorSkills, const int* actorAttributes);
|
bool attrSkillCheck (const ESM::Spell* spell, const int* actorSkills, const int* actorAttributes);
|
||||||
|
|
|
@ -1049,6 +1049,9 @@ bool CharacterController::updateCreatureState()
|
||||||
mUpperBodyState = UpperCharState_StartToMinAttack;
|
mUpperBodyState = UpperCharState_StartToMinAttack;
|
||||||
|
|
||||||
mAttackStrength = std::min(1.f, 0.1f + Misc::Rng::rollClosedProbability());
|
mAttackStrength = std::min(1.f, 0.1f + Misc::Rng::rollClosedProbability());
|
||||||
|
|
||||||
|
if (weapType == WeapType_HandToHand)
|
||||||
|
playSwishSound(0.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1370,13 +1373,7 @@ bool CharacterController::updateWeaponState()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::string sound = "SwishM";
|
playSwishSound(attackStrength);
|
||||||
if(attackStrength < 0.5f)
|
|
||||||
sndMgr->playSound3D(mPtr, sound, 1.0f, 0.8f); //Weak attack
|
|
||||||
else if(attackStrength < 1.0f)
|
|
||||||
sndMgr->playSound3D(mPtr, sound, 1.0f, 1.0f); //Medium attack
|
|
||||||
else
|
|
||||||
sndMgr->playSound3D(mPtr, sound, 1.0f, 1.2f); //Strong attack
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mAttackStrength = attackStrength;
|
mAttackStrength = attackStrength;
|
||||||
|
@ -2271,6 +2268,19 @@ void CharacterController::setHeadTrackTarget(const MWWorld::ConstPtr &target)
|
||||||
mHeadTrackTarget = target;
|
mHeadTrackTarget = target;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CharacterController::playSwishSound(float attackStrength)
|
||||||
|
{
|
||||||
|
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
||||||
|
|
||||||
|
std::string sound = "Weapon Swish";
|
||||||
|
if(attackStrength < 0.5f)
|
||||||
|
sndMgr->playSound3D(mPtr, sound, 1.0f, 0.8f); //Weak attack
|
||||||
|
else if(attackStrength < 1.0f)
|
||||||
|
sndMgr->playSound3D(mPtr, sound, 1.0f, 1.0f); //Medium attack
|
||||||
|
else
|
||||||
|
sndMgr->playSound3D(mPtr, sound, 1.0f, 1.2f); //Strong attack
|
||||||
|
}
|
||||||
|
|
||||||
void CharacterController::updateHeadTracking(float duration)
|
void CharacterController::updateHeadTracking(float duration)
|
||||||
{
|
{
|
||||||
const osg::Node* head = mAnimation->getNode("Bip01 Head");
|
const osg::Node* head = mAnimation->getNode("Bip01 Head");
|
||||||
|
|
|
@ -281,6 +281,8 @@ public:
|
||||||
|
|
||||||
/// Make this character turn its head towards \a target. To turn off head tracking, pass an empty Ptr.
|
/// Make this character turn its head towards \a target. To turn off head tracking, pass an empty Ptr.
|
||||||
void setHeadTrackTarget(const MWWorld::ConstPtr& target);
|
void setHeadTrackTarget(const MWWorld::ConstPtr& target);
|
||||||
|
|
||||||
|
void playSwishSound(float attackStrength);
|
||||||
};
|
};
|
||||||
|
|
||||||
MWWorld::ContainerStoreIterator getActiveWeapon(CreatureStats &stats, MWWorld::InventoryStore &inv, WeaponType *weaptype);
|
MWWorld::ContainerStoreIterator getActiveWeapon(CreatureStats &stats, MWWorld::InventoryStore &inv, WeaponType *weaptype);
|
||||||
|
|
|
@ -431,4 +431,19 @@ namespace MWMechanics
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float getFightDistanceBias(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2)
|
||||||
|
{
|
||||||
|
osg::Vec3f pos1 (actor1.getRefData().getPosition().asVec3());
|
||||||
|
osg::Vec3f pos2 (actor2.getRefData().getPosition().asVec3());
|
||||||
|
|
||||||
|
float d = (pos1 - pos2).length();
|
||||||
|
|
||||||
|
static const int iFightDistanceBase = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
|
||||||
|
"iFightDistanceBase")->getInt();
|
||||||
|
static const float fFightDistanceMultiplier = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
|
||||||
|
"fFightDistanceMultiplier")->getFloat();
|
||||||
|
|
||||||
|
return (iFightDistanceBase - fFightDistanceMultiplier * d);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,7 @@ void applyFatigueLoss(const MWWorld::Ptr& attacker, const MWWorld::Ptr& weapon,
|
||||||
/// e.g. If attacker is a fish, is victim in water? Or, if attacker can't swim, is victim on land?
|
/// e.g. If attacker is a fish, is victim in water? Or, if attacker can't swim, is victim on land?
|
||||||
bool isEnvironmentCompatible(const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim);
|
bool isEnvironmentCompatible(const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim);
|
||||||
|
|
||||||
|
float getFightDistanceBias(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -25,25 +25,11 @@
|
||||||
#include "autocalcspell.hpp"
|
#include "autocalcspell.hpp"
|
||||||
#include "npcstats.hpp"
|
#include "npcstats.hpp"
|
||||||
#include "actorutil.hpp"
|
#include "actorutil.hpp"
|
||||||
|
#include "combat.hpp"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
float getFightDistanceBias(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2)
|
|
||||||
{
|
|
||||||
osg::Vec3f pos1 (actor1.getRefData().getPosition().asVec3());
|
|
||||||
osg::Vec3f pos2 (actor2.getRefData().getPosition().asVec3());
|
|
||||||
|
|
||||||
float d = (pos1 - pos2).length();
|
|
||||||
|
|
||||||
static const int iFightDistanceBase = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
|
|
||||||
"iFightDistanceBase")->getInt();
|
|
||||||
static const float fFightDistanceMultiplier = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
|
|
||||||
"fFightDistanceMultiplier")->getFloat();
|
|
||||||
|
|
||||||
return (iFightDistanceBase - fFightDistanceMultiplier * d);
|
|
||||||
}
|
|
||||||
|
|
||||||
float getFightDispositionBias(float disposition)
|
float getFightDispositionBias(float disposition)
|
||||||
{
|
{
|
||||||
static const float fFightDispMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
|
static const float fFightDispMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
|
||||||
|
@ -212,15 +198,6 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
|
|
||||||
// F_PCStart spells
|
// F_PCStart spells
|
||||||
static const float fPCbaseMagickaMult = esmStore.get<ESM::GameSetting>().find("fPCbaseMagickaMult")->getFloat();
|
|
||||||
|
|
||||||
float baseMagicka = fPCbaseMagickaMult * creatureStats.getAttribute(ESM::Attribute::Intelligence).getBase();
|
|
||||||
bool reachedLimit = false;
|
|
||||||
const ESM::Spell* weakestSpell = NULL;
|
|
||||||
int minCost = INT_MAX;
|
|
||||||
|
|
||||||
std::vector<std::string> selectedSpells;
|
|
||||||
|
|
||||||
const ESM::Race* race = NULL;
|
const ESM::Race* race = NULL;
|
||||||
if (mRaceSelected)
|
if (mRaceSelected)
|
||||||
race = esmStore.get<ESM::Race>().find(player->mRace);
|
race = esmStore.get<ESM::Race>().find(player->mRace);
|
||||||
|
@ -233,61 +210,7 @@ namespace MWMechanics
|
||||||
for (int i=0; i<ESM::Attribute::Length; ++i)
|
for (int i=0; i<ESM::Attribute::Length; ++i)
|
||||||
attributes[i] = npcStats.getAttribute(i).getBase();
|
attributes[i] = npcStats.getAttribute(i).getBase();
|
||||||
|
|
||||||
const MWWorld::Store<ESM::Spell> &spells =
|
std::vector<std::string> selectedSpells = autoCalcPlayerSpells(skills, attributes, race);
|
||||||
esmStore.get<ESM::Spell>();
|
|
||||||
for (MWWorld::Store<ESM::Spell>::iterator iter = spells.begin(); iter != spells.end(); ++iter)
|
|
||||||
{
|
|
||||||
const ESM::Spell* spell = &*iter;
|
|
||||||
|
|
||||||
if (spell->mData.mType != ESM::Spell::ST_Spell)
|
|
||||||
continue;
|
|
||||||
if (!(spell->mData.mFlags & ESM::Spell::F_PCStart))
|
|
||||||
continue;
|
|
||||||
if (reachedLimit && spell->mData.mCost <= minCost)
|
|
||||||
continue;
|
|
||||||
if (race && std::find(race->mPowers.mList.begin(), race->mPowers.mList.end(), spell->mId) != race->mPowers.mList.end())
|
|
||||||
continue;
|
|
||||||
if (baseMagicka < spell->mData.mCost)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
static const float fAutoPCSpellChance = esmStore.get<ESM::GameSetting>().find("fAutoPCSpellChance")->getFloat();
|
|
||||||
if (calcAutoCastChance(spell, skills, attributes, -1) < fAutoPCSpellChance)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!attrSkillCheck(spell, skills, attributes))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
selectedSpells.push_back(spell->mId);
|
|
||||||
|
|
||||||
if (reachedLimit)
|
|
||||||
{
|
|
||||||
std::vector<std::string>::iterator it = std::find(selectedSpells.begin(), selectedSpells.end(), weakestSpell->mId);
|
|
||||||
if (it != selectedSpells.end())
|
|
||||||
selectedSpells.erase(it);
|
|
||||||
|
|
||||||
minCost = INT_MAX;
|
|
||||||
for (std::vector<std::string>::iterator weakIt = selectedSpells.begin(); weakIt != selectedSpells.end(); ++weakIt)
|
|
||||||
{
|
|
||||||
const ESM::Spell* testSpell = esmStore.get<ESM::Spell>().find(*weakIt);
|
|
||||||
if (testSpell->mData.mCost < minCost)
|
|
||||||
{
|
|
||||||
minCost = testSpell->mData.mCost;
|
|
||||||
weakestSpell = testSpell;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (spell->mData.mCost < minCost)
|
|
||||||
{
|
|
||||||
weakestSpell = spell;
|
|
||||||
minCost = weakestSpell->mData.mCost;
|
|
||||||
}
|
|
||||||
static const unsigned int iAutoPCSpellMax = esmStore.get<ESM::GameSetting>().find("iAutoPCSpellMax")->getInt();
|
|
||||||
if (selectedSpells.size() == iAutoPCSpellMax)
|
|
||||||
reachedLimit = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (std::vector<std::string>::iterator it = selectedSpells.begin(); it != selectedSpells.end(); ++it)
|
for (std::vector<std::string>::iterator it = selectedSpells.begin(); it != selectedSpells.end(); ++it)
|
||||||
creatureStats.getSpells().add(*it);
|
creatureStats.getSpells().add(*it);
|
||||||
|
@ -313,7 +236,7 @@ namespace MWMechanics
|
||||||
: mWatchedTimeToStartDrowning(0), mWatchedStatsEmpty (true), mUpdatePlayer (true), mClassSelected (false),
|
: mWatchedTimeToStartDrowning(0), mWatchedStatsEmpty (true), mUpdatePlayer (true), mClassSelected (false),
|
||||||
mRaceSelected (false), mAI(true)
|
mRaceSelected (false), mAI(true)
|
||||||
{
|
{
|
||||||
//buildPlayer no longer here, needs to be done explicitely after all subsystems are up and running
|
//buildPlayer no longer here, needs to be done explicitly after all subsystems are up and running
|
||||||
}
|
}
|
||||||
|
|
||||||
void MechanicsManager::add(const MWWorld::Ptr& ptr)
|
void MechanicsManager::add(const MWWorld::Ptr& ptr)
|
||||||
|
@ -1608,27 +1531,23 @@ namespace MWMechanics
|
||||||
player->restoreSkillsAttributes();
|
player->restoreSkillsAttributes();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Equipped items other than WerewolfRobe may reference bones that do not even
|
|
||||||
// exist with the werewolf object root, so make sure to unequip all items
|
|
||||||
// *before* we become a werewolf.
|
|
||||||
MWWorld::InventoryStore& invStore = actor.getClass().getInventoryStore(actor);
|
|
||||||
invStore.unequipAll(actor);
|
|
||||||
|
|
||||||
// Werewolfs can not cast spells, so we need to unset the prepared spell if there is one.
|
// Werewolfs can not cast spells, so we need to unset the prepared spell if there is one.
|
||||||
if (npcStats.getDrawState() == MWMechanics::DrawState_Spell)
|
if (npcStats.getDrawState() == MWMechanics::DrawState_Spell)
|
||||||
npcStats.setDrawState(MWMechanics::DrawState_Nothing);
|
npcStats.setDrawState(MWMechanics::DrawState_Nothing);
|
||||||
|
|
||||||
npcStats.setWerewolf(werewolf);
|
npcStats.setWerewolf(werewolf);
|
||||||
|
|
||||||
|
MWWorld::InventoryStore &inv = actor.getClass().getInventoryStore(actor);
|
||||||
|
|
||||||
if(werewolf)
|
if(werewolf)
|
||||||
{
|
{
|
||||||
MWWorld::InventoryStore &inv = actor.getClass().getInventoryStore(actor);
|
inv.unequipAll(actor);
|
||||||
|
|
||||||
inv.equip(MWWorld::InventoryStore::Slot_Robe, inv.ContainerStore::add("werewolfrobe", 1, actor), actor);
|
inv.equip(MWWorld::InventoryStore::Slot_Robe, inv.ContainerStore::add("werewolfrobe", 1, actor), actor);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
actor.getClass().getContainerStore(actor).remove("werewolfrobe", 1, actor);
|
inv.unequipSlot(MWWorld::InventoryStore::Slot_Robe, actor);
|
||||||
|
inv.ContainerStore::remove("werewolfrobe", 1, actor);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(actor == player->getPlayer())
|
if(actor == player->getPlayer())
|
||||||
|
|
|
@ -19,7 +19,7 @@ namespace MWMechanics
|
||||||
bool proximityToDoor(const MWWorld::Ptr& actor,
|
bool proximityToDoor(const MWWorld::Ptr& actor,
|
||||||
float minSqr = MIN_DIST_TO_DOOR_SQUARED);
|
float minSqr = MIN_DIST_TO_DOOR_SQUARED);
|
||||||
|
|
||||||
/// Returns door pointer within range. No guarentee is given as too which one
|
/// Returns door pointer within range. No guarantee is given as to which one
|
||||||
/** \return Pointer to the door, or NULL if none exists **/
|
/** \return Pointer to the door, or NULL if none exists **/
|
||||||
MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor,
|
MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor,
|
||||||
float minSqr = MIN_DIST_TO_DOOR_SQUARED);
|
float minSqr = MIN_DIST_TO_DOOR_SQUARED);
|
||||||
|
|
|
@ -223,7 +223,7 @@ namespace MWMechanics
|
||||||
return 1 - resistance / 100.f;
|
return 1 - resistance / 100.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if the given affect can be applied to the target. If \a castByPlayer, emits a message box on failure.
|
/// Check if the given effect can be applied to the target. If \a castByPlayer, emits a message box on failure.
|
||||||
bool checkEffectTarget (int effectId, const MWWorld::Ptr& target, const MWWorld::Ptr& caster, bool castByPlayer)
|
bool checkEffectTarget (int effectId, const MWWorld::Ptr& target, const MWWorld::Ptr& caster, bool castByPlayer)
|
||||||
{
|
{
|
||||||
switch (effectId)
|
switch (effectId)
|
||||||
|
@ -491,7 +491,7 @@ namespace MWMechanics
|
||||||
appliedLastingEffects.push_back(effect);
|
appliedLastingEffects.push_back(effect);
|
||||||
|
|
||||||
// For absorb effects, also apply the effect to the caster - but with a negative
|
// For absorb effects, also apply the effect to the caster - but with a negative
|
||||||
// magnitude, since we're transfering stats from the target to the caster
|
// magnitude, since we're transferring stats from the target to the caster
|
||||||
if (!caster.isEmpty() && caster.getClass().isActor())
|
if (!caster.isEmpty() && caster.getClass().isActor())
|
||||||
{
|
{
|
||||||
for (int i=0; i<5; ++i)
|
for (int i=0; i<5; ++i)
|
||||||
|
@ -913,7 +913,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(mCaster);
|
MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(mCaster);
|
||||||
|
|
||||||
if (mCaster.getClass().isActor()) // TODO: Non-actors should also create a spell cast vfx
|
if (animation && mCaster.getClass().isActor()) // TODO: Non-actors should also create a spell cast vfx even if they are disabled (animation == NULL)
|
||||||
{
|
{
|
||||||
const ESM::Static* castStatic;
|
const ESM::Static* castStatic;
|
||||||
|
|
||||||
|
@ -927,7 +927,7 @@ namespace MWMechanics
|
||||||
animation->addEffect("meshes\\" + castStatic->mModel, effect->mIndex, false, "", texture);
|
animation->addEffect("meshes\\" + castStatic->mModel, effect->mIndex, false, "", texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mCaster.getClass().isActor())
|
if (animation && !mCaster.getClass().isActor())
|
||||||
animation->addSpellCastGlow(effect);
|
animation->addSpellCastGlow(effect);
|
||||||
|
|
||||||
static const std::string schools[] = {
|
static const std::string schools[] = {
|
||||||
|
@ -980,8 +980,10 @@ namespace MWMechanics
|
||||||
if (charge == 0)
|
if (charge == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// FIXME: charge should be a float, not int so that damage < 1 per frame can be applied.
|
// Store remainder of disintegrate amount (automatically subtracted if > 1)
|
||||||
// This was also a bug in the original engine.
|
item->getCellRef().applyChargeRemainderToBeSubtracted(disintegrate - std::floor(disintegrate));
|
||||||
|
|
||||||
|
charge = item->getClass().getItemHealth(*item);
|
||||||
charge -=
|
charge -=
|
||||||
std::min(static_cast<int>(disintegrate),
|
std::min(static_cast<int>(disintegrate),
|
||||||
charge);
|
charge);
|
||||||
|
@ -1009,10 +1011,10 @@ namespace MWMechanics
|
||||||
creatureStats.setDynamic(index, stat);
|
creatureStats.setDynamic(index, stat);
|
||||||
}
|
}
|
||||||
|
|
||||||
void effectTick(CreatureStats& creatureStats, const MWWorld::Ptr& actor, const EffectKey &effectKey, float magnitude)
|
bool effectTick(CreatureStats& creatureStats, const MWWorld::Ptr& actor, const EffectKey &effectKey, float magnitude)
|
||||||
{
|
{
|
||||||
if (magnitude == 0.f)
|
if (magnitude == 0.f)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
bool receivedMagicDamage = false;
|
bool receivedMagicDamage = false;
|
||||||
|
|
||||||
|
@ -1144,10 +1146,13 @@ namespace MWMechanics
|
||||||
case ESM::MagicEffect::RemoveCurse:
|
case ESM::MagicEffect::RemoveCurse:
|
||||||
actor.getClass().getCreatureStats(actor).getSpells().purgeCurses();
|
actor.getClass().getCreatureStats(actor).getSpells().purgeCurses();
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (receivedMagicDamage && actor == getPlayer())
|
if (receivedMagicDamage && actor == getPlayer())
|
||||||
MWBase::Environment::get().getWindowManager()->activateHitOverlay(false);
|
MWBase::Environment::get().getWindowManager()->activateHitOverlay(false);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,9 +59,13 @@ namespace MWMechanics
|
||||||
float getEffectMultiplier(short effectId, const MWWorld::Ptr& actor, const MWWorld::Ptr& caster,
|
float getEffectMultiplier(short effectId, const MWWorld::Ptr& actor, const MWWorld::Ptr& caster,
|
||||||
const ESM::Spell* spell = NULL, const MagicEffects* effects = NULL);
|
const ESM::Spell* spell = NULL, const MagicEffects* effects = NULL);
|
||||||
|
|
||||||
|
bool checkEffectTarget (int effectId, const MWWorld::Ptr& target, const MWWorld::Ptr& caster, bool castByPlayer);
|
||||||
|
|
||||||
int getEffectiveEnchantmentCastCost (float castCost, const MWWorld::Ptr& actor);
|
int getEffectiveEnchantmentCastCost (float castCost, const MWWorld::Ptr& actor);
|
||||||
|
|
||||||
void effectTick(CreatureStats& creatureStats, const MWWorld::Ptr& actor, const MWMechanics::EffectKey& effectKey, float magnitude);
|
/// Apply a magic effect that is applied in tick intervals until its remaining time ends or it is removed
|
||||||
|
/// @return Was the effect a tickable effect with a magnitude?
|
||||||
|
bool effectTick(CreatureStats& creatureStats, const MWWorld::Ptr& actor, const MWMechanics::EffectKey& effectKey, float magnitude);
|
||||||
|
|
||||||
class CastSpell
|
class CastSpell
|
||||||
{
|
{
|
||||||
|
|
|
@ -69,7 +69,14 @@ namespace MWPhysics
|
||||||
return osg::RadiansToDegrees(std::acos(normal * osg::Vec3f(0.f, 0.f, 1.f)));
|
return osg::RadiansToDegrees(std::acos(normal * osg::Vec3f(0.f, 0.f, 1.f)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool stepMove(const btCollisionObject *colobj, osg::Vec3f &position,
|
enum StepMoveResult
|
||||||
|
{
|
||||||
|
Result_Blocked, // unable to move over obstacle
|
||||||
|
Result_MaxSlope, // unable to end movement on this slope
|
||||||
|
Result_Success
|
||||||
|
};
|
||||||
|
|
||||||
|
static StepMoveResult stepMove(const btCollisionObject *colobj, osg::Vec3f &position,
|
||||||
const osg::Vec3f &toMove, float &remainingTime, const btCollisionWorld* collisionWorld)
|
const osg::Vec3f &toMove, float &remainingTime, const btCollisionWorld* collisionWorld)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -120,7 +127,7 @@ namespace MWPhysics
|
||||||
|
|
||||||
stepper.doTrace(colobj, position, position+osg::Vec3f(0.0f,0.0f,sStepSizeUp), collisionWorld);
|
stepper.doTrace(colobj, position, position+osg::Vec3f(0.0f,0.0f,sStepSizeUp), collisionWorld);
|
||||||
if(stepper.mFraction < std::numeric_limits<float>::epsilon())
|
if(stepper.mFraction < std::numeric_limits<float>::epsilon())
|
||||||
return false; // didn't even move the smallest representable amount
|
return Result_Blocked; // didn't even move the smallest representable amount
|
||||||
// (TODO: shouldn't this be larger? Why bother with such a small amount?)
|
// (TODO: shouldn't this be larger? Why bother with such a small amount?)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -138,7 +145,7 @@ namespace MWPhysics
|
||||||
*/
|
*/
|
||||||
tracer.doTrace(colobj, stepper.mEndPos, stepper.mEndPos + toMove, collisionWorld);
|
tracer.doTrace(colobj, stepper.mEndPos, stepper.mEndPos + toMove, collisionWorld);
|
||||||
if(tracer.mFraction < std::numeric_limits<float>::epsilon())
|
if(tracer.mFraction < std::numeric_limits<float>::epsilon())
|
||||||
return false; // didn't even move the smallest representable amount
|
return Result_Blocked; // didn't even move the smallest representable amount
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Try moving back down sStepSizeDown using stepper.
|
* Try moving back down sStepSizeDown using stepper.
|
||||||
|
@ -156,22 +163,22 @@ namespace MWPhysics
|
||||||
* ==============================================
|
* ==============================================
|
||||||
*/
|
*/
|
||||||
stepper.doTrace(colobj, tracer.mEndPos, tracer.mEndPos-osg::Vec3f(0.0f,0.0f,sStepSizeDown), collisionWorld);
|
stepper.doTrace(colobj, tracer.mEndPos, tracer.mEndPos-osg::Vec3f(0.0f,0.0f,sStepSizeDown), collisionWorld);
|
||||||
if(stepper.mFraction < 1.0f && getSlope(stepper.mPlaneNormal) <= sMaxSlope)
|
if (getSlope(stepper.mPlaneNormal) > sMaxSlope)
|
||||||
|
return Result_MaxSlope;
|
||||||
|
if(stepper.mFraction < 1.0f)
|
||||||
{
|
{
|
||||||
// don't allow stepping up other actors
|
// don't allow stepping up other actors
|
||||||
if (stepper.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Actor)
|
if (stepper.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Actor)
|
||||||
return false;
|
return Result_Blocked;
|
||||||
// only step down onto semi-horizontal surfaces. don't step down onto the side of a house or a wall.
|
// only step down onto semi-horizontal surfaces. don't step down onto the side of a house or a wall.
|
||||||
// TODO: stepper.mPlaneNormal does not appear to be reliable - needs more testing
|
// TODO: stepper.mPlaneNormal does not appear to be reliable - needs more testing
|
||||||
// NOTE: caller's variables 'position' & 'remainingTime' are modified here
|
// NOTE: caller's variables 'position' & 'remainingTime' are modified here
|
||||||
position = stepper.mEndPos;
|
position = stepper.mEndPos;
|
||||||
remainingTime *= (1.0f-tracer.mFraction); // remaining time is proportional to remaining distance
|
remainingTime *= (1.0f-tracer.mFraction); // remaining time is proportional to remaining distance
|
||||||
return true;
|
return Result_Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
// moved between 0 and just under sStepSize distance but slope was too great,
|
return Result_Blocked;
|
||||||
// or moved full sStepSize distance (FIXME: is this a bug?)
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -361,14 +368,15 @@ namespace MWPhysics
|
||||||
osg::Vec3f oldPosition = newPosition;
|
osg::Vec3f oldPosition = newPosition;
|
||||||
// We hit something. Try to step up onto it. (NOTE: stepMove does not allow stepping over)
|
// We hit something. Try to step up onto it. (NOTE: stepMove does not allow stepping over)
|
||||||
// NOTE: stepMove modifies newPosition if successful
|
// NOTE: stepMove modifies newPosition if successful
|
||||||
bool result = stepMove(colobj, newPosition, velocity*remainingTime, remainingTime, collisionWorld);
|
const float minStep = 10.f;
|
||||||
if (!result) // to make sure the maximum stepping distance isn't framerate-dependent or movement-speed dependent
|
StepMoveResult result = stepMove(colobj, newPosition, velocity*remainingTime, remainingTime, collisionWorld);
|
||||||
|
if (result == Result_MaxSlope && (velocity*remainingTime).length() < minStep) // to make sure the maximum stepping distance isn't framerate-dependent or movement-speed dependent
|
||||||
{
|
{
|
||||||
osg::Vec3f normalizedVelocity = velocity;
|
osg::Vec3f normalizedVelocity = velocity;
|
||||||
normalizedVelocity.normalize();
|
normalizedVelocity.normalize();
|
||||||
result = stepMove(colobj, newPosition, normalizedVelocity*10.f, remainingTime, collisionWorld);
|
result = stepMove(colobj, newPosition, normalizedVelocity*minStep, remainingTime, collisionWorld);
|
||||||
}
|
}
|
||||||
if(result)
|
if(result == Result_Success)
|
||||||
{
|
{
|
||||||
// don't let pure water creatures move out of water after stepMove
|
// don't let pure water creatures move out of water after stepMove
|
||||||
if (ptr.getClass().isPureWaterCreature(ptr)
|
if (ptr.getClass().isPureWaterCreature(ptr)
|
||||||
|
@ -450,8 +458,8 @@ namespace MWPhysics
|
||||||
if (inertia.z() < 0)
|
if (inertia.z() < 0)
|
||||||
inertia.z() *= slowFall;
|
inertia.z() *= slowFall;
|
||||||
if (slowFall < 1.f) {
|
if (slowFall < 1.f) {
|
||||||
inertia.x() = 0;
|
inertia.x() *= slowFall;
|
||||||
inertia.y() = 0;
|
inertia.y() *= slowFall;
|
||||||
}
|
}
|
||||||
physicActor->setInertialForce(inertia);
|
physicActor->setInertialForce(inertia);
|
||||||
}
|
}
|
||||||
|
@ -985,6 +993,18 @@ namespace MWPhysics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PhysicsSystem::canMoveToWaterSurface(const MWWorld::ConstPtr &actor, const float waterlevel)
|
||||||
|
{
|
||||||
|
const Actor* physicActor = getActor(actor);
|
||||||
|
const float halfZ = physicActor->getHalfExtents().z();
|
||||||
|
const osg::Vec3f actorPosition = physicActor->getPosition();
|
||||||
|
const osg::Vec3f startingPosition(actorPosition.x(), actorPosition.y(), actorPosition.z() + halfZ);
|
||||||
|
const osg::Vec3f destinationPosition(actorPosition.x(), actorPosition.y(), waterlevel + halfZ);
|
||||||
|
ActorTracer tracer;
|
||||||
|
tracer.doTrace(physicActor->getCollisionObject(), startingPosition, destinationPosition, mCollisionWorld);
|
||||||
|
return (tracer.mFraction >= 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
osg::Vec3f PhysicsSystem::getHalfExtents(const MWWorld::ConstPtr &actor) const
|
osg::Vec3f PhysicsSystem::getHalfExtents(const MWWorld::ConstPtr &actor) const
|
||||||
{
|
{
|
||||||
const Actor* physactor = getActor(actor);
|
const Actor* physactor = getActor(actor);
|
||||||
|
@ -1309,25 +1329,29 @@ namespace MWPhysics
|
||||||
PtrVelocityList::iterator iter = mMovementQueue.begin();
|
PtrVelocityList::iterator iter = mMovementQueue.begin();
|
||||||
for(;iter != mMovementQueue.end();++iter)
|
for(;iter != mMovementQueue.end();++iter)
|
||||||
{
|
{
|
||||||
|
ActorMap::iterator foundActor = mActors.find(iter->first);
|
||||||
|
if (foundActor == mActors.end()) // actor was already removed from the scene
|
||||||
|
continue;
|
||||||
|
Actor* physicActor = foundActor->second;
|
||||||
|
|
||||||
float waterlevel = -std::numeric_limits<float>::max();
|
float waterlevel = -std::numeric_limits<float>::max();
|
||||||
const MWWorld::CellStore *cell = iter->first.getCell();
|
const MWWorld::CellStore *cell = iter->first.getCell();
|
||||||
if(cell->getCell()->hasWater())
|
if(cell->getCell()->hasWater())
|
||||||
waterlevel = cell->getWaterLevel();
|
waterlevel = cell->getWaterLevel();
|
||||||
|
|
||||||
|
|
||||||
const MWMechanics::MagicEffects& effects = iter->first.getClass().getCreatureStats(iter->first).getMagicEffects();
|
const MWMechanics::MagicEffects& effects = iter->first.getClass().getCreatureStats(iter->first).getMagicEffects();
|
||||||
|
|
||||||
bool waterCollision = false;
|
bool waterCollision = false;
|
||||||
if (effects.get(ESM::MagicEffect::WaterWalking).getMagnitude()
|
if (cell->getCell()->hasWater() && effects.get(ESM::MagicEffect::WaterWalking).getMagnitude())
|
||||||
&& cell->getCell()->hasWater()
|
{
|
||||||
&& !world->isUnderwater(iter->first.getCell(),
|
if (!world->isUnderwater(iter->first.getCell(), osg::Vec3f(iter->first.getRefData().getPosition().asVec3())))
|
||||||
osg::Vec3f(iter->first.getRefData().getPosition().asVec3())))
|
waterCollision = true;
|
||||||
waterCollision = true;
|
else if (physicActor->getCollisionMode() && canMoveToWaterSurface(iter->first, waterlevel))
|
||||||
|
{
|
||||||
ActorMap::iterator foundActor = mActors.find(iter->first);
|
const osg::Vec3f actorPosition = physicActor->getPosition();
|
||||||
if (foundActor == mActors.end()) // actor was already removed from the scene
|
physicActor->setPosition(osg::Vec3f(actorPosition.x(), actorPosition.y(), waterlevel));
|
||||||
continue;
|
}
|
||||||
Actor* physicActor = foundActor->second;
|
}
|
||||||
physicActor->setCanWaterWalk(waterCollision);
|
physicActor->setCanWaterWalk(waterCollision);
|
||||||
|
|
||||||
// Slow fall reduces fall speed by a factor of (effect magnitude / 200)
|
// Slow fall reduces fall speed by a factor of (effect magnitude / 200)
|
||||||
|
|
|
@ -123,6 +123,8 @@ namespace MWPhysics
|
||||||
|
|
||||||
bool isOnGround (const MWWorld::Ptr& actor);
|
bool isOnGround (const MWWorld::Ptr& actor);
|
||||||
|
|
||||||
|
bool canMoveToWaterSurface (const MWWorld::ConstPtr &actor, const float waterlevel);
|
||||||
|
|
||||||
/// Get physical half extents (scaled) of the given actor.
|
/// Get physical half extents (scaled) of the given actor.
|
||||||
osg::Vec3f getHalfExtents(const MWWorld::ConstPtr& actor) const;
|
osg::Vec3f getHalfExtents(const MWWorld::ConstPtr& actor) const;
|
||||||
|
|
||||||
|
|
|
@ -686,9 +686,9 @@ namespace MWRender
|
||||||
state.mAutoDisable = autodisable;
|
state.mAutoDisable = autodisable;
|
||||||
mStates[groupname] = state;
|
mStates[groupname] = state;
|
||||||
|
|
||||||
NifOsg::TextKeyMap::const_iterator textkey(textkeys.lower_bound(state.getTime()));
|
|
||||||
if (state.mPlaying)
|
if (state.mPlaying)
|
||||||
{
|
{
|
||||||
|
NifOsg::TextKeyMap::const_iterator textkey(textkeys.lower_bound(state.getTime()));
|
||||||
while(textkey != textkeys.end() && textkey->first <= state.getTime())
|
while(textkey != textkeys.end() && textkey->first <= state.getTime())
|
||||||
{
|
{
|
||||||
handleTextKey(state, groupname, textkey, textkeys);
|
handleTextKey(state, groupname, textkey, textkeys);
|
||||||
|
@ -976,14 +976,14 @@ namespace MWRender
|
||||||
|
|
||||||
while(!(velocity > 1.0f) && ++animiter != mAnimSources.rend())
|
while(!(velocity > 1.0f) && ++animiter != mAnimSources.rend())
|
||||||
{
|
{
|
||||||
const NifOsg::TextKeyMap &keys = (*animiter)->getTextKeys();
|
const NifOsg::TextKeyMap &keys2 = (*animiter)->getTextKeys();
|
||||||
|
|
||||||
const AnimSource::ControllerMap& ctrls2 = (*animiter)->mControllerMap[0];
|
const AnimSource::ControllerMap& ctrls2 = (*animiter)->mControllerMap[0];
|
||||||
for (AnimSource::ControllerMap::const_iterator it = ctrls2.begin(); it != ctrls2.end(); ++it)
|
for (AnimSource::ControllerMap::const_iterator it = ctrls2.begin(); it != ctrls2.end(); ++it)
|
||||||
{
|
{
|
||||||
if (Misc::StringUtils::ciEqual(it->first, mAccumRoot->getName()))
|
if (Misc::StringUtils::ciEqual(it->first, mAccumRoot->getName()))
|
||||||
{
|
{
|
||||||
velocity = calcAnimVelocity(keys, it->second, mAccumulate, groupname);
|
velocity = calcAnimVelocity(keys2, it->second, mAccumulate, groupname);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -302,7 +302,7 @@ protected:
|
||||||
|
|
||||||
/** Sets the root model of the object.
|
/** Sets the root model of the object.
|
||||||
*
|
*
|
||||||
* Note that you must make sure all animation sources are cleared before reseting the object
|
* Note that you must make sure all animation sources are cleared before resetting the object
|
||||||
* root. All nodes previously retrieved with getNode will also become invalidated.
|
* root. All nodes previously retrieved with getNode will also become invalidated.
|
||||||
* @param forceskeleton Wrap the object root in a Skeleton, even if it contains no skinned parts. Use this if you intend to add skinned parts manually.
|
* @param forceskeleton Wrap the object root in a Skeleton, even if it contains no skinned parts. Use this if you intend to add skinned parts manually.
|
||||||
* @param baseonly If true, then any meshes or particle systems in the model are ignored
|
* @param baseonly If true, then any meshes or particle systems in the model are ignored
|
||||||
|
|
|
@ -221,10 +221,10 @@ namespace MWRender
|
||||||
groupname = "inventoryhandtohand";
|
groupname = "inventoryhandtohand";
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const std::string &type = iter->getTypeName();
|
const std::string &typeName = iter->getTypeName();
|
||||||
if(type == typeid(ESM::Lockpick).name() || type == typeid(ESM::Probe).name())
|
if(typeName == typeid(ESM::Lockpick).name() || typeName == typeid(ESM::Probe).name())
|
||||||
groupname = "inventoryweapononehand";
|
groupname = "inventoryweapononehand";
|
||||||
else if(type == typeid(ESM::Weapon).name())
|
else if(typeName == typeid(ESM::Weapon).name())
|
||||||
{
|
{
|
||||||
MWWorld::LiveCellRef<ESM::Weapon> *ref = iter->get<ESM::Weapon>();
|
MWWorld::LiveCellRef<ESM::Weapon> *ref = iter->get<ESM::Weapon>();
|
||||||
|
|
||||||
|
|
|
@ -403,6 +403,9 @@ void NpcAnimation::rebuild()
|
||||||
{
|
{
|
||||||
updateNpcBase();
|
updateNpcBase();
|
||||||
|
|
||||||
|
if (mAlpha != 1.f)
|
||||||
|
mResourceSystem->getSceneManager()->recreateShaders(mObjectRoot);
|
||||||
|
|
||||||
MWBase::Environment::get().getMechanicsManager()->forceStateUpdate(mPtr);
|
MWBase::Environment::get().getMechanicsManager()->forceStateUpdate(mPtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -503,10 +506,10 @@ void NpcAnimation::updateNpcBase()
|
||||||
|
|
||||||
if(!isWerewolf)
|
if(!isWerewolf)
|
||||||
{
|
{
|
||||||
if(Misc::StringUtils::lowerCase(mNpc->mRace).find("argonian") != std::string::npos)
|
|
||||||
addAnimSource("meshes\\xargonian_swimkna.nif");
|
|
||||||
if(mNpc->mModel.length() > 0)
|
if(mNpc->mModel.length() > 0)
|
||||||
addAnimSource(Misc::ResourceHelpers::correctActorModelPath("meshes\\" + mNpc->mModel, mResourceSystem->getVFS()));
|
addAnimSource(Misc::ResourceHelpers::correctActorModelPath("meshes\\" + mNpc->mModel, mResourceSystem->getVFS()));
|
||||||
|
if(Misc::StringUtils::lowerCase(mNpc->mRace).find("argonian") != std::string::npos)
|
||||||
|
addAnimSource("meshes\\xargonian_swimkna.nif");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -458,9 +458,9 @@ namespace MWRender
|
||||||
{
|
{
|
||||||
mEffectManager->update(dt);
|
mEffectManager->update(dt);
|
||||||
mSky->update(dt);
|
mSky->update(dt);
|
||||||
|
mWater->update(dt);
|
||||||
}
|
}
|
||||||
|
|
||||||
mWater->update(dt);
|
|
||||||
mCamera->update(dt, paused);
|
mCamera->update(dt, paused);
|
||||||
|
|
||||||
osg::Vec3f focal, cameraPos;
|
osg::Vec3f focal, cameraPos;
|
||||||
|
|
|
@ -39,11 +39,11 @@ namespace
|
||||||
{
|
{
|
||||||
std::ostringstream texname;
|
std::ostringstream texname;
|
||||||
texname << "textures/water/" << tex << std::setw(2) << std::setfill('0') << i << ".dds";
|
texname << "textures/water/" << tex << std::setw(2) << std::setfill('0') << i << ".dds";
|
||||||
osg::ref_ptr<osg::Texture2D> tex (new osg::Texture2D(resourceSystem->getImageManager()->getImage(texname.str())));
|
osg::ref_ptr<osg::Texture2D> tex2 (new osg::Texture2D(resourceSystem->getImageManager()->getImage(texname.str())));
|
||||||
tex->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
|
tex2->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
|
||||||
tex->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
|
tex2->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
|
||||||
resourceSystem->getSceneManager()->applyFilterSettings(tex);
|
resourceSystem->getSceneManager()->applyFilterSettings(tex2);
|
||||||
textures.push_back(tex);
|
textures.push_back(tex2);
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::ref_ptr<NifOsg::FlipController> controller (new NifOsg::FlipController(0, 0.3f/rippleFrameCount, textures));
|
osg::ref_ptr<NifOsg::FlipController> controller (new NifOsg::FlipController(0, 0.3f/rippleFrameCount, textures));
|
||||||
|
@ -117,6 +117,7 @@ RippleSimulation::~RippleSimulation()
|
||||||
|
|
||||||
void RippleSimulation::update(float dt)
|
void RippleSimulation::update(float dt)
|
||||||
{
|
{
|
||||||
|
const MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||||
for (std::vector<Emitter>::iterator it=mEmitters.begin(); it !=mEmitters.end(); ++it)
|
for (std::vector<Emitter>::iterator it=mEmitters.begin(); it !=mEmitters.end(); ++it)
|
||||||
{
|
{
|
||||||
if (it->mPtr == MWBase::Environment::get().getWorld ()->getPlayerPtr())
|
if (it->mPtr == MWBase::Environment::get().getWorld ()->getPlayerPtr())
|
||||||
|
@ -128,10 +129,8 @@ void RippleSimulation::update(float dt)
|
||||||
|
|
||||||
osg::Vec3f currentPos (it->mPtr.getRefData().getPosition().asVec3());
|
osg::Vec3f currentPos (it->mPtr.getRefData().getPosition().asVec3());
|
||||||
|
|
||||||
if ( (currentPos - it->mLastEmitPosition).length() > 10
|
bool shouldEmit = ( world->isUnderwater (it->mPtr.getCell(), it->mPtr.getRefData().getPosition().asVec3()) && !world->isSubmerged(it->mPtr) ) || world->isWalkingOnWater(it->mPtr);
|
||||||
// Only emit when close to the water surface, not above it and not too deep in the water
|
if ( shouldEmit && (currentPos - it->mLastEmitPosition).length() > 10 )
|
||||||
&& MWBase::Environment::get().getWorld ()->isUnderwater (it->mPtr.getCell(), it->mPtr.getRefData().getPosition().asVec3())
|
|
||||||
&& !MWBase::Environment::get().getWorld()->isSubmerged(it->mPtr))
|
|
||||||
{
|
{
|
||||||
it->mLastEmitPosition = currentPos;
|
it->mLastEmitPosition = currentPos;
|
||||||
|
|
||||||
|
|
|
@ -1329,7 +1329,7 @@ void SkyManager::createRain()
|
||||||
mRainParticleSystem = new osgParticle::ParticleSystem;
|
mRainParticleSystem = new osgParticle::ParticleSystem;
|
||||||
mRainParticleSystem->setParticleAlignment(osgParticle::ParticleSystem::FIXED);
|
mRainParticleSystem->setParticleAlignment(osgParticle::ParticleSystem::FIXED);
|
||||||
mRainParticleSystem->setAlignVectorX(osg::Vec3f(0.1,0,0));
|
mRainParticleSystem->setAlignVectorX(osg::Vec3f(0.1,0,0));
|
||||||
mRainParticleSystem->setAlignVectorY(osg::Vec3f(0,0,-1));
|
mRainParticleSystem->setAlignVectorY(osg::Vec3f(0,0,1));
|
||||||
|
|
||||||
osg::ref_ptr<osg::StateSet> stateset (mRainParticleSystem->getOrCreateStateSet());
|
osg::ref_ptr<osg::StateSet> stateset (mRainParticleSystem->getOrCreateStateSet());
|
||||||
|
|
||||||
|
|
|
@ -238,15 +238,15 @@ namespace MWScript
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char type = declarations.getType (iter->first);
|
char type = declarations.getType (iter->first);
|
||||||
char index = declarations.getIndex (iter->first);
|
int index2 = declarations.getIndex (iter->first);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case 's': mShorts.at (index) = iter->second.getInteger(); break;
|
case 's': mShorts.at (index2) = iter->second.getInteger(); break;
|
||||||
case 'l': mLongs.at (index) = iter->second.getInteger(); break;
|
case 'l': mLongs.at (index2) = iter->second.getInteger(); break;
|
||||||
case 'f': mFloats.at (index) = iter->second.getFloat(); break;
|
case 'f': mFloats.at (index2) = iter->second.getFloat(); break;
|
||||||
|
|
||||||
// silently ignore locals that don't exist anymore
|
// silently ignore locals that don't exist anymore
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,8 +34,9 @@
|
||||||
|
|
||||||
namespace MWSound
|
namespace MWSound
|
||||||
{
|
{
|
||||||
SoundManager::SoundManager(const VFS::Manager* vfs, bool useSound)
|
SoundManager::SoundManager(const VFS::Manager* vfs, const std::map<std::string,std::string>& fallbackMap, bool useSound)
|
||||||
: mVFS(vfs)
|
: mVFS(vfs)
|
||||||
|
, mFallback(fallbackMap)
|
||||||
, mOutput(new DEFAULT_OUTPUT(*this))
|
, mOutput(new DEFAULT_OUTPUT(*this))
|
||||||
, mMasterVolume(1.0f)
|
, mMasterVolume(1.0f)
|
||||||
, mSFXVolume(1.0f)
|
, mSFXVolume(1.0f)
|
||||||
|
@ -61,6 +62,13 @@ namespace MWSound
|
||||||
mFootstepsVolume = Settings::Manager::getFloat("footsteps volume", "Sound");
|
mFootstepsVolume = Settings::Manager::getFloat("footsteps volume", "Sound");
|
||||||
mFootstepsVolume = std::min(std::max(mFootstepsVolume, 0.0f), 1.0f);
|
mFootstepsVolume = std::min(std::max(mFootstepsVolume, 0.0f), 1.0f);
|
||||||
|
|
||||||
|
mNearWaterRadius = mFallback.getFallbackInt("Water_NearWaterRadius");
|
||||||
|
mNearWaterPoints = mFallback.getFallbackInt("Water_NearWaterPoints");
|
||||||
|
mNearWaterIndoorTolerance = mFallback.getFallbackFloat("Water_NearWaterIndoorTolerance");
|
||||||
|
mNearWaterOutdoorTolerance = mFallback.getFallbackFloat("Water_NearWaterOutdoorTolerance");
|
||||||
|
mNearWaterIndoorID = mFallback.getFallbackString("Water_NearWaterIndoorID");
|
||||||
|
mNearWaterOutdoorID = mFallback.getFallbackString("Water_NearWaterOutdoorID");
|
||||||
|
|
||||||
mBufferCacheMin = std::max(Settings::Manager::getInt("buffer cache min", "Sound"), 1);
|
mBufferCacheMin = std::max(Settings::Manager::getInt("buffer cache min", "Sound"), 1);
|
||||||
mBufferCacheMax = std::max(Settings::Manager::getInt("buffer cache max", "Sound"), 1);
|
mBufferCacheMax = std::max(Settings::Manager::getInt("buffer cache max", "Sound"), 1);
|
||||||
mBufferCacheMax *= 1024*1024;
|
mBufferCacheMax *= 1024*1024;
|
||||||
|
@ -796,6 +804,96 @@ namespace MWSound
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SoundManager::updateWaterSound(float /*duration*/)
|
||||||
|
{
|
||||||
|
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||||
|
const MWWorld::ConstPtr player = world->getPlayerPtr();
|
||||||
|
osg::Vec3f pos = player.getRefData().getPosition().asVec3();
|
||||||
|
|
||||||
|
float volume = 0.0f;
|
||||||
|
const std::string& soundId = player.getCell()->isExterior() ? mNearWaterOutdoorID : mNearWaterIndoorID;
|
||||||
|
|
||||||
|
if (!mListenerUnderwater)
|
||||||
|
{
|
||||||
|
if (player.getCell()->getCell()->hasWater())
|
||||||
|
{
|
||||||
|
float dist = std::abs(player.getCell()->getWaterLevel() - pos.z());
|
||||||
|
|
||||||
|
if (player.getCell()->isExterior() && dist < mNearWaterOutdoorTolerance)
|
||||||
|
{
|
||||||
|
volume = (mNearWaterOutdoorTolerance - dist) / mNearWaterOutdoorTolerance;
|
||||||
|
|
||||||
|
if (mNearWaterPoints > 1)
|
||||||
|
{
|
||||||
|
int underwaterPoints = 0;
|
||||||
|
|
||||||
|
float step = mNearWaterRadius * 2.0f / (mNearWaterPoints - 1);
|
||||||
|
|
||||||
|
for (int x = 0; x < mNearWaterPoints; x++)
|
||||||
|
{
|
||||||
|
for (int y = 0; y < mNearWaterPoints; y++)
|
||||||
|
{
|
||||||
|
float height = world->getTerrainHeightAt(
|
||||||
|
osg::Vec3f(pos.x() - mNearWaterRadius + x*step, pos.y() - mNearWaterRadius + y*step, 0.0f));
|
||||||
|
|
||||||
|
if (height < 0)
|
||||||
|
underwaterPoints++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
volume *= underwaterPoints * 2.0f / (mNearWaterPoints*mNearWaterPoints);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!player.getCell()->isExterior() && dist < mNearWaterIndoorTolerance)
|
||||||
|
{
|
||||||
|
volume = (mNearWaterIndoorTolerance - dist) / mNearWaterIndoorTolerance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
volume = 1.0f;
|
||||||
|
|
||||||
|
volume = std::min(volume, 1.0f);
|
||||||
|
|
||||||
|
if (mNearWaterSound)
|
||||||
|
{
|
||||||
|
if (volume == 0.0f)
|
||||||
|
{
|
||||||
|
mOutput->finishSound(mNearWaterSound);
|
||||||
|
mNearWaterSound.reset();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bool soundIdChanged = false;
|
||||||
|
|
||||||
|
Sound_Buffer* sfx = lookupSound(Misc::StringUtils::lowerCase(soundId));
|
||||||
|
|
||||||
|
for (SoundMap::const_iterator snditer = mActiveSounds.begin(); snditer != mActiveSounds.end(); ++snditer)
|
||||||
|
{
|
||||||
|
for (SoundBufferRefPairList::const_iterator pairiter = snditer->second.begin(); pairiter != snditer->second.end(); ++pairiter)
|
||||||
|
{
|
||||||
|
if (pairiter->first == mNearWaterSound)
|
||||||
|
{
|
||||||
|
if (pairiter->second != sfx)
|
||||||
|
soundIdChanged = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (soundIdChanged)
|
||||||
|
{
|
||||||
|
mOutput->finishSound(mNearWaterSound);
|
||||||
|
mNearWaterSound = playSound(soundId, volume, 1.0f, Play_TypeSfx, Play_Loop);
|
||||||
|
}
|
||||||
|
else if (sfx)
|
||||||
|
mNearWaterSound->setVolume(volume * sfx->mVolume);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (volume > 0.0f)
|
||||||
|
mNearWaterSound = playSound(soundId, volume, 1.0f, Play_TypeSfx, Play_Loop);
|
||||||
|
}
|
||||||
|
|
||||||
void SoundManager::updateSounds(float duration)
|
void SoundManager::updateSounds(float duration)
|
||||||
{
|
{
|
||||||
static float timePassed = 0.0;
|
static float timePassed = 0.0;
|
||||||
|
@ -941,6 +1039,7 @@ namespace MWSound
|
||||||
{
|
{
|
||||||
updateSounds(duration);
|
updateSounds(duration);
|
||||||
updateRegionSound(duration);
|
updateRegionSound(duration);
|
||||||
|
updateWaterSound(duration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1105,6 +1204,7 @@ namespace MWSound
|
||||||
mOutput->finishStream(*trkiter);
|
mOutput->finishStream(*trkiter);
|
||||||
mActiveTracks.clear();
|
mActiveTracks.clear();
|
||||||
mUnderwaterSound.reset();
|
mUnderwaterSound.reset();
|
||||||
|
mNearWaterSound.reset();
|
||||||
stopMusic();
|
stopMusic();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
|
|
||||||
#include <components/settings/settings.hpp>
|
#include <components/settings/settings.hpp>
|
||||||
|
|
||||||
|
#include <components/fallback/fallback.hpp>
|
||||||
|
|
||||||
#include "../mwbase/soundmanager.hpp"
|
#include "../mwbase/soundmanager.hpp"
|
||||||
|
|
||||||
namespace VFS
|
namespace VFS
|
||||||
|
@ -44,6 +46,8 @@ namespace MWSound
|
||||||
{
|
{
|
||||||
const VFS::Manager* mVFS;
|
const VFS::Manager* mVFS;
|
||||||
|
|
||||||
|
Fallback::Map mFallback;
|
||||||
|
|
||||||
std::auto_ptr<Sound_Output> mOutput;
|
std::auto_ptr<Sound_Output> mOutput;
|
||||||
|
|
||||||
// Caches available music tracks by <playlist name, (sound files) >
|
// Caches available music tracks by <playlist name, (sound files) >
|
||||||
|
@ -56,6 +60,13 @@ namespace MWSound
|
||||||
float mVoiceVolume;
|
float mVoiceVolume;
|
||||||
float mFootstepsVolume;
|
float mFootstepsVolume;
|
||||||
|
|
||||||
|
int mNearWaterRadius;
|
||||||
|
int mNearWaterPoints;
|
||||||
|
float mNearWaterIndoorTolerance;
|
||||||
|
float mNearWaterOutdoorTolerance;
|
||||||
|
std::string mNearWaterIndoorID;
|
||||||
|
std::string mNearWaterOutdoorID;
|
||||||
|
|
||||||
typedef std::auto_ptr<std::deque<Sound_Buffer> > SoundBufferList;
|
typedef std::auto_ptr<std::deque<Sound_Buffer> > SoundBufferList;
|
||||||
// List of sound buffers, grown as needed. New enties are added to the
|
// List of sound buffers, grown as needed. New enties are added to the
|
||||||
// back, allowing existing Sound_Buffer references/pointers to remain
|
// back, allowing existing Sound_Buffer references/pointers to remain
|
||||||
|
@ -94,6 +105,7 @@ namespace MWSound
|
||||||
int mPausedSoundTypes;
|
int mPausedSoundTypes;
|
||||||
|
|
||||||
MWBase::SoundPtr mUnderwaterSound;
|
MWBase::SoundPtr mUnderwaterSound;
|
||||||
|
MWBase::SoundPtr mNearWaterSound;
|
||||||
|
|
||||||
Sound_Buffer *insertSound(const std::string &soundId, const ESM::Sound *sound);
|
Sound_Buffer *insertSound(const std::string &soundId, const ESM::Sound *sound);
|
||||||
|
|
||||||
|
@ -108,6 +120,7 @@ namespace MWSound
|
||||||
void streamMusicFull(const std::string& filename);
|
void streamMusicFull(const std::string& filename);
|
||||||
void updateSounds(float duration);
|
void updateSounds(float duration);
|
||||||
void updateRegionSound(float duration);
|
void updateRegionSound(float duration);
|
||||||
|
void updateWaterSound(float duration);
|
||||||
|
|
||||||
float volumeFromType(PlayType type) const;
|
float volumeFromType(PlayType type) const;
|
||||||
|
|
||||||
|
@ -119,7 +132,7 @@ namespace MWSound
|
||||||
friend class OpenAL_Output;
|
friend class OpenAL_Output;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SoundManager(const VFS::Manager* vfs, bool useSound);
|
SoundManager(const VFS::Manager* vfs, const std::map<std::string, std::string>& fallbackMap, bool useSound);
|
||||||
virtual ~SoundManager();
|
virtual ~SoundManager();
|
||||||
|
|
||||||
virtual void processChangedSettings(const Settings::CategorySettingVector& settings);
|
virtual void processChangedSettings(const Settings::CategorySettingVector& settings);
|
||||||
|
|
|
@ -249,7 +249,8 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
|
||||||
+MWBase::Environment::get().getScriptManager()->getGlobalScripts().countSavedGameRecords()
|
+MWBase::Environment::get().getScriptManager()->getGlobalScripts().countSavedGameRecords()
|
||||||
+MWBase::Environment::get().getDialogueManager()->countSavedGameRecords()
|
+MWBase::Environment::get().getDialogueManager()->countSavedGameRecords()
|
||||||
+MWBase::Environment::get().getWindowManager()->countSavedGameRecords()
|
+MWBase::Environment::get().getWindowManager()->countSavedGameRecords()
|
||||||
+MWBase::Environment::get().getMechanicsManager()->countSavedGameRecords();
|
+MWBase::Environment::get().getMechanicsManager()->countSavedGameRecords()
|
||||||
|
+MWBase::Environment::get().getInputManager()->countSavedGameRecords();
|
||||||
writer.setRecordCount (recordCount);
|
writer.setRecordCount (recordCount);
|
||||||
|
|
||||||
writer.save (stream);
|
writer.save (stream);
|
||||||
|
@ -271,6 +272,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
|
||||||
MWBase::Environment::get().getScriptManager()->getGlobalScripts().write (writer, listener);
|
MWBase::Environment::get().getScriptManager()->getGlobalScripts().write (writer, listener);
|
||||||
MWBase::Environment::get().getWindowManager()->write(writer, listener);
|
MWBase::Environment::get().getWindowManager()->write(writer, listener);
|
||||||
MWBase::Environment::get().getMechanicsManager()->write(writer, listener);
|
MWBase::Environment::get().getMechanicsManager()->write(writer, listener);
|
||||||
|
MWBase::Environment::get().getInputManager()->write(writer, listener);
|
||||||
|
|
||||||
// Ensure we have written the number of records that was estimated
|
// Ensure we have written the number of records that was estimated
|
||||||
if (writer.getRecordCount() != recordCount+1) // 1 extra for TES3 record
|
if (writer.getRecordCount() != recordCount+1) // 1 extra for TES3 record
|
||||||
|
@ -462,6 +464,10 @@ void MWState::StateManager::loadGame (const Character *character, const std::str
|
||||||
MWBase::Environment::get().getMechanicsManager()->readRecord(reader, n.intval);
|
MWBase::Environment::get().getMechanicsManager()->readRecord(reader, n.intval);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ESM::REC_INPU:
|
||||||
|
MWBase::Environment::get().getInputManager()->readRecord(reader, n.intval);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
||||||
// ignore invalid records
|
// ignore invalid records
|
||||||
|
|
|
@ -93,6 +93,24 @@ namespace MWWorld
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CellRef::applyChargeRemainderToBeSubtracted(float chargeRemainder)
|
||||||
|
{
|
||||||
|
mCellRef.mChargeIntRemainder += std::abs(chargeRemainder);
|
||||||
|
if (mCellRef.mChargeIntRemainder > 1.0f)
|
||||||
|
{
|
||||||
|
float newChargeRemainder = (mCellRef.mChargeIntRemainder - std::floor(mCellRef.mChargeIntRemainder));
|
||||||
|
if (mCellRef.mChargeInt <= static_cast<int>(mCellRef.mChargeIntRemainder))
|
||||||
|
{
|
||||||
|
mCellRef.mChargeInt = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mCellRef.mChargeInt -= static_cast<int>(mCellRef.mChargeIntRemainder);
|
||||||
|
}
|
||||||
|
mCellRef.mChargeIntRemainder = newChargeRemainder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
float CellRef::getChargeFloat() const
|
float CellRef::getChargeFloat() const
|
||||||
{
|
{
|
||||||
return mCellRef.mChargeFloat;
|
return mCellRef.mChargeFloat;
|
||||||
|
|
|
@ -65,6 +65,7 @@ namespace MWWorld
|
||||||
float getChargeFloat() const; // Implemented as union with int charge
|
float getChargeFloat() const; // Implemented as union with int charge
|
||||||
void setCharge(int charge);
|
void setCharge(int charge);
|
||||||
void setChargeFloat(float charge);
|
void setChargeFloat(float charge);
|
||||||
|
void applyChargeRemainderToBeSubtracted(float chargeRemainder); // Stores remainders and applies if > 1
|
||||||
|
|
||||||
// The NPC that owns this object (and will get angry if you steal it)
|
// The NPC that owns this object (and will get angry if you steal it)
|
||||||
std::string getOwner() const;
|
std::string getOwner() const;
|
||||||
|
|
|
@ -204,6 +204,14 @@ namespace MWWorld
|
||||||
return (ref.mRef.mRefnum == pRefnum);
|
return (ref.mRef.mRefnum == pRefnum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ptr CellStore::getCurrentPtr(LiveCellRefBase *ref)
|
||||||
|
{
|
||||||
|
MovedRefTracker::iterator found = mMovedToAnotherCell.find(ref);
|
||||||
|
if (found != mMovedToAnotherCell.end())
|
||||||
|
return Ptr(ref, found->second);
|
||||||
|
return Ptr(ref, this);
|
||||||
|
}
|
||||||
|
|
||||||
void CellStore::moveFrom(const Ptr &object, CellStore *from)
|
void CellStore::moveFrom(const Ptr &object, CellStore *from)
|
||||||
{
|
{
|
||||||
if (mState != State_Loaded)
|
if (mState != State_Loaded)
|
||||||
|
@ -964,26 +972,26 @@ namespace MWWorld
|
||||||
mLastRespawn = MWBase::Environment::get().getWorld()->getTimeStamp();
|
mLastRespawn = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||||
for (CellRefList<ESM::Container>::List::iterator it (mContainers.mList.begin()); it!=mContainers.mList.end(); ++it)
|
for (CellRefList<ESM::Container>::List::iterator it (mContainers.mList.begin()); it!=mContainers.mList.end(); ++it)
|
||||||
{
|
{
|
||||||
Ptr ptr (&*it, this);
|
Ptr ptr = getCurrentPtr(&*it);
|
||||||
ptr.getClass().respawn(ptr);
|
ptr.getClass().respawn(ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (CellRefList<ESM::Creature>::List::iterator it (mCreatures.mList.begin()); it!=mCreatures.mList.end(); ++it)
|
for (CellRefList<ESM::Creature>::List::iterator it (mCreatures.mList.begin()); it!=mCreatures.mList.end(); ++it)
|
||||||
{
|
{
|
||||||
Ptr ptr (&*it, this);
|
Ptr ptr = getCurrentPtr(&*it);
|
||||||
clearCorpse(ptr);
|
clearCorpse(ptr);
|
||||||
ptr.getClass().respawn(ptr);
|
ptr.getClass().respawn(ptr);
|
||||||
}
|
}
|
||||||
for (CellRefList<ESM::NPC>::List::iterator it (mNpcs.mList.begin()); it!=mNpcs.mList.end(); ++it)
|
for (CellRefList<ESM::NPC>::List::iterator it (mNpcs.mList.begin()); it!=mNpcs.mList.end(); ++it)
|
||||||
{
|
{
|
||||||
Ptr ptr (&*it, this);
|
Ptr ptr = getCurrentPtr(&*it);
|
||||||
clearCorpse(ptr);
|
clearCorpse(ptr);
|
||||||
ptr.getClass().respawn(ptr);
|
ptr.getClass().respawn(ptr);
|
||||||
}
|
}
|
||||||
for (CellRefList<ESM::CreatureLevList>::List::iterator it (mCreatureLists.mList.begin()); it!=mCreatureLists.mList.end(); ++it)
|
for (CellRefList<ESM::CreatureLevList>::List::iterator it (mCreatureLists.mList.begin()); it!=mCreatureLists.mList.end(); ++it)
|
||||||
{
|
{
|
||||||
Ptr ptr (&*it, this);
|
Ptr ptr = getCurrentPtr(&*it);
|
||||||
// no need to clearCorpse, handled as part of mCreatures
|
// no need to clearCorpse, handled as part of mCreatures
|
||||||
ptr.getClass().respawn(ptr);
|
ptr.getClass().respawn(ptr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,6 +111,9 @@ namespace MWWorld
|
||||||
// Merged list of ref's currently in this cell - i.e. with added refs from mMovedHere, removed refs from mMovedToAnotherCell
|
// Merged list of ref's currently in this cell - i.e. with added refs from mMovedHere, removed refs from mMovedToAnotherCell
|
||||||
std::vector<LiveCellRefBase*> mMergedRefs;
|
std::vector<LiveCellRefBase*> mMergedRefs;
|
||||||
|
|
||||||
|
// Get the Ptr for the given ref which originated from this cell (possibly moved to another cell at this point).
|
||||||
|
Ptr getCurrentPtr(MWWorld::LiveCellRefBase* ref);
|
||||||
|
|
||||||
/// Moves object from the given cell to this cell.
|
/// Moves object from the given cell to this cell.
|
||||||
void moveFrom(const MWWorld::Ptr& object, MWWorld::CellStore* from);
|
void moveFrom(const MWWorld::Ptr& object, MWWorld::CellStore* from);
|
||||||
|
|
||||||
|
|
|
@ -393,7 +393,26 @@ namespace MWWorld
|
||||||
|
|
||||||
bool Class::isPureWaterCreature(const MWWorld::Ptr& ptr) const
|
bool Class::isPureWaterCreature(const MWWorld::Ptr& ptr) const
|
||||||
{
|
{
|
||||||
return canSwim(ptr) && !canWalk(ptr);
|
return canSwim(ptr)
|
||||||
|
&& !isBipedal(ptr)
|
||||||
|
&& !canFly(ptr)
|
||||||
|
&& !canWalk(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Class::isPureFlyingCreature(const Ptr& ptr) const
|
||||||
|
{
|
||||||
|
return canFly(ptr)
|
||||||
|
&& !isBipedal(ptr)
|
||||||
|
&& !canSwim(ptr)
|
||||||
|
&& !canWalk(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Class::isPureLandCreature(const Ptr& ptr) const
|
||||||
|
{
|
||||||
|
return canWalk(ptr)
|
||||||
|
&& !isBipedal(ptr)
|
||||||
|
&& !canFly(ptr)
|
||||||
|
&& !canSwim(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Class::isMobile(const MWWorld::Ptr& ptr) const
|
bool Class::isMobile(const MWWorld::Ptr& ptr) const
|
||||||
|
|
|
@ -312,6 +312,8 @@ namespace MWWorld
|
||||||
virtual bool canSwim(const MWWorld::ConstPtr& ptr) const;
|
virtual bool canSwim(const MWWorld::ConstPtr& ptr) const;
|
||||||
virtual bool canWalk(const MWWorld::ConstPtr& ptr) const;
|
virtual bool canWalk(const MWWorld::ConstPtr& ptr) const;
|
||||||
bool isPureWaterCreature(const MWWorld::Ptr& ptr) const;
|
bool isPureWaterCreature(const MWWorld::Ptr& ptr) const;
|
||||||
|
bool isPureFlyingCreature(const MWWorld::Ptr& ptr) const;
|
||||||
|
bool isPureLandCreature(const MWWorld::Ptr& ptr) const;
|
||||||
bool isMobile(const MWWorld::Ptr& ptr) const;
|
bool isMobile(const MWWorld::Ptr& ptr) const;
|
||||||
|
|
||||||
virtual int getSkill(const MWWorld::Ptr& ptr, int skill) const;
|
virtual int getSkill(const MWWorld::Ptr& ptr, int skill) const;
|
||||||
|
|
|
@ -553,14 +553,14 @@ void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MW
|
||||||
if(listInMap != allowedForReplace.end())
|
if(listInMap != allowedForReplace.end())
|
||||||
restockNum -= std::min(restockNum, listInMap->second);
|
restockNum -= std::min(restockNum, listInMap->second);
|
||||||
//restock
|
//restock
|
||||||
addInitialItem(itemOrList, owner, restockNum, true);
|
addInitialItem(itemOrList, owner, -restockNum, true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//Restocking static item - just restock to the max count
|
//Restocking static item - just restock to the max count
|
||||||
int currentCount = count(itemOrList);
|
int currentCount = count(itemOrList);
|
||||||
if (currentCount < std::abs(it->mCount))
|
if (currentCount < std::abs(it->mCount))
|
||||||
addInitialItem(itemOrList, owner, std::abs(it->mCount) - currentCount, true);
|
addInitialItem(itemOrList, owner, -(std::abs(it->mCount) - currentCount), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
flagAsModified();
|
flagAsModified();
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <components/esm/loadench.hpp>
|
#include <components/esm/loadench.hpp>
|
||||||
#include <components/esm/inventorystate.hpp>
|
#include <components/esm/inventorystate.hpp>
|
||||||
#include <components/misc/rng.hpp>
|
#include <components/misc/rng.hpp>
|
||||||
|
#include <components/settings/settings.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
@ -214,36 +215,71 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::getSlot (int slot)
|
||||||
return mSlots[slot];
|
return mSlots[slot];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MWWorld::InventoryStore::canActorAutoEquip(const MWWorld::Ptr& actor, const MWWorld::Ptr& item)
|
||||||
|
{
|
||||||
|
if (!Settings::Manager::getBool("prevent merchant equipping", "Game"))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Only autoEquip if we are the original owner of the item.
|
||||||
|
// This stops merchants from auto equipping anything you sell to them.
|
||||||
|
// ...unless this is a companion, he should always equip items given to him.
|
||||||
|
if (!Misc::StringUtils::ciEqual(item.getCellRef().getOwner(), actor.getCellRef().getRefId()) &&
|
||||||
|
(actor.getClass().getScript(actor).empty() ||
|
||||||
|
!actor.getRefData().getLocals().getIntVar(actor.getClass().getScript(actor), "companion"))
|
||||||
|
&& !actor.getClass().getCreatureStats(actor).isDead() // Corpses can be dressed up by the player as desired
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor)
|
void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor)
|
||||||
{
|
{
|
||||||
|
if (!actor.getClass().isNpc())
|
||||||
|
// autoEquip is no-op for creatures
|
||||||
|
return;
|
||||||
|
|
||||||
|
const MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||||
|
const MWWorld::Store<ESM::GameSetting> &store = world->getStore().get<ESM::GameSetting>();
|
||||||
|
MWMechanics::NpcStats& stats = actor.getClass().getNpcStats(actor);
|
||||||
|
|
||||||
|
static float fUnarmoredBase1 = store.find("fUnarmoredBase1")->getFloat();
|
||||||
|
static float fUnarmoredBase2 = store.find("fUnarmoredBase2")->getFloat();
|
||||||
|
int unarmoredSkill = stats.getSkill(ESM::Skill::Unarmored).getModified();
|
||||||
|
|
||||||
|
float unarmoredRating = static_cast<int>((fUnarmoredBase1 * unarmoredSkill) * (fUnarmoredBase2 * unarmoredSkill));
|
||||||
|
|
||||||
TSlots slots_;
|
TSlots slots_;
|
||||||
initSlots (slots_);
|
initSlots (slots_);
|
||||||
|
|
||||||
// Disable model update during auto-equip
|
// Disable model update during auto-equip
|
||||||
mUpdatesEnabled = false;
|
mUpdatesEnabled = false;
|
||||||
|
|
||||||
for (ContainerStoreIterator iter (begin()); iter!=end(); ++iter)
|
// Autoequip clothing, armor and weapons.
|
||||||
|
// Equipping lights is handled in Actors::updateEquippedLight based on environment light.
|
||||||
|
|
||||||
|
for (ContainerStoreIterator iter (begin(ContainerStore::Type_Clothing | ContainerStore::Type_Armor)); iter!=end(); ++iter)
|
||||||
{
|
{
|
||||||
Ptr test = *iter;
|
Ptr test = *iter;
|
||||||
|
|
||||||
// Don't autoEquip lights. Handled in Actors::updateEquippedLight based on environment light.
|
if (!canActorAutoEquip(actor, test))
|
||||||
if (test.getTypeName() == typeid(ESM::Light).name())
|
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
switch(test.getClass().canBeEquipped (test, actor).first)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
continue;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only autoEquip if we are the original owner of the item.
|
if (iter.getType() == ContainerStore::Type_Armor &&
|
||||||
// This stops merchants from auto equipping anything you sell to them.
|
test.getClass().getEffectiveArmorRating(test, actor) <= std::max(unarmoredRating, 0.f))
|
||||||
// ...unless this is a companion, he should always equip items given to him.
|
|
||||||
if (!Misc::StringUtils::ciEqual(test.getCellRef().getOwner(), actor.getCellRef().getRefId()) &&
|
|
||||||
(actor.getClass().getScript(actor).empty() ||
|
|
||||||
!actor.getRefData().getLocals().getIntVar(actor.getClass().getScript(actor), "companion"))
|
|
||||||
&& !actor.getClass().getCreatureStats(actor).isDead() // Corpses can be dressed up by the player as desired
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
int testSkill = test.getClass().getEquipmentSkill (test);
|
|
||||||
|
|
||||||
std::pair<std::vector<int>, bool> itemsSlots =
|
std::pair<std::vector<int>, bool> itemsSlots =
|
||||||
iter->getClass().getEquipmentSlots (*iter);
|
iter->getClass().getEquipmentSlots (*iter);
|
||||||
|
@ -251,49 +287,33 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor)
|
||||||
for (std::vector<int>::const_iterator iter2 (itemsSlots.first.begin());
|
for (std::vector<int>::const_iterator iter2 (itemsSlots.first.begin());
|
||||||
iter2!=itemsSlots.first.end(); ++iter2)
|
iter2!=itemsSlots.first.end(); ++iter2)
|
||||||
{
|
{
|
||||||
if (*iter2 == Slot_CarriedRight) // Items in right hand are situational use, so don't equip them.
|
|
||||||
// Equipping weapons is handled by AiCombat. Anything else (lockpicks, probes) can't be used by NPCs anyway (yet)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (iter.getType() == MWWorld::ContainerStore::Type_Weapon)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (slots_.at (*iter2)!=end())
|
if (slots_.at (*iter2)!=end())
|
||||||
{
|
{
|
||||||
Ptr old = *slots_.at (*iter2);
|
Ptr old = *slots_.at (*iter2);
|
||||||
|
|
||||||
// check skill
|
if (iter.getType() == ContainerStore::Type_Armor)
|
||||||
int oldSkill = old.getClass().getEquipmentSkill (old);
|
|
||||||
|
|
||||||
bool use = false;
|
|
||||||
if (testSkill!=-1 && oldSkill==-1)
|
|
||||||
use = true;
|
|
||||||
else if (testSkill!=-1 && oldSkill!=-1 && testSkill!=oldSkill)
|
|
||||||
{
|
{
|
||||||
if (actor.getClass().getSkill(actor, oldSkill) > actor.getClass().getSkill (actor, testSkill))
|
if (old.getTypeName() == typeid(ESM::Armor).name())
|
||||||
continue; // rejected, because old item better matched the NPC's skills.
|
|
||||||
|
|
||||||
if (actor.getClass().getSkill(actor, oldSkill) < actor.getClass().getSkill (actor, testSkill))
|
|
||||||
use = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!use)
|
|
||||||
{
|
|
||||||
// check value
|
|
||||||
if (old.getClass().getValue (old)>=
|
|
||||||
test.getClass().getValue (test))
|
|
||||||
{
|
{
|
||||||
continue;
|
if (old.getClass().getEffectiveArmorRating(old, actor) >= test.getClass().getEffectiveArmorRating(test, actor))
|
||||||
|
// old armor had better armor rating
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
// suitable armor should replace already equipped clothing
|
||||||
|
}
|
||||||
|
else if (iter.getType() == ContainerStore::Type_Clothing)
|
||||||
|
{
|
||||||
|
if (old.getTypeName() == typeid(ESM::Clothing).name())
|
||||||
|
{
|
||||||
|
// check value
|
||||||
|
if (old.getClass().getValue (old) > test.getClass().getValue (test))
|
||||||
|
// old clothing was more valuable
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
// suitable clothing should NOT replace already equipped armor
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
switch(test.getClass().canBeEquipped (test, actor).first)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
continue;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!itemsSlots.second) // if itemsSlots.second is true, item can stay stacked when equipped
|
if (!itemsSlots.second) // if itemsSlots.second is true, item can stay stacked when equipped
|
||||||
|
@ -310,6 +330,99 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const ESM::Skill::SkillEnum weaponSkills[] =
|
||||||
|
{
|
||||||
|
ESM::Skill::LongBlade,
|
||||||
|
ESM::Skill::Axe,
|
||||||
|
ESM::Skill::Spear,
|
||||||
|
ESM::Skill::ShortBlade,
|
||||||
|
ESM::Skill::Marksman,
|
||||||
|
ESM::Skill::BluntWeapon
|
||||||
|
};
|
||||||
|
const size_t weaponSkillsLength = sizeof(weaponSkills) / sizeof(weaponSkills[0]);
|
||||||
|
|
||||||
|
bool weaponSkillVisited[weaponSkillsLength] = { false };
|
||||||
|
|
||||||
|
for (int i = 0; i < static_cast<int>(weaponSkillsLength); ++i)
|
||||||
|
{
|
||||||
|
int max = 0;
|
||||||
|
int maxWeaponSkill = -1;
|
||||||
|
|
||||||
|
for (int j = 0; j < static_cast<int>(weaponSkillsLength); ++j)
|
||||||
|
{
|
||||||
|
int skillValue = stats.getSkill(static_cast<int>(weaponSkills[j])).getModified();
|
||||||
|
|
||||||
|
if (skillValue > max && !weaponSkillVisited[j])
|
||||||
|
{
|
||||||
|
max = skillValue;
|
||||||
|
maxWeaponSkill = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxWeaponSkill == -1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
max = 0;
|
||||||
|
ContainerStoreIterator weapon(end());
|
||||||
|
|
||||||
|
for (ContainerStoreIterator iter(begin(ContainerStore::Type_Weapon)); iter!=end(); ++iter)
|
||||||
|
{
|
||||||
|
if (!canActorAutoEquip(actor, *iter))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const ESM::Weapon* esmWeapon = iter->get<ESM::Weapon>()->mBase;
|
||||||
|
|
||||||
|
if (esmWeapon->mData.mType == ESM::Weapon::Arrow || esmWeapon->mData.mType == ESM::Weapon::Bolt)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (iter->getClass().getEquipmentSkill(*iter) == weaponSkills[maxWeaponSkill])
|
||||||
|
{
|
||||||
|
if (esmWeapon->mData.mChop[1] >= max)
|
||||||
|
{
|
||||||
|
max = esmWeapon->mData.mChop[1];
|
||||||
|
weapon = iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (esmWeapon->mData.mSlash[1] >= max)
|
||||||
|
{
|
||||||
|
max = esmWeapon->mData.mSlash[1];
|
||||||
|
weapon = iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (esmWeapon->mData.mThrust[1] >= max)
|
||||||
|
{
|
||||||
|
max = esmWeapon->mData.mThrust[1];
|
||||||
|
weapon = iter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (weapon != end() && weapon->getClass().canBeEquipped(*weapon, actor).first)
|
||||||
|
{
|
||||||
|
std::pair<std::vector<int>, bool> itemsSlots =
|
||||||
|
weapon->getClass().getEquipmentSlots (*weapon);
|
||||||
|
|
||||||
|
for (std::vector<int>::const_iterator slot (itemsSlots.first.begin());
|
||||||
|
slot!=itemsSlots.first.end(); ++slot)
|
||||||
|
{
|
||||||
|
if (!itemsSlots.second)
|
||||||
|
{
|
||||||
|
if (weapon->getRefData().getCount() > 1)
|
||||||
|
{
|
||||||
|
unstack(*weapon, actor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
slots_[*slot] = weapon;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
weaponSkillVisited[maxWeaponSkill] = true;
|
||||||
|
}
|
||||||
|
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
|
|
||||||
for (std::size_t i=0; i<slots_.size(); ++i)
|
for (std::size_t i=0; i<slots_.size(); ++i)
|
||||||
|
@ -402,8 +515,8 @@ void MWWorld::InventoryStore::updateMagicEffects(const Ptr& actor)
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find (
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find (
|
||||||
effectIt->mEffectID);
|
effectIt->mEffectID);
|
||||||
|
|
||||||
// Fully resisted?
|
// Fully resisted or can't be applied to target?
|
||||||
if (params[i].mMultiplier == 0)
|
if (params[i].mMultiplier == 0 || !MWMechanics::checkEffectTarget(effectIt->mEffectID, actor, actor, actor == MWMechanics::getPlayer()))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * params[i].mRandom;
|
float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * params[i].mRandom;
|
||||||
|
@ -657,6 +770,9 @@ void MWWorld::InventoryStore::visitEffectSources(MWMechanics::EffectSourceVisito
|
||||||
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt (enchantment.mEffects.mList.begin());
|
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt (enchantment.mEffects.mList.begin());
|
||||||
effectIt!=enchantment.mEffects.mList.end(); ++effectIt)
|
effectIt!=enchantment.mEffects.mList.end(); ++effectIt)
|
||||||
{
|
{
|
||||||
|
// Don't get spell icon display information for enchantments that weren't actually applied
|
||||||
|
if (mMagicEffects.get(MWMechanics::EffectKey(*effectIt)).getMagnitude() == 0)
|
||||||
|
continue;
|
||||||
const EffectParams& params = mPermanentMagicEffectMagnitudes[(**iter).getCellRef().getRefId()][i];
|
const EffectParams& params = mPermanentMagicEffectMagnitudes[(**iter).getCellRef().getRefId()][i];
|
||||||
float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * params.mRandom;
|
float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * params.mRandom;
|
||||||
magnitude *= params.mMultiplier;
|
magnitude *= params.mMultiplier;
|
||||||
|
|
|
@ -115,6 +115,8 @@ namespace MWWorld
|
||||||
virtual void storeEquipmentState (const MWWorld::LiveCellRefBase& ref, int index, ESM::InventoryState& inventory) const;
|
virtual void storeEquipmentState (const MWWorld::LiveCellRefBase& ref, int index, ESM::InventoryState& inventory) const;
|
||||||
virtual void readEquipmentState (const MWWorld::ContainerStoreIterator& iter, int index, const ESM::InventoryState& inventory);
|
virtual void readEquipmentState (const MWWorld::ContainerStoreIterator& iter, int index, const ESM::InventoryState& inventory);
|
||||||
|
|
||||||
|
bool canActorAutoEquip(const MWWorld::Ptr& actor, const MWWorld::Ptr& item);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
InventoryStore();
|
InventoryStore();
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue