mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-16 18:19:55 +00:00
Merge branch 'master' of https://github.com/OpenMW/openmw
# Conflicts: # docs/source/openmw-mods/index.rst
This commit is contained in:
commit
bf805813e5
145 changed files with 2968 additions and 933 deletions
|
@ -1,6 +1,6 @@
|
|||
os:
|
||||
- linux
|
||||
- osx
|
||||
# - osx
|
||||
osx_image: xcode7.2
|
||||
language: cpp
|
||||
sudo: required
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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" \
|
||||
|
|
|
@ -46,7 +46,7 @@ if(EXISTS ${PROJECT_SOURCE_DIR}/.git)
|
|||
else(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/shallow)
|
||||
message(STATUS "Shallow Git clone detected, not attempting to retrieve version info")
|
||||
endif(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/shallow)
|
||||
endif(EXISTS ${PROJECT_SOURCE_DIR}/.git)
|
||||
endif(EXISTS ${PROJECT_SOURCE_DIR}/.git)
|
||||
|
||||
# Macros
|
||||
include(OpenMWMacros)
|
||||
|
@ -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 ()
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace ESM
|
|||
namespace ESSImport
|
||||
{
|
||||
|
||||
/// Local variable assigments for a running script
|
||||
/// Local variable assignments for a running script
|
||||
struct SCRI
|
||||
{
|
||||
std::string mScript;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ namespace CSMPrefs
|
|||
enum SecondaryMode
|
||||
{
|
||||
SM_Replace, ///< The secondary signal replaces the regular signal when the modifier is active
|
||||
SM_Detach, ///< The secondary signal is emitted independant of the regular signal, even if not active
|
||||
SM_Detach, ///< The secondary signal is emitted independent of the regular signal, even if not active
|
||||
SM_Ignore ///< The secondary signal will not ever be emitted
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -659,7 +659,7 @@ void CSMTools::ReferenceableCheckStage::npcCheck (
|
|||
{
|
||||
if ((npc.mFlags & ESM::NPC::Autocalc) == 0) //0x0010 = autocalculated flag
|
||||
{
|
||||
messages.push_back (std::make_pair (id, npc.mId + " mNpdtType or flags mismatch!")); //should not happend?
|
||||
messages.push_back (std::make_pair (id, npc.mId + " mNpdtType or flags mismatch!")); //should not happen?
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -915,7 +915,7 @@ void CSMTools::ReferenceableCheckStage::inventoryListCheck(
|
|||
id + " contains non-existing item (" + itemName + ")"));
|
||||
else
|
||||
{
|
||||
// Needs to accomodate Containers, Creatures, and NPCs
|
||||
// Needs to accommodate containers, creatures, and NPCs
|
||||
switch (localIndex.second)
|
||||
{
|
||||
case CSMWorld::UniversalId::Type_Potion:
|
||||
|
|
|
@ -1627,264 +1627,264 @@ const char * CSMWorld::DefaultGmsts::OptionalStrings[CSMWorld::DefaultGmsts::Opt
|
|||
|
||||
const float CSMWorld::DefaultGmsts::FloatsDefaultValues[CSMWorld::DefaultGmsts::FloatCount] =
|
||||
{
|
||||
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] =
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -198,12 +198,12 @@ QModelIndex CSMWorld::IdTree::parent (const QModelIndex& index) const
|
|||
return QModelIndex();
|
||||
|
||||
unsigned int id = index.internalId();
|
||||
const std::pair<int, int>& adress(unfoldIndexAddress(id));
|
||||
const std::pair<int, int>& address(unfoldIndexAddress(id));
|
||||
|
||||
if (adress.first >= this->rowCount() || adress.second >= this->columnCount())
|
||||
if (address.first >= this->rowCount() || address.second >= this->columnCount())
|
||||
throw "Parent index is not present in the model";
|
||||
|
||||
return createIndex(adress.first, adress.second);
|
||||
return createIndex(address.first, address.second);
|
||||
}
|
||||
|
||||
unsigned int CSMWorld::IdTree::foldIndexAddress (const QModelIndex& index) const
|
||||
|
|
|
@ -63,7 +63,7 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool
|
|||
std::cerr << "Position: #" << index.first << " " << index.second
|
||||
<<", 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
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ namespace CSVRender
|
|||
updateCellData(mData.getCells().getRecord(cellIndex));
|
||||
}
|
||||
|
||||
// Keep water existance/height up to date
|
||||
// Keep water existence/height up to date
|
||||
QAbstractItemModel* cells = mData.getTableModel(CSMWorld::UniversalId::Type_Cells);
|
||||
connect(cells, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)),
|
||||
this, SLOT(cellDataChanged(const QModelIndex&, const QModelIndex&)));
|
||||
|
|
|
@ -516,7 +516,7 @@ void CSVRender::PagedWorldspaceWidget::useViewHint (const std::string& hint)
|
|||
// Current coordinate
|
||||
int x, y;
|
||||
|
||||
// Loop throught all the coordinates to add them to selection
|
||||
// Loop through all the coordinates to add them to selection
|
||||
while (stream >> ignore1 >> ignore2 >> x >> y)
|
||||
selection.add (CSMWorld::CellCoordinates (x, y));
|
||||
|
||||
|
|
|
@ -214,7 +214,7 @@ SceneWidget::SceneWidget(boost::shared_ptr<Resource::ResourceSystem> resourceSys
|
|||
|
||||
SceneWidget::~SceneWidget()
|
||||
{
|
||||
// Since we're holding on to the scene templates past the existance of this graphics context, we'll need to manually release the created objects
|
||||
// Since we're holding on to the scene templates past the existence of this graphics context, we'll need to manually release the created objects
|
||||
mResourceSystem->getSceneManager()->releaseGLObjects(mView->getCamera()->getGraphicsContext()->getState());
|
||||
}
|
||||
|
||||
|
|
|
@ -45,8 +45,8 @@ namespace CSVWorld
|
|||
///< \note Non-existent cells are not listed.
|
||||
|
||||
QModelIndexList getSelectedCells (bool existent = true, bool nonExistent = false) const;
|
||||
///< \param existant Include existant cells.
|
||||
/// \param nonExistant Include non-existant cells.
|
||||
///< \param existent Include existent cells.
|
||||
/// \param nonExistent Include non-existent cells.
|
||||
|
||||
QModelIndexList getMissingRegionCells() const;
|
||||
///< Unselected cells within all regions that have at least one selected cell.
|
||||
|
|
|
@ -42,7 +42,7 @@ add_openmw_dir (mwgui
|
|||
itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview
|
||||
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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -233,7 +233,7 @@ namespace MWBase
|
|||
virtual void removeDialog(MWGui::Layout* dialog) = 0;
|
||||
|
||||
///Gracefully attempts to exit the topmost GUI mode
|
||||
/** No guarentee of actually closing the window **/
|
||||
/** No guarantee of actually closing the window **/
|
||||
virtual void exitCurrentGuiMode() = 0;
|
||||
|
||||
virtual void messageBox (const std::string& message, enum MWGui::ShowInDialogueMode showInDialogueMode = MWGui::ShowInDialogueMode_IfPossible) = 0;
|
||||
|
|
|
@ -548,7 +548,7 @@ namespace MWBase
|
|||
/// Resets all actors in the current active cells to their original location within that cell.
|
||||
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;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -174,7 +174,7 @@ namespace MWDialogue
|
|||
executeScript (info->mResultScript);
|
||||
mLastTopic = Misc::StringUtils::lowerCase(it->mId);
|
||||
|
||||
// update topics again to accomodate changes resulting from executeScript
|
||||
// update topics again to accommodate changes resulting from executeScript
|
||||
updateTopics();
|
||||
|
||||
return;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
212
apps/openmw/mwgui/itemchargeview.cpp
Normal file
212
apps/openmw/mwgui/itemchargeview.cpp
Normal file
|
@ -0,0 +1,212 @@
|
|||
#include "itemchargeview.hpp"
|
||||
|
||||
#include <set>
|
||||
|
||||
#include <MyGUI_Gui.h>
|
||||
#include <MyGUI_TextBox.h>
|
||||
#include <MyGUI_ScrollView.h>
|
||||
#include <MyGUI_FactoryManager.h>
|
||||
|
||||
#include <components/esm/loadench.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include "itemmodel.hpp"
|
||||
#include "itemwidget.hpp"
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
ItemChargeView::ItemChargeView()
|
||||
: mScrollView(NULL),
|
||||
mDisplayMode(DisplayMode_Health)
|
||||
{
|
||||
}
|
||||
|
||||
void ItemChargeView::registerComponents()
|
||||
{
|
||||
MyGUI::FactoryManager::getInstance().registerFactory<ItemChargeView>("Widget");
|
||||
}
|
||||
|
||||
void ItemChargeView::initialiseOverride()
|
||||
{
|
||||
Base::initialiseOverride();
|
||||
|
||||
assignWidget(mScrollView, "ScrollView");
|
||||
if (mScrollView == NULL)
|
||||
throw std::runtime_error("Item charge view needs a scroll view");
|
||||
|
||||
mScrollView->setCanvasAlign(MyGUI::Align::Left | MyGUI::Align::Top);
|
||||
}
|
||||
|
||||
void ItemChargeView::setModel(ItemModel* model)
|
||||
{
|
||||
mModel.reset(model);
|
||||
}
|
||||
|
||||
void ItemChargeView::setDisplayMode(ItemChargeView::DisplayMode type)
|
||||
{
|
||||
mDisplayMode = type;
|
||||
update();
|
||||
}
|
||||
|
||||
void ItemChargeView::update()
|
||||
{
|
||||
if (!mModel.get())
|
||||
{
|
||||
layoutWidgets();
|
||||
return;
|
||||
}
|
||||
|
||||
mModel->update();
|
||||
|
||||
Lines lines;
|
||||
std::set<Lines::const_iterator> visitedLines;
|
||||
|
||||
for (size_t i = 0; i < mModel->getItemCount(); ++i)
|
||||
{
|
||||
ItemStack stack = mModel->getItem(static_cast<ItemModel::ModelIndex>(i));
|
||||
|
||||
bool found = false;
|
||||
for (Lines::const_iterator iter = mLines.begin(); iter != mLines.end(); ++iter)
|
||||
{
|
||||
if (iter->mItemPtr == stack.mBase)
|
||||
{
|
||||
found = true;
|
||||
visitedLines.insert(iter);
|
||||
|
||||
// update line widgets
|
||||
updateLine(*iter);
|
||||
lines.push_back(*iter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
// add line widgets
|
||||
Line line;
|
||||
line.mItemPtr = stack.mBase;
|
||||
|
||||
line.mText = mScrollView->createWidget<MyGUI::TextBox>("SandText", MyGUI::IntCoord(), MyGUI::Align::Default);
|
||||
line.mText->setNeedMouseFocus(false);
|
||||
|
||||
line.mIcon = mScrollView->createWidget<ItemWidget>("MW_ItemIconSmall", MyGUI::IntCoord(), MyGUI::Align::Default);
|
||||
line.mIcon->setItem(line.mItemPtr);
|
||||
line.mIcon->setUserString("ToolTipType", "ItemPtr");
|
||||
line.mIcon->setUserData(line.mItemPtr);
|
||||
line.mIcon->eventMouseButtonClick += MyGUI::newDelegate(this, &ItemChargeView::onIconClicked);
|
||||
line.mIcon->eventMouseWheel += MyGUI::newDelegate(this, &ItemChargeView::onMouseWheelMoved);
|
||||
|
||||
line.mCharge = mScrollView->createWidget<Widgets::MWDynamicStat>("MW_ChargeBar", MyGUI::IntCoord(), MyGUI::Align::Default);
|
||||
line.mCharge->setNeedMouseFocus(false);
|
||||
|
||||
updateLine(line);
|
||||
|
||||
lines.push_back(line);
|
||||
}
|
||||
}
|
||||
|
||||
for (Lines::iterator iter = mLines.begin(); iter != mLines.end(); ++iter)
|
||||
{
|
||||
if (visitedLines.count(iter))
|
||||
continue;
|
||||
|
||||
// remove line widgets
|
||||
MyGUI::Gui::getInstance().destroyWidget(iter->mText);
|
||||
MyGUI::Gui::getInstance().destroyWidget(iter->mIcon);
|
||||
MyGUI::Gui::getInstance().destroyWidget(iter->mCharge);
|
||||
}
|
||||
|
||||
mLines.swap(lines);
|
||||
|
||||
layoutWidgets();
|
||||
}
|
||||
|
||||
void ItemChargeView::layoutWidgets()
|
||||
{
|
||||
int currentY = 0;
|
||||
|
||||
for (Lines::const_iterator iter = mLines.begin(); iter != mLines.end(); ++iter)
|
||||
{
|
||||
iter->mText->setCoord(8, currentY, mScrollView->getWidth()-8, 18);
|
||||
currentY += 19;
|
||||
|
||||
iter->mIcon->setCoord(16, currentY, 32, 32);
|
||||
iter->mCharge->setCoord(72, currentY+2, std::max(199, mScrollView->getWidth()-72-38), 20);
|
||||
currentY += 32 + 4;
|
||||
}
|
||||
|
||||
// Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the scrollbar is hidden
|
||||
mScrollView->setVisibleVScroll(false);
|
||||
mScrollView->setCanvasSize(MyGUI::IntSize(mScrollView->getWidth(), std::max(mScrollView->getHeight(), currentY)));
|
||||
mScrollView->setVisibleVScroll(true);
|
||||
}
|
||||
|
||||
void ItemChargeView::resetScrollbars()
|
||||
{
|
||||
mScrollView->setViewOffset(MyGUI::IntPoint(0, 0));
|
||||
}
|
||||
|
||||
void ItemChargeView::setSize(const MyGUI::IntSize& value)
|
||||
{
|
||||
bool changed = (value.width != getWidth() || value.height != getHeight());
|
||||
Base::setSize(value);
|
||||
if (changed)
|
||||
layoutWidgets();
|
||||
}
|
||||
|
||||
void ItemChargeView::setCoord(const MyGUI::IntCoord& value)
|
||||
{
|
||||
bool changed = (value.width != getWidth() || value.height != getHeight());
|
||||
Base::setCoord(value);
|
||||
if (changed)
|
||||
layoutWidgets();
|
||||
}
|
||||
|
||||
void ItemChargeView::updateLine(const ItemChargeView::Line& line)
|
||||
{
|
||||
line.mText->setCaption(line.mItemPtr.getClass().getName(line.mItemPtr));
|
||||
|
||||
line.mCharge->setVisible(false);
|
||||
switch (mDisplayMode)
|
||||
{
|
||||
case DisplayMode_Health:
|
||||
if (!line.mItemPtr.getClass().hasItemHealth(line.mItemPtr))
|
||||
break;
|
||||
|
||||
line.mCharge->setVisible(true);
|
||||
line.mCharge->setValue(line.mItemPtr.getClass().getItemHealth(line.mItemPtr),
|
||||
line.mItemPtr.getClass().getItemMaxHealth(line.mItemPtr));
|
||||
break;
|
||||
case DisplayMode_EnchantmentCharge:
|
||||
std::string enchId = line.mItemPtr.getClass().getEnchantment(line.mItemPtr);
|
||||
if (enchId.empty())
|
||||
break;
|
||||
const ESM::Enchantment* ench = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().search(enchId);
|
||||
if (!ench)
|
||||
break;
|
||||
|
||||
line.mCharge->setVisible(true);
|
||||
line.mCharge->setValue(static_cast<int>(line.mItemPtr.getCellRef().getEnchantmentCharge()),
|
||||
ench->mData.mCharge);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ItemChargeView::onIconClicked(MyGUI::Widget* sender)
|
||||
{
|
||||
eventItemClicked(this, *sender->getUserData<MWWorld::Ptr>());
|
||||
}
|
||||
|
||||
void ItemChargeView::onMouseWheelMoved(MyGUI::Widget* /*sender*/, int rel)
|
||||
{
|
||||
if (mScrollView->getViewOffset().top + rel*0.3f > 0)
|
||||
mScrollView->setViewOffset(MyGUI::IntPoint(0, 0));
|
||||
else
|
||||
mScrollView->setViewOffset(MyGUI::IntPoint(0, static_cast<int>(mScrollView->getViewOffset().top + rel*0.3f)));
|
||||
}
|
||||
}
|
78
apps/openmw/mwgui/itemchargeview.hpp
Normal file
78
apps/openmw/mwgui/itemchargeview.hpp
Normal file
|
@ -0,0 +1,78 @@
|
|||
#ifndef MWGUI_ITEMCHARGEVIEW_H
|
||||
#define MWGUI_ITEMCHARGEVIEW_H
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include <MyGUI_Widget.h>
|
||||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
|
||||
#include "widgets.hpp"
|
||||
|
||||
namespace MyGUI
|
||||
{
|
||||
class TextBox;
|
||||
class ScrollView;
|
||||
}
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
class ItemModel;
|
||||
class ItemWidget;
|
||||
|
||||
class ItemChargeView : public MyGUI::Widget
|
||||
{
|
||||
MYGUI_RTTI_DERIVED(ItemChargeView)
|
||||
public:
|
||||
enum DisplayMode
|
||||
{
|
||||
DisplayMode_Health,
|
||||
DisplayMode_EnchantmentCharge
|
||||
};
|
||||
|
||||
ItemChargeView();
|
||||
|
||||
/// Register needed components with MyGUI's factory manager
|
||||
static void registerComponents();
|
||||
|
||||
virtual void initialiseOverride();
|
||||
|
||||
/// Takes ownership of \a model
|
||||
void setModel(ItemModel* model);
|
||||
|
||||
void setDisplayMode(DisplayMode type);
|
||||
|
||||
void update();
|
||||
void layoutWidgets();
|
||||
void resetScrollbars();
|
||||
|
||||
virtual void setSize(const MyGUI::IntSize& value);
|
||||
virtual void setCoord(const MyGUI::IntCoord& value);
|
||||
|
||||
MyGUI::delegates::CMultiDelegate2<MyGUI::Widget*, const MWWorld::Ptr&> eventItemClicked;
|
||||
|
||||
private:
|
||||
struct Line
|
||||
{
|
||||
MWWorld::Ptr mItemPtr;
|
||||
MyGUI::TextBox* mText;
|
||||
ItemWidget* mIcon;
|
||||
Widgets::MWDynamicStatPtr mCharge;
|
||||
};
|
||||
|
||||
void updateLine(const Line& line);
|
||||
|
||||
void onIconClicked(MyGUI::Widget* sender);
|
||||
void onMouseWheelMoved(MyGUI::Widget* sender, int rel);
|
||||
|
||||
typedef std::vector<Line> Lines;
|
||||
Lines mLines;
|
||||
|
||||
std::auto_ptr<ItemModel> mModel;
|
||||
MyGUI::ScrollView* mScrollView;
|
||||
DisplayMode mDisplayMode;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -101,6 +101,8 @@ namespace MWGui
|
|||
{
|
||||
if (mFrame)
|
||||
mFrame->setImageTexture("");
|
||||
if (mItemShadow)
|
||||
mItemShadow->setImageTexture("");
|
||||
mItem->setImageTexture("");
|
||||
mText->setCaption("");
|
||||
return;
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -66,6 +66,8 @@ namespace MWGui
|
|||
|
||||
void configureWidgets(MyGUI::Widget* widget);
|
||||
void updateSliderLabel(MyGUI::ScrollBar* scroller, const std::string& value);
|
||||
|
||||
void layoutControlsBox();
|
||||
|
||||
private:
|
||||
void resetScrollbars();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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}");
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "character.hpp"
|
||||
#include "aicombataction.hpp"
|
||||
#include "combat.hpp"
|
||||
#include "coordinateconverter.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
@ -50,23 +51,40 @@ namespace MWMechanics
|
|||
bool mForceNoShortcut;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -152,7 +152,7 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characte
|
|||
|
||||
if (dist > 450)
|
||||
actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, true); //Make NPC run
|
||||
else if (dist < 325) //Have a bit of a dead zone, otherwise npc will constantly flip between running and not when right on the edge of the running threshhold
|
||||
else if (dist < 325) //Have a bit of a dead zone, otherwise npc will constantly flip between running and not when right on the edge of the running threshold
|
||||
actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, false); //make NPC walk
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
@ -313,7 +236,7 @@ namespace MWMechanics
|
|||
: mWatchedTimeToStartDrowning(0), mWatchedStatsEmpty (true), mUpdatePlayer (true), mClassSelected (false),
|
||||
mRaceSelected (false), mAI(true)
|
||||
{
|
||||
//buildPlayer no longer here, needs to be done explicitely after all subsystems are up and running
|
||||
//buildPlayer no longer here, needs to be done explicitly after all subsystems are up and running
|
||||
}
|
||||
|
||||
void MechanicsManager::add(const MWWorld::Ptr& ptr)
|
||||
|
@ -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())
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace MWMechanics
|
|||
bool proximityToDoor(const MWWorld::Ptr& actor,
|
||||
float minSqr = MIN_DIST_TO_DOOR_SQUARED);
|
||||
|
||||
/// Returns door pointer within range. No guarentee is given as too which one
|
||||
/// Returns door pointer within range. No guarantee is given as to which one
|
||||
/** \return Pointer to the door, or NULL if none exists **/
|
||||
MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor,
|
||||
float minSqr = MIN_DIST_TO_DOOR_SQUARED);
|
||||
|
|
|
@ -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)
|
||||
|
@ -491,7 +491,7 @@ namespace MWMechanics
|
|||
appliedLastingEffects.push_back(effect);
|
||||
|
||||
// For absorb effects, also apply the effect to the caster - but with a negative
|
||||
// magnitude, since we're transfering stats from the target to the caster
|
||||
// magnitude, since we're transferring stats from the target to the caster
|
||||
if (!caster.isEmpty() && caster.getClass().isActor())
|
||||
{
|
||||
for (int i=0; i<5; ++i)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -302,7 +302,7 @@ protected:
|
|||
|
||||
/** Sets the root model of the object.
|
||||
*
|
||||
* Note that you must make sure all animation sources are cleared before reseting the object
|
||||
* Note that you must make sure all animation sources are cleared before resetting the object
|
||||
* root. All nodes previously retrieved with getNode will also become invalidated.
|
||||
* @param forceskeleton Wrap the object root in a Skeleton, even if it contains no skinned parts. Use this if you intend to add skinned parts manually.
|
||||
* @param baseonly If true, then any meshes or particle systems in the model are ignored
|
||||
|
|
|
@ -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>();
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue