1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-16 18:19:55 +00:00

Merge branch 'master' into master

This commit is contained in:
Bret Curtis 2016-12-13 22:07:40 +01:00 committed by GitHub
commit 065bf47e38
126 changed files with 2806 additions and 896 deletions

View file

@ -23,10 +23,12 @@ Programmers
Alexander Olofsson (Ace)
Allofich
AnyOldName3
Aussiemon
Austin Salgat (Salgat)
Artem Kotsynyak (greye)
artemutin
Arthur Moore (EmperorArthur)
Assumeru
athile
Ben Shealy (bentsherman)
Bret Curtis (psi29a)
@ -73,6 +75,7 @@ Programmers
Karl-Felix Glatzer (k1ll)
Kevin Poitra (PuppyKevin)
Koncord
Kurnevsky Evgeny (kurnevsky)
Lars Söderberg (Lazaroth)
lazydev
Leon Saunders (emoose)
@ -119,6 +122,7 @@ Programmers
Scott Howard
Sebastian Wick (swick)
Sergey Shambir
ShadowRadiance
sir_herrbatka
smbas
Stefan Galowicz (bogglez)

View file

@ -1,10 +1,11 @@
#!/bin/sh
brew update
brew rm cmake || true
brew rm pkgconfig || 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
unzip ~/openmw-deps.zip -d /private/tmp/openmw-deps > /dev/null

View file

@ -4,13 +4,12 @@ export CXX=clang++
export CC=clang
DEPENDENCIES_ROOT="/private/tmp/openmw-deps/openmw-deps"
QT_PATH="/usr/local/opt/qt5"
QT_PATH="/usr/local/opt/qt55"
mkdir build
cd build
cmake \
-D CMAKE_EXE_LINKER_FLAGS="-lz" \
-D CMAKE_PREFIX_PATH="$DEPENDENCIES_ROOT;$QT_PATH" \
-D CMAKE_OSX_DEPLOYMENT_TARGET="10.8" \
-D CMAKE_OSX_SYSROOT="macosx10.11" \

View file

@ -96,7 +96,7 @@ endif()
# Set up common paths
if (APPLE)
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)
# Paths
SET(BINDIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Where to install binaries")
@ -286,6 +286,11 @@ endif (APPLE)
# Set up DEBUG define
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/)
# Specify build paths
@ -307,11 +312,15 @@ endif (APPLE)
configure_file(${OpenMW_SOURCE_DIR}/files/settings-default.cfg
"${OpenMW_BINARY_DIR}/settings-default.cfg")
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg.local
"${OpenMW_BINARY_DIR}/openmw.cfg")
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg
"${OpenMW_BINARY_DIR}/openmw.cfg.install")
if (NOT APPLE)
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg.local
"${OpenMW_BINARY_DIR}/openmw.cfg")
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg
"${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
"${OpenMW_BINARY_DIR}/openmw-cs.cfg")
@ -419,8 +428,10 @@ IF(NOT WIN32 AND NOT APPLE)
ENDIF(NOT WIN32 AND NOT APPLE)
if(WIN32)
FILE(GLOB dll_files "${OpenMW_BINARY_DIR}/Release/*.dll")
INSTALL(FILES ${dll_files} DESTINATION ".")
FILE(GLOB dll_files_debug "${OpenMW_BINARY_DIR}/Debug/*.dll")
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_SOURCE_DIR}/CHANGELOG.md" DESTINATION "." RENAME "CHANGELOG.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_BINARY_DIR}/settings-default.cfg"
"${OpenMW_BINARY_DIR}/gamecontrollerdb.txt"
"${OpenMW_BINARY_DIR}/Release/openmw.exe"
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)
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)
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()
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ".")
FILE(GLOB plugin_dir "${OpenMW_BINARY_DIR}/Release/osgPlugins-*")
INSTALL(DIRECTORY ${plugin_dir} DESTINATION ".")
FILE(GLOB plugin_dir_debug "${OpenMW_BINARY_DIR}/Debug/osgPlugins-*")
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_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)
endif ()
set(INSTALL_SUBDIR OpenMW)
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)
install(DIRECTORY "${APP_BUNDLE_DIR}" USE_SOURCE_PERMISSIONS DESTINATION "." COMPONENT Runtime)
set(CPACK_GENERATOR "DragNDrop")
set(CPACK_PACKAGE_VERSION ${OPENMW_VERSION})
@ -740,8 +731,8 @@ if (APPLE)
set(CPACK_PACKAGE_VERSION_MINOR ${OPENMW_VERSION_MINOR})
set(CPACK_PACKAGE_VERSION_PATCH ${OPENMW_VERSION_RELEASE})
set(INSTALLED_OPENMW_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}")
set(INSTALLED_OPENCS_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}")
set(INSTALLED_OPENMW_APP "\${CMAKE_INSTALL_PREFIX}/${APP_BUNDLE_NAME}")
set(INSTALLED_OPENCS_APP "\${CMAKE_INSTALL_PREFIX}/${OPENCS_BUNDLE_NAME}")
install(CODE "
set(BU_CHMOD_BUNDLE_ITEMS ON)
@ -785,8 +776,8 @@ if (APPLE)
set(${plugins_var} ${PLUGINS} PARENT_SCOPE)
endfunction (install_plugins_for_bundle)
install_plugins_for_bundle("${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}" PLUGINS)
install_plugins_for_bundle("${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}" OPENCS_PLUGINS)
install_plugins_for_bundle("${APP_BUNDLE_NAME}" 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(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}
COMMENT "Generating documentation for the github-pages at ${DOXYGEN_PAGES_OUTPUT_DIR}" VERBATIM)
endif ()

View file

@ -42,3 +42,7 @@ if (BUILD_WITH_CODE_COVERAGE)
add_definitions (--coverage)
target_link_libraries(openmw-essimporter gcov)
endif()
if (WIN32)
INSTALL(TARGETS openmw-essimporter RUNTIME DESTINATION ".")
endif(WIN32)

View file

@ -271,23 +271,34 @@ private:
class ConvertPCDT : public Converter
{
public:
ConvertPCDT() : mFirstPersonCam(true) {}
ConvertPCDT()
: mFirstPersonCam(true),
mTeleportingEnabled(true),
mLevitationEnabled(true)
{}
virtual void read(ESM::ESMReader &esm)
{
PCDT pcdt;
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)
{
esm.startRecord(ESM::REC_ENAB);
esm.writeHNT("TELE", mTeleportingEnabled);
esm.writeHNT("LEVT", mLevitationEnabled);
esm.endRecord(ESM::REC_ENAB);
esm.startRecord(ESM::REC_CAM_);
esm.writeHNT("FIRS", mFirstPersonCam);
esm.endRecord(ESM::REC_CAM_);
}
private:
bool mFirstPersonCam;
bool mTeleportingEnabled;
bool mLevitationEnabled;
};
class ConvertCNTC : public Converter

View file

@ -5,7 +5,7 @@
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.mObject.mNpcStats.mBounty = pcdt.mBounty;
@ -25,18 +25,28 @@ namespace ESSImport
out.mObject.mNpcStats.mSkills[i].mProgress = pcdt.mPNAM.mSkillProgress[i];
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;
if (pcdt.mPNAM.mDrawState & PCDT::DrawState_Spell)
if (pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_SpellDrawn)
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();
it != pcdt.mKnownDialogueTopics.end(); ++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;
}
}

View file

@ -4,11 +4,12 @@
#include "importplayer.hpp"
#include <components/esm/player.hpp>
#include <components/esm/controlsstate.hpp>
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);
}

View file

@ -51,6 +51,7 @@ namespace
{
for (int x=0; x<128; ++x)
{
assert(image->data(x,y));
*(image->data(x,y)+2) = *it++;
*(image->data(x,y)+1) = *it++;
*image->data(x,y) = *it++;
@ -422,6 +423,10 @@ namespace ESSImport
writer.startRecord (ESM::REC_DIAS);
context.mDialogueState.save(writer);
writer.endRecord(ESM::REC_DIAS);
writer.startRecord(ESM::REC_INPU);
context.mControlsState.save(writer);
writer.endRecord(ESM::REC_INPU);
}

View file

@ -9,6 +9,7 @@
#include <components/esm/globalmap.hpp>
#include <components/esm/loadcrea.hpp>
#include <components/esm/loadnpc.hpp>
#include <components/esm/controlsstate.hpp>
#include "importnpcc.hpp"
#include "importcrec.hpp"
@ -32,6 +33,8 @@ namespace ESSImport
ESM::DialogueState mDialogueState;
ESM::ControlsState mControlsState;
// cells which should show an explored overlay on the global map
std::set<std::pair<int, int> > mExploredCells;

View file

@ -38,14 +38,20 @@ struct PCDT
std::vector<std::string> mKnownDialogueTopics;
enum DrawState_
enum PlayerFlags
{
DrawState_Weapon = 0x80,
DrawState_Spell = 0x100
};
enum CameraFlags
{
CameraFlag_ThirdPerson = 0x2
PlayerFlags_ViewSwitchDisabled = 0x1,
PlayerFlags_ControlsDisabled = 0x4,
PlayerFlags_WeaponDrawn = 0x80,
PlayerFlags_SpellDrawn = 0x100,
PlayerFlags_JumpingDisabled = 0x1000,
PlayerFlags_LookingDisabled = 0x2000,
PlayerFlags_VanityModeDisabled = 0x4000,
PlayerFlags_WeaponDrawingDisabled = 0x8000,
PlayerFlags_SpellDrawingDisabled = 0x10000,
PlayerFlags_ThirdPerson = 0x20000,
PlayerFlags_TeleportingDisabled = 0x40000,
PlayerFlags_LevitationDisabled = 0x80000
};
#pragma pack(push)
@ -62,8 +68,7 @@ struct PCDT
struct PNAM
{
short mDrawState; // DrawState
short mCameraFlags; // CameraFlags
int mPlayerFlags; // controls, camera and draw state
unsigned int mLevelProgress;
float mSkillProgress[27]; // skill progress, non-uniform scaled
unsigned char mSkillIncreases[8]; // number of skill increases for each attribute

View file

@ -87,6 +87,10 @@ add_executable(openmw-launcher
${UI_HDRS}
)
if (WIN32)
INSTALL(TARGETS openmw-launcher RUNTIME DESTINATION ".")
endif (WIN32)
target_link_libraries(openmw-launcher
${SDL2_LIBRARY_ONLY}
components

View file

@ -35,14 +35,6 @@ int main(int argc, char *argv[])
// Now we make sure the current dir is set to application path
QDir dir(QCoreApplication::applicationDirPath());
#ifdef Q_OS_MAC
if (dir.dirName() == "MacOS") {
dir.cdUp();
dir.cdUp();
dir.cdUp();
}
#endif
QDir::setCurrent(dir.absolutePath());
Launcher::MainDialog mainWin;

View file

@ -293,6 +293,7 @@ bool Launcher::MainDialog::setupGameSettings()
{
mGameSettings.clear();
QString localPath = QString::fromUtf8(mCfgMgr.getLocalPath().string().c_str());
QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().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
QStringList paths;
paths.append(globalPath + QString("openmw.cfg"));
paths.append(QString("openmw.cfg"));
paths.append(localPath + QString("openmw.cfg"));
paths.append(userPath + QString("openmw.cfg"));
foreach (const QString &path, paths) {
qDebug() << "Loading config file:" << path.toUtf8().constData();
foreach (const QString &path2, paths) {
qDebug() << "Loading config file:" << path2.toUtf8().constData();
QFile file(path);
file.setFileName(path2);
if (file.exists()) {
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
cfgError(tr("Error opening OpenMW configuration file"),
@ -346,13 +347,13 @@ bool Launcher::MainDialog::setupGameSettings()
QStringList dataDirs;
// Check if the paths actually contain data files
foreach (const QString path, mGameSettings.getDataDirs()) {
QDir dir(path);
foreach (const QString path3, mGameSettings.getDataDirs()) {
QDir dir(path3);
QStringList filters;
filters << "*.esp" << "*.esm" << "*.omwgame" << "*.omwaddon";
if (!dir.entryList(filters).isEmpty())
dataDirs.append(path);
dataDirs.append(path3);
}
if (dataDirs.isEmpty())

View file

@ -22,7 +22,8 @@ target_link_libraries(openmw-iniimporter
if (WIN32)
target_link_libraries(openmw-iniimporter
${Boost_LOCALE_LIBRARY})
endif()
INSTALL(TARGETS openmw-iniimporter RUNTIME DESTINATION ".")
endif(WIN32)
if (MINGW)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -municode")

View file

@ -162,9 +162,15 @@ endif()
include_directories(${CMAKE_CURRENT_BINARY_DIR})
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()
set (OPENCS_MAC_ICON "")
set (OPENCS_CFG "")
set (OPENCS_DEFAULT_FILTERS_FILE "")
set (OPENCS_OPENMW_CFG "")
endif(APPLE)
add_executable(openmw-cs
@ -174,12 +180,23 @@ add_executable(openmw-cs
${OPENCS_MOC_SRC}
${OPENCS_RES_SRC}
${OPENCS_MAC_ICON}
${OPENCS_CFG}
${OPENCS_DEFAULT_FILTERS_FILE}
${OPENCS_OPENMW_CFG}
)
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
RUNTIME_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}"
OUTPUT_NAME "OpenMW-CS"
OUTPUT_NAME ${OPENCS_BUNDLE_NAME}
MACOSX_BUNDLE_ICON_FILE "openmw-cs.icns"
MACOSX_BUNDLE_BUNDLE_NAME "OpenCS"
MACOSX_BUNDLE_GUI_IDENTIFIER "org.openmw.opencs"
@ -190,6 +207,16 @@ if(APPLE)
set_source_files_properties(${OPENCS_MAC_ICON} PROPERTIES
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)
target_link_libraries(openmw-cs
@ -223,9 +250,18 @@ endif()
if (WIN32)
target_link_libraries(openmw-cs ${Boost_LOCALE_LIBRARY})
INSTALL(TARGETS openmw-cs RUNTIME DESTINATION ".")
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.cfg" DESTINATION ".")
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)
INSTALL(TARGETS openmw-cs BUNDLE DESTINATION OpenMW COMPONENT BUNDLE)
INSTALL(TARGETS openmw-cs BUNDLE DESTINATION "." COMPONENT BUNDLE)
endif()

View file

@ -62,11 +62,6 @@ int main(int argc, char *argv[])
#ifdef Q_OS_MAC
QDir dir(QCoreApplication::applicationDirPath());
if (dir.dirName() == "MacOS") {
dir.cdUp();
dir.cdUp();
dir.cdUp();
}
QDir::setCurrent(dir.absolutePath());
#endif

View file

@ -184,7 +184,7 @@ void CSMTools::MergeLandTexturesStage::perform (int stage, CSMDoc::Messages& mes
CSMWorld::LandTexture texture =
mState.mSource.getData().getLandTextures().getRecord (index).get();
std::ostringstream stream;
stream.clear();
stream << mNext->second-1 << "_0";
texture.mIndex = mNext->second-1;

View file

@ -1627,264 +1627,264 @@ const char * CSMWorld::DefaultGmsts::OptionalStrings[CSMWorld::DefaultGmsts::Opt
const float CSMWorld::DefaultGmsts::FloatsDefaultValues[CSMWorld::DefaultGmsts::FloatCount] =
{
0.3, // fAIFleeFleeMult
7.0, // fAIFleeHealthMult
3.0, // fAIMagicSpellMult
1.0, // fAIMeleeArmorMult
1.0, // fAIMeleeSummWeaponMult
2.0, // fAIMeleeWeaponMult
5.0, // fAIRangeMagicSpellMult
5.0, // fAIRangeMeleeWeaponMult
2000.0, // fAlarmRadius
1.0, // fAthleticsRunBonus
40.0, // fAudioDefaultMaxDistance
5.0, // fAudioDefaultMinDistance
50.0, // fAudioMaxDistanceMult
20.0, // fAudioMinDistanceMult
60.0, // fAudioVoiceDefaultMaxDistance
10.0, // fAudioVoiceDefaultMinDistance
50.0, // fAutoPCSpellChance
80.0, // fAutoSpellChance
50.0, // fBargainOfferBase
-4.0, // fBargainOfferMulti
24.0, // fBarterGoldResetDelay
1.75, // fBaseRunMultiplier
1.25, // fBlockStillBonus
150.0, // fBribe1000Mod
75.0, // fBribe100Mod
35.0, // fBribe10Mod
60.0, // fCombatAngleXY
60.0, // fCombatAngleZ
0.25, // fCombatArmorMinMult
-90.0, // fCombatBlockLeftAngle
30.0, // fCombatBlockRightAngle
4.0, // fCombatCriticalStrikeMult
0.1, // fCombatDelayCreature
0.1, // fCombatDelayNPC
128.0, // fCombatDistance
0.3, // fCombatDistanceWerewolfMod
30.0, // fCombatForceSideAngle
0.2, // fCombatInvisoMult
1.5, // fCombatKODamageMult
45.0, // fCombatTorsoSideAngle
0.3, // fCombatTorsoStartPercent
0.8, // fCombatTorsoStopPercent
15.0, // fConstantEffectMult
72.0, // fCorpseClearDelay
72.0, // fCorpseRespawnDelay
0.5, // fCrimeGoldDiscountMult
0.9, // fCrimeGoldTurnInMult
1.0, // fCrimeStealing
0.5, // fDamageStrengthBase
0.1, // fDamageStrengthMult
5.0, // fDifficultyMult
2.5, // fDiseaseXferChance
-10.0, // fDispAttacking
-1.0, // fDispBargainFailMod
1.0, // fDispBargainSuccessMod
0.0, // fDispCrimeMod
-10.0, // fDispDiseaseMod
3.0, // fDispFactionMod
1.0, // fDispFactionRankBase
0.5, // fDispFactionRankMult
1.0, // fDispositionMod
50.0, // fDispPersonalityBase
0.5, // fDispPersonalityMult
-25.0, // fDispPickPocketMod
5.0, // fDispRaceMod
-0.5, // fDispStealing
-5.0, // fDispWeaponDrawn
0.5, // fEffectCostMult
0.1, // fElementalShieldMult
3.0, // fEnchantmentChanceMult
0.5, // fEnchantmentConstantChanceMult
100.0, // fEnchantmentConstantDurationMult
0.1, // fEnchantmentMult
1000.0, // fEnchantmentValueMult
0.3, // fEncumberedMoveEffect
5.0, // fEncumbranceStrMult
0.04, // fEndFatigueMult
0.25, // fFallAcroBase
0.01, // fFallAcroMult
400.0, // fFallDamageDistanceMin
0.0, // fFallDistanceBase
0.07, // fFallDistanceMult
2.0, // fFatigueAttackBase
0.0, // fFatigueAttackMult
1.25, // fFatigueBase
4.0, // fFatigueBlockBase
0.0, // fFatigueBlockMult
5.0, // fFatigueJumpBase
0.0, // fFatigueJumpMult
0.5, // fFatigueMult
2.5, // fFatigueReturnBase
0.02, // fFatigueReturnMult
5.0, // fFatigueRunBase
2.0, // fFatigueRunMult
1.5, // fFatigueSneakBase
1.5, // fFatigueSneakMult
0.0, // fFatigueSpellBase
0.0, // fFatigueSpellCostMult
0.0, // fFatigueSpellMult
7.0, // fFatigueSwimRunBase
0.0, // fFatigueSwimRunMult
2.5, // fFatigueSwimWalkBase
0.0, // fFatigueSwimWalkMult
0.2, // fFightDispMult
0.005, // fFightDistanceMultiplier
50.0, // fFightStealing
3000.0, // fFleeDistance
512.0, // fGreetDistanceReset
0.1, // fHandtoHandHealthPer
1.0, // fHandToHandReach
0.5, // fHoldBreathEndMult
20.0, // fHoldBreathTime
0.75, // fIdleChanceMultiplier
1.0, // fIngredientMult
0.5, // fInteriorHeadTrackMult
128.0, // fJumpAcrobaticsBase
4.0, // fJumpAcroMultiplier
0.5, // fJumpEncumbranceBase
1.0, // fJumpEncumbranceMultiplier
0.5, // fJumpMoveBase
0.5, // fJumpMoveMult
1.0, // fJumpRunMultiplier
0.5, // fKnockDownMult
5.0, // fLevelMod
0.1, // fLevelUpHealthEndMult
0.6, // fLightMaxMod
10.0, // fLuckMod
10.0, // fMagesGuildTravel
1.5, // fMagicCreatureCastDelay
0.0167, // fMagicDetectRefreshRate
1.0, // fMagicItemConstantMult
1.0, // fMagicItemCostMult
1.0, // fMagicItemOnceMult
1.0, // fMagicItemPriceMult
0.05, // fMagicItemRechargePerSecond
1.0, // fMagicItemStrikeMult
1.0, // fMagicItemUsedMult
3.0, // fMagicStartIconBlink
0.5, // fMagicSunBlockedMult
0.75, // fMajorSkillBonus
300.0, // fMaxFlySpeed
0.5, // fMaxHandToHandMult
400.0, // fMaxHeadTrackDistance
200.0, // fMaxWalkSpeed
300.0, // fMaxWalkSpeedCreature
0.9, // fMedMaxMod
0.1, // fMessageTimePerChar
5.0, // fMinFlySpeed
0.1, // fMinHandToHandMult
1.0, // fMinorSkillBonus
100.0, // fMinWalkSpeed
5.0, // fMinWalkSpeedCreature
1.25, // fMiscSkillBonus
2.0, // fNPCbaseMagickaMult
0.5, // fNPCHealthBarFade
3.0, // fNPCHealthBarTime
1.0, // fPCbaseMagickaMult
0.3, // fPerDieRollMult
5.0, // fPersonalityMod
1.0, // fPerTempMult
-1.0, // fPickLockMult
0.3, // fPickPocketMod
20.0, // fPotionMinUsefulDuration
0.5, // fPotionStrengthMult
0.5, // fPotionT1DurMult
1.5, // fPotionT1MagMult
20.0, // fPotionT4BaseStrengthMult
12.0, // fPotionT4EquipStrengthMult
3000.0, // fProjectileMaxSpeed
400.0, // fProjectileMinSpeed
25.0, // fProjectileThrownStoreChance
3.0, // fRepairAmountMult
1.0, // fRepairMult
1.0, // fReputationMod
0.15, // fRestMagicMult
0.0, // fSeriousWoundMult
0.25, // fSleepRandMod
0.3, // fSleepRestMod
-1.0, // fSneakBootMult
0.5, // fSneakDistanceBase
0.002, // fSneakDistanceMultiplier
0.5, // fSneakNoViewMult
1.0, // fSneakSkillMult
0.75, // fSneakSpeedMultiplier
1.0, // fSneakUseDelay
500.0, // fSneakUseDist
1.5, // fSneakViewMult
3.0, // fSoulGemMult
0.8, // fSpecialSkillBonus
7.0, // fSpellMakingValueMult
2.0, // fSpellPriceMult
10.0, // fSpellValueMult
0.25, // fStromWalkMult
0.7, // fStromWindSpeed
3.0, // fSuffocationDamage
0.9, // fSwimHeightScale
0.1, // fSwimRunAthleticsMult
0.5, // fSwimRunBase
0.02, // fSwimWalkAthleticsMult
0.5, // fSwimWalkBase
1.0, // fSwingBlockBase
1.0, // fSwingBlockMult
1000.0, // fTargetSpellMaxSpeed
1000.0, // fThrownWeaponMaxSpeed
300.0, // fThrownWeaponMinSpeed
0.0, // fTrapCostMult
4000.0, // fTravelMult
16000.0,// fTravelTimeMult
0.1, // fUnarmoredBase1
0.065, // fUnarmoredBase2
30.0, // fVanityDelay
10.0, // fVoiceIdleOdds
0.0, // fWaterReflectUpdateAlways
10.0, // fWaterReflectUpdateSeldom
0.1, // fWeaponDamageMult
1.0, // fWeaponFatigueBlockMult
0.25, // fWeaponFatigueMult
150.0, // fWereWolfAcrobatics
150.0, // fWereWolfAgility
1.0, // fWereWolfAlchemy
1.0, // fWereWolfAlteration
1.0, // fWereWolfArmorer
150.0, // fWereWolfAthletics
1.0, // fWereWolfAxe
1.0, // fWereWolfBlock
1.0, // fWereWolfBluntWeapon
1.0, // fWereWolfConjuration
1.0, // fWereWolfDestruction
1.0, // fWereWolfEnchant
150.0, // fWereWolfEndurance
400.0, // fWereWolfFatigue
100.0, // fWereWolfHandtoHand
2.0, // fWereWolfHealth
1.0, // fWereWolfHeavyArmor
1.0, // fWereWolfIllusion
1.0, // fWereWolfIntellegence
1.0, // fWereWolfLightArmor
1.0, // fWereWolfLongBlade
1.0, // fWereWolfLuck
100.0, // fWereWolfMagicka
1.0, // fWereWolfMarksman
1.0, // fWereWolfMediumArmor
1.0, // fWereWolfMerchantile
1.0, // fWereWolfMysticism
1.0, // fWereWolfPersonality
1.0, // fWereWolfRestoration
1.5, // fWereWolfRunMult
1.0, // fWereWolfSecurity
1.0, // fWereWolfShortBlade
1.5, // fWereWolfSilverWeaponDamageMult
1.0, // fWereWolfSneak
1.0, // fWereWolfSpear
1.0, // fWereWolfSpeechcraft
150.0, // fWereWolfSpeed
150.0, // fWereWolfStrength
100.0, // fWereWolfUnarmored
1.0, // fWereWolfWillPower
15.0 // fWortChanceValue
0.3f, // fAIFleeFleeMult
7.0f, // fAIFleeHealthMult
3.0f, // fAIMagicSpellMult
1.0f, // fAIMeleeArmorMult
1.0f, // fAIMeleeSummWeaponMult
2.0f, // fAIMeleeWeaponMult
5.0f, // fAIRangeMagicSpellMult
5.0f, // fAIRangeMeleeWeaponMult
2000.0f, // fAlarmRadius
1.0f, // fAthleticsRunBonus
40.0f, // fAudioDefaultMaxDistance
5.0f, // fAudioDefaultMinDistance
50.0f, // fAudioMaxDistanceMult
20.0f, // fAudioMinDistanceMult
60.0f, // fAudioVoiceDefaultMaxDistance
10.0f, // fAudioVoiceDefaultMinDistance
50.0f, // fAutoPCSpellChance
80.0f, // fAutoSpellChance
50.0f, // fBargainOfferBase
-4.0f, // fBargainOfferMulti
24.0f, // fBarterGoldResetDelay
1.75f, // fBaseRunMultiplier
1.25f, // fBlockStillBonus
150.0f, // fBribe1000Mod
75.0f, // fBribe100Mod
35.0f, // fBribe10Mod
60.0f, // fCombatAngleXY
60.0f, // fCombatAngleZ
0.25f, // fCombatArmorMinMult
-90.0f, // fCombatBlockLeftAngle
30.0f, // fCombatBlockRightAngle
4.0f, // fCombatCriticalStrikeMult
0.1f, // fCombatDelayCreature
0.1f, // fCombatDelayNPC
128.0f, // fCombatDistance
0.3f, // fCombatDistanceWerewolfMod
30.0f, // fCombatForceSideAngle
0.2f, // fCombatInvisoMult
1.5f, // fCombatKODamageMult
45.0f, // fCombatTorsoSideAngle
0.3f, // fCombatTorsoStartPercent
0.8f, // fCombatTorsoStopPercent
15.0f, // fConstantEffectMult
72.0f, // fCorpseClearDelay
72.0f, // fCorpseRespawnDelay
0.5f, // fCrimeGoldDiscountMult
0.9f, // fCrimeGoldTurnInMult
1.0f, // fCrimeStealing
0.5f, // fDamageStrengthBase
0.1f, // fDamageStrengthMult
5.0f, // fDifficultyMult
2.5f, // fDiseaseXferChance
-10.0f, // fDispAttacking
-1.0f, // fDispBargainFailMod
1.0f, // fDispBargainSuccessMod
0.0f, // fDispCrimeMod
-10.0f, // fDispDiseaseMod
3.0f, // fDispFactionMod
1.0f, // fDispFactionRankBase
0.5f, // fDispFactionRankMult
1.0f, // fDispositionMod
50.0f, // fDispPersonalityBase
0.5f, // fDispPersonalityMult
-25.0f, // fDispPickPocketMod
5.0f, // fDispRaceMod
-0.5f, // fDispStealing
-5.0f, // fDispWeaponDrawn
0.5f, // fEffectCostMult
0.1f, // fElementalShieldMult
3.0f, // fEnchantmentChanceMult
0.5f, // fEnchantmentConstantChanceMult
100.0f, // fEnchantmentConstantDurationMult
0.1f, // fEnchantmentMult
1000.0f, // fEnchantmentValueMult
0.3f, // fEncumberedMoveEffect
5.0f, // fEncumbranceStrMult
0.04f, // fEndFatigueMult
0.25f, // fFallAcroBase
0.01f, // fFallAcroMult
400.0f, // fFallDamageDistanceMin
0.0f, // fFallDistanceBase
0.07f, // fFallDistanceMult
2.0f, // fFatigueAttackBase
0.0f, // fFatigueAttackMult
1.25f, // fFatigueBase
4.0f, // fFatigueBlockBase
0.0f, // fFatigueBlockMult
5.0f, // fFatigueJumpBase
0.0f, // fFatigueJumpMult
0.5f, // fFatigueMult
2.5f, // fFatigueReturnBase
0.02f, // fFatigueReturnMult
5.0f, // fFatigueRunBase
2.0f, // fFatigueRunMult
1.5f, // fFatigueSneakBase
1.5f, // fFatigueSneakMult
0.0f, // fFatigueSpellBase
0.0f, // fFatigueSpellCostMult
0.0f, // fFatigueSpellMult
7.0f, // fFatigueSwimRunBase
0.0f, // fFatigueSwimRunMult
2.5f, // fFatigueSwimWalkBase
0.0f, // fFatigueSwimWalkMult
0.2f, // fFightDispMult
0.005f, // fFightDistanceMultiplier
50.0f, // fFightStealing
3000.0f, // fFleeDistance
512.0f, // fGreetDistanceReset
0.1f, // fHandtoHandHealthPer
1.0f, // fHandToHandReach
0.5f, // fHoldBreathEndMult
20.0f, // fHoldBreathTime
0.75f, // fIdleChanceMultiplier
1.0f, // fIngredientMult
0.5f, // fInteriorHeadTrackMult
128.0f, // fJumpAcrobaticsBase
4.0f, // fJumpAcroMultiplier
0.5f, // fJumpEncumbranceBase
1.0f, // fJumpEncumbranceMultiplier
0.5f, // fJumpMoveBase
0.5f, // fJumpMoveMult
1.0f, // fJumpRunMultiplier
0.5f, // fKnockDownMult
5.0f, // fLevelMod
0.1f, // fLevelUpHealthEndMult
0.6f, // fLightMaxMod
10.0f, // fLuckMod
10.0f, // fMagesGuildTravel
1.5f, // fMagicCreatureCastDelay
0.0167f, // fMagicDetectRefreshRate
1.0f, // fMagicItemConstantMult
1.0f, // fMagicItemCostMult
1.0f, // fMagicItemOnceMult
1.0f, // fMagicItemPriceMult
0.05f, // fMagicItemRechargePerSecond
1.0f, // fMagicItemStrikeMult
1.0f, // fMagicItemUsedMult
3.0f, // fMagicStartIconBlink
0.5f, // fMagicSunBlockedMult
0.75f, // fMajorSkillBonus
300.0f, // fMaxFlySpeed
0.5f, // fMaxHandToHandMult
400.0f, // fMaxHeadTrackDistance
200.0f, // fMaxWalkSpeed
300.0f, // fMaxWalkSpeedCreature
0.9f, // fMedMaxMod
0.1f, // fMessageTimePerChar
5.0f, // fMinFlySpeed
0.1f, // fMinHandToHandMult
1.0f, // fMinorSkillBonus
100.0f, // fMinWalkSpeed
5.0f, // fMinWalkSpeedCreature
1.25f, // fMiscSkillBonus
2.0f, // fNPCbaseMagickaMult
0.5f, // fNPCHealthBarFade
3.0f, // fNPCHealthBarTime
1.0f, // fPCbaseMagickaMult
0.3f, // fPerDieRollMult
5.0f, // fPersonalityMod
1.0f, // fPerTempMult
-1.0f, // fPickLockMult
0.3f, // fPickPocketMod
20.0f, // fPotionMinUsefulDuration
0.5f, // fPotionStrengthMult
0.5f, // fPotionT1DurMult
1.5f, // fPotionT1MagMult
20.0f, // fPotionT4BaseStrengthMult
12.0f, // fPotionT4EquipStrengthMult
3000.0f, // fProjectileMaxSpeed
400.0f, // fProjectileMinSpeed
25.0f, // fProjectileThrownStoreChance
3.0f, // fRepairAmountMult
1.0f, // fRepairMult
1.0f, // fReputationMod
0.15f, // fRestMagicMult
0.0f, // fSeriousWoundMult
0.25f, // fSleepRandMod
0.3f, // fSleepRestMod
-1.0f, // fSneakBootMult
0.5f, // fSneakDistanceBase
0.002f, // fSneakDistanceMultiplier
0.5f, // fSneakNoViewMult
1.0f, // fSneakSkillMult
0.75f, // fSneakSpeedMultiplier
1.0f, // fSneakUseDelay
500.0f, // fSneakUseDist
1.5f, // fSneakViewMult
3.0f, // fSoulGemMult
0.8f, // fSpecialSkillBonus
7.0f, // fSpellMakingValueMult
2.0f, // fSpellPriceMult
10.0f, // fSpellValueMult
0.25f, // fStromWalkMult
0.7f, // fStromWindSpeed
3.0f, // fSuffocationDamage
0.9f, // fSwimHeightScale
0.1f, // fSwimRunAthleticsMult
0.5f, // fSwimRunBase
0.02f, // fSwimWalkAthleticsMult
0.5f, // fSwimWalkBase
1.0f, // fSwingBlockBase
1.0f, // fSwingBlockMult
1000.0f, // fTargetSpellMaxSpeed
1000.0f, // fThrownWeaponMaxSpeed
300.0f, // fThrownWeaponMinSpeed
0.0f, // fTrapCostMult
4000.0f, // fTravelMult
16000.0f,// fTravelTimeMult
0.1f, // fUnarmoredBase1
0.065f, // fUnarmoredBase2
30.0f, // fVanityDelay
10.0f, // fVoiceIdleOdds
0.0f, // fWaterReflectUpdateAlways
10.0f, // fWaterReflectUpdateSeldom
0.1f, // fWeaponDamageMult
1.0f, // fWeaponFatigueBlockMult
0.25f, // fWeaponFatigueMult
150.0f, // fWereWolfAcrobatics
150.0f, // fWereWolfAgility
1.0f, // fWereWolfAlchemy
1.0f, // fWereWolfAlteration
1.0f, // fWereWolfArmorer
150.0f, // fWereWolfAthletics
1.0f, // fWereWolfAxe
1.0f, // fWereWolfBlock
1.0f, // fWereWolfBluntWeapon
1.0f, // fWereWolfConjuration
1.0f, // fWereWolfDestruction
1.0f, // fWereWolfEnchant
150.0f, // fWereWolfEndurance
400.0f, // fWereWolfFatigue
100.0f, // fWereWolfHandtoHand
2.0f, // fWereWolfHealth
1.0f, // fWereWolfHeavyArmor
1.0f, // fWereWolfIllusion
1.0f, // fWereWolfIntellegence
1.0f, // fWereWolfLightArmor
1.0f, // fWereWolfLongBlade
1.0f, // fWereWolfLuck
100.0f, // fWereWolfMagicka
1.0f, // fWereWolfMarksman
1.0f, // fWereWolfMediumArmor
1.0f, // fWereWolfMerchantile
1.0f, // fWereWolfMysticism
1.0f, // fWereWolfPersonality
1.0f, // fWereWolfRestoration
1.5f, // fWereWolfRunMult
1.0f, // fWereWolfSecurity
1.0f, // fWereWolfShortBlade
1.5f, // fWereWolfSilverWeaponDamageMult
1.0f, // fWereWolfSneak
1.0f, // fWereWolfSpear
1.0f, // fWereWolfSpeechcraft
150.0f, // fWereWolfSpeed
150.0f, // fWereWolfStrength
100.0f, // fWereWolfUnarmored
1.0f, // fWereWolfWillPower
15.0f // fWortChanceValue
};
const int CSMWorld::DefaultGmsts::IntsDefaultValues[CSMWorld::DefaultGmsts::IntCount] =

View file

@ -191,7 +191,7 @@ void CSMWorld::IdTable::setRecord (const std::string& id, const RecordBase& reco
if (index==-1)
{
int index = mIdCollection->getAppendIndex (id, type);
index = mIdCollection->getAppendIndex (id, type);
beginInsertRows (QModelIndex(), index, index);

View file

@ -63,7 +63,7 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool
std::cerr << "Position: #" << index.first << " " << index.second
<<", Target #"<< mref.mTarget[0] << " " << mref.mTarget[1] << std::endl;
std::ostringstream stream;
stream.clear();
stream << "#" << mref.mTarget[0] << " " << mref.mTarget[1];
ref.mCell = stream.str(); // overwrite
}

View file

@ -42,7 +42,7 @@ add_openmw_dir (mwgui
itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview
tradeitemmodel companionitemmodel pickpocketitemmodel controllers savegamedialog
recharge mode videowidget backgroundimage itemwidget screenfader debugwindow spellmodel spellview
draganddrop timeadvancer jailscreen
draganddrop timeadvancer jailscreen itemchargeview
)
add_openmw_dir (mwdialogue
@ -179,6 +179,21 @@ target_link_libraries(openmw ${CMAKE_THREAD_LIBS_INIT})
endif()
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(IOKIT_FRAMEWORK IOKit)
target_link_libraries(openmw ${COCOA_FRAMEWORK} ${IOKIT_FRAMEWORK})
@ -186,7 +201,7 @@ if(APPLE)
if (FFmpeg_FOUND)
find_library(COREVIDEO_FRAMEWORK CoreVideo)
find_library(VDA_FRAMEWORK VideoDecodeAcceleration)
target_link_libraries(openmw ${COREVIDEO_FRAMEWORK} ${VDA_FRAMEWORK})
target_link_libraries(openmw z ${COREVIDEO_FRAMEWORK} ${VDA_FRAMEWORK})
endif()
endif(APPLE)
@ -202,3 +217,8 @@ if (MSVC)
endif (CMAKE_CL_64)
add_definitions("-D_USE_MATH_DEFINES")
endif (MSVC)
if (WIN32)
INSTALL(TARGETS openmw RUNTIME DESTINATION ".")
endif (WIN32)

View file

@ -493,7 +493,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
mEnvironment.setWindowManager (window);
// Create sound system
mEnvironment.setSoundManager (new MWSound::SoundManager(mVFS.get(), mUseSound));
mEnvironment.setSoundManager (new MWSound::SoundManager(mVFS.get(), mFallbackMap, mUseSound));
if (!mSkipMenu)
{

View file

@ -352,9 +352,8 @@ int main(int argc, char**argv)
#endif
#ifdef __APPLE__
// FIXME: set current dir to bundle path
//boost::filesystem::path bundlePath = boost::filesystem::path(Ogre::macBundlePath()).parent_path();
//boost::filesystem::current_path(bundlePath);
boost::filesystem::path binary_path = boost::filesystem::system_complete(boost::filesystem::path(argv[0]));
boost::filesystem::current_path(binary_path.parent_path());
#endif
engine.reset(new OMW::Engine(cfgMgr));

View file

@ -5,6 +5,19 @@
#include <set>
#include <vector>
#include <stdint.h>
namespace Loading
{
class Listener;
}
namespace ESM
{
class ESMReader;
class ESMWriter;
}
namespace MWBase
{
/// \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
/// @return true if joystick, false otherwise
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;
};
}

View file

@ -548,7 +548,7 @@ namespace MWBase
/// Resets all actors in the current active cells to their original location within that cell.
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.
/// @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 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;
};
}

View file

@ -118,9 +118,9 @@ namespace MWClass
}
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
MWWorld::ManualRef ref(store, id);
ref.getPtr().getCellRef().setPosition(ptr.getCellRef().getPosition());
MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->placeObject(ref.getPtr(), ptr.getCell() , ptr.getCellRef().getPosition());
MWWorld::ManualRef manualRef(store, id);
manualRef.getPtr().getCellRef().setPosition(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.mSpawn = false;
}

View file

@ -200,15 +200,15 @@ namespace MWGui
std::set<MWMechanics::EffectKey> effectIds = mAlchemy->listEffects();
Widgets::SpellEffectList list;
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;
params.mEffectID = it->mId;
const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(it->mId);
params.mEffectID = it2->mId;
const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(it2->mId);
if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill)
params.mSkill = it->mArg;
params.mSkill = it2->mArg;
else if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetAttribute)
params.mAttribute = it->mArg;
params.mAttribute = it2->mArg;
params.mIsConstant = true;
params.mNoTarget = true;

View file

@ -226,7 +226,7 @@ namespace MWGui
coord.top += lineHeight;
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;
spellWidget = mSpellArea->createWidget<Widgets::MWSpell>("MW_StatName", coord, MyGUI::Align::Default, std::string("Spell") + MyGUI::utility::toString(i));

View file

@ -132,6 +132,12 @@ namespace MWGui
mReviewDialog->configureSkills(major, minor);
}
void CharacterCreation::onFrame(float duration)
{
if (mReviewDialog)
mReviewDialog->onFrame(duration);
}
void CharacterCreation::spawnDialog(const char id)
{
try

View file

@ -50,6 +50,8 @@ namespace MWGui
void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value);
void configureSkills (const SkillList& major, const SkillList& minor);
void onFrame(float duration);
private:
osg::Group* mParent;
Resource::ResourceSystem* mResourceSystem;

View file

@ -85,8 +85,8 @@ void InventoryItemModel::update()
if (mActor.getClass().hasInventoryStore(mActor))
{
MWWorld::InventoryStore& store = mActor.getClass().getInventoryStore(mActor);
if (store.isEquipped(newItem.mBase))
MWWorld::InventoryStore& invStore = mActor.getClass().getInventoryStore(mActor);
if (invStore.isEquipped(newItem.mBase))
newItem.mType = ItemStack::Type_Equipped;
}

View 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)));
}
}

View 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

View file

@ -101,6 +101,8 @@ namespace MWGui
{
if (mFrame)
mFrame->setImageTexture("");
if (mItemShadow)
mItemShadow->setImageTexture("");
mItem->setImageTexture("");
mText->setCaption("");
return;

View file

@ -5,6 +5,8 @@
#include <MyGUI_ScrollView.h>
#include <MyGUI_Gui.h>
#include <components/widgets/box.hpp>
#include <components/misc/rng.hpp>
#include "../mwbase/world.hpp"
@ -21,6 +23,9 @@
#include "widgets.hpp"
#include "itemwidget.hpp"
#include "itemchargeview.hpp"
#include "sortfilteritemmodel.hpp"
#include "inventoryitemmodel.hpp"
namespace MWGui
{
@ -29,13 +34,15 @@ Recharge::Recharge()
: WindowBase("openmw_recharge_dialog.layout")
{
getWidget(mBox, "Box");
getWidget(mView, "View");
getWidget(mGemBox, "GemBox");
getWidget(mGemIcon, "GemIcon");
getWidget(mChargeLabel, "ChargeLabel");
getWidget(mCancelButton, "CancelButton");
mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &Recharge::onCancel);
mBox->eventItemClicked += MyGUI::newDelegate(this, &Recharge::onItemClicked);
mBox->setDisplayMode(ItemChargeView::DisplayMode_EnchantmentCharge);
setVisible(false);
}
@ -43,8 +50,13 @@ Recharge::Recharge()
void Recharge::open()
{
center();
SortFilterItemModel * model = new SortFilterItemModel(new InventoryItemModel(MWMechanics::getPlayer()));
model->setFilter(SortFilterItemModel::Filter_OnlyRechargable);
mBox->setModel(model);
// Reset scrollbars
mView->setViewOffset(MyGUI::IntPoint(0, 0));
mBox->resetScrollbars();
}
void Recharge::exit()
@ -72,66 +84,16 @@ void Recharge::updateView()
bool toolBoxVisible = (gem.getRefData().getCount() != 0);
mGemBox->setVisible(toolBoxVisible);
mGemBox->setUserString("Hidden", toolBoxVisible ? "false" : "true");
bool toolBoxWasVisible = (mBox->getPosition().top != mGemBox->getPosition().top);
mBox->update();
if (toolBoxVisible && !toolBoxWasVisible)
{
// shrink
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));
}
Gui::Box* box = dynamic_cast<Gui::Box*>(mMainWidget);
if (box == NULL)
throw std::runtime_error("main widget must be a box");
while (mView->getChildCount())
MyGUI::Gui::getInstance().destroyWidget(mView->getChildAt(0));
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);
box->notifyChildrenSizeChanged();
center();
}
void Recharge::onCancel(MyGUI::Widget *sender)
@ -139,15 +101,13 @@ void Recharge::onCancel(MyGUI::Widget *sender)
exit();
}
void Recharge::onItemClicked(MyGUI::Widget *sender)
void Recharge::onItemClicked(MyGUI::Widget *sender, const MWWorld::Ptr& item)
{
MWWorld::Ptr gem = *mGemIcon->getUserData<MWWorld::Ptr>();
if (!gem.getRefData().getCount())
return;
MWWorld::Ptr item = *sender->getUserData<MWWorld::Ptr>();
MWWorld::Ptr player = MWMechanics::getPlayer();
MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player);
MWMechanics::NpcStats& npcStats = player.getClass().getNpcStats(player);
@ -198,12 +158,4 @@ void Recharge::onItemClicked(MyGUI::Widget *sender)
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)));
}
}

View file

@ -12,6 +12,7 @@ namespace MWGui
{
class ItemWidget;
class ItemChargeView;
class Recharge : public WindowBase
{
@ -25,8 +26,7 @@ public:
void start (const MWWorld::Ptr& gem);
protected:
MyGUI::Widget* mBox;
MyGUI::ScrollView* mView;
ItemChargeView* mBox;
MyGUI::Widget* mGemBox;
@ -38,7 +38,7 @@ protected:
void updateView();
void onItemClicked (MyGUI::Widget* sender);
void onItemClicked (MyGUI::Widget* sender, const MWWorld::Ptr& item);
void onCancel (MyGUI::Widget* sender);
void onMouseWheel(MyGUI::Widget* _sender, int _rel);

View file

@ -4,6 +4,9 @@
#include <MyGUI_ScrollView.h>
#include <MyGUI_Gui.h>
#include <MyGUI_ItemBox.h>
#include <components/widgets/box.hpp>
#include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp"
@ -17,6 +20,9 @@
#include "widgets.hpp"
#include "itemwidget.hpp"
#include "itemchargeview.hpp"
#include "sortfilteritemmodel.hpp"
#include "inventoryitemmodel.hpp"
namespace MWGui
{
@ -25,7 +31,6 @@ Repair::Repair()
: WindowBase("openmw_repair.layout")
{
getWidget(mRepairBox, "RepairBox");
getWidget(mRepairView, "RepairView");
getWidget(mToolBox, "ToolBox");
getWidget(mToolIcon, "ToolIcon");
getWidget(mUsesLabel, "UsesLabel");
@ -33,13 +38,21 @@ Repair::Repair()
getWidget(mCancelButton, "CancelButton");
mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &Repair::onCancel);
mRepairBox->eventItemClicked += MyGUI::newDelegate(this, &Repair::onRepairItem);
mRepairBox->setDisplayMode(ItemChargeView::DisplayMode_Health);
}
void Repair::open()
{
center();
SortFilterItemModel * model = new SortFilterItemModel(new InventoryItemModel(MWMechanics::getPlayer()));
model->setFilter(SortFilterItemModel::Filter_OnlyRepairable);
mRepairBox->setModel(model);
// Reset scrollbars
mRepairView->setViewOffset(MyGUI::IntPoint(0, 0));
mRepairBox->resetScrollbars();
}
void Repair::exit()
@ -75,89 +88,31 @@ void Repair::updateRepairView()
bool toolBoxVisible = (mRepair.getTool().getRefData().getCount() != 0);
mToolBox->setVisible(toolBoxVisible);
mToolBox->setUserString("Hidden", toolBoxVisible ? "false" : "true");
bool toolBoxWasVisible = (mRepairBox->getPosition().top != mToolBox->getPosition().top);
mRepairBox->update();
if (toolBoxVisible && !toolBoxWasVisible)
{
// shrink
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));
}
Gui::Box* box = dynamic_cast<Gui::Box*>(mMainWidget);
if (box == NULL)
throw std::runtime_error("main widget must be a box");
while (mRepairView->getChildCount())
MyGUI::Gui::getInstance().destroyWidget(mRepairView->getChildAt(0));
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);
box->notifyChildrenSizeChanged();
center();
}
void Repair::onCancel(MyGUI::Widget *sender)
void Repair::onCancel(MyGUI::Widget* /*sender*/)
{
exit();
}
void Repair::onRepairItem(MyGUI::Widget *sender)
void Repair::onRepairItem(MyGUI::Widget* /*sender*/, const MWWorld::Ptr& ptr)
{
if (!mRepair.getTool().getRefData().getCount())
return;
mRepair.repair(*sender->getUserData<MWWorld::Ptr>());
mRepair.repair(ptr);
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)));
}
}

View file

@ -9,6 +9,7 @@ namespace MWGui
{
class ItemWidget;
class ItemChargeView;
class Repair : public WindowBase
{
@ -22,8 +23,7 @@ public:
void startRepairItem (const MWWorld::Ptr& item);
protected:
MyGUI::Widget* mRepairBox;
MyGUI::ScrollView* mRepairView;
ItemChargeView* mRepairBox;
MyGUI::Widget* mToolBox;
@ -38,9 +38,8 @@ protected:
void updateRepairView();
void onRepairItem (MyGUI::Widget* sender);
void onCancel (MyGUI::Widget* sender);
void onMouseWheel(MyGUI::Widget* _sender, int _rel);
void onRepairItem(MyGUI::Widget* sender, const MWWorld::Ptr& ptr);
void onCancel(MyGUI::Widget* sender);
};

View file

@ -10,6 +10,7 @@
#include "../mwbase/world.hpp"
#include "../mwbase/windowmanager.hpp"
#include "../mwworld/esmstore.hpp"
#include "../mwmechanics/autocalcspell.hpp"
#include "tooltips.hpp"
@ -29,7 +30,8 @@ namespace MWGui
const int ReviewDialog::sLineHeight = 18;
ReviewDialog::ReviewDialog()
: WindowModal("openmw_chargen_review.layout")
: WindowModal("openmw_chargen_review.layout"),
mUpdateSkillArea(false)
{
// Centre dialog
center();
@ -102,7 +104,16 @@ namespace MWGui
void ReviewDialog::open()
{
WindowModal::open();
updateSkillArea();
mUpdateSkillArea = true;
}
void ReviewDialog::onFrame(float /*duration*/)
{
if (mUpdateSkillArea)
{
updateSkillArea();
mUpdateSkillArea = false;
}
}
void ReviewDialog::setPlayerName(const std::string &name)
@ -121,6 +132,8 @@ namespace MWGui
ToolTips::createRaceToolTip(mRaceWidget, race);
mRaceWidget->setCaption(race->mName);
}
mUpdateSkillArea = true;
}
void ReviewDialog::setClass(const ESM::Class& class_)
@ -141,6 +154,8 @@ namespace MWGui
mBirthSignWidget->setCaption(sign->mName);
ToolTips::createBirthsignToolTip(mBirthSignWidget, mBirthSignId);
}
mUpdateSkillArea = true;
}
void ReviewDialog::setHealth(const MWMechanics::DynamicStat<float>& value)
@ -170,7 +185,11 @@ namespace MWGui
if (attr == mAttributeWidgets.end())
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)
@ -191,6 +210,7 @@ namespace MWGui
widget->_setWidgetState(state);
}
mUpdateSkillArea = true;
}
void ReviewDialog::configureSkills(const std::vector<int>& major, const std::vector<int>& minor)
@ -211,7 +231,7 @@ namespace MWGui
mMiscSkills.push_back(skill);
}
updateSkillArea();
mUpdateSkillArea = true;
}
void ReviewDialog::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2)
@ -245,7 +265,7 @@ namespace MWGui
skillNameWidget->setCaption(text);
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->_setWidgetState(state);
skillValueWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel);
@ -273,6 +293,20 @@ namespace MWGui
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)
{
// Add a line separator if there are items above
@ -332,6 +366,80 @@ namespace MWGui
if (!mMiscSkills.empty())
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
mSkillView->setVisibleVScroll(false);
mSkillView->setCanvasSize (mSkillView->getWidth(), std::max(mSkillView->getHeight(), coord1.top));

View file

@ -6,6 +6,11 @@
#include "windowbase.hpp"
#include "widgets.hpp"
namespace ESM
{
struct Spell;
}
namespace MWGui
{
class WindowManager;
@ -42,6 +47,8 @@ namespace MWGui
virtual void open();
void onFrame(float duration);
// Events
typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void;
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);
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 ESM::Spell* spell, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
void updateSkillArea();
static const int sLineHeight;
@ -92,6 +100,8 @@ namespace MWGui
std::string mName, mRaceId, mBirthSignId;
ESM::Class mKlass;
std::vector<MyGUI::Widget*> mSkillWidgets; //< Skills and other information
bool mUpdateSkillArea;
};
}
#endif

View file

@ -466,9 +466,6 @@ namespace MWGui
else
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)
{
std::string desc = MWBase::Environment::get().getInputManager()->getActionDescription (*it);
@ -481,16 +478,15 @@ namespace MWGui
else
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);
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->setTextAlign (MyGUI::Align::Right);
rightText->setUserData(*it); // save the action id for callbacks
rightText->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onRebindAction);
rightText->eventMouseWheel += MyGUI::newDelegate(this, &SettingsWindow::onInputTabMouseWheel);
curH += h;
Gui::ButtonGroup group;
group.push_back(leftText);
@ -498,9 +494,25 @@ namespace MWGui
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
mControlsBox->setVisibleVScroll(false);
mControlsBox->setCanvasSize (mControlsBox->getWidth(), std::max(curH, mControlsBox->getHeight()));
mControlsBox->setCanvasSize (mControlsBox->getWidth(), std::max(totalH, mControlsBox->getHeight()));
mControlsBox->setVisibleVScroll(true);
}
@ -556,7 +568,7 @@ namespace MWGui
void SettingsWindow::onWindowResize(MyGUI::Window *_sender)
{
updateControlsBox();
layoutControlsBox();
}
void SettingsWindow::resetScrollbars()

View file

@ -67,6 +67,8 @@ namespace MWGui
void configureWidgets(MyGUI::Widget* widget);
void updateSliderLabel(MyGUI::ScrollBar* scroller, const std::string& value);
void layoutControlsBox();
private:
void resetScrollbars();
};

View file

@ -1,5 +1,7 @@
#include "sortfilteritemmodel.hpp"
#include <iostream>
#include <components/misc/stringops.hpp>
#include <components/esm/loadalch.hpp>
@ -14,9 +16,14 @@
#include <components/esm/loadprob.hpp>
#include <components/esm/loadrepa.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/nullaction.hpp"
#include "../mwworld/esmstore.hpp"
namespace
{
@ -139,6 +146,31 @@ namespace MWGui
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;
}

View file

@ -39,6 +39,8 @@ namespace MWGui
static const int Filter_OnlyEnchantable = (1<<2);
static const int Filter_OnlyChargedSoulstones = (1<<3);
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:

View file

@ -11,6 +11,7 @@
#include "../mwworld/inventorystore.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/esmstore.hpp"
#include "../mwworld/player.hpp"
#include "../mwmechanics/spellcasting.hpp"
#include "../mwmechanics/spells.hpp"
@ -122,8 +123,15 @@ namespace MWGui
const ESM::Spell* spell =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(spellId);
if (spell->mData.mFlags & ESM::Spell::F_Always
|| spell->mData.mType == ESM::Spell::ST_Power)
MWWorld::Ptr player = MWMechanics::getPlayer();
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}");
}

View file

@ -256,7 +256,7 @@ namespace MWGui
std::string key = it->first.substr(0, underscorePos);
std::string widgetName = it->first.substr(underscorePos+1, it->first.size()-(underscorePos+1));
std::string type = "Property";
type = "Property";
size_t caretPos = key.find("^");
if (caretPos != std::string::npos)
{

View file

@ -109,6 +109,7 @@
#include "container.hpp"
#include "controllers.hpp"
#include "jailscreen.hpp"
#include "itemchargeview.hpp"
namespace MWGui
{
@ -223,6 +224,7 @@ namespace MWGui
MyGUI::FactoryManager::getInstance().registerFactory<osgMyGUI::ScalingLayer>("Layer");
BookPage::registerMyGUIComponents ();
ItemView::registerComponents();
ItemChargeView::registerComponents();
ItemWidget::registerComponents();
SpellView::registerComponents();
Gui::registerAllWidgets();
@ -1004,6 +1006,9 @@ namespace MWGui
mScreenFader->update(frameDuration);
mDebugWindow->onFrame(frameDuration);
if (mCharGen)
mCharGen->onFrame(frameDuration);
}
void WindowManager::changeCell(const MWWorld::CellStore* cell)

View file

@ -16,6 +16,9 @@
#include <components/sdlutil/sdlinputwrapper.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/windowmanager.hpp"
@ -1574,6 +1577,44 @@ namespace MWInput
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()
{
loadKeyDefaults(true);

View file

@ -149,6 +149,10 @@ namespace MWInput
void clearAllKeyBindings (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:
SDL_Window* mWindow;
bool mWindowVisible;

View file

@ -512,8 +512,8 @@ namespace MWMechanics
if (magnitude > 0 && remainingTime > 0 && remainingTime < mDuration)
{
CreatureStats& creatureStats = mActor.getClass().getCreatureStats(mActor);
effectTick(creatureStats, mActor, key, magnitude * remainingTime);
creatureStats.getMagicEffects().add(key, -magnitude);
if (effectTick(creatureStats, mActor, key, magnitude * remainingTime))
creatureStats.getMagicEffects().add(key, -magnitude);
}
}
};
@ -527,8 +527,10 @@ namespace MWMechanics
if (duration > 0)
{
// apply correct magnitude for tickable effects that have just expired,
// in case duration > remaining time of effect
// Apply correct magnitude for tickable effects that have just expired,
// 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);
creatureStats.getActiveSpells().visitEffectSources(visitor);

View file

@ -41,9 +41,7 @@ namespace MWMechanics
if (pathTo(actor, dest, duration, MWBase::Environment::get().getWorld()->getMaxActivationDistance())) //Stop when you get in activation range
{
// activate when reached
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr(mObjectId,false);
MWBase::Environment::get().getWorld()->activate(target, actor);
return true;
}

View file

@ -18,6 +18,7 @@
#include "character.hpp"
#include "aicombataction.hpp"
#include "combat.hpp"
#include "coordinateconverter.hpp"
namespace
{
@ -51,22 +52,39 @@ namespace MWMechanics
ESM::Position mShortcutFailPos;
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():
mAttackCooldown(0),
mAttackCooldown(0.0f),
mTimerReact(AI_REACTION_TIME),
mTimerCombatMove(0),
mTimerCombatMove(0.0f),
mReadyToAttack(false),
mAttack(false),
mAttackRange(0),
mAttackRange(0.0f),
mCombatMove(false),
mLastTargetPos(0,0,0),
mCell(NULL),
mCurrentAction(),
mActionCooldown(0),
mActionCooldown(0.0f),
mStrength(),
mForceNoShortcut(false),
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);
@ -76,6 +94,10 @@ namespace MWMechanics
const ESM::Weapon* weapon, bool distantCombat);
void updateAttack(CharacterController& characterController);
void stopAttack();
void startFleeing();
void stopFleeing();
bool isFleeing();
};
AiCombat::AiCombat(const MWWorld::Ptr& actor) :
@ -157,16 +179,27 @@ namespace MWMechanics
|| target.getClass().getCreatureStats(target).isDead())
return true;
if (storage.mCurrentAction.get()) // need to wait to init action with it's attack range
if (!storage.isFleeing())
{
//Update every frame
bool is_target_reached = pathTo(actor, target.getRefData().getPosition().pos, duration, storage.mAttackRange);
if (is_target_reached) storage.mReadyToAttack = true;
}
if (storage.mCurrentAction.get()) // need to wait to init action with its attack range
{
//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);
if (storage.mReadyToAttack) updateActorsMovement(actor, duration, storage);
storage.updateAttack(characterController);
storage.updateCombatMove(duration);
if (storage.mReadyToAttack) updateActorsMovement(actor, duration, storage);
storage.updateAttack(characterController);
}
else
{
updateFleeing(actor, target, duration, storage);
}
storage.mActionCooldown -= duration;
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)
{
if (isTargetMagicallyHidden(target))
{
storage.stopAttack();
return; // TODO: run away instead of doing nothing
}
const MWWorld::CellStore*& currentCell = storage.mCell;
bool cellChange = currentCell && (actor.getCell() != currentCell);
if(!currentCell || cellChange)
@ -198,30 +225,61 @@ namespace MWMechanics
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();
actorClass.getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true);
float& actionCooldown = storage.mActionCooldown;
if (actionCooldown > 0)
return;
float &rangeAttack = storage.mAttackRange;
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();
}
const ESM::Weapon *weapon = NULL;
bool isRangedCombat = false;
if (currentAction.get())
if (!currentAction)
return;
if (storage.isFleeing() != currentAction->isFleeing())
{
rangeAttack = currentAction->getCombatRange(isRangedCombat);
// Get weapon characteristics
weapon = currentAction->getWeapon();
if (currentAction->isFleeing())
{
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();
osg::Vec3f vActorPos(pos.asVec3());
osg::Vec3f vTargetPos(target.getRefData().getPosition().asVec3());
@ -229,19 +287,7 @@ namespace MWMechanics
osg::Vec3f vAimDir = MWBase::Environment::get().getWorld()->aimToTarget(actor, target);
float distToTarget = MWBase::Environment::get().getWorld()->getHitDistance(actor, target);
if (!currentAction)
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;
}
storage.mReadyToAttack = (currentAction->isAttackingOrSpell() && distToTarget <= rangeAttack && storage.mLOS);
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)
{
// apply combat movement
@ -446,6 +597,26 @@ namespace MWMechanics
mReadyToAttack = 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;
}
}

View file

@ -61,6 +61,10 @@ namespace MWMechanics
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
void updateActorsMovement(const MWWorld::Ptr& actor, float duration, AiCombatStorage& storage);
void rotateActorOnAxis(const MWWorld::Ptr& actor, int axis,

View file

@ -5,14 +5,17 @@
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwbase/mechanicsmanager.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/esmstore.hpp"
#include "../mwworld/inventorystore.hpp"
#include "../mwworld/actionequip.hpp"
#include "../mwworld/cellstore.hpp"
#include "npcstats.hpp"
#include "spellcasting.hpp"
#include "combat.hpp"
namespace
{
@ -517,6 +520,7 @@ namespace MWMechanics
Spells& spells = actor.getClass().getCreatureStats(actor).getSpells();
float bestActionRating = 0.f;
float antiFleeRating = 0.f;
// Default to hand-to-hand combat
boost::shared_ptr<Action> bestAction (new ActionWeapon(MWWorld::Ptr()));
if (actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf())
@ -536,6 +540,7 @@ namespace MWMechanics
{
bestActionRating = rating;
bestAction.reset(new ActionPotion(*it));
antiFleeRating = std::numeric_limits<float>::max();
}
}
@ -546,6 +551,7 @@ namespace MWMechanics
{
bestActionRating = rating;
bestAction.reset(new ActionEnchantedItem(it));
antiFleeRating = std::numeric_limits<float>::max();
}
}
@ -593,6 +599,7 @@ namespace MWMechanics
bestActionRating = rating;
bestAction.reset(new ActionWeapon(*it, ammo));
antiFleeRating = vanillaRateWeaponAndAmmo(*it, ammo, actor, enemy);
}
}
}
@ -606,13 +613,308 @@ namespace MWMechanics
{
bestActionRating = rating;
bestAction.reset(new ActionSpell(spell->mId));
antiFleeRating = vanillaRateSpell(spell, actor, enemy);
}
}
if (makeFleeDecision(actor, enemy, antiFleeRating))
bestAction.reset(new ActionFlee());
if (bestAction.get())
bestAction->prepare(actor);
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;
}
}

View file

@ -20,6 +20,18 @@ namespace MWMechanics
virtual float getActionCooldown() { return 0.f; }
virtual const ESM::Weapon* getWeapon() const { return NULL; };
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
@ -89,6 +101,15 @@ namespace MWMechanics
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);
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

View file

@ -141,6 +141,79 @@ namespace MWMechanics
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)
{
const std::vector<ESM::ENAMstruct>& effects = spell->mEffects.mList;

View file

@ -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> autoCalcPlayerSpells(const int* actorSkills, const int* actorAttributes, const ESM::Race* race);
// Helpers
bool attrSkillCheck (const ESM::Spell* spell, const int* actorSkills, const int* actorAttributes);

View file

@ -1049,6 +1049,9 @@ bool CharacterController::updateCreatureState()
mUpperBodyState = UpperCharState_StartToMinAttack;
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
{
std::string sound = "SwishM";
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
playSwishSound(attackStrength);
}
}
mAttackStrength = attackStrength;
@ -2271,6 +2268,19 @@ void CharacterController::setHeadTrackTarget(const MWWorld::ConstPtr &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)
{
const osg::Node* head = mAnimation->getNode("Bip01 Head");

View file

@ -281,6 +281,8 @@ public:
/// 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 playSwishSound(float attackStrength);
};
MWWorld::ContainerStoreIterator getActiveWeapon(CreatureStats &stats, MWWorld::InventoryStore &inv, WeaponType *weaptype);

View file

@ -431,4 +431,19 @@ namespace MWMechanics
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);
}
}

View file

@ -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?
bool isEnvironmentCompatible(const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim);
float getFightDistanceBias(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2);
}
#endif

View file

@ -25,25 +25,11 @@
#include "autocalcspell.hpp"
#include "npcstats.hpp"
#include "actorutil.hpp"
#include "combat.hpp"
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)
{
static const float fFightDispMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
@ -212,15 +198,6 @@ namespace MWMechanics
}
// 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;
if (mRaceSelected)
race = esmStore.get<ESM::Race>().find(player->mRace);
@ -233,61 +210,7 @@ namespace MWMechanics
for (int i=0; i<ESM::Attribute::Length; ++i)
attributes[i] = npcStats.getAttribute(i).getBase();
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, 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;
}
}
std::vector<std::string> selectedSpells = autoCalcPlayerSpells(skills, attributes, race);
for (std::vector<std::string>::iterator it = selectedSpells.begin(); it != selectedSpells.end(); ++it)
creatureStats.getSpells().add(*it);
@ -1608,27 +1531,23 @@ namespace MWMechanics
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.
if (npcStats.getDrawState() == MWMechanics::DrawState_Spell)
npcStats.setDrawState(MWMechanics::DrawState_Nothing);
npcStats.setWerewolf(werewolf);
MWWorld::InventoryStore &inv = actor.getClass().getInventoryStore(actor);
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);
}
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())

View file

@ -223,7 +223,7 @@ namespace MWMechanics
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)
{
switch (effectId)
@ -913,7 +913,7 @@ namespace MWMechanics
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;
@ -927,7 +927,7 @@ namespace MWMechanics
animation->addEffect("meshes\\" + castStatic->mModel, effect->mIndex, false, "", texture);
}
if (!mCaster.getClass().isActor())
if (animation && !mCaster.getClass().isActor())
animation->addSpellCastGlow(effect);
static const std::string schools[] = {
@ -980,8 +980,10 @@ namespace MWMechanics
if (charge == 0)
return false;
// FIXME: charge should be a float, not int so that damage < 1 per frame can be applied.
// This was also a bug in the original engine.
// Store remainder of disintegrate amount (automatically subtracted if > 1)
item->getCellRef().applyChargeRemainderToBeSubtracted(disintegrate - std::floor(disintegrate));
charge = item->getClass().getItemHealth(*item);
charge -=
std::min(static_cast<int>(disintegrate),
charge);
@ -1009,10 +1011,10 @@ namespace MWMechanics
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)
return;
return false;
bool receivedMagicDamage = false;
@ -1144,10 +1146,13 @@ namespace MWMechanics
case ESM::MagicEffect::RemoveCurse:
actor.getClass().getCreatureStats(actor).getSpells().purgeCurses();
break;
default:
return false;
}
if (receivedMagicDamage && actor == getPlayer())
MWBase::Environment::get().getWindowManager()->activateHitOverlay(false);
return true;
}
}

View file

@ -59,9 +59,13 @@ namespace MWMechanics
float getEffectMultiplier(short effectId, const MWWorld::Ptr& actor, const MWWorld::Ptr& caster,
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);
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
{

View file

@ -69,7 +69,14 @@ namespace MWPhysics
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)
{
/*
@ -120,7 +127,7 @@ namespace MWPhysics
stepper.doTrace(colobj, position, position+osg::Vec3f(0.0f,0.0f,sStepSizeUp), collisionWorld);
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?)
/*
@ -138,7 +145,7 @@ namespace MWPhysics
*/
tracer.doTrace(colobj, stepper.mEndPos, stepper.mEndPos + toMove, collisionWorld);
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.
@ -156,22 +163,22 @@ namespace MWPhysics
* ==============================================
*/
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
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.
// TODO: stepper.mPlaneNormal does not appear to be reliable - needs more testing
// NOTE: caller's variables 'position' & 'remainingTime' are modified here
position = stepper.mEndPos;
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,
// or moved full sStepSize distance (FIXME: is this a bug?)
return false;
return Result_Blocked;
}
@ -361,14 +368,15 @@ namespace MWPhysics
osg::Vec3f oldPosition = newPosition;
// We hit something. Try to step up onto it. (NOTE: stepMove does not allow stepping over)
// NOTE: stepMove modifies newPosition if successful
bool result = stepMove(colobj, newPosition, velocity*remainingTime, remainingTime, collisionWorld);
if (!result) // to make sure the maximum stepping distance isn't framerate-dependent or movement-speed dependent
const float minStep = 10.f;
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;
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
if (ptr.getClass().isPureWaterCreature(ptr)
@ -450,8 +458,8 @@ namespace MWPhysics
if (inertia.z() < 0)
inertia.z() *= slowFall;
if (slowFall < 1.f) {
inertia.x() = 0;
inertia.y() = 0;
inertia.x() *= slowFall;
inertia.y() *= slowFall;
}
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
{
const Actor* physactor = getActor(actor);
@ -1309,25 +1329,29 @@ namespace MWPhysics
PtrVelocityList::iterator iter = mMovementQueue.begin();
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();
const MWWorld::CellStore *cell = iter->first.getCell();
if(cell->getCell()->hasWater())
waterlevel = cell->getWaterLevel();
const MWMechanics::MagicEffects& effects = iter->first.getClass().getCreatureStats(iter->first).getMagicEffects();
bool waterCollision = false;
if (effects.get(ESM::MagicEffect::WaterWalking).getMagnitude()
&& cell->getCell()->hasWater()
&& !world->isUnderwater(iter->first.getCell(),
osg::Vec3f(iter->first.getRefData().getPosition().asVec3())))
waterCollision = true;
ActorMap::iterator foundActor = mActors.find(iter->first);
if (foundActor == mActors.end()) // actor was already removed from the scene
continue;
Actor* physicActor = foundActor->second;
if (cell->getCell()->hasWater() && effects.get(ESM::MagicEffect::WaterWalking).getMagnitude())
{
if (!world->isUnderwater(iter->first.getCell(), osg::Vec3f(iter->first.getRefData().getPosition().asVec3())))
waterCollision = true;
else if (physicActor->getCollisionMode() && canMoveToWaterSurface(iter->first, waterlevel))
{
const osg::Vec3f actorPosition = physicActor->getPosition();
physicActor->setPosition(osg::Vec3f(actorPosition.x(), actorPosition.y(), waterlevel));
}
}
physicActor->setCanWaterWalk(waterCollision);
// Slow fall reduces fall speed by a factor of (effect magnitude / 200)

View file

@ -123,6 +123,8 @@ namespace MWPhysics
bool isOnGround (const MWWorld::Ptr& actor);
bool canMoveToWaterSurface (const MWWorld::ConstPtr &actor, const float waterlevel);
/// Get physical half extents (scaled) of the given actor.
osg::Vec3f getHalfExtents(const MWWorld::ConstPtr& actor) const;

View file

@ -686,9 +686,9 @@ namespace MWRender
state.mAutoDisable = autodisable;
mStates[groupname] = state;
NifOsg::TextKeyMap::const_iterator textkey(textkeys.lower_bound(state.getTime()));
if (state.mPlaying)
{
NifOsg::TextKeyMap::const_iterator textkey(textkeys.lower_bound(state.getTime()));
while(textkey != textkeys.end() && textkey->first <= state.getTime())
{
handleTextKey(state, groupname, textkey, textkeys);
@ -976,14 +976,14 @@ namespace MWRender
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];
for (AnimSource::ControllerMap::const_iterator it = ctrls2.begin(); it != ctrls2.end(); ++it)
{
if (Misc::StringUtils::ciEqual(it->first, mAccumRoot->getName()))
{
velocity = calcAnimVelocity(keys, it->second, mAccumulate, groupname);
velocity = calcAnimVelocity(keys2, it->second, mAccumulate, groupname);
break;
}
}

View file

@ -221,10 +221,10 @@ namespace MWRender
groupname = "inventoryhandtohand";
else
{
const std::string &type = iter->getTypeName();
if(type == typeid(ESM::Lockpick).name() || type == typeid(ESM::Probe).name())
const std::string &typeName = iter->getTypeName();
if(typeName == typeid(ESM::Lockpick).name() || typeName == typeid(ESM::Probe).name())
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>();

View file

@ -403,6 +403,9 @@ void NpcAnimation::rebuild()
{
updateNpcBase();
if (mAlpha != 1.f)
mResourceSystem->getSceneManager()->recreateShaders(mObjectRoot);
MWBase::Environment::get().getMechanicsManager()->forceStateUpdate(mPtr);
}
@ -503,10 +506,10 @@ void NpcAnimation::updateNpcBase()
if(!isWerewolf)
{
if(Misc::StringUtils::lowerCase(mNpc->mRace).find("argonian") != std::string::npos)
addAnimSource("meshes\\xargonian_swimkna.nif");
if(mNpc->mModel.length() > 0)
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

View file

@ -458,9 +458,9 @@ namespace MWRender
{
mEffectManager->update(dt);
mSky->update(dt);
mWater->update(dt);
}
mWater->update(dt);
mCamera->update(dt, paused);
osg::Vec3f focal, cameraPos;

View file

@ -39,11 +39,11 @@ namespace
{
std::ostringstream texname;
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())));
tex->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
tex->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
resourceSystem->getSceneManager()->applyFilterSettings(tex);
textures.push_back(tex);
osg::ref_ptr<osg::Texture2D> tex2 (new osg::Texture2D(resourceSystem->getImageManager()->getImage(texname.str())));
tex2->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
tex2->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
resourceSystem->getSceneManager()->applyFilterSettings(tex2);
textures.push_back(tex2);
}
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)
{
const MWBase::World* world = MWBase::Environment::get().getWorld();
for (std::vector<Emitter>::iterator it=mEmitters.begin(); it !=mEmitters.end(); ++it)
{
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());
if ( (currentPos - it->mLastEmitPosition).length() > 10
// Only emit when close to the water surface, not above it and not too deep in the water
&& MWBase::Environment::get().getWorld ()->isUnderwater (it->mPtr.getCell(), it->mPtr.getRefData().getPosition().asVec3())
&& !MWBase::Environment::get().getWorld()->isSubmerged(it->mPtr))
bool shouldEmit = ( world->isUnderwater (it->mPtr.getCell(), it->mPtr.getRefData().getPosition().asVec3()) && !world->isSubmerged(it->mPtr) ) || world->isWalkingOnWater(it->mPtr);
if ( shouldEmit && (currentPos - it->mLastEmitPosition).length() > 10 )
{
it->mLastEmitPosition = currentPos;

View file

@ -1329,7 +1329,7 @@ void SkyManager::createRain()
mRainParticleSystem = new osgParticle::ParticleSystem;
mRainParticleSystem->setParticleAlignment(osgParticle::ParticleSystem::FIXED);
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());

View file

@ -238,15 +238,15 @@ namespace MWScript
else
{
char type = declarations.getType (iter->first);
char index = declarations.getIndex (iter->first);
int index2 = declarations.getIndex (iter->first);
try
{
switch (type)
{
case 's': mShorts.at (index) = iter->second.getInteger(); break;
case 'l': mLongs.at (index) = iter->second.getInteger(); break;
case 'f': mFloats.at (index) = iter->second.getFloat(); break;
case 's': mShorts.at (index2) = iter->second.getInteger(); break;
case 'l': mLongs.at (index2) = iter->second.getInteger(); break;
case 'f': mFloats.at (index2) = iter->second.getFloat(); break;
// silently ignore locals that don't exist anymore
}

View file

@ -34,8 +34,9 @@
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)
, mFallback(fallbackMap)
, mOutput(new DEFAULT_OUTPUT(*this))
, mMasterVolume(1.0f)
, mSFXVolume(1.0f)
@ -61,6 +62,13 @@ namespace MWSound
mFootstepsVolume = Settings::Manager::getFloat("footsteps volume", "Sound");
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);
mBufferCacheMax = std::max(Settings::Manager::getInt("buffer cache max", "Sound"), 1);
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)
{
static float timePassed = 0.0;
@ -941,6 +1039,7 @@ namespace MWSound
{
updateSounds(duration);
updateRegionSound(duration);
updateWaterSound(duration);
}
}
@ -1105,6 +1204,7 @@ namespace MWSound
mOutput->finishStream(*trkiter);
mActiveTracks.clear();
mUnderwaterSound.reset();
mNearWaterSound.reset();
stopMusic();
}
}

View file

@ -11,6 +11,8 @@
#include <components/settings/settings.hpp>
#include <components/fallback/fallback.hpp>
#include "../mwbase/soundmanager.hpp"
namespace VFS
@ -44,6 +46,8 @@ namespace MWSound
{
const VFS::Manager* mVFS;
Fallback::Map mFallback;
std::auto_ptr<Sound_Output> mOutput;
// Caches available music tracks by <playlist name, (sound files) >
@ -56,6 +60,13 @@ namespace MWSound
float mVoiceVolume;
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;
// List of sound buffers, grown as needed. New enties are added to the
// back, allowing existing Sound_Buffer references/pointers to remain
@ -94,6 +105,7 @@ namespace MWSound
int mPausedSoundTypes;
MWBase::SoundPtr mUnderwaterSound;
MWBase::SoundPtr mNearWaterSound;
Sound_Buffer *insertSound(const std::string &soundId, const ESM::Sound *sound);
@ -108,6 +120,7 @@ namespace MWSound
void streamMusicFull(const std::string& filename);
void updateSounds(float duration);
void updateRegionSound(float duration);
void updateWaterSound(float duration);
float volumeFromType(PlayType type) const;
@ -119,7 +132,7 @@ namespace MWSound
friend class OpenAL_Output;
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 void processChangedSettings(const Settings::CategorySettingVector& settings);

View file

@ -249,7 +249,8 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
+MWBase::Environment::get().getScriptManager()->getGlobalScripts().countSavedGameRecords()
+MWBase::Environment::get().getDialogueManager()->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.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().getWindowManager()->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
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);
break;
case ESM::REC_INPU:
MWBase::Environment::get().getInputManager()->readRecord(reader, n.intval);
break;
default:
// ignore invalid records

View file

@ -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
{
return mCellRef.mChargeFloat;

View file

@ -65,6 +65,7 @@ namespace MWWorld
float getChargeFloat() const; // Implemented as union with int charge
void setCharge(int 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)
std::string getOwner() const;

View file

@ -204,6 +204,14 @@ namespace MWWorld
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)
{
if (mState != State_Loaded)
@ -964,26 +972,26 @@ namespace MWWorld
mLastRespawn = MWBase::Environment::get().getWorld()->getTimeStamp();
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);
}
}
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);
ptr.getClass().respawn(ptr);
}
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);
ptr.getClass().respawn(ptr);
}
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
ptr.getClass().respawn(ptr);
}

View file

@ -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
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.
void moveFrom(const MWWorld::Ptr& object, MWWorld::CellStore* from);

View file

@ -393,7 +393,26 @@ namespace MWWorld
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

View file

@ -312,6 +312,8 @@ namespace MWWorld
virtual bool canSwim(const MWWorld::ConstPtr& ptr) const;
virtual bool canWalk(const MWWorld::ConstPtr& 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;
virtual int getSkill(const MWWorld::Ptr& ptr, int skill) const;

View file

@ -553,14 +553,14 @@ void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MW
if(listInMap != allowedForReplace.end())
restockNum -= std::min(restockNum, listInMap->second);
//restock
addInitialItem(itemOrList, owner, restockNum, true);
addInitialItem(itemOrList, owner, -restockNum, true);
}
else
{
//Restocking static item - just restock to the max count
int currentCount = count(itemOrList);
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();

View file

@ -6,6 +6,7 @@
#include <components/esm/loadench.hpp>
#include <components/esm/inventorystate.hpp>
#include <components/misc/rng.hpp>
#include <components/settings/settings.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
@ -214,36 +215,71 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::getSlot (int 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)
{
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_;
initSlots (slots_);
// Disable model update during auto-equip
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;
// Don't autoEquip lights. Handled in Actors::updateEquippedLight based on environment light.
if (test.getTypeName() == typeid(ESM::Light).name())
{
if (!canActorAutoEquip(actor, test))
continue;
switch(test.getClass().canBeEquipped (test, actor).first)
{
case 0:
continue;
default:
break;
}
// 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(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
)
if (iter.getType() == ContainerStore::Type_Armor &&
test.getClass().getEffectiveArmorRating(test, actor) <= std::max(unarmoredRating, 0.f))
{
continue;
}
int testSkill = test.getClass().getEquipmentSkill (test);
std::pair<std::vector<int>, bool> itemsSlots =
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());
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())
{
Ptr old = *slots_.at (*iter2);
// check skill
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 (iter.getType() == ContainerStore::Type_Armor)
{
if (actor.getClass().getSkill(actor, oldSkill) > actor.getClass().getSkill (actor, testSkill))
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))
if (old.getTypeName() == typeid(ESM::Armor).name())
{
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
@ -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;
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 (
effectIt->mEffectID);
// Fully resisted?
if (params[i].mMultiplier == 0)
// Fully resisted or can't be applied to target?
if (params[i].mMultiplier == 0 || !MWMechanics::checkEffectTarget(effectIt->mEffectID, actor, actor, actor == MWMechanics::getPlayer()))
continue;
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());
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];
float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * params.mRandom;
magnitude *= params.mMultiplier;

View file

@ -115,6 +115,8 @@ namespace MWWorld
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);
bool canActorAutoEquip(const MWWorld::Ptr& actor, const MWWorld::Ptr& item);
public:
InventoryStore();

View file

@ -16,6 +16,7 @@ namespace
cellRef.mScale = 1;
cellRef.mFactionRank = 0;
cellRef.mChargeInt = -1;
cellRef.mChargeIntRemainder = 0.0f;
cellRef.mGoldValue = 1;
cellRef.mEnchantmentCharge = -1;
cellRef.mTeleport = false;

View file

@ -136,7 +136,7 @@ namespace MWWorld
};
void ProjectileManager::createModel(State &state, const std::string &model, const osg::Vec3f& pos, const osg::Quat& orient, bool rotate, std::string texture)
void ProjectileManager::createModel(State &state, const std::string &model, const osg::Vec3f& pos, const osg::Quat& orient, bool rotate, bool createLight, std::string texture)
{
state.mNode = new osg::PositionAttitudeTransform;
state.mNode->setNodeMask(MWRender::Mask_Effect);
@ -167,6 +167,55 @@ namespace MWWorld
mResourceSystem->getSceneManager()->getInstance("meshes\\" + weapon->mModel, findVisitor.mFoundNode);
}
if (createLight)
{
// Case: magical effects (combine colors of individual effects)
osg::Vec4 lightDiffuseColor;
if (state.mIdMagic.size() > 0)
{
float lightDiffuseRed = 0.0f;
float lightDiffuseGreen = 0.0f;
float lightDiffuseBlue = 0.0f;
for (std::vector<ESM::ENAMstruct>::const_iterator it = ((MagicBoltState&)state).mEffects.mList.begin(); it != ((MagicBoltState&)state).mEffects.mList.end(); ++it)
{
const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(
it->mEffectID);
lightDiffuseRed += ((float) magicEffect->mData.mRed / 255.f);
lightDiffuseGreen += ((float) magicEffect->mData.mGreen / 255.f);
lightDiffuseBlue += ((float) magicEffect->mData.mBlue / 255.f);
}
int numberOfEffects = ((MagicBoltState&)state).mEffects.mList.size();
lightDiffuseColor = osg::Vec4(lightDiffuseRed / numberOfEffects
, lightDiffuseGreen / numberOfEffects
, lightDiffuseBlue / numberOfEffects
, 1.0f);
}
else
{
// Case: no magical effects, but still creating light
lightDiffuseColor = osg::Vec4(0.814f, 0.682f, 0.652f, 1.0f);
}
// Add light
osg::ref_ptr<osg::Light> projectileLight(new osg::Light);
projectileLight->setAmbient(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
projectileLight->setDiffuse(lightDiffuseColor);
projectileLight->setSpecular(osg::Vec4(0.0f, 0.0f, 0.0f, 0.0f));
projectileLight->setConstantAttenuation(0.f);
projectileLight->setLinearAttenuation(0.1f);
projectileLight->setQuadraticAttenuation(0.f);
projectileLight->setPosition(osg::Vec4(pos, 1.0));
// Add light source
SceneUtil::LightSource* projectileLightSource = new SceneUtil::LightSource;
projectileLightSource->setNodeMask(MWRender::Mask_Lighting);
projectileLightSource->setRadius(66.f);
// Attach to scene node
state.mNode->addChild(projectileLightSource);
projectileLightSource->setLight(projectileLight);
}
SceneUtil::DisableFreezeOnCullVisitor disableFreezeOnCullVisitor;
state.mNode->accept(disableFreezeOnCullVisitor);
@ -229,7 +278,7 @@ namespace MWWorld
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), state.mIdMagic.at(0));
MWWorld::Ptr ptr = ref.getPtr();
createModel(state, ptr.getClass().getModel(ptr), pos, orient, true, texture);
createModel(state, ptr.getClass().getModel(ptr), pos, orient, true, true, texture);
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
for (size_t it = 0; it != state.mSoundIds.size(); it++)
@ -253,7 +302,7 @@ namespace MWWorld
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), projectile.getCellRef().getRefId());
MWWorld::Ptr ptr = ref.getPtr();
createModel(state, ptr.getClass().getModel(ptr), pos, orient, false);
createModel(state, ptr.getClass().getModel(ptr), pos, orient, false, false);
mProjectiles.push_back(state);
}
@ -369,7 +418,7 @@ namespace MWWorld
// Try to get a Ptr to the bow that was used. It might no longer exist.
MWWorld::Ptr bow = projectileRef.getPtr();
if (!caster.isEmpty())
if (!caster.isEmpty() && it->mIdArrow != it->mBowId)
{
MWWorld::InventoryStore& inv = caster.getClass().getInventoryStore(caster);
MWWorld::ContainerStoreIterator invIt = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
@ -483,7 +532,7 @@ namespace MWWorld
return true;
}
createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), false);
createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), false, false);
mProjectiles.push_back(state);
return true;
@ -518,7 +567,7 @@ namespace MWWorld
return true;
}
createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), true, texture);
createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), true, true, texture);
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();

View file

@ -122,7 +122,7 @@ namespace MWWorld
void moveProjectiles(float dt);
void moveMagicBolts(float dt);
void createModel (State& state, const std::string& model, const osg::Vec3f& pos, const osg::Quat& orient, bool rotate, std::string texture = "");
void createModel (State& state, const std::string& model, const osg::Vec3f& pos, const osg::Quat& orient, bool rotate, bool createLight, std::string texture = "");
void update (State& state, float duration);
void operator=(const ProjectileManager&);

View file

@ -421,11 +421,17 @@ namespace MWWorld
gmst["sBribeFail"] = ESM::Variant("Bribe Fail");
gmst["fNPCHealthBarTime"] = ESM::Variant(5.f);
gmst["fNPCHealthBarFade"] = ESM::Variant(1.f);
gmst["fFleeDistance"] = ESM::Variant(3000.f);
gmst["sMaxSale"] = ESM::Variant("Max Sale");
// Werewolf (BM)
gmst["fWereWolfRunMult"] = ESM::Variant(1.f);
gmst["fWereWolfSilverWeaponDamageMult"] = ESM::Variant(1.f);
gmst["iWerewolfFightMod"] = ESM::Variant(1);
gmst["fWereWolfRunMult"] = ESM::Variant(1.3f);
gmst["fWereWolfSilverWeaponDamageMult"] = ESM::Variant(2.f);
gmst["iWerewolfFightMod"] = ESM::Variant(100);
gmst["iWereWolfFleeMod"] = ESM::Variant(100);
gmst["iWereWolfLevelToAttack"] = ESM::Variant(20);
gmst["iWereWolfBounty"] = ESM::Variant(1000);
gmst["fCombatDistanceWerewolfMod"] = ESM::Variant(0.3f);
std::map<std::string, ESM::Variant> globals;
// vanilla Morrowind does not define dayspassed.
@ -1295,7 +1301,7 @@ namespace MWWorld
float terrainHeight = -std::numeric_limits<float>::max();
if (ptr.getCell()->isExterior())
terrainHeight = mRendering->getTerrainHeightAt(pos.asVec3());
terrainHeight = getTerrainHeightAt(pos.asVec3());
if (pos.pos[2] < terrainHeight)
pos.pos[2] = terrainHeight;
@ -2078,11 +2084,16 @@ namespace MWWorld
if (!cell->getCell()->hasWater())
return true;
// Based on observations from the original engine, the depth
// limit at which water walking can still be cast on a target
// in water appears to be the same as what the highest swimmable
// z position would be with SwimHeightScale + 1.
return !isUnderwater(target, mSwimHeightScale + 1);
float waterlevel = cell->getWaterLevel();
// SwimHeightScale affects the upper z position an actor can swim to
// while in water. Based on observation from the original engine,
// the upper z position you get with a +1 SwimHeightScale is the depth
// limit for being able to cast water walking on an underwater target.
if (isUnderwater(target, mSwimHeightScale + 1) || (isUnderwater(cell, target.getRefData().getPosition().asVec3()) && !mPhysics->canMoveToWaterSurface(target, waterlevel)))
return false; // not castable if too deep or if not enough room to move actor to surface
else
return true;
}
bool World::isOnGround(const MWWorld::Ptr &ptr) const
@ -2183,7 +2194,7 @@ namespace MWWorld
if (!actor)
throw std::runtime_error("can't find player");
if ((actor->getCollisionMode() && !mPhysics->isOnSolidGround(player)) || isUnderwater(currentCell, playerPos))
if ((actor->getCollisionMode() && !mPhysics->isOnSolidGround(player)) || isUnderwater(currentCell, playerPos) || isWalkingOnWater(player))
return 2;
if((currentCell->getCell()->mData.mFlags&ESM::Cell::NoSleep) || player.getClass().getNpcStats(player).isWerewolf())
@ -3121,6 +3132,19 @@ namespace MWWorld
return MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_Jail);
}
float World::getTerrainHeightAt(const osg::Vec3f& worldPos) const
{
return mRendering->getTerrainHeightAt(worldPos);
}
osg::Vec3f World::getHalfExtents(const ConstPtr& actor, bool rendering) const
{
if (rendering)
return mPhysics->getRenderingHalfExtents(actor);
else
return mPhysics->getHalfExtents(actor);
}
void World::spawnRandomCreature(const std::string &creatureList)
{
const ESM::CreatureLevList* list = getStore().get<ESM::CreatureLevList>().find(creatureList);
@ -3289,7 +3313,7 @@ namespace MWWorld
}
}
bool World::isWalkingOnWater(const ConstPtr &actor)
bool World::isWalkingOnWater(const ConstPtr &actor) const
{
const MWPhysics::Actor* physicActor = mPhysics->getActor(actor);
if (physicActor && physicActor->isWalkingOnWater())

View file

@ -651,7 +651,7 @@ namespace MWWorld
/// Resets all actors in the current active cells to their original location within that cell.
virtual void resetActors();
virtual bool isWalkingOnWater (const MWWorld::ConstPtr& actor);
virtual bool isWalkingOnWater (const MWWorld::ConstPtr& actor) const;
/// Return a vector aiming the actor's weapon towards a target.
/// @note The length of the vector is the distance between actor and target.
@ -661,6 +661,12 @@ namespace MWWorld
virtual float getHitDistance(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target);
virtual bool isPlayerInJail() const;
/// Return terrain height at \a worldPos position.
virtual float getTerrainHeightAt(const osg::Vec3f& worldPos) const;
/// Return physical or rendering half extents of the given actor.
virtual osg::Vec3f getHalfExtents(const MWWorld::ConstPtr& actor, bool rendering=false) const;
};
}

View file

@ -140,3 +140,6 @@ if (CMAKE_SYSTEM_NAME MATCHES "Linux")
target_link_libraries(openmw-wizard dl Xt)
endif()
if (WIN32)
INSTALL(TARGETS openmw-wizard RUNTIME DESTINATION ".")
endif(WIN32)

View file

@ -24,7 +24,7 @@ Wizard::ComponentSelectionPage::ComponentSelectionPage(QWidget *parent) :
}
void Wizard::ComponentSelectionPage::updateButton(QListWidgetItem *item)
void Wizard::ComponentSelectionPage::updateButton(QListWidgetItem*)
{
if (field(QLatin1String("installation.new")).toBool() == true)
return; // Morrowind is always checked here

View file

@ -63,13 +63,13 @@ bool Wizard::ExistingInstallationPage::validatePage()
The Wizard needs to update settings in this file.<br><br> \
Press \"Browse...\" to specify the location manually.<br>"));
QAbstractButton *browseButton =
QAbstractButton *browseButton2 =
msgBox.addButton(QObject::tr("B&rowse..."), QMessageBox::ActionRole);
msgBox.exec();
QString iniFile;
if (msgBox.clickedButton() == browseButton) {
if (msgBox.clickedButton() == browseButton2) {
iniFile = QFileDialog::getOpenFileName(
this,
QObject::tr("Select configuration file"),

View file

@ -20,12 +20,6 @@ int main(int argc, char *argv[])
QDir dir(QCoreApplication::applicationDirPath());
#ifdef Q_OS_MAC
if (dir.dirName() == "MacOS") {
dir.cdUp();
dir.cdUp();
dir.cdUp();
}
// force Qt to load only LOCAL plugins, don't touch system Qt installation
QDir pluginsPath(QCoreApplication::applicationDirPath());
pluginsPath.cdUp();

View file

@ -162,10 +162,10 @@ void Wizard::MainWizard::setupGameSettings()
paths.append(QLatin1String("openmw.cfg"));
paths.append(globalPath + QLatin1String("openmw.cfg"));
foreach (const QString &path, paths) {
qDebug() << "Loading config file:" << path.toUtf8().constData();
foreach (const QString &path2, paths) {
qDebug() << "Loading config file:" << path2.toUtf8().constData();
QFile file(path);
file.setFileName(path2);
if (file.exists()) {
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
QMessageBox msgBox;

View file

@ -77,7 +77,7 @@ add_component_dir (esm
loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter
savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap inventorystate containerstate npcstate creaturestate dialoguestate statstate
npcstats creaturestats weatherstate quickkeys fogstate spellstate activespells creaturelevliststate doorstate projectilestate debugprofile
aisequence magiceffects util custommarkerstate stolenitems transport animationstate
aisequence magiceffects util custommarkerstate stolenitems transport animationstate controlsstate
)
add_component_dir (esmterrain
@ -206,7 +206,7 @@ target_link_libraries(components
${OSGFX_LIBRARIES}
${OSGANIMATION_LIBRARIES}
${Bullet_LIBRARIES}
${SDL2_LIBRARY}
${SDL2_LIBRARIES}
# For MyGUI platform
${GL_LIB}
${MyGUI_LIBRARIES}

View file

@ -110,26 +110,26 @@ Qt::ItemFlags ContentSelectorModel::ContentModel::flags(const QModelIndex &index
bool gamefileChecked = (file->gameFiles().count() == 0);
foreach (const QString &fileName, file->gameFiles())
{
foreach (EsmFile *dependency, mFiles)
for (QListIterator<EsmFile *> dependencyIter(mFiles); dependencyIter.hasNext(); dependencyIter.next())
{
//compare filenames only. Multiple instances
//of the filename (with different paths) is not relevant here.
bool depFound = (dependency->fileName().compare(fileName, Qt::CaseInsensitive) == 0);
bool depFound = (dependencyIter.peekNext()->fileName().compare(fileName, Qt::CaseInsensitive) == 0);
if (!depFound)
continue;
if (!gamefileChecked)
{
if (isChecked (dependency->filePath()))
gamefileChecked = (dependency->isGameFile());
if (isChecked (dependencyIter.peekNext()->filePath()))
gamefileChecked = (dependencyIter.peekNext()->isGameFile());
}
// force it to iterate all files in cases where the current
// dependency is a game file to ensure that a later duplicate
// game file is / is not checked.
// (i.e., break only if it's not a gamefile or the game file has been checked previously)
if (gamefileChecked || !(dependency->isGameFile()))
if (gamefileChecked || !(dependencyIter.peekNext()->isGameFile()))
break;
}
}
@ -283,12 +283,11 @@ bool ContentSelectorModel::ContentModel::setData(const QModelIndex &index, const
else
return success;
foreach (EsmFile *file, mFiles)
foreach (EsmFile *file2, mFiles)
{
if (file->gameFiles().contains(fileName, Qt::CaseInsensitive))
if (file2->gameFiles().contains(fileName, Qt::CaseInsensitive))
{
QModelIndex idx = indexFromItem(file);
QModelIndex idx = indexFromItem(file2);
emit dataChanged(idx, idx);
}
}
@ -425,9 +424,9 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path)
filters << "*.esp" << "*.esm" << "*.omwgame" << "*.omwaddon";
dir.setNameFilters(filters);
foreach (const QString &path, dir.entryList())
foreach (const QString &path2, dir.entryList())
{
QFileInfo info(dir.absoluteFilePath(path));
QFileInfo info(dir.absoluteFilePath(path2));
if (item(info.absoluteFilePath()) != 0)
continue;
@ -437,12 +436,13 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path)
ToUTF8::Utf8Encoder encoder =
ToUTF8::calculateEncoding(mEncoding.toStdString());
fileReader.setEncoder(&encoder);
fileReader.open(std::string(dir.absoluteFilePath(path).toUtf8().constData()));
fileReader.open(std::string(dir.absoluteFilePath(path2).toUtf8().constData()));
EsmFile *file = new EsmFile(path);
EsmFile *file = new EsmFile(path2);
foreach (const ESM::Header::MasterData &item, fileReader.getGameFiles())
file->addGameFile(QString::fromUtf8(item.name.c_str()));
for (std::vector<ESM::Header::MasterData>::const_iterator itemIter = fileReader.getGameFiles().begin();
itemIter != fileReader.getGameFiles().end(); ++itemIter)
file->addGameFile(QString::fromUtf8(itemIter->name.c_str()));
file->setAuthor (QString::fromUtf8(fileReader.getAuthor().c_str()));
file->setDate (info.lastModified());

View file

@ -192,8 +192,8 @@ void ContentSelectorView::ContentSelector::setGameFileSelected(int index, bool s
const ContentSelectorModel::EsmFile* file = mContentModel->item(fileName);
if (file != NULL)
{
QModelIndex index(mContentModel->indexFromItem(file));
mContentModel->setData(index, selected, Qt::UserRole + 1);
QModelIndex index2(mContentModel->indexFromItem(file));
mContentModel->setData(index2, selected, Qt::UserRole + 1);
}
}

View file

@ -21,7 +21,18 @@ namespace ESM
anim.mGroup = esm.getHString();
esm.getHNOT(anim.mTime, "TIME");
esm.getHNOT(anim.mAbsolute, "ABST");
esm.getHNT(anim.mLoopCount, "COUN");
esm.getSubNameIs("COUN");
// workaround bug in earlier version where size_t was used
esm.getSubHeader();
if (esm.getSubSize() == 8)
esm.getT(anim.mLoopCount);
else
{
uint32_t loopcount;
esm.getT(loopcount);
anim.mLoopCount = (uint64_t) loopcount;
}
mScriptedAnims.push_back(anim);
}

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