forked from mirror/openmw-tes3mp
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
34389e15cd
74 changed files with 573 additions and 190 deletions
|
@ -1,6 +1,6 @@
|
||||||
os:
|
os:
|
||||||
- linux
|
- linux
|
||||||
- osx
|
# - osx
|
||||||
osx_image: xcode7.2
|
osx_image: xcode7.2
|
||||||
language: cpp
|
language: cpp
|
||||||
sudo: required
|
sudo: required
|
||||||
|
|
|
@ -23,6 +23,7 @@ Programmers
|
||||||
Alexander Olofsson (Ace)
|
Alexander Olofsson (Ace)
|
||||||
Allofich
|
Allofich
|
||||||
AnyOldName3
|
AnyOldName3
|
||||||
|
Aussiemon
|
||||||
Austin Salgat (Salgat)
|
Austin Salgat (Salgat)
|
||||||
Artem Kotsynyak (greye)
|
Artem Kotsynyak (greye)
|
||||||
artemutin
|
artemutin
|
||||||
|
@ -74,6 +75,7 @@ Programmers
|
||||||
Karl-Felix Glatzer (k1ll)
|
Karl-Felix Glatzer (k1ll)
|
||||||
Kevin Poitra (PuppyKevin)
|
Kevin Poitra (PuppyKevin)
|
||||||
Koncord
|
Koncord
|
||||||
|
Kurnevsky Evgeny (kurnevsky)
|
||||||
Lars Söderberg (Lazaroth)
|
Lars Söderberg (Lazaroth)
|
||||||
lazydev
|
lazydev
|
||||||
Leon Saunders (emoose)
|
Leon Saunders (emoose)
|
||||||
|
@ -120,6 +122,7 @@ Programmers
|
||||||
Scott Howard
|
Scott Howard
|
||||||
Sebastian Wick (swick)
|
Sebastian Wick (swick)
|
||||||
Sergey Shambir
|
Sergey Shambir
|
||||||
|
ShadowRadiance
|
||||||
sir_herrbatka
|
sir_herrbatka
|
||||||
smbas
|
smbas
|
||||||
Stefan Galowicz (bogglez)
|
Stefan Galowicz (bogglez)
|
||||||
|
|
|
@ -96,7 +96,7 @@ endif()
|
||||||
# Set up common paths
|
# Set up common paths
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
set(MORROWIND_DATA_FILES "./data" CACHE PATH "location of Morrowind data files")
|
set(MORROWIND_DATA_FILES "./data" CACHE PATH "location of Morrowind data files")
|
||||||
set(OPENMW_RESOURCE_FILES "./resources" CACHE PATH "location of OpenMW resources files")
|
set(OPENMW_RESOURCE_FILES "../Resources/resources" CACHE PATH "location of OpenMW resources files")
|
||||||
elseif(UNIX)
|
elseif(UNIX)
|
||||||
# Paths
|
# Paths
|
||||||
SET(BINDIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Where to install binaries")
|
SET(BINDIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Where to install binaries")
|
||||||
|
@ -286,6 +286,11 @@ endif (APPLE)
|
||||||
# Set up DEBUG define
|
# Set up DEBUG define
|
||||||
set_directory_properties(PROPERTIES COMPILE_DEFINITIONS_DEBUG DEBUG=1)
|
set_directory_properties(PROPERTIES COMPILE_DEFINITIONS_DEBUG DEBUG=1)
|
||||||
|
|
||||||
|
if (NOT APPLE)
|
||||||
|
set(OPENMW_MYGUI_FILES_ROOT ${OpenMW_BINARY_DIR})
|
||||||
|
set(OPENMW_SHADERS_ROOT ${OpenMW_BINARY_DIR})
|
||||||
|
endif ()
|
||||||
|
|
||||||
add_subdirectory(files/)
|
add_subdirectory(files/)
|
||||||
|
|
||||||
# Specify build paths
|
# Specify build paths
|
||||||
|
@ -307,11 +312,15 @@ endif (APPLE)
|
||||||
configure_file(${OpenMW_SOURCE_DIR}/files/settings-default.cfg
|
configure_file(${OpenMW_SOURCE_DIR}/files/settings-default.cfg
|
||||||
"${OpenMW_BINARY_DIR}/settings-default.cfg")
|
"${OpenMW_BINARY_DIR}/settings-default.cfg")
|
||||||
|
|
||||||
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg.local
|
if (NOT APPLE)
|
||||||
"${OpenMW_BINARY_DIR}/openmw.cfg")
|
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg.local
|
||||||
|
"${OpenMW_BINARY_DIR}/openmw.cfg")
|
||||||
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg
|
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg
|
||||||
"${OpenMW_BINARY_DIR}/openmw.cfg.install")
|
"${OpenMW_BINARY_DIR}/openmw.cfg.install")
|
||||||
|
else ()
|
||||||
|
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg
|
||||||
|
"${OpenMW_BINARY_DIR}/openmw.cfg")
|
||||||
|
endif ()
|
||||||
|
|
||||||
configure_file(${OpenMW_SOURCE_DIR}/files/openmw-cs.cfg
|
configure_file(${OpenMW_SOURCE_DIR}/files/openmw-cs.cfg
|
||||||
"${OpenMW_BINARY_DIR}/openmw-cs.cfg")
|
"${OpenMW_BINARY_DIR}/openmw-cs.cfg")
|
||||||
|
@ -714,14 +723,7 @@ if (APPLE)
|
||||||
configure_file("${QT_COCOA_PLUGIN_PATH}" "${OPENCS_BUNDLE_NAME}/Contents/MacOS/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}" COPYONLY)
|
configure_file("${QT_COCOA_PLUGIN_PATH}" "${OPENCS_BUNDLE_NAME}/Contents/MacOS/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}" COPYONLY)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
set(INSTALL_SUBDIR OpenMW)
|
install(DIRECTORY "${APP_BUNDLE_DIR}" USE_SOURCE_PERMISSIONS DESTINATION "." COMPONENT Runtime)
|
||||||
|
|
||||||
install(DIRECTORY "${APP_BUNDLE_DIR}" USE_SOURCE_PERMISSIONS DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
|
|
||||||
install(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
|
|
||||||
install(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" RENAME "openmw.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
|
|
||||||
install(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
|
|
||||||
install(FILES "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
|
|
||||||
install(FILES "${OpenMW_BINARY_DIR}/openmw-cs.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
|
|
||||||
|
|
||||||
set(CPACK_GENERATOR "DragNDrop")
|
set(CPACK_GENERATOR "DragNDrop")
|
||||||
set(CPACK_PACKAGE_VERSION ${OPENMW_VERSION})
|
set(CPACK_PACKAGE_VERSION ${OPENMW_VERSION})
|
||||||
|
@ -729,8 +731,8 @@ if (APPLE)
|
||||||
set(CPACK_PACKAGE_VERSION_MINOR ${OPENMW_VERSION_MINOR})
|
set(CPACK_PACKAGE_VERSION_MINOR ${OPENMW_VERSION_MINOR})
|
||||||
set(CPACK_PACKAGE_VERSION_PATCH ${OPENMW_VERSION_RELEASE})
|
set(CPACK_PACKAGE_VERSION_PATCH ${OPENMW_VERSION_RELEASE})
|
||||||
|
|
||||||
set(INSTALLED_OPENMW_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}")
|
set(INSTALLED_OPENMW_APP "\${CMAKE_INSTALL_PREFIX}/${APP_BUNDLE_NAME}")
|
||||||
set(INSTALLED_OPENCS_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}")
|
set(INSTALLED_OPENCS_APP "\${CMAKE_INSTALL_PREFIX}/${OPENCS_BUNDLE_NAME}")
|
||||||
|
|
||||||
install(CODE "
|
install(CODE "
|
||||||
set(BU_CHMOD_BUNDLE_ITEMS ON)
|
set(BU_CHMOD_BUNDLE_ITEMS ON)
|
||||||
|
@ -774,8 +776,8 @@ if (APPLE)
|
||||||
set(${plugins_var} ${PLUGINS} PARENT_SCOPE)
|
set(${plugins_var} ${PLUGINS} PARENT_SCOPE)
|
||||||
endfunction (install_plugins_for_bundle)
|
endfunction (install_plugins_for_bundle)
|
||||||
|
|
||||||
install_plugins_for_bundle("${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}" PLUGINS)
|
install_plugins_for_bundle("${APP_BUNDLE_NAME}" PLUGINS)
|
||||||
install_plugins_for_bundle("${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}" OPENCS_PLUGINS)
|
install_plugins_for_bundle("${OPENCS_BUNDLE_NAME}" OPENCS_PLUGINS)
|
||||||
|
|
||||||
set(PLUGINS ${PLUGINS} "${INSTALLED_OPENMW_APP}/Contents/MacOS/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}")
|
set(PLUGINS ${PLUGINS} "${INSTALLED_OPENMW_APP}/Contents/MacOS/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}")
|
||||||
set(OPENCS_PLUGINS ${OPENCS_PLUGINS} "${INSTALLED_OPENCS_APP}/Contents/MacOS/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}")
|
set(OPENCS_PLUGINS ${OPENCS_PLUGINS} "${INSTALLED_OPENCS_APP}/Contents/MacOS/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}")
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace ESM
|
||||||
namespace ESSImport
|
namespace ESSImport
|
||||||
{
|
{
|
||||||
|
|
||||||
/// Local variable assigments for a running script
|
/// Local variable assignments for a running script
|
||||||
struct SCRI
|
struct SCRI
|
||||||
{
|
{
|
||||||
std::string mScript;
|
std::string mScript;
|
||||||
|
|
|
@ -35,14 +35,6 @@ int main(int argc, char *argv[])
|
||||||
// Now we make sure the current dir is set to application path
|
// Now we make sure the current dir is set to application path
|
||||||
QDir dir(QCoreApplication::applicationDirPath());
|
QDir dir(QCoreApplication::applicationDirPath());
|
||||||
|
|
||||||
#ifdef Q_OS_MAC
|
|
||||||
if (dir.dirName() == "MacOS") {
|
|
||||||
dir.cdUp();
|
|
||||||
dir.cdUp();
|
|
||||||
dir.cdUp();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QDir::setCurrent(dir.absolutePath());
|
QDir::setCurrent(dir.absolutePath());
|
||||||
|
|
||||||
Launcher::MainDialog mainWin;
|
Launcher::MainDialog mainWin;
|
||||||
|
|
|
@ -162,9 +162,15 @@ endif()
|
||||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
set (OPENCS_MAC_ICON ${CMAKE_SOURCE_DIR}/files/mac/openmw-cs.icns)
|
set (OPENCS_MAC_ICON "${CMAKE_SOURCE_DIR}/files/mac/openmw-cs.icns")
|
||||||
|
set (OPENCS_CFG "${OpenMW_BINARY_DIR}/openmw-cs.cfg")
|
||||||
|
set (OPENCS_DEFAULT_FILTERS_FILE "${OpenMW_BINARY_DIR}/resources/defaultfilters")
|
||||||
|
set (OPENCS_OPENMW_CFG "${OpenMW_BINARY_DIR}/openmw.cfg")
|
||||||
else()
|
else()
|
||||||
set (OPENCS_MAC_ICON "")
|
set (OPENCS_MAC_ICON "")
|
||||||
|
set (OPENCS_CFG "")
|
||||||
|
set (OPENCS_DEFAULT_FILTERS_FILE "")
|
||||||
|
set (OPENCS_OPENMW_CFG "")
|
||||||
endif(APPLE)
|
endif(APPLE)
|
||||||
|
|
||||||
add_executable(openmw-cs
|
add_executable(openmw-cs
|
||||||
|
@ -174,12 +180,23 @@ add_executable(openmw-cs
|
||||||
${OPENCS_MOC_SRC}
|
${OPENCS_MOC_SRC}
|
||||||
${OPENCS_RES_SRC}
|
${OPENCS_RES_SRC}
|
||||||
${OPENCS_MAC_ICON}
|
${OPENCS_MAC_ICON}
|
||||||
|
${OPENCS_CFG}
|
||||||
|
${OPENCS_DEFAULT_FILTERS_FILE}
|
||||||
|
${OPENCS_OPENMW_CFG}
|
||||||
)
|
)
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
|
set(OPENCS_BUNDLE_NAME "OpenMW-CS")
|
||||||
|
set(OPENCS_BUNDLE_RESOURCES_DIR "${OpenMW_BINARY_DIR}/${OPENCS_BUNDLE_NAME}.app/Contents/Resources")
|
||||||
|
|
||||||
|
set(OPENMW_MYGUI_FILES_ROOT ${OPENCS_BUNDLE_RESOURCES_DIR})
|
||||||
|
set(OPENMW_SHADERS_ROOT ${OPENCS_BUNDLE_RESOURCES_DIR})
|
||||||
|
|
||||||
|
add_subdirectory(../../files/ ${CMAKE_CURRENT_BINARY_DIR}/files)
|
||||||
|
|
||||||
set_target_properties(openmw-cs PROPERTIES
|
set_target_properties(openmw-cs PROPERTIES
|
||||||
RUNTIME_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}"
|
RUNTIME_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}"
|
||||||
OUTPUT_NAME "OpenMW-CS"
|
OUTPUT_NAME ${OPENCS_BUNDLE_NAME}
|
||||||
MACOSX_BUNDLE_ICON_FILE "openmw-cs.icns"
|
MACOSX_BUNDLE_ICON_FILE "openmw-cs.icns"
|
||||||
MACOSX_BUNDLE_BUNDLE_NAME "OpenCS"
|
MACOSX_BUNDLE_BUNDLE_NAME "OpenCS"
|
||||||
MACOSX_BUNDLE_GUI_IDENTIFIER "org.openmw.opencs"
|
MACOSX_BUNDLE_GUI_IDENTIFIER "org.openmw.opencs"
|
||||||
|
@ -190,6 +207,16 @@ if(APPLE)
|
||||||
|
|
||||||
set_source_files_properties(${OPENCS_MAC_ICON} PROPERTIES
|
set_source_files_properties(${OPENCS_MAC_ICON} PROPERTIES
|
||||||
MACOSX_PACKAGE_LOCATION Resources)
|
MACOSX_PACKAGE_LOCATION Resources)
|
||||||
|
set_source_files_properties(${OPENCS_CFG} PROPERTIES
|
||||||
|
MACOSX_PACKAGE_LOCATION Resources)
|
||||||
|
set_source_files_properties(${OPENCS_DEFAULT_FILTERS_FILE} PROPERTIES
|
||||||
|
MACOSX_PACKAGE_LOCATION Resources/resources)
|
||||||
|
set_source_files_properties(${OPENCS_OPENMW_CFG} PROPERTIES
|
||||||
|
MACOSX_PACKAGE_LOCATION Resources)
|
||||||
|
|
||||||
|
add_custom_command(TARGET openmw-cs
|
||||||
|
POST_BUILD
|
||||||
|
COMMAND cp "${OpenMW_BINARY_DIR}/resources/version" "${OPENCS_BUNDLE_RESOURCES_DIR}/resources")
|
||||||
endif(APPLE)
|
endif(APPLE)
|
||||||
|
|
||||||
target_link_libraries(openmw-cs
|
target_link_libraries(openmw-cs
|
||||||
|
@ -236,5 +263,5 @@ endif (MSVC)
|
||||||
|
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
INSTALL(TARGETS openmw-cs BUNDLE DESTINATION OpenMW COMPONENT BUNDLE)
|
INSTALL(TARGETS openmw-cs BUNDLE DESTINATION "." COMPONENT BUNDLE)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -62,11 +62,6 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
#ifdef Q_OS_MAC
|
#ifdef Q_OS_MAC
|
||||||
QDir dir(QCoreApplication::applicationDirPath());
|
QDir dir(QCoreApplication::applicationDirPath());
|
||||||
if (dir.dirName() == "MacOS") {
|
|
||||||
dir.cdUp();
|
|
||||||
dir.cdUp();
|
|
||||||
dir.cdUp();
|
|
||||||
}
|
|
||||||
QDir::setCurrent(dir.absolutePath());
|
QDir::setCurrent(dir.absolutePath());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ namespace CSMPrefs
|
||||||
enum SecondaryMode
|
enum SecondaryMode
|
||||||
{
|
{
|
||||||
SM_Replace, ///< The secondary signal replaces the regular signal when the modifier is active
|
SM_Replace, ///< The secondary signal replaces the regular signal when the modifier is active
|
||||||
SM_Detach, ///< The secondary signal is emitted independant of the regular signal, even if not active
|
SM_Detach, ///< The secondary signal is emitted independent of the regular signal, even if not active
|
||||||
SM_Ignore ///< The secondary signal will not ever be emitted
|
SM_Ignore ///< The secondary signal will not ever be emitted
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -425,7 +425,7 @@ void CSMTools::ReferenceableCheckStage::creatureCheck (
|
||||||
|
|
||||||
//stats checks
|
//stats checks
|
||||||
if (creature.mData.mLevel < 1)
|
if (creature.mData.mLevel < 1)
|
||||||
messages.push_back (std::make_pair (id, creature.mId + " has non-postive level"));
|
messages.push_back (std::make_pair (id, creature.mId + " has non-positive level"));
|
||||||
|
|
||||||
if (creature.mData.mStrength < 0)
|
if (creature.mData.mStrength < 0)
|
||||||
messages.push_back (std::make_pair (id, creature.mId + " has negative strength"));
|
messages.push_back (std::make_pair (id, creature.mId + " has negative strength"));
|
||||||
|
@ -659,7 +659,7 @@ void CSMTools::ReferenceableCheckStage::npcCheck (
|
||||||
{
|
{
|
||||||
if ((npc.mFlags & ESM::NPC::Autocalc) == 0) //0x0010 = autocalculated flag
|
if ((npc.mFlags & ESM::NPC::Autocalc) == 0) //0x0010 = autocalculated flag
|
||||||
{
|
{
|
||||||
messages.push_back (std::make_pair (id, npc.mId + " mNpdtType or flags mismatch!")); //should not happend?
|
messages.push_back (std::make_pair (id, npc.mId + " mNpdtType or flags mismatch!")); //should not happen?
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -915,7 +915,7 @@ void CSMTools::ReferenceableCheckStage::inventoryListCheck(
|
||||||
id + " contains non-existing item (" + itemName + ")"));
|
id + " contains non-existing item (" + itemName + ")"));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Needs to accomodate Containers, Creatures, and NPCs
|
// Needs to accommodate containers, creatures, and NPCs
|
||||||
switch (localIndex.second)
|
switch (localIndex.second)
|
||||||
{
|
{
|
||||||
case CSMWorld::UniversalId::Type_Potion:
|
case CSMWorld::UniversalId::Type_Potion:
|
||||||
|
|
|
@ -65,7 +65,7 @@ namespace CSMWorld
|
||||||
|
|
||||||
void setRecord (const std::string& id, const RecordBase& record,
|
void setRecord (const std::string& id, const RecordBase& record,
|
||||||
UniversalId::Type type = UniversalId::Type_None);
|
UniversalId::Type type = UniversalId::Type_None);
|
||||||
///< Add record or overwrite existing recrod.
|
///< Add record or overwrite existing record.
|
||||||
|
|
||||||
const RecordBase& getRecord (const std::string& id) const;
|
const RecordBase& getRecord (const std::string& id) const;
|
||||||
|
|
||||||
|
|
|
@ -198,12 +198,12 @@ QModelIndex CSMWorld::IdTree::parent (const QModelIndex& index) const
|
||||||
return QModelIndex();
|
return QModelIndex();
|
||||||
|
|
||||||
unsigned int id = index.internalId();
|
unsigned int id = index.internalId();
|
||||||
const std::pair<int, int>& adress(unfoldIndexAddress(id));
|
const std::pair<int, int>& address(unfoldIndexAddress(id));
|
||||||
|
|
||||||
if (adress.first >= this->rowCount() || adress.second >= this->columnCount())
|
if (address.first >= this->rowCount() || address.second >= this->columnCount())
|
||||||
throw "Parent index is not present in the model";
|
throw "Parent index is not present in the model";
|
||||||
|
|
||||||
return createIndex(adress.first, adress.second);
|
return createIndex(address.first, address.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int CSMWorld::IdTree::foldIndexAddress (const QModelIndex& index) const
|
unsigned int CSMWorld::IdTree::foldIndexAddress (const QModelIndex& index) const
|
||||||
|
|
|
@ -8,9 +8,9 @@
|
||||||
/*! \brief
|
/*! \brief
|
||||||
* Class for holding the model. Uses typical qt table abstraction/interface for granting access
|
* Class for holding the model. Uses typical qt table abstraction/interface for granting access
|
||||||
* to the individiual fields of the records, Some records are holding nested data (for instance
|
* to the individiual fields of the records, Some records are holding nested data (for instance
|
||||||
* inventory list of the npc). In casses like this, table model offers interface to access
|
* inventory list of the npc). In cases like this, table model offers interface to access
|
||||||
* nested data in the qt way - that is specify parent. Since some of those nested data require
|
* nested data in the qt way - that is specify parent. Since some of those nested data require
|
||||||
* multiple columns to represent informations, single int (default way to index model in the
|
* multiple columns to represent information, single int (default way to index model in the
|
||||||
* qmodelindex) is not sufficiant. Therefore tablemodelindex class can hold two ints for the
|
* qmodelindex) is not sufficiant. Therefore tablemodelindex class can hold two ints for the
|
||||||
* sake of indexing two dimensions of the table. This model does not support multiple levels of
|
* sake of indexing two dimensions of the table. This model does not support multiple levels of
|
||||||
* the nested data. Vast majority of methods makes sense only for the top level data.
|
* the nested data. Vast majority of methods makes sense only for the top level data.
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
* Adapters acts as indirection layer, abstracting details of the record types (in the wrappers) from the higher levels of model.
|
* Adapters acts as indirection layer, abstracting details of the record types (in the wrappers) from the higher levels of model.
|
||||||
* Please notice that nested adaptor uses helper classes for actually performing any actions. Different record types require different helpers (needs to be created in the subclass and then fetched via member function).
|
* Please notice that nested adaptor uses helper classes for actually performing any actions. Different record types require different helpers (needs to be created in the subclass and then fetched via member function).
|
||||||
*
|
*
|
||||||
* Important point: don't forget to make sure that getData on the nestedColumn returns true (otherwise code will not treat the index pointing to the column as having childs!
|
* Important point: don't forget to make sure that getData on the nestedColumn returns true (otherwise code will not treat the index pointing to the column as having children!
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class QVariant;
|
class QVariant;
|
||||||
|
|
|
@ -50,7 +50,7 @@ namespace CSVRender
|
||||||
updateCellData(mData.getCells().getRecord(cellIndex));
|
updateCellData(mData.getCells().getRecord(cellIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keep water existance/height up to date
|
// Keep water existence/height up to date
|
||||||
QAbstractItemModel* cells = mData.getTableModel(CSMWorld::UniversalId::Type_Cells);
|
QAbstractItemModel* cells = mData.getTableModel(CSMWorld::UniversalId::Type_Cells);
|
||||||
connect(cells, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)),
|
connect(cells, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)),
|
||||||
this, SLOT(cellDataChanged(const QModelIndex&, const QModelIndex&)));
|
this, SLOT(cellDataChanged(const QModelIndex&, const QModelIndex&)));
|
||||||
|
|
|
@ -516,7 +516,7 @@ void CSVRender::PagedWorldspaceWidget::useViewHint (const std::string& hint)
|
||||||
// Current coordinate
|
// Current coordinate
|
||||||
int x, y;
|
int x, y;
|
||||||
|
|
||||||
// Loop throught all the coordinates to add them to selection
|
// Loop through all the coordinates to add them to selection
|
||||||
while (stream >> ignore1 >> ignore2 >> x >> y)
|
while (stream >> ignore1 >> ignore2 >> x >> y)
|
||||||
selection.add (CSMWorld::CellCoordinates (x, y));
|
selection.add (CSMWorld::CellCoordinates (x, y));
|
||||||
|
|
||||||
|
|
|
@ -214,7 +214,7 @@ SceneWidget::SceneWidget(boost::shared_ptr<Resource::ResourceSystem> resourceSys
|
||||||
|
|
||||||
SceneWidget::~SceneWidget()
|
SceneWidget::~SceneWidget()
|
||||||
{
|
{
|
||||||
// Since we're holding on to the scene templates past the existance of this graphics context, we'll need to manually release the created objects
|
// Since we're holding on to the scene templates past the existence of this graphics context, we'll need to manually release the created objects
|
||||||
mResourceSystem->getSceneManager()->releaseGLObjects(mView->getCamera()->getGraphicsContext()->getState());
|
mResourceSystem->getSceneManager()->releaseGLObjects(mView->getCamera()->getGraphicsContext()->getState());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,8 +45,8 @@ namespace CSVWorld
|
||||||
///< \note Non-existent cells are not listed.
|
///< \note Non-existent cells are not listed.
|
||||||
|
|
||||||
QModelIndexList getSelectedCells (bool existent = true, bool nonExistent = false) const;
|
QModelIndexList getSelectedCells (bool existent = true, bool nonExistent = false) const;
|
||||||
///< \param existant Include existant cells.
|
///< \param existent Include existent cells.
|
||||||
/// \param nonExistant Include non-existant cells.
|
/// \param nonExistent Include non-existent cells.
|
||||||
|
|
||||||
QModelIndexList getMissingRegionCells() const;
|
QModelIndexList getMissingRegionCells() const;
|
||||||
///< Unselected cells within all regions that have at least one selected cell.
|
///< Unselected cells within all regions that have at least one selected cell.
|
||||||
|
|
|
@ -179,6 +179,21 @@ target_link_libraries(openmw ${CMAKE_THREAD_LIBS_INIT})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
|
set(BUNDLE_RESOURCES_DIR "${APP_BUNDLE_DIR}/Contents/Resources")
|
||||||
|
|
||||||
|
set(OPENMW_MYGUI_FILES_ROOT ${BUNDLE_RESOURCES_DIR})
|
||||||
|
set(OPENMW_SHADERS_ROOT ${BUNDLE_RESOURCES_DIR})
|
||||||
|
|
||||||
|
add_subdirectory(../../files/ ${CMAKE_CURRENT_BINARY_DIR}/files)
|
||||||
|
|
||||||
|
configure_file("${OpenMW_BINARY_DIR}/settings-default.cfg" ${BUNDLE_RESOURCES_DIR} COPYONLY)
|
||||||
|
configure_file("${OpenMW_BINARY_DIR}/openmw.cfg" ${BUNDLE_RESOURCES_DIR} COPYONLY)
|
||||||
|
configure_file("${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" ${BUNDLE_RESOURCES_DIR} COPYONLY)
|
||||||
|
|
||||||
|
add_custom_command(TARGET openmw
|
||||||
|
POST_BUILD
|
||||||
|
COMMAND cp "${OpenMW_BINARY_DIR}/resources/version" "${BUNDLE_RESOURCES_DIR}/resources")
|
||||||
|
|
||||||
find_library(COCOA_FRAMEWORK Cocoa)
|
find_library(COCOA_FRAMEWORK Cocoa)
|
||||||
find_library(IOKIT_FRAMEWORK IOKit)
|
find_library(IOKIT_FRAMEWORK IOKit)
|
||||||
target_link_libraries(openmw ${COCOA_FRAMEWORK} ${IOKIT_FRAMEWORK})
|
target_link_libraries(openmw ${COCOA_FRAMEWORK} ${IOKIT_FRAMEWORK})
|
||||||
|
|
|
@ -41,4 +41,4 @@
|
||||||
|
|
||||||
/// \namespace MWScript
|
/// \namespace MWScript
|
||||||
/// \ingroup openmw
|
/// \ingroup openmw
|
||||||
/// \brief MW-specific script extentions and integration of the script system into OpenMW
|
/// \brief MW-specific script extensions and integration of the script system into OpenMW
|
||||||
|
|
|
@ -493,7 +493,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
||||||
mEnvironment.setWindowManager (window);
|
mEnvironment.setWindowManager (window);
|
||||||
|
|
||||||
// Create sound system
|
// Create sound system
|
||||||
mEnvironment.setSoundManager (new MWSound::SoundManager(mVFS.get(), mUseSound));
|
mEnvironment.setSoundManager (new MWSound::SoundManager(mVFS.get(), mFallbackMap, mUseSound));
|
||||||
|
|
||||||
if (!mSkipMenu)
|
if (!mSkipMenu)
|
||||||
{
|
{
|
||||||
|
|
|
@ -352,9 +352,8 @@ int main(int argc, char**argv)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
// FIXME: set current dir to bundle path
|
boost::filesystem::path binary_path = boost::filesystem::system_complete(boost::filesystem::path(argv[0]));
|
||||||
//boost::filesystem::path bundlePath = boost::filesystem::path(Ogre::macBundlePath()).parent_path();
|
boost::filesystem::current_path(binary_path.parent_path());
|
||||||
//boost::filesystem::current_path(bundlePath);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
engine.reset(new OMW::Engine(cfgMgr));
|
engine.reset(new OMW::Engine(cfgMgr));
|
||||||
|
|
|
@ -233,7 +233,7 @@ namespace MWBase
|
||||||
virtual void removeDialog(MWGui::Layout* dialog) = 0;
|
virtual void removeDialog(MWGui::Layout* dialog) = 0;
|
||||||
|
|
||||||
///Gracefully attempts to exit the topmost GUI mode
|
///Gracefully attempts to exit the topmost GUI mode
|
||||||
/** No guarentee of actually closing the window **/
|
/** No guarantee of actually closing the window **/
|
||||||
virtual void exitCurrentGuiMode() = 0;
|
virtual void exitCurrentGuiMode() = 0;
|
||||||
|
|
||||||
virtual void messageBox (const std::string& message, enum MWGui::ShowInDialogueMode showInDialogueMode = MWGui::ShowInDialogueMode_IfPossible) = 0;
|
virtual void messageBox (const std::string& message, enum MWGui::ShowInDialogueMode showInDialogueMode = MWGui::ShowInDialogueMode_IfPossible) = 0;
|
||||||
|
|
|
@ -231,7 +231,7 @@ namespace MWClass
|
||||||
if(lockLevel!=0)
|
if(lockLevel!=0)
|
||||||
ptr.getCellRef().setLockLevel(abs(lockLevel)); //Changes lock to locklevel, in positive
|
ptr.getCellRef().setLockLevel(abs(lockLevel)); //Changes lock to locklevel, in positive
|
||||||
else
|
else
|
||||||
ptr.getCellRef().setLockLevel(abs(ptr.getCellRef().getLockLevel())); //No locklevel given, just flip the origional one
|
ptr.getCellRef().setLockLevel(abs(ptr.getCellRef().getLockLevel())); //No locklevel given, just flip the original one
|
||||||
}
|
}
|
||||||
|
|
||||||
void Door::unlock (const MWWorld::Ptr& ptr) const
|
void Door::unlock (const MWWorld::Ptr& ptr) const
|
||||||
|
|
|
@ -122,7 +122,7 @@ namespace MWClass
|
||||||
|
|
||||||
info.effects = MWGui::Widgets::MWEffectList::effectListFromESM(&ref->mBase->mEffects);
|
info.effects = MWGui::Widgets::MWEffectList::effectListFromESM(&ref->mBase->mEffects);
|
||||||
|
|
||||||
// hide effects the player doesnt know about
|
// hide effects the player doesn't know about
|
||||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr();
|
MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr();
|
||||||
for (unsigned int i=0; i<info.effects.size(); ++i)
|
for (unsigned int i=0; i<info.effects.size(); ++i)
|
||||||
info.effects[i].mKnown = MWMechanics::Alchemy::knownEffect(i, player);
|
info.effects[i].mKnown = MWMechanics::Alchemy::knownEffect(i, player);
|
||||||
|
|
|
@ -174,7 +174,7 @@ namespace MWDialogue
|
||||||
executeScript (info->mResultScript);
|
executeScript (info->mResultScript);
|
||||||
mLastTopic = Misc::StringUtils::lowerCase(it->mId);
|
mLastTopic = Misc::StringUtils::lowerCase(it->mId);
|
||||||
|
|
||||||
// update topics again to accomodate changes resulting from executeScript
|
// update topics again to accommodate changes resulting from executeScript
|
||||||
updateTopics();
|
updateTopics();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -101,6 +101,8 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
if (mFrame)
|
if (mFrame)
|
||||||
mFrame->setImageTexture("");
|
mFrame->setImageTexture("");
|
||||||
|
if (mItemShadow)
|
||||||
|
mItemShadow->setImageTexture("");
|
||||||
mItem->setImageTexture("");
|
mItem->setImageTexture("");
|
||||||
mText->setCaption("");
|
mText->setCaption("");
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -512,8 +512,8 @@ namespace MWMechanics
|
||||||
if (magnitude > 0 && remainingTime > 0 && remainingTime < mDuration)
|
if (magnitude > 0 && remainingTime > 0 && remainingTime < mDuration)
|
||||||
{
|
{
|
||||||
CreatureStats& creatureStats = mActor.getClass().getCreatureStats(mActor);
|
CreatureStats& creatureStats = mActor.getClass().getCreatureStats(mActor);
|
||||||
effectTick(creatureStats, mActor, key, magnitude * remainingTime);
|
if (effectTick(creatureStats, mActor, key, magnitude * remainingTime))
|
||||||
creatureStats.getMagicEffects().add(key, -magnitude);
|
creatureStats.getMagicEffects().add(key, -magnitude);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -527,8 +527,10 @@ namespace MWMechanics
|
||||||
|
|
||||||
if (duration > 0)
|
if (duration > 0)
|
||||||
{
|
{
|
||||||
// apply correct magnitude for tickable effects that have just expired,
|
// Apply correct magnitude for tickable effects that have just expired,
|
||||||
// in case duration > remaining time of effect
|
// in case duration > remaining time of effect.
|
||||||
|
// One case where this will happen is when the player uses the rest/wait command
|
||||||
|
// while there is a tickable effect active that should expire before the end of the rest/wait.
|
||||||
ExpiryVisitor visitor(ptr, duration);
|
ExpiryVisitor visitor(ptr, duration);
|
||||||
creatureStats.getActiveSpells().visitEffectSources(visitor);
|
creatureStats.getActiveSpells().visitEffectSources(visitor);
|
||||||
|
|
||||||
|
@ -1269,8 +1271,6 @@ namespace MWMechanics
|
||||||
stats.getActiveSpells().clear();
|
stats.getActiveSpells().clear();
|
||||||
calculateCreatureStatModifiers(iter->first, 0);
|
calculateCreatureStatModifiers(iter->first, 0);
|
||||||
|
|
||||||
MWBase::Environment::get().getWorld()->enableActorCollision(iter->first, false);
|
|
||||||
|
|
||||||
if (cls.isEssential(iter->first))
|
if (cls.isEssential(iter->first))
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sKilledEssential}");
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sKilledEssential}");
|
||||||
}
|
}
|
||||||
|
@ -1288,6 +1288,11 @@ namespace MWMechanics
|
||||||
//player's death animation is over
|
//player's death animation is over
|
||||||
MWBase::Environment::get().getStateManager()->askLoadRecent();
|
MWBase::Environment::get().getStateManager()->askLoadRecent();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// NPC death animation is over, disable actor collision
|
||||||
|
MWBase::Environment::get().getWorld()->enableActorCollision(iter->first, false);
|
||||||
|
}
|
||||||
|
|
||||||
// Play Death Music if it was the player dying
|
// Play Death Music if it was the player dying
|
||||||
if(iter->first == getPlayer())
|
if(iter->first == getPlayer())
|
||||||
|
|
|
@ -60,30 +60,30 @@ namespace MWMechanics
|
||||||
FleeState_RunToDestination
|
FleeState_RunToDestination
|
||||||
};
|
};
|
||||||
FleeState mFleeState;
|
FleeState mFleeState;
|
||||||
bool mFleeLOS;
|
bool mLOS;
|
||||||
float mFleeUpdateLOSTimer;
|
float mUpdateLOSTimer;
|
||||||
float mFleeBlindRunTimer;
|
float mFleeBlindRunTimer;
|
||||||
ESM::Pathgrid::Point mFleeDest;
|
ESM::Pathgrid::Point mFleeDest;
|
||||||
|
|
||||||
AiCombatStorage():
|
AiCombatStorage():
|
||||||
mAttackCooldown(0),
|
mAttackCooldown(0.0f),
|
||||||
mTimerReact(AI_REACTION_TIME),
|
mTimerReact(AI_REACTION_TIME),
|
||||||
mTimerCombatMove(0),
|
mTimerCombatMove(0.0f),
|
||||||
mReadyToAttack(false),
|
mReadyToAttack(false),
|
||||||
mAttack(false),
|
mAttack(false),
|
||||||
mAttackRange(0),
|
mAttackRange(0.0f),
|
||||||
mCombatMove(false),
|
mCombatMove(false),
|
||||||
mLastTargetPos(0,0,0),
|
mLastTargetPos(0,0,0),
|
||||||
mCell(NULL),
|
mCell(NULL),
|
||||||
mCurrentAction(),
|
mCurrentAction(),
|
||||||
mActionCooldown(0),
|
mActionCooldown(0.0f),
|
||||||
mStrength(),
|
mStrength(),
|
||||||
mForceNoShortcut(false),
|
mForceNoShortcut(false),
|
||||||
mShortcutFailPos(),
|
mShortcutFailPos(),
|
||||||
mMovement(),
|
mMovement(),
|
||||||
mFleeState(FleeState_None),
|
mFleeState(FleeState_None),
|
||||||
mFleeLOS(false),
|
mLOS(false),
|
||||||
mFleeUpdateLOSTimer(0.0f),
|
mUpdateLOSTimer(0.0f),
|
||||||
mFleeBlindRunTimer(0.0f)
|
mFleeBlindRunTimer(0.0f)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
@ -157,7 +157,7 @@ namespace MWMechanics
|
||||||
*
|
*
|
||||||
* TODO:
|
* TODO:
|
||||||
*
|
*
|
||||||
* Use the Observer Pattern to co-ordinate attacks, provide intelligence on
|
* Use the observer pattern to coordinate attacks, provide intelligence on
|
||||||
* whether the target was hit, etc.
|
* whether the target was hit, etc.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -181,10 +181,14 @@ namespace MWMechanics
|
||||||
|
|
||||||
if (!storage.isFleeing())
|
if (!storage.isFleeing())
|
||||||
{
|
{
|
||||||
if (storage.mCurrentAction.get()) // need to wait to init action with it's attack range
|
if (storage.mCurrentAction.get()) // need to wait to init action with its attack range
|
||||||
{
|
{
|
||||||
//Update every frame
|
//Update every frame. UpdateLOS uses a timer, so the LOS check does not happen every frame.
|
||||||
bool is_target_reached = pathTo(actor, target.getRefData().getPosition().pos, duration, storage.mAttackRange);
|
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;
|
if (is_target_reached) storage.mReadyToAttack = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,7 +287,7 @@ namespace MWMechanics
|
||||||
osg::Vec3f vAimDir = MWBase::Environment::get().getWorld()->aimToTarget(actor, target);
|
osg::Vec3f vAimDir = MWBase::Environment::get().getWorld()->aimToTarget(actor, target);
|
||||||
float distToTarget = MWBase::Environment::get().getWorld()->getHitDistance(actor, target);
|
float distToTarget = MWBase::Environment::get().getWorld()->getHitDistance(actor, target);
|
||||||
|
|
||||||
storage.mReadyToAttack = (currentAction->isAttackingOrSpell() && distToTarget <= rangeAttack);
|
storage.mReadyToAttack = (currentAction->isAttackingOrSpell() && distToTarget <= rangeAttack && storage.mLOS);
|
||||||
|
|
||||||
if (storage.mReadyToAttack)
|
if (storage.mReadyToAttack)
|
||||||
{
|
{
|
||||||
|
@ -309,18 +313,23 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MWMechanics::AiCombat::updateFleeing(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, float duration, MWMechanics::AiCombatStorage& storage)
|
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;
|
static const float LOS_UPDATE_DURATION = 0.5f;
|
||||||
static const float BLIND_RUN_DURATION = 1.0f;
|
if (storage.mUpdateLOSTimer <= 0.f)
|
||||||
|
|
||||||
if (storage.mFleeUpdateLOSTimer <= 0.f)
|
|
||||||
{
|
{
|
||||||
storage.mFleeLOS = MWBase::Environment::get().getWorld()->getLOS(actor, target);
|
storage.mLOS = MWBase::Environment::get().getWorld()->getLOS(actor, target);
|
||||||
storage.mFleeUpdateLOSTimer = LOS_UPDATE_DURATION;
|
storage.mUpdateLOSTimer = LOS_UPDATE_DURATION;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
storage.mFleeUpdateLOSTimer -= duration;
|
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;
|
AiCombatStorage::FleeState& state = storage.mFleeState;
|
||||||
switch (state)
|
switch (state)
|
||||||
|
@ -332,7 +341,7 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
float triggerDist = getMaxAttackDistance(target);
|
float triggerDist = getMaxAttackDistance(target);
|
||||||
|
|
||||||
if (storage.mFleeLOS &&
|
if (storage.mLOS &&
|
||||||
(triggerDist >= 1000 || getDistanceMinusHalfExtents(actor, target) <= triggerDist))
|
(triggerDist >= 1000 || getDistanceMinusHalfExtents(actor, target) <= triggerDist))
|
||||||
{
|
{
|
||||||
const ESM::Pathgrid* pathgrid =
|
const ESM::Pathgrid* pathgrid =
|
||||||
|
@ -399,7 +408,7 @@ namespace MWMechanics
|
||||||
static const float fFleeDistance = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fFleeDistance")->getFloat();
|
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();
|
float dist = (actor.getRefData().getPosition().asVec3() - target.getRefData().getPosition().asVec3()).length();
|
||||||
if ((dist > fFleeDistance && !storage.mFleeLOS)
|
if ((dist > fFleeDistance && !storage.mLOS)
|
||||||
|| pathTo(actor, storage.mFleeDest, duration))
|
|| pathTo(actor, storage.mFleeDest, duration))
|
||||||
{
|
{
|
||||||
state = AiCombatStorage::FleeState_Idle;
|
state = AiCombatStorage::FleeState_Idle;
|
||||||
|
@ -602,9 +611,6 @@ namespace MWMechanics
|
||||||
mMovement.mPosition[2] = 0;
|
mMovement.mPosition[2] = 0;
|
||||||
mFleeState = FleeState_None;
|
mFleeState = FleeState_None;
|
||||||
mFleeDest = ESM::Pathgrid::Point(0, 0, 0);
|
mFleeDest = ESM::Pathgrid::Point(0, 0, 0);
|
||||||
mFleeLOS = false;
|
|
||||||
mFleeUpdateLOSTimer = 0.0f;
|
|
||||||
mFleeUpdateLOSTimer = 0.0f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AiCombatStorage::isFleeing()
|
bool AiCombatStorage::isFleeing()
|
||||||
|
|
|
@ -61,6 +61,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
void attack(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, AiCombatStorage& storage, CharacterController& characterController);
|
void attack(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, AiCombatStorage& storage, CharacterController& characterController);
|
||||||
|
|
||||||
|
void updateLOS(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, float duration, AiCombatStorage& storage);
|
||||||
|
|
||||||
void updateFleeing(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, float duration, AiCombatStorage& storage);
|
void updateFleeing(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, float duration, AiCombatStorage& storage);
|
||||||
|
|
||||||
/// Transfer desired movement (from AiCombatStorage) to Actor
|
/// Transfer desired movement (from AiCombatStorage) to Actor
|
||||||
|
|
|
@ -152,7 +152,7 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characte
|
||||||
|
|
||||||
if (dist > 450)
|
if (dist > 450)
|
||||||
actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, true); //Make NPC run
|
actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, true); //Make NPC run
|
||||||
else if (dist < 325) //Have a bit of a dead zone, otherwise npc will constantly flip between running and not when right on the edge of the running threshhold
|
else if (dist < 325) //Have a bit of a dead zone, otherwise npc will constantly flip between running and not when right on the edge of the running threshold
|
||||||
actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, false); //make NPC walk
|
actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, false); //make NPC walk
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ namespace MWMechanics
|
||||||
class AiPackage
|
class AiPackage
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
///Enumerates the various AITypes availible.
|
///Enumerates the various AITypes available
|
||||||
enum TypeId {
|
enum TypeId {
|
||||||
TypeIdNone = -1,
|
TypeIdNone = -1,
|
||||||
TypeIdWander = 0,
|
TypeIdWander = 0,
|
||||||
|
|
|
@ -336,7 +336,7 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
ESM::Pathgrid::Point dest(PathFinder::MakePathgridPoint(mReturnPosition));
|
ESM::Pathgrid::Point dest(PathFinder::MakePathgridPoint(mReturnPosition));
|
||||||
|
|
||||||
// actor position is already in world co-ordinates
|
// actor position is already in world coordinates
|
||||||
ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos));
|
ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos));
|
||||||
|
|
||||||
// don't take shortcuts for wandering
|
// don't take shortcuts for wandering
|
||||||
|
@ -649,7 +649,7 @@ namespace MWMechanics
|
||||||
ESM::Pathgrid::Point dest(storage.mAllowedNodes[randNode]);
|
ESM::Pathgrid::Point dest(storage.mAllowedNodes[randNode]);
|
||||||
ToWorldCoordinates(dest, storage.mCell->getCell());
|
ToWorldCoordinates(dest, storage.mCell->getCell());
|
||||||
|
|
||||||
// actor position is already in world co-ordinates
|
// actor position is already in world coordinates
|
||||||
ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(actorPos));
|
ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(actorPos));
|
||||||
|
|
||||||
// don't take shortcuts for wandering
|
// don't take shortcuts for wandering
|
||||||
|
@ -693,8 +693,8 @@ namespace MWMechanics
|
||||||
ESM::Pathgrid::Point pt = paths.back();
|
ESM::Pathgrid::Point pt = paths.back();
|
||||||
for(unsigned int j = 0; j < nodes.size(); j++)
|
for(unsigned int j = 0; j < nodes.size(); j++)
|
||||||
{
|
{
|
||||||
// FIXME: doesn't hadle a door with the same X/Y
|
// FIXME: doesn't handle a door with the same X/Y
|
||||||
// co-ordinates but with a different Z
|
// coordinates but with a different Z
|
||||||
if(nodes[j].mX == pt.mX && nodes[j].mY == pt.mY)
|
if(nodes[j].mX == pt.mX && nodes[j].mY == pt.mY)
|
||||||
{
|
{
|
||||||
nodes.erase(nodes.begin() + j);
|
nodes.erase(nodes.begin() + j);
|
||||||
|
@ -828,7 +828,7 @@ namespace MWMechanics
|
||||||
// ... pathgrids don't usually include water, so swimmers ignore them
|
// ... pathgrids don't usually include water, so swimmers ignore them
|
||||||
if (mDistance && storage.mCanWanderAlongPathGrid && !actor.getClass().isPureWaterCreature(actor))
|
if (mDistance && storage.mCanWanderAlongPathGrid && !actor.getClass().isPureWaterCreature(actor))
|
||||||
{
|
{
|
||||||
// get NPC's position in local (i.e. cell) co-ordinates
|
// get NPC's position in local (i.e. cell) coordinates
|
||||||
osg::Vec3f npcPos(mInitialActorPosition);
|
osg::Vec3f npcPos(mInitialActorPosition);
|
||||||
CoordinateConverter(cell).toLocal(npcPos);
|
CoordinateConverter(cell).toLocal(npcPos);
|
||||||
|
|
||||||
|
@ -837,7 +837,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
// mAllowedNodes for this actor with pathgrid point indexes based on mDistance
|
// mAllowedNodes for this actor with pathgrid point indexes based on mDistance
|
||||||
// and if the point is connected to the closest current point
|
// and if the point is connected to the closest current point
|
||||||
// NOTE: mPoints and mAllowedNodes are in local co-ordinates
|
// NOTE: mPoints and mAllowedNodes are in local coordinates
|
||||||
int pointIndex = 0;
|
int pointIndex = 0;
|
||||||
for(unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++)
|
for(unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++)
|
||||||
{
|
{
|
||||||
|
|
|
@ -119,7 +119,7 @@ namespace MWMechanics
|
||||||
GroupIndex_MaxIdle = 9
|
GroupIndex_MaxIdle = 9
|
||||||
};
|
};
|
||||||
|
|
||||||
/// convert point from local (i.e. cell) to world co-ordinates
|
/// convert point from local (i.e. cell) to world coordinates
|
||||||
void ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::Cell * cell);
|
void ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::Cell * cell);
|
||||||
|
|
||||||
void SetCurrentNodeToClosestAllowedNode(osg::Vec3f npcPos, AiWanderStorage& storage);
|
void SetCurrentNodeToClosestAllowedNode(osg::Vec3f npcPos, AiWanderStorage& storage);
|
||||||
|
|
|
@ -1049,6 +1049,9 @@ bool CharacterController::updateCreatureState()
|
||||||
mUpperBodyState = UpperCharState_StartToMinAttack;
|
mUpperBodyState = UpperCharState_StartToMinAttack;
|
||||||
|
|
||||||
mAttackStrength = std::min(1.f, 0.1f + Misc::Rng::rollClosedProbability());
|
mAttackStrength = std::min(1.f, 0.1f + Misc::Rng::rollClosedProbability());
|
||||||
|
|
||||||
|
if (weapType == WeapType_HandToHand)
|
||||||
|
playSwishSound(0.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1370,13 +1373,7 @@ bool CharacterController::updateWeaponState()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::string sound = "SwishM";
|
playSwishSound(attackStrength);
|
||||||
if(attackStrength < 0.5f)
|
|
||||||
sndMgr->playSound3D(mPtr, sound, 1.0f, 0.8f); //Weak attack
|
|
||||||
else if(attackStrength < 1.0f)
|
|
||||||
sndMgr->playSound3D(mPtr, sound, 1.0f, 1.0f); //Medium attack
|
|
||||||
else
|
|
||||||
sndMgr->playSound3D(mPtr, sound, 1.0f, 1.2f); //Strong attack
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mAttackStrength = attackStrength;
|
mAttackStrength = attackStrength;
|
||||||
|
@ -2271,6 +2268,19 @@ void CharacterController::setHeadTrackTarget(const MWWorld::ConstPtr &target)
|
||||||
mHeadTrackTarget = target;
|
mHeadTrackTarget = target;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CharacterController::playSwishSound(float attackStrength)
|
||||||
|
{
|
||||||
|
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
||||||
|
|
||||||
|
std::string sound = "Weapon Swish";
|
||||||
|
if(attackStrength < 0.5f)
|
||||||
|
sndMgr->playSound3D(mPtr, sound, 1.0f, 0.8f); //Weak attack
|
||||||
|
else if(attackStrength < 1.0f)
|
||||||
|
sndMgr->playSound3D(mPtr, sound, 1.0f, 1.0f); //Medium attack
|
||||||
|
else
|
||||||
|
sndMgr->playSound3D(mPtr, sound, 1.0f, 1.2f); //Strong attack
|
||||||
|
}
|
||||||
|
|
||||||
void CharacterController::updateHeadTracking(float duration)
|
void CharacterController::updateHeadTracking(float duration)
|
||||||
{
|
{
|
||||||
const osg::Node* head = mAnimation->getNode("Bip01 Head");
|
const osg::Node* head = mAnimation->getNode("Bip01 Head");
|
||||||
|
|
|
@ -281,6 +281,8 @@ public:
|
||||||
|
|
||||||
/// Make this character turn its head towards \a target. To turn off head tracking, pass an empty Ptr.
|
/// Make this character turn its head towards \a target. To turn off head tracking, pass an empty Ptr.
|
||||||
void setHeadTrackTarget(const MWWorld::ConstPtr& target);
|
void setHeadTrackTarget(const MWWorld::ConstPtr& target);
|
||||||
|
|
||||||
|
void playSwishSound(float attackStrength);
|
||||||
};
|
};
|
||||||
|
|
||||||
MWWorld::ContainerStoreIterator getActiveWeapon(CreatureStats &stats, MWWorld::InventoryStore &inv, WeaponType *weaptype);
|
MWWorld::ContainerStoreIterator getActiveWeapon(CreatureStats &stats, MWWorld::InventoryStore &inv, WeaponType *weaptype);
|
||||||
|
|
|
@ -236,7 +236,7 @@ namespace MWMechanics
|
||||||
: mWatchedTimeToStartDrowning(0), mWatchedStatsEmpty (true), mUpdatePlayer (true), mClassSelected (false),
|
: mWatchedTimeToStartDrowning(0), mWatchedStatsEmpty (true), mUpdatePlayer (true), mClassSelected (false),
|
||||||
mRaceSelected (false), mAI(true)
|
mRaceSelected (false), mAI(true)
|
||||||
{
|
{
|
||||||
//buildPlayer no longer here, needs to be done explicitely after all subsystems are up and running
|
//buildPlayer no longer here, needs to be done explicitly after all subsystems are up and running
|
||||||
}
|
}
|
||||||
|
|
||||||
void MechanicsManager::add(const MWWorld::Ptr& ptr)
|
void MechanicsManager::add(const MWWorld::Ptr& ptr)
|
||||||
|
|
|
@ -19,7 +19,7 @@ namespace MWMechanics
|
||||||
bool proximityToDoor(const MWWorld::Ptr& actor,
|
bool proximityToDoor(const MWWorld::Ptr& actor,
|
||||||
float minSqr = MIN_DIST_TO_DOOR_SQUARED);
|
float minSqr = MIN_DIST_TO_DOOR_SQUARED);
|
||||||
|
|
||||||
/// Returns door pointer within range. No guarentee is given as too which one
|
/// Returns door pointer within range. No guarantee is given as to which one
|
||||||
/** \return Pointer to the door, or NULL if none exists **/
|
/** \return Pointer to the door, or NULL if none exists **/
|
||||||
MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor,
|
MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor,
|
||||||
float minSqr = MIN_DIST_TO_DOOR_SQUARED);
|
float minSqr = MIN_DIST_TO_DOOR_SQUARED);
|
||||||
|
|
|
@ -139,7 +139,7 @@ namespace MWMechanics
|
||||||
* NOTE: It may be desirable to simply go directly to the endPoint if for
|
* NOTE: It may be desirable to simply go directly to the endPoint if for
|
||||||
* example there are no pathgrids in this cell.
|
* example there are no pathgrids in this cell.
|
||||||
*
|
*
|
||||||
* NOTE: startPoint & endPoint are in world co-ordinates
|
* NOTE: startPoint & endPoint are in world coordinates
|
||||||
*
|
*
|
||||||
* Updates mPath using aStarSearch() or ray test (if shortcut allowed).
|
* Updates mPath using aStarSearch() or ray test (if shortcut allowed).
|
||||||
* mPath consists of pathgrid points, except the last element which is
|
* mPath consists of pathgrid points, except the last element which is
|
||||||
|
@ -148,7 +148,7 @@ namespace MWMechanics
|
||||||
* pathgrid point (e.g. wander) then it may be worth while to call
|
* pathgrid point (e.g. wander) then it may be worth while to call
|
||||||
* pop_back() to remove the redundant entry.
|
* pop_back() to remove the redundant entry.
|
||||||
*
|
*
|
||||||
* NOTE: co-ordinates must be converted prior to calling GetClosestPoint()
|
* NOTE: coordinates must be converted prior to calling GetClosestPoint()
|
||||||
*
|
*
|
||||||
* |
|
* |
|
||||||
* | cell
|
* | cell
|
||||||
|
@ -164,8 +164,8 @@ namespace MWMechanics
|
||||||
* +-----------------------------
|
* +-----------------------------
|
||||||
*
|
*
|
||||||
* i = x value of cell itself (multiply by ESM::Land::REAL_SIZE to convert)
|
* i = x value of cell itself (multiply by ESM::Land::REAL_SIZE to convert)
|
||||||
* j = @.x in local co-ordinates (i.e. within the cell)
|
* j = @.x in local coordinates (i.e. within the cell)
|
||||||
* k = @.x in world co-ordinates
|
* k = @.x in world coordinates
|
||||||
*/
|
*/
|
||||||
void PathFinder::buildPath(const ESM::Pathgrid::Point &startPoint,
|
void PathFinder::buildPath(const ESM::Pathgrid::Point &startPoint,
|
||||||
const ESM::Pathgrid::Point &endPoint,
|
const ESM::Pathgrid::Point &endPoint,
|
||||||
|
@ -188,7 +188,7 @@ namespace MWMechanics
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: GetClosestPoint expects local co-ordinates
|
// NOTE: GetClosestPoint expects local coordinates
|
||||||
CoordinateConverter converter(mCell->getCell());
|
CoordinateConverter converter(mCell->getCell());
|
||||||
|
|
||||||
// NOTE: It is possible that GetClosestPoint returns a pathgrind point index
|
// NOTE: It is possible that GetClosestPoint returns a pathgrind point index
|
||||||
|
@ -230,7 +230,7 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
mPath = mCell->aStarSearch(startNode, endNode.first);
|
mPath = mCell->aStarSearch(startNode, endNode.first);
|
||||||
|
|
||||||
// convert supplied path to world co-ordinates
|
// convert supplied path to world coordinates
|
||||||
for (std::list<ESM::Pathgrid::Point>::iterator iter(mPath.begin()); iter != mPath.end(); ++iter)
|
for (std::list<ESM::Pathgrid::Point>::iterator iter(mPath.begin()); iter != mPath.end(); ++iter)
|
||||||
{
|
{
|
||||||
converter.toWorld(*iter);
|
converter.toWorld(*iter);
|
||||||
|
|
|
@ -84,7 +84,7 @@ namespace MWMechanics
|
||||||
/** Synchronize new path with old one to avoid visiting 1 waypoint 2 times
|
/** Synchronize new path with old one to avoid visiting 1 waypoint 2 times
|
||||||
@note
|
@note
|
||||||
BuildPath() takes closest PathGrid point to NPC as first point of path.
|
BuildPath() takes closest PathGrid point to NPC as first point of path.
|
||||||
This is undesireable if NPC has just passed a Pathgrid point, as this
|
This is undesirable if NPC has just passed a Pathgrid point, as this
|
||||||
makes the 2nd point of the new path == the 1st point of old path.
|
makes the 2nd point of the new path == the 1st point of old path.
|
||||||
Which results in NPC "running in a circle" back to the just passed waypoint.
|
Which results in NPC "running in a circle" back to the just passed waypoint.
|
||||||
*/
|
*/
|
||||||
|
@ -122,11 +122,11 @@ namespace MWMechanics
|
||||||
return (MWMechanics::PathFinder::MakeOsgVec3(point) - pos).length2();
|
return (MWMechanics::PathFinder::MakeOsgVec3(point) - pos).length2();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the closest pathgrid point index from the specified position co
|
// Return the closest pathgrid point index from the specified position
|
||||||
// -ordinates. NOTE: Does not check if there is a sensible way to get there
|
// coordinates. NOTE: Does not check if there is a sensible way to get there
|
||||||
// (e.g. a cliff in front).
|
// (e.g. a cliff in front).
|
||||||
//
|
//
|
||||||
// NOTE: pos is expected to be in local co-ordinates, as is grid->mPoints
|
// NOTE: pos is expected to be in local coordinates, as is grid->mPoints
|
||||||
//
|
//
|
||||||
static int GetClosestPoint(const ESM::Pathgrid* grid, const osg::Vec3f& pos)
|
static int GetClosestPoint(const ESM::Pathgrid* grid, const osg::Vec3f& pos)
|
||||||
{
|
{
|
||||||
|
|
|
@ -225,7 +225,7 @@ namespace MWMechanics
|
||||||
* Should be possible to make this MT safe.
|
* Should be possible to make this MT safe.
|
||||||
*
|
*
|
||||||
* Returns path which may be empty. path contains pathgrid points in local
|
* Returns path which may be empty. path contains pathgrid points in local
|
||||||
* cell co-ordinates (indoors) or world co-ordinates (external).
|
* cell coordinates (indoors) or world coordinates (external).
|
||||||
*
|
*
|
||||||
* Input params:
|
* Input params:
|
||||||
* start, goal - pathgrid point indexes (for this cell)
|
* start, goal - pathgrid point indexes (for this cell)
|
||||||
|
@ -239,7 +239,7 @@ namespace MWMechanics
|
||||||
* TODO: An intersting exercise might be to cache the paths created for a
|
* TODO: An intersting exercise might be to cache the paths created for a
|
||||||
* start/goal pair. To cache the results the paths need to be in
|
* start/goal pair. To cache the results the paths need to be in
|
||||||
* pathgrid points form (currently they are converted to world
|
* pathgrid points form (currently they are converted to world
|
||||||
* co-ordinates). Essentially trading speed w/ memory.
|
* coordinates). Essentially trading speed w/ memory.
|
||||||
*/
|
*/
|
||||||
std::list<ESM::Pathgrid::Point> PathgridGraph::aStarSearch(const int start,
|
std::list<ESM::Pathgrid::Point> PathgridGraph::aStarSearch(const int start,
|
||||||
const int goal) const
|
const int goal) const
|
||||||
|
@ -312,7 +312,7 @@ namespace MWMechanics
|
||||||
if(current != goal)
|
if(current != goal)
|
||||||
return path; // for some reason couldn't build a path
|
return path; // for some reason couldn't build a path
|
||||||
|
|
||||||
// reconstruct path to return, using local co-ordinates
|
// reconstruct path to return, using local coordinates
|
||||||
while(graphParent[current] != -1)
|
while(graphParent[current] != -1)
|
||||||
{
|
{
|
||||||
path.push_front(mPathgrid->mPoints[current]);
|
path.push_front(mPathgrid->mPoints[current]);
|
||||||
|
|
|
@ -30,7 +30,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
// the input parameters are pathgrid point indexes
|
// the input parameters are pathgrid point indexes
|
||||||
// the output list is in local (internal cells) or world (external
|
// the output list is in local (internal cells) or world (external
|
||||||
// cells) co-ordinates
|
// cells) coordinates
|
||||||
//
|
//
|
||||||
// NOTE: if start equals end an empty path is returned
|
// NOTE: if start equals end an empty path is returned
|
||||||
std::list<ESM::Pathgrid::Point> aStarSearch(const int start,
|
std::list<ESM::Pathgrid::Point> aStarSearch(const int start,
|
||||||
|
|
|
@ -491,7 +491,7 @@ namespace MWMechanics
|
||||||
appliedLastingEffects.push_back(effect);
|
appliedLastingEffects.push_back(effect);
|
||||||
|
|
||||||
// For absorb effects, also apply the effect to the caster - but with a negative
|
// For absorb effects, also apply the effect to the caster - but with a negative
|
||||||
// magnitude, since we're transfering stats from the target to the caster
|
// magnitude, since we're transferring stats from the target to the caster
|
||||||
if (!caster.isEmpty() && caster.getClass().isActor())
|
if (!caster.isEmpty() && caster.getClass().isActor())
|
||||||
{
|
{
|
||||||
for (int i=0; i<5; ++i)
|
for (int i=0; i<5; ++i)
|
||||||
|
@ -913,7 +913,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(mCaster);
|
MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(mCaster);
|
||||||
|
|
||||||
if (mCaster.getClass().isActor()) // TODO: Non-actors should also create a spell cast vfx
|
if (animation && mCaster.getClass().isActor()) // TODO: Non-actors should also create a spell cast vfx even if they are disabled (animation == NULL)
|
||||||
{
|
{
|
||||||
const ESM::Static* castStatic;
|
const ESM::Static* castStatic;
|
||||||
|
|
||||||
|
@ -927,7 +927,7 @@ namespace MWMechanics
|
||||||
animation->addEffect("meshes\\" + castStatic->mModel, effect->mIndex, false, "", texture);
|
animation->addEffect("meshes\\" + castStatic->mModel, effect->mIndex, false, "", texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mCaster.getClass().isActor())
|
if (animation && !mCaster.getClass().isActor())
|
||||||
animation->addSpellCastGlow(effect);
|
animation->addSpellCastGlow(effect);
|
||||||
|
|
||||||
static const std::string schools[] = {
|
static const std::string schools[] = {
|
||||||
|
@ -980,8 +980,10 @@ namespace MWMechanics
|
||||||
if (charge == 0)
|
if (charge == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// FIXME: charge should be a float, not int so that damage < 1 per frame can be applied.
|
// Store remainder of disintegrate amount (automatically subtracted if > 1)
|
||||||
// This was also a bug in the original engine.
|
item->getCellRef().applyChargeRemainderToBeSubtracted(disintegrate - std::floor(disintegrate));
|
||||||
|
|
||||||
|
charge = item->getClass().getItemHealth(*item);
|
||||||
charge -=
|
charge -=
|
||||||
std::min(static_cast<int>(disintegrate),
|
std::min(static_cast<int>(disintegrate),
|
||||||
charge);
|
charge);
|
||||||
|
@ -1009,10 +1011,10 @@ namespace MWMechanics
|
||||||
creatureStats.setDynamic(index, stat);
|
creatureStats.setDynamic(index, stat);
|
||||||
}
|
}
|
||||||
|
|
||||||
void effectTick(CreatureStats& creatureStats, const MWWorld::Ptr& actor, const EffectKey &effectKey, float magnitude)
|
bool effectTick(CreatureStats& creatureStats, const MWWorld::Ptr& actor, const EffectKey &effectKey, float magnitude)
|
||||||
{
|
{
|
||||||
if (magnitude == 0.f)
|
if (magnitude == 0.f)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
bool receivedMagicDamage = false;
|
bool receivedMagicDamage = false;
|
||||||
|
|
||||||
|
@ -1144,10 +1146,13 @@ namespace MWMechanics
|
||||||
case ESM::MagicEffect::RemoveCurse:
|
case ESM::MagicEffect::RemoveCurse:
|
||||||
actor.getClass().getCreatureStats(actor).getSpells().purgeCurses();
|
actor.getClass().getCreatureStats(actor).getSpells().purgeCurses();
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (receivedMagicDamage && actor == getPlayer())
|
if (receivedMagicDamage && actor == getPlayer())
|
||||||
MWBase::Environment::get().getWindowManager()->activateHitOverlay(false);
|
MWBase::Environment::get().getWindowManager()->activateHitOverlay(false);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,9 @@ namespace MWMechanics
|
||||||
|
|
||||||
int getEffectiveEnchantmentCastCost (float castCost, const MWWorld::Ptr& actor);
|
int getEffectiveEnchantmentCastCost (float castCost, const MWWorld::Ptr& actor);
|
||||||
|
|
||||||
void effectTick(CreatureStats& creatureStats, const MWWorld::Ptr& actor, const MWMechanics::EffectKey& effectKey, float magnitude);
|
/// Apply a magic effect that is applied in tick intervals until its remaining time ends or it is removed
|
||||||
|
/// @return Was the effect a tickable effect with a magnitude?
|
||||||
|
bool effectTick(CreatureStats& creatureStats, const MWWorld::Ptr& actor, const MWMechanics::EffectKey& effectKey, float magnitude);
|
||||||
|
|
||||||
class CastSpell
|
class CastSpell
|
||||||
{
|
{
|
||||||
|
|
|
@ -69,7 +69,14 @@ namespace MWPhysics
|
||||||
return osg::RadiansToDegrees(std::acos(normal * osg::Vec3f(0.f, 0.f, 1.f)));
|
return osg::RadiansToDegrees(std::acos(normal * osg::Vec3f(0.f, 0.f, 1.f)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool stepMove(const btCollisionObject *colobj, osg::Vec3f &position,
|
enum StepMoveResult
|
||||||
|
{
|
||||||
|
Result_Blocked, // unable to move over obstacle
|
||||||
|
Result_MaxSlope, // unable to end movement on this slope
|
||||||
|
Result_Success
|
||||||
|
};
|
||||||
|
|
||||||
|
static StepMoveResult stepMove(const btCollisionObject *colobj, osg::Vec3f &position,
|
||||||
const osg::Vec3f &toMove, float &remainingTime, const btCollisionWorld* collisionWorld)
|
const osg::Vec3f &toMove, float &remainingTime, const btCollisionWorld* collisionWorld)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -120,7 +127,7 @@ namespace MWPhysics
|
||||||
|
|
||||||
stepper.doTrace(colobj, position, position+osg::Vec3f(0.0f,0.0f,sStepSizeUp), collisionWorld);
|
stepper.doTrace(colobj, position, position+osg::Vec3f(0.0f,0.0f,sStepSizeUp), collisionWorld);
|
||||||
if(stepper.mFraction < std::numeric_limits<float>::epsilon())
|
if(stepper.mFraction < std::numeric_limits<float>::epsilon())
|
||||||
return false; // didn't even move the smallest representable amount
|
return Result_Blocked; // didn't even move the smallest representable amount
|
||||||
// (TODO: shouldn't this be larger? Why bother with such a small amount?)
|
// (TODO: shouldn't this be larger? Why bother with such a small amount?)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -138,7 +145,7 @@ namespace MWPhysics
|
||||||
*/
|
*/
|
||||||
tracer.doTrace(colobj, stepper.mEndPos, stepper.mEndPos + toMove, collisionWorld);
|
tracer.doTrace(colobj, stepper.mEndPos, stepper.mEndPos + toMove, collisionWorld);
|
||||||
if(tracer.mFraction < std::numeric_limits<float>::epsilon())
|
if(tracer.mFraction < std::numeric_limits<float>::epsilon())
|
||||||
return false; // didn't even move the smallest representable amount
|
return Result_Blocked; // didn't even move the smallest representable amount
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Try moving back down sStepSizeDown using stepper.
|
* Try moving back down sStepSizeDown using stepper.
|
||||||
|
@ -156,22 +163,22 @@ namespace MWPhysics
|
||||||
* ==============================================
|
* ==============================================
|
||||||
*/
|
*/
|
||||||
stepper.doTrace(colobj, tracer.mEndPos, tracer.mEndPos-osg::Vec3f(0.0f,0.0f,sStepSizeDown), collisionWorld);
|
stepper.doTrace(colobj, tracer.mEndPos, tracer.mEndPos-osg::Vec3f(0.0f,0.0f,sStepSizeDown), collisionWorld);
|
||||||
if(stepper.mFraction < 1.0f && getSlope(stepper.mPlaneNormal) <= sMaxSlope)
|
if (getSlope(stepper.mPlaneNormal) > sMaxSlope)
|
||||||
|
return Result_MaxSlope;
|
||||||
|
if(stepper.mFraction < 1.0f)
|
||||||
{
|
{
|
||||||
// don't allow stepping up other actors
|
// don't allow stepping up other actors
|
||||||
if (stepper.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Actor)
|
if (stepper.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Actor)
|
||||||
return false;
|
return Result_Blocked;
|
||||||
// only step down onto semi-horizontal surfaces. don't step down onto the side of a house or a wall.
|
// only step down onto semi-horizontal surfaces. don't step down onto the side of a house or a wall.
|
||||||
// TODO: stepper.mPlaneNormal does not appear to be reliable - needs more testing
|
// TODO: stepper.mPlaneNormal does not appear to be reliable - needs more testing
|
||||||
// NOTE: caller's variables 'position' & 'remainingTime' are modified here
|
// NOTE: caller's variables 'position' & 'remainingTime' are modified here
|
||||||
position = stepper.mEndPos;
|
position = stepper.mEndPos;
|
||||||
remainingTime *= (1.0f-tracer.mFraction); // remaining time is proportional to remaining distance
|
remainingTime *= (1.0f-tracer.mFraction); // remaining time is proportional to remaining distance
|
||||||
return true;
|
return Result_Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
// moved between 0 and just under sStepSize distance but slope was too great,
|
return Result_Blocked;
|
||||||
// or moved full sStepSize distance (FIXME: is this a bug?)
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -361,14 +368,15 @@ namespace MWPhysics
|
||||||
osg::Vec3f oldPosition = newPosition;
|
osg::Vec3f oldPosition = newPosition;
|
||||||
// We hit something. Try to step up onto it. (NOTE: stepMove does not allow stepping over)
|
// We hit something. Try to step up onto it. (NOTE: stepMove does not allow stepping over)
|
||||||
// NOTE: stepMove modifies newPosition if successful
|
// NOTE: stepMove modifies newPosition if successful
|
||||||
bool result = stepMove(colobj, newPosition, velocity*remainingTime, remainingTime, collisionWorld);
|
const float minStep = 10.f;
|
||||||
if (!result) // to make sure the maximum stepping distance isn't framerate-dependent or movement-speed dependent
|
StepMoveResult result = stepMove(colobj, newPosition, velocity*remainingTime, remainingTime, collisionWorld);
|
||||||
|
if (result == Result_MaxSlope && (velocity*remainingTime).length() < minStep) // to make sure the maximum stepping distance isn't framerate-dependent or movement-speed dependent
|
||||||
{
|
{
|
||||||
osg::Vec3f normalizedVelocity = velocity;
|
osg::Vec3f normalizedVelocity = velocity;
|
||||||
normalizedVelocity.normalize();
|
normalizedVelocity.normalize();
|
||||||
result = stepMove(colobj, newPosition, normalizedVelocity*10.f, remainingTime, collisionWorld);
|
result = stepMove(colobj, newPosition, normalizedVelocity*minStep, remainingTime, collisionWorld);
|
||||||
}
|
}
|
||||||
if(result)
|
if(result == Result_Success)
|
||||||
{
|
{
|
||||||
// don't let pure water creatures move out of water after stepMove
|
// don't let pure water creatures move out of water after stepMove
|
||||||
if (ptr.getClass().isPureWaterCreature(ptr)
|
if (ptr.getClass().isPureWaterCreature(ptr)
|
||||||
|
@ -450,8 +458,8 @@ namespace MWPhysics
|
||||||
if (inertia.z() < 0)
|
if (inertia.z() < 0)
|
||||||
inertia.z() *= slowFall;
|
inertia.z() *= slowFall;
|
||||||
if (slowFall < 1.f) {
|
if (slowFall < 1.f) {
|
||||||
inertia.x() = 0;
|
inertia.x() *= slowFall;
|
||||||
inertia.y() = 0;
|
inertia.y() *= slowFall;
|
||||||
}
|
}
|
||||||
physicActor->setInertialForce(inertia);
|
physicActor->setInertialForce(inertia);
|
||||||
}
|
}
|
||||||
|
|
|
@ -200,7 +200,7 @@ namespace MWPhysics
|
||||||
typedef std::map<MWWorld::Ptr, MWWorld::Ptr> CollisionMap;
|
typedef std::map<MWWorld::Ptr, MWWorld::Ptr> CollisionMap;
|
||||||
CollisionMap mStandingCollisions;
|
CollisionMap mStandingCollisions;
|
||||||
|
|
||||||
// replaces all occurences of 'old' in the map by 'updated', no matter if its a key or value
|
// replaces all occurrences of 'old' in the map by 'updated', no matter if it's a key or value
|
||||||
void updateCollisionMapPtr(CollisionMap& map, const MWWorld::Ptr &old, const MWWorld::Ptr &updated);
|
void updateCollisionMapPtr(CollisionMap& map, const MWWorld::Ptr &old, const MWWorld::Ptr &updated);
|
||||||
|
|
||||||
PtrVelocityList mMovementQueue;
|
PtrVelocityList mMovementQueue;
|
||||||
|
|
|
@ -302,7 +302,7 @@ protected:
|
||||||
|
|
||||||
/** Sets the root model of the object.
|
/** Sets the root model of the object.
|
||||||
*
|
*
|
||||||
* Note that you must make sure all animation sources are cleared before reseting the object
|
* Note that you must make sure all animation sources are cleared before resetting the object
|
||||||
* root. All nodes previously retrieved with getNode will also become invalidated.
|
* root. All nodes previously retrieved with getNode will also become invalidated.
|
||||||
* @param forceskeleton Wrap the object root in a Skeleton, even if it contains no skinned parts. Use this if you intend to add skinned parts manually.
|
* @param forceskeleton Wrap the object root in a Skeleton, even if it contains no skinned parts. Use this if you intend to add skinned parts manually.
|
||||||
* @param baseonly If true, then any meshes or particle systems in the model are ignored
|
* @param baseonly If true, then any meshes or particle systems in the model are ignored
|
||||||
|
|
|
@ -211,7 +211,7 @@ namespace MWRender
|
||||||
|
|
||||||
osg::Vec3f mStormDirection;
|
osg::Vec3f mStormDirection;
|
||||||
|
|
||||||
// remember some settings so we don't have to apply them again if they didnt change
|
// remember some settings so we don't have to apply them again if they didn't change
|
||||||
std::string mClouds;
|
std::string mClouds;
|
||||||
std::string mNextClouds;
|
std::string mNextClouds;
|
||||||
float mCloudBlendFactor;
|
float mCloudBlendFactor;
|
||||||
|
|
|
@ -11,7 +11,7 @@ namespace MWScript
|
||||||
|
|
||||||
enum Type
|
enum Type
|
||||||
{
|
{
|
||||||
Type_Full, // global, local, targetted
|
Type_Full, // global, local, targeted
|
||||||
Type_Dialogue,
|
Type_Dialogue,
|
||||||
Type_Console
|
Type_Console
|
||||||
};
|
};
|
||||||
|
|
|
@ -34,8 +34,9 @@
|
||||||
|
|
||||||
namespace MWSound
|
namespace MWSound
|
||||||
{
|
{
|
||||||
SoundManager::SoundManager(const VFS::Manager* vfs, bool useSound)
|
SoundManager::SoundManager(const VFS::Manager* vfs, const std::map<std::string,std::string>& fallbackMap, bool useSound)
|
||||||
: mVFS(vfs)
|
: mVFS(vfs)
|
||||||
|
, mFallback(fallbackMap)
|
||||||
, mOutput(new DEFAULT_OUTPUT(*this))
|
, mOutput(new DEFAULT_OUTPUT(*this))
|
||||||
, mMasterVolume(1.0f)
|
, mMasterVolume(1.0f)
|
||||||
, mSFXVolume(1.0f)
|
, mSFXVolume(1.0f)
|
||||||
|
@ -61,6 +62,13 @@ namespace MWSound
|
||||||
mFootstepsVolume = Settings::Manager::getFloat("footsteps volume", "Sound");
|
mFootstepsVolume = Settings::Manager::getFloat("footsteps volume", "Sound");
|
||||||
mFootstepsVolume = std::min(std::max(mFootstepsVolume, 0.0f), 1.0f);
|
mFootstepsVolume = std::min(std::max(mFootstepsVolume, 0.0f), 1.0f);
|
||||||
|
|
||||||
|
mNearWaterRadius = mFallback.getFallbackInt("Water_NearWaterRadius");
|
||||||
|
mNearWaterPoints = mFallback.getFallbackInt("Water_NearWaterPoints");
|
||||||
|
mNearWaterIndoorTolerance = mFallback.getFallbackFloat("Water_NearWaterIndoorTolerance");
|
||||||
|
mNearWaterOutdoorTolerance = mFallback.getFallbackFloat("Water_NearWaterOutdoorTolerance");
|
||||||
|
mNearWaterIndoorID = mFallback.getFallbackString("Water_NearWaterIndoorID");
|
||||||
|
mNearWaterOutdoorID = mFallback.getFallbackString("Water_NearWaterOutdoorID");
|
||||||
|
|
||||||
mBufferCacheMin = std::max(Settings::Manager::getInt("buffer cache min", "Sound"), 1);
|
mBufferCacheMin = std::max(Settings::Manager::getInt("buffer cache min", "Sound"), 1);
|
||||||
mBufferCacheMax = std::max(Settings::Manager::getInt("buffer cache max", "Sound"), 1);
|
mBufferCacheMax = std::max(Settings::Manager::getInt("buffer cache max", "Sound"), 1);
|
||||||
mBufferCacheMax *= 1024*1024;
|
mBufferCacheMax *= 1024*1024;
|
||||||
|
@ -796,6 +804,96 @@ namespace MWSound
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SoundManager::updateWaterSound(float /*duration*/)
|
||||||
|
{
|
||||||
|
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||||
|
const MWWorld::ConstPtr player = world->getPlayerPtr();
|
||||||
|
osg::Vec3f pos = player.getRefData().getPosition().asVec3();
|
||||||
|
|
||||||
|
float volume = 0.0f;
|
||||||
|
const std::string& soundId = player.getCell()->isExterior() ? mNearWaterOutdoorID : mNearWaterIndoorID;
|
||||||
|
|
||||||
|
if (!mListenerUnderwater)
|
||||||
|
{
|
||||||
|
if (player.getCell()->getCell()->hasWater())
|
||||||
|
{
|
||||||
|
float dist = std::abs(player.getCell()->getWaterLevel() - pos.z());
|
||||||
|
|
||||||
|
if (player.getCell()->isExterior() && dist < mNearWaterOutdoorTolerance)
|
||||||
|
{
|
||||||
|
volume = (mNearWaterOutdoorTolerance - dist) / mNearWaterOutdoorTolerance;
|
||||||
|
|
||||||
|
if (mNearWaterPoints > 1)
|
||||||
|
{
|
||||||
|
int underwaterPoints = 0;
|
||||||
|
|
||||||
|
float step = mNearWaterRadius * 2.0f / (mNearWaterPoints - 1);
|
||||||
|
|
||||||
|
for (int x = 0; x < mNearWaterPoints; x++)
|
||||||
|
{
|
||||||
|
for (int y = 0; y < mNearWaterPoints; y++)
|
||||||
|
{
|
||||||
|
float height = world->getTerrainHeightAt(
|
||||||
|
osg::Vec3f(pos.x() - mNearWaterRadius + x*step, pos.y() - mNearWaterRadius + y*step, 0.0f));
|
||||||
|
|
||||||
|
if (height < 0)
|
||||||
|
underwaterPoints++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
volume *= underwaterPoints * 2.0f / (mNearWaterPoints*mNearWaterPoints);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!player.getCell()->isExterior() && dist < mNearWaterIndoorTolerance)
|
||||||
|
{
|
||||||
|
volume = (mNearWaterIndoorTolerance - dist) / mNearWaterIndoorTolerance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
volume = 1.0f;
|
||||||
|
|
||||||
|
volume = std::min(volume, 1.0f);
|
||||||
|
|
||||||
|
if (mNearWaterSound)
|
||||||
|
{
|
||||||
|
if (volume == 0.0f)
|
||||||
|
{
|
||||||
|
mOutput->finishSound(mNearWaterSound);
|
||||||
|
mNearWaterSound.reset();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bool soundIdChanged = false;
|
||||||
|
|
||||||
|
Sound_Buffer* sfx = lookupSound(Misc::StringUtils::lowerCase(soundId));
|
||||||
|
|
||||||
|
for (SoundMap::const_iterator snditer = mActiveSounds.begin(); snditer != mActiveSounds.end(); ++snditer)
|
||||||
|
{
|
||||||
|
for (SoundBufferRefPairList::const_iterator pairiter = snditer->second.begin(); pairiter != snditer->second.end(); ++pairiter)
|
||||||
|
{
|
||||||
|
if (pairiter->first == mNearWaterSound)
|
||||||
|
{
|
||||||
|
if (pairiter->second != sfx)
|
||||||
|
soundIdChanged = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (soundIdChanged)
|
||||||
|
{
|
||||||
|
mOutput->finishSound(mNearWaterSound);
|
||||||
|
mNearWaterSound = playSound(soundId, volume, 1.0f, Play_TypeSfx, Play_Loop);
|
||||||
|
}
|
||||||
|
else if (sfx)
|
||||||
|
mNearWaterSound->setVolume(volume * sfx->mVolume);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (volume > 0.0f)
|
||||||
|
mNearWaterSound = playSound(soundId, volume, 1.0f, Play_TypeSfx, Play_Loop);
|
||||||
|
}
|
||||||
|
|
||||||
void SoundManager::updateSounds(float duration)
|
void SoundManager::updateSounds(float duration)
|
||||||
{
|
{
|
||||||
static float timePassed = 0.0;
|
static float timePassed = 0.0;
|
||||||
|
@ -941,6 +1039,7 @@ namespace MWSound
|
||||||
{
|
{
|
||||||
updateSounds(duration);
|
updateSounds(duration);
|
||||||
updateRegionSound(duration);
|
updateRegionSound(duration);
|
||||||
|
updateWaterSound(duration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1105,6 +1204,7 @@ namespace MWSound
|
||||||
mOutput->finishStream(*trkiter);
|
mOutput->finishStream(*trkiter);
|
||||||
mActiveTracks.clear();
|
mActiveTracks.clear();
|
||||||
mUnderwaterSound.reset();
|
mUnderwaterSound.reset();
|
||||||
|
mNearWaterSound.reset();
|
||||||
stopMusic();
|
stopMusic();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
|
|
||||||
#include <components/settings/settings.hpp>
|
#include <components/settings/settings.hpp>
|
||||||
|
|
||||||
|
#include <components/fallback/fallback.hpp>
|
||||||
|
|
||||||
#include "../mwbase/soundmanager.hpp"
|
#include "../mwbase/soundmanager.hpp"
|
||||||
|
|
||||||
namespace VFS
|
namespace VFS
|
||||||
|
@ -44,6 +46,8 @@ namespace MWSound
|
||||||
{
|
{
|
||||||
const VFS::Manager* mVFS;
|
const VFS::Manager* mVFS;
|
||||||
|
|
||||||
|
Fallback::Map mFallback;
|
||||||
|
|
||||||
std::auto_ptr<Sound_Output> mOutput;
|
std::auto_ptr<Sound_Output> mOutput;
|
||||||
|
|
||||||
// Caches available music tracks by <playlist name, (sound files) >
|
// Caches available music tracks by <playlist name, (sound files) >
|
||||||
|
@ -56,6 +60,13 @@ namespace MWSound
|
||||||
float mVoiceVolume;
|
float mVoiceVolume;
|
||||||
float mFootstepsVolume;
|
float mFootstepsVolume;
|
||||||
|
|
||||||
|
int mNearWaterRadius;
|
||||||
|
int mNearWaterPoints;
|
||||||
|
float mNearWaterIndoorTolerance;
|
||||||
|
float mNearWaterOutdoorTolerance;
|
||||||
|
std::string mNearWaterIndoorID;
|
||||||
|
std::string mNearWaterOutdoorID;
|
||||||
|
|
||||||
typedef std::auto_ptr<std::deque<Sound_Buffer> > SoundBufferList;
|
typedef std::auto_ptr<std::deque<Sound_Buffer> > SoundBufferList;
|
||||||
// List of sound buffers, grown as needed. New enties are added to the
|
// List of sound buffers, grown as needed. New enties are added to the
|
||||||
// back, allowing existing Sound_Buffer references/pointers to remain
|
// back, allowing existing Sound_Buffer references/pointers to remain
|
||||||
|
@ -94,6 +105,7 @@ namespace MWSound
|
||||||
int mPausedSoundTypes;
|
int mPausedSoundTypes;
|
||||||
|
|
||||||
MWBase::SoundPtr mUnderwaterSound;
|
MWBase::SoundPtr mUnderwaterSound;
|
||||||
|
MWBase::SoundPtr mNearWaterSound;
|
||||||
|
|
||||||
Sound_Buffer *insertSound(const std::string &soundId, const ESM::Sound *sound);
|
Sound_Buffer *insertSound(const std::string &soundId, const ESM::Sound *sound);
|
||||||
|
|
||||||
|
@ -108,6 +120,7 @@ namespace MWSound
|
||||||
void streamMusicFull(const std::string& filename);
|
void streamMusicFull(const std::string& filename);
|
||||||
void updateSounds(float duration);
|
void updateSounds(float duration);
|
||||||
void updateRegionSound(float duration);
|
void updateRegionSound(float duration);
|
||||||
|
void updateWaterSound(float duration);
|
||||||
|
|
||||||
float volumeFromType(PlayType type) const;
|
float volumeFromType(PlayType type) const;
|
||||||
|
|
||||||
|
@ -119,7 +132,7 @@ namespace MWSound
|
||||||
friend class OpenAL_Output;
|
friend class OpenAL_Output;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SoundManager(const VFS::Manager* vfs, bool useSound);
|
SoundManager(const VFS::Manager* vfs, const std::map<std::string, std::string>& fallbackMap, bool useSound);
|
||||||
virtual ~SoundManager();
|
virtual ~SoundManager();
|
||||||
|
|
||||||
virtual void processChangedSettings(const Settings::CategorySettingVector& settings);
|
virtual void processChangedSettings(const Settings::CategorySettingVector& settings);
|
||||||
|
|
|
@ -93,6 +93,24 @@ namespace MWWorld
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CellRef::applyChargeRemainderToBeSubtracted(float chargeRemainder)
|
||||||
|
{
|
||||||
|
mCellRef.mChargeIntRemainder += std::abs(chargeRemainder);
|
||||||
|
if (mCellRef.mChargeIntRemainder > 1.0f)
|
||||||
|
{
|
||||||
|
float newChargeRemainder = (mCellRef.mChargeIntRemainder - std::floor(mCellRef.mChargeIntRemainder));
|
||||||
|
if (mCellRef.mChargeInt <= static_cast<int>(mCellRef.mChargeIntRemainder))
|
||||||
|
{
|
||||||
|
mCellRef.mChargeInt = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mCellRef.mChargeInt -= static_cast<int>(mCellRef.mChargeIntRemainder);
|
||||||
|
}
|
||||||
|
mCellRef.mChargeIntRemainder = newChargeRemainder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
float CellRef::getChargeFloat() const
|
float CellRef::getChargeFloat() const
|
||||||
{
|
{
|
||||||
return mCellRef.mChargeFloat;
|
return mCellRef.mChargeFloat;
|
||||||
|
|
|
@ -65,6 +65,7 @@ namespace MWWorld
|
||||||
float getChargeFloat() const; // Implemented as union with int charge
|
float getChargeFloat() const; // Implemented as union with int charge
|
||||||
void setCharge(int charge);
|
void setCharge(int charge);
|
||||||
void setChargeFloat(float charge);
|
void setChargeFloat(float charge);
|
||||||
|
void applyChargeRemainderToBeSubtracted(float chargeRemainder); // Stores remainders and applies if > 1
|
||||||
|
|
||||||
// The NPC that owns this object (and will get angry if you steal it)
|
// The NPC that owns this object (and will get angry if you steal it)
|
||||||
std::string getOwner() const;
|
std::string getOwner() const;
|
||||||
|
|
|
@ -16,6 +16,7 @@ namespace
|
||||||
cellRef.mScale = 1;
|
cellRef.mScale = 1;
|
||||||
cellRef.mFactionRank = 0;
|
cellRef.mFactionRank = 0;
|
||||||
cellRef.mChargeInt = -1;
|
cellRef.mChargeInt = -1;
|
||||||
|
cellRef.mChargeIntRemainder = 0.0f;
|
||||||
cellRef.mGoldValue = 1;
|
cellRef.mGoldValue = 1;
|
||||||
cellRef.mEnchantmentCharge = -1;
|
cellRef.mEnchantmentCharge = -1;
|
||||||
cellRef.mTeleport = false;
|
cellRef.mTeleport = false;
|
||||||
|
|
|
@ -93,6 +93,31 @@ namespace
|
||||||
}
|
}
|
||||||
return projectileEffects;
|
return projectileEffects;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
osg::Vec4 getMagicBoltLightDiffuseColor(const ESM::EffectList& effects)
|
||||||
|
{
|
||||||
|
// Calculate combined light diffuse color from magical effects
|
||||||
|
osg::Vec4 lightDiffuseColor;
|
||||||
|
float lightDiffuseRed = 0.0f;
|
||||||
|
float lightDiffuseGreen = 0.0f;
|
||||||
|
float lightDiffuseBlue = 0.0f;
|
||||||
|
for (std::vector<ESM::ENAMstruct>::const_iterator iter(effects.mList.begin());
|
||||||
|
iter != effects.mList.end(); ++iter)
|
||||||
|
{
|
||||||
|
const ESM::MagicEffect *magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(
|
||||||
|
iter->mEffectID);
|
||||||
|
lightDiffuseRed += (static_cast<float>(magicEffect->mData.mRed) / 255.f);
|
||||||
|
lightDiffuseGreen += (static_cast<float>(magicEffect->mData.mGreen) / 255.f);
|
||||||
|
lightDiffuseBlue += (static_cast<float>(magicEffect->mData.mBlue) / 255.f);
|
||||||
|
}
|
||||||
|
int numberOfEffects = effects.mList.size();
|
||||||
|
lightDiffuseColor = osg::Vec4(lightDiffuseRed / numberOfEffects
|
||||||
|
, lightDiffuseGreen / numberOfEffects
|
||||||
|
, lightDiffuseBlue / numberOfEffects
|
||||||
|
, 1.0f);
|
||||||
|
|
||||||
|
return lightDiffuseColor;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
|
@ -136,7 +161,8 @@ namespace MWWorld
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
void ProjectileManager::createModel(State &state, const std::string &model, const osg::Vec3f& pos, const osg::Quat& orient, bool rotate, std::string texture)
|
void ProjectileManager::createModel(State &state, const std::string &model, const osg::Vec3f& pos, const osg::Quat& orient,
|
||||||
|
bool rotate, bool createLight, osg::Vec4 lightDiffuseColor, std::string texture)
|
||||||
{
|
{
|
||||||
state.mNode = new osg::PositionAttitudeTransform;
|
state.mNode = new osg::PositionAttitudeTransform;
|
||||||
state.mNode->setNodeMask(MWRender::Mask_Effect);
|
state.mNode->setNodeMask(MWRender::Mask_Effect);
|
||||||
|
@ -167,6 +193,25 @@ namespace MWWorld
|
||||||
mResourceSystem->getSceneManager()->getInstance("meshes\\" + weapon->mModel, findVisitor.mFoundNode);
|
mResourceSystem->getSceneManager()->getInstance("meshes\\" + weapon->mModel, findVisitor.mFoundNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (createLight)
|
||||||
|
{
|
||||||
|
osg::ref_ptr<osg::Light> projectileLight(new osg::Light);
|
||||||
|
projectileLight->setAmbient(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
|
||||||
|
projectileLight->setDiffuse(lightDiffuseColor);
|
||||||
|
projectileLight->setSpecular(osg::Vec4(0.0f, 0.0f, 0.0f, 0.0f));
|
||||||
|
projectileLight->setConstantAttenuation(0.f);
|
||||||
|
projectileLight->setLinearAttenuation(0.1f);
|
||||||
|
projectileLight->setQuadraticAttenuation(0.f);
|
||||||
|
projectileLight->setPosition(osg::Vec4(pos, 1.0));
|
||||||
|
|
||||||
|
SceneUtil::LightSource* projectileLightSource = new SceneUtil::LightSource;
|
||||||
|
projectileLightSource->setNodeMask(MWRender::Mask_Lighting);
|
||||||
|
projectileLightSource->setRadius(66.f);
|
||||||
|
|
||||||
|
state.mNode->addChild(projectileLightSource);
|
||||||
|
projectileLightSource->setLight(projectileLight);
|
||||||
|
}
|
||||||
|
|
||||||
SceneUtil::DisableFreezeOnCullVisitor disableFreezeOnCullVisitor;
|
SceneUtil::DisableFreezeOnCullVisitor disableFreezeOnCullVisitor;
|
||||||
state.mNode->accept(disableFreezeOnCullVisitor);
|
state.mNode->accept(disableFreezeOnCullVisitor);
|
||||||
|
|
||||||
|
@ -229,7 +274,8 @@ namespace MWWorld
|
||||||
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), state.mIdMagic.at(0));
|
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), state.mIdMagic.at(0));
|
||||||
MWWorld::Ptr ptr = ref.getPtr();
|
MWWorld::Ptr ptr = ref.getPtr();
|
||||||
|
|
||||||
createModel(state, ptr.getClass().getModel(ptr), pos, orient, true, texture);
|
osg::Vec4 lightDiffuseColor = getMagicBoltLightDiffuseColor(effects);
|
||||||
|
createModel(state, ptr.getClass().getModel(ptr), pos, orient, true, true, lightDiffuseColor, texture);
|
||||||
|
|
||||||
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
||||||
for (size_t it = 0; it != state.mSoundIds.size(); it++)
|
for (size_t it = 0; it != state.mSoundIds.size(); it++)
|
||||||
|
@ -253,7 +299,7 @@ namespace MWWorld
|
||||||
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), projectile.getCellRef().getRefId());
|
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), projectile.getCellRef().getRefId());
|
||||||
MWWorld::Ptr ptr = ref.getPtr();
|
MWWorld::Ptr ptr = ref.getPtr();
|
||||||
|
|
||||||
createModel(state, ptr.getClass().getModel(ptr), pos, orient, false);
|
createModel(state, ptr.getClass().getModel(ptr), pos, orient, false, false, osg::Vec4(0,0,0,0));
|
||||||
|
|
||||||
mProjectiles.push_back(state);
|
mProjectiles.push_back(state);
|
||||||
}
|
}
|
||||||
|
@ -483,7 +529,7 @@ namespace MWWorld
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), false);
|
createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), false, false, osg::Vec4(0,0,0,0));
|
||||||
|
|
||||||
mProjectiles.push_back(state);
|
mProjectiles.push_back(state);
|
||||||
return true;
|
return true;
|
||||||
|
@ -518,7 +564,8 @@ namespace MWWorld
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), true, texture);
|
osg::Vec4 lightDiffuseColor = getMagicBoltLightDiffuseColor(esm.mEffects);
|
||||||
|
createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), true, true, lightDiffuseColor, texture);
|
||||||
|
|
||||||
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
||||||
|
|
||||||
|
|
|
@ -122,7 +122,8 @@ namespace MWWorld
|
||||||
void moveProjectiles(float dt);
|
void moveProjectiles(float dt);
|
||||||
void moveMagicBolts(float dt);
|
void moveMagicBolts(float dt);
|
||||||
|
|
||||||
void createModel (State& state, const std::string& model, const osg::Vec3f& pos, const osg::Quat& orient, bool rotate, std::string texture = "");
|
void createModel (State& state, const std::string& model, const osg::Vec3f& pos, const osg::Quat& orient,
|
||||||
|
bool rotate, bool createLight, osg::Vec4 lightDiffuseColor, std::string texture = "");
|
||||||
void update (State& state, float duration);
|
void update (State& state, float duration);
|
||||||
|
|
||||||
void operator=(const ProjectileManager&);
|
void operator=(const ProjectileManager&);
|
||||||
|
|
|
@ -1069,7 +1069,7 @@ inline void WeatherManager::calculateResult(const int weatherID, const float gam
|
||||||
mResult.mSunDiscColor = lerp(osg::Vec4f(1,1,1,1), current.mSunDiscSunsetColor, factor);
|
mResult.mSunDiscColor = lerp(osg::Vec4f(1,1,1,1), current.mSunDiscSunsetColor, factor);
|
||||||
// The SunDiscSunsetColor in the INI isn't exactly the resulting color on screen, most likely because
|
// The SunDiscSunsetColor in the INI isn't exactly the resulting color on screen, most likely because
|
||||||
// MW applied the color to the ambient term as well. After the ambient and emissive terms are added together, the fixed pipeline
|
// MW applied the color to the ambient term as well. After the ambient and emissive terms are added together, the fixed pipeline
|
||||||
// would then clamp the total lighting to (1,1,1). A noticable change in color tone can be observed when only one of the color components gets clamped.
|
// would then clamp the total lighting to (1,1,1). A noticeable change in color tone can be observed when only one of the color components gets clamped.
|
||||||
// Unfortunately that means we can't use the INI color as is, have to replicate the above nonsense.
|
// Unfortunately that means we can't use the INI color as is, have to replicate the above nonsense.
|
||||||
mResult.mSunDiscColor = mResult.mSunDiscColor + osg::componentMultiply(mResult.mSunDiscColor, mResult.mAmbientColor);
|
mResult.mSunDiscColor = mResult.mSunDiscColor + osg::componentMultiply(mResult.mSunDiscColor, mResult.mAmbientColor);
|
||||||
for (int i=0; i<3; ++i)
|
for (int i=0; i<3; ++i)
|
||||||
|
|
|
@ -198,8 +198,8 @@ bool Wizard::IniSettings::parseInx(const QString &path)
|
||||||
const QString section(array.left(index));
|
const QString section(array.left(index));
|
||||||
|
|
||||||
// Figure how many characters to read for the key
|
// Figure how many characters to read for the key
|
||||||
int lenght = array.indexOf("\x06", section.length() + 3) - (section.length() + 3);
|
int length = array.indexOf("\x06", section.length() + 3) - (section.length() + 3);
|
||||||
const QString key(array.mid(section.length() + 3, lenght));
|
const QString key(array.mid(section.length() + 3, length));
|
||||||
|
|
||||||
QString value(array.mid(section.length() + key.length() + 6));
|
QString value(array.mid(section.length() + key.length() + 6));
|
||||||
|
|
||||||
|
|
|
@ -20,12 +20,6 @@ int main(int argc, char *argv[])
|
||||||
QDir dir(QCoreApplication::applicationDirPath());
|
QDir dir(QCoreApplication::applicationDirPath());
|
||||||
|
|
||||||
#ifdef Q_OS_MAC
|
#ifdef Q_OS_MAC
|
||||||
if (dir.dirName() == "MacOS") {
|
|
||||||
dir.cdUp();
|
|
||||||
dir.cdUp();
|
|
||||||
dir.cdUp();
|
|
||||||
}
|
|
||||||
|
|
||||||
// force Qt to load only LOCAL plugins, don't touch system Qt installation
|
// force Qt to load only LOCAL plugins, don't touch system Qt installation
|
||||||
QDir pluginsPath(QCoreApplication::applicationDirPath());
|
QDir pluginsPath(QCoreApplication::applicationDirPath());
|
||||||
pluginsPath.cdUp();
|
pluginsPath.cdUp();
|
||||||
|
|
|
@ -196,6 +196,7 @@ void ESM::CellRef::blank()
|
||||||
mFaction.clear();
|
mFaction.clear();
|
||||||
mFactionRank = -2;
|
mFactionRank = -2;
|
||||||
mChargeInt = -1;
|
mChargeInt = -1;
|
||||||
|
mChargeIntRemainder = 0.0f;
|
||||||
mEnchantmentCharge = -1;
|
mEnchantmentCharge = -1;
|
||||||
mGoldValue = 0;
|
mGoldValue = 0;
|
||||||
mDestCell.clear();
|
mDestCell.clear();
|
||||||
|
|
|
@ -69,6 +69,7 @@ namespace ESM
|
||||||
int mChargeInt; // Used by everything except lights
|
int mChargeInt; // Used by everything except lights
|
||||||
float mChargeFloat; // Used only by lights
|
float mChargeFloat; // Used only by lights
|
||||||
};
|
};
|
||||||
|
float mChargeIntRemainder; // Stores amount of charge not subtracted from mChargeInt
|
||||||
|
|
||||||
// Remaining enchantment charge. This could be -1 if the charge was not touched yet (i.e. full).
|
// Remaining enchantment charge. This could be -1 if the charge was not touched yet (i.e. full).
|
||||||
float mEnchantmentCharge;
|
float mEnchantmentCharge;
|
||||||
|
|
|
@ -68,7 +68,7 @@ boost::filesystem::path MacOsPath::getCachePath() const
|
||||||
|
|
||||||
boost::filesystem::path MacOsPath::getLocalPath() const
|
boost::filesystem::path MacOsPath::getLocalPath() const
|
||||||
{
|
{
|
||||||
return boost::filesystem::path("./");
|
return boost::filesystem::path("../Resources/");
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::filesystem::path MacOsPath::getGlobalDataPath() const
|
boost::filesystem::path MacOsPath::getGlobalDataPath() const
|
||||||
|
|
|
@ -87,6 +87,15 @@ namespace Nif
|
||||||
nif->skip(17);
|
nif->skip(17);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NiSphericalCollider::read(NIFStream* nif)
|
||||||
|
{
|
||||||
|
Controlled::read(nif);
|
||||||
|
|
||||||
|
mBounceFactor = nif->getFloat();
|
||||||
|
mRadius = nif->getFloat();
|
||||||
|
mCenter = nif->getVector3();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -111,6 +111,16 @@ public:
|
||||||
float mPlaneDistance;
|
float mPlaneDistance;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class NiSphericalCollider : public Controlled
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
float mBounceFactor;
|
||||||
|
float mRadius;
|
||||||
|
osg::Vec3f mCenter;
|
||||||
|
|
||||||
|
void read(NIFStream *nif);
|
||||||
|
};
|
||||||
|
|
||||||
class NiParticleRotation : public Controlled
|
class NiParticleRotation : public Controlled
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -89,6 +89,7 @@ static std::map<std::string,RecordFactoryEntry> makeFactory()
|
||||||
newFactory.insert(makeEntry("NiStringExtraData", &construct <NiStringExtraData> , RC_NiStringExtraData ));
|
newFactory.insert(makeEntry("NiStringExtraData", &construct <NiStringExtraData> , RC_NiStringExtraData ));
|
||||||
newFactory.insert(makeEntry("NiGravity", &construct <NiGravity> , RC_NiGravity ));
|
newFactory.insert(makeEntry("NiGravity", &construct <NiGravity> , RC_NiGravity ));
|
||||||
newFactory.insert(makeEntry("NiPlanarCollider", &construct <NiPlanarCollider> , RC_NiPlanarCollider ));
|
newFactory.insert(makeEntry("NiPlanarCollider", &construct <NiPlanarCollider> , RC_NiPlanarCollider ));
|
||||||
|
newFactory.insert(makeEntry("NiSphericalCollider", &construct <NiSphericalCollider> , RC_NiSphericalCollider ));
|
||||||
newFactory.insert(makeEntry("NiParticleGrowFade", &construct <NiParticleGrowFade> , RC_NiParticleGrowFade ));
|
newFactory.insert(makeEntry("NiParticleGrowFade", &construct <NiParticleGrowFade> , RC_NiParticleGrowFade ));
|
||||||
newFactory.insert(makeEntry("NiParticleColorModifier", &construct <NiParticleColorModifier> , RC_NiParticleColorModifier ));
|
newFactory.insert(makeEntry("NiParticleColorModifier", &construct <NiParticleColorModifier> , RC_NiParticleColorModifier ));
|
||||||
newFactory.insert(makeEntry("NiParticleRotation", &construct <NiParticleRotation> , RC_NiParticleRotation ));
|
newFactory.insert(makeEntry("NiParticleRotation", &construct <NiParticleRotation> , RC_NiParticleRotation ));
|
||||||
|
|
|
@ -92,7 +92,8 @@ enum RecordType
|
||||||
RC_NiSequenceStreamHelper,
|
RC_NiSequenceStreamHelper,
|
||||||
RC_NiSourceTexture,
|
RC_NiSourceTexture,
|
||||||
RC_NiSkinInstance,
|
RC_NiSkinInstance,
|
||||||
RC_RootCollisionNode
|
RC_RootCollisionNode,
|
||||||
|
RC_NiSphericalCollider
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Base class for all records
|
/// Base class for all records
|
||||||
|
|
|
@ -871,6 +871,13 @@ namespace NifOsg
|
||||||
const Nif::NiPlanarCollider* planarcollider = static_cast<const Nif::NiPlanarCollider*>(colliders.getPtr());
|
const Nif::NiPlanarCollider* planarcollider = static_cast<const Nif::NiPlanarCollider*>(colliders.getPtr());
|
||||||
program->addOperator(new PlanarCollider(planarcollider));
|
program->addOperator(new PlanarCollider(planarcollider));
|
||||||
}
|
}
|
||||||
|
else if (colliders->recType == Nif::RC_NiSphericalCollider)
|
||||||
|
{
|
||||||
|
const Nif::NiSphericalCollider* sphericalcollider = static_cast<const Nif::NiSphericalCollider*>(colliders.getPtr());
|
||||||
|
program->addOperator(new SphericalCollider(sphericalcollider));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
std::cerr << "Unhandled particle collider " << colliders->recName << " in " << mFilename << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -376,4 +376,73 @@ void PlanarCollider::operate(osgParticle::Particle *particle, double dt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SphericalCollider::SphericalCollider(const Nif::NiSphericalCollider* collider)
|
||||||
|
: mBounceFactor(collider->mBounceFactor),
|
||||||
|
mSphere(collider->mCenter, collider->mRadius)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SphericalCollider::SphericalCollider()
|
||||||
|
: mBounceFactor(1.0f)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
SphericalCollider::SphericalCollider(const SphericalCollider& copy, const osg::CopyOp& copyop)
|
||||||
|
: osgParticle::Operator(copy, copyop)
|
||||||
|
, mBounceFactor(copy.mBounceFactor)
|
||||||
|
, mSphere(copy.mSphere)
|
||||||
|
, mSphereInParticleSpace(copy.mSphereInParticleSpace)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SphericalCollider::beginOperate(osgParticle::Program* program)
|
||||||
|
{
|
||||||
|
mSphereInParticleSpace = mSphere;
|
||||||
|
if (program->getReferenceFrame() == osgParticle::ParticleProcessor::ABSOLUTE_RF)
|
||||||
|
mSphereInParticleSpace.center() = program->transformLocalToWorld(mSphereInParticleSpace.center());
|
||||||
|
}
|
||||||
|
|
||||||
|
void SphericalCollider::operate(osgParticle::Particle* particle, double dt)
|
||||||
|
{
|
||||||
|
osg::Vec3f cent = (particle->getPosition() - mSphereInParticleSpace.center()); // vector from sphere center to particle
|
||||||
|
|
||||||
|
bool insideSphere = cent.length2() <= mSphereInParticleSpace.radius2();
|
||||||
|
|
||||||
|
if (insideSphere
|
||||||
|
|| (cent * particle->getVelocity() < 0.0f)) // if outside, make sure the particle is flying towards the sphere
|
||||||
|
{
|
||||||
|
// Collision test (finding point of contact) is performed by solving a quadratic equation:
|
||||||
|
// ||vec(cent) + vec(vel)*k|| = R /^2
|
||||||
|
// k^2 + 2*k*(vec(cent)*vec(vel))/||vec(vel)||^2 + (||vec(cent)||^2 - R^2)/||vec(vel)||^2 = 0
|
||||||
|
|
||||||
|
float b = -(cent * particle->getVelocity()) / particle->getVelocity().length2();
|
||||||
|
|
||||||
|
osg::Vec3f u = cent + particle->getVelocity() * b;
|
||||||
|
|
||||||
|
if (insideSphere
|
||||||
|
|| (u.length2() < mSphereInParticleSpace.radius2()))
|
||||||
|
{
|
||||||
|
float d = (mSphereInParticleSpace.radius2() - u.length2()) / particle->getVelocity().length2();
|
||||||
|
float k = insideSphere ? (std::sqrt(d) + b) : (b - std::sqrt(d));
|
||||||
|
|
||||||
|
if (k < dt)
|
||||||
|
{
|
||||||
|
// collision detected; reflect off the tangent plane
|
||||||
|
osg::Vec3f contact = particle->getPosition() + particle->getVelocity() * k;
|
||||||
|
|
||||||
|
osg::Vec3 normal = (contact - mSphereInParticleSpace.center());
|
||||||
|
normal.normalize();
|
||||||
|
|
||||||
|
float dotproduct = particle->getVelocity() * normal;
|
||||||
|
|
||||||
|
osg::Vec3 reflectedVelocity = particle->getVelocity() - normal * (2 * dotproduct);
|
||||||
|
reflectedVelocity *= mBounceFactor;
|
||||||
|
particle->setVelocity(reflectedVelocity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ namespace Nif
|
||||||
{
|
{
|
||||||
class NiGravity;
|
class NiGravity;
|
||||||
class NiPlanarCollider;
|
class NiPlanarCollider;
|
||||||
|
class NiSphericalCollider;
|
||||||
class NiColorData;
|
class NiColorData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,6 +111,23 @@ namespace NifOsg
|
||||||
osg::Plane mPlaneInParticleSpace;
|
osg::Plane mPlaneInParticleSpace;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class SphericalCollider : public osgParticle::Operator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SphericalCollider(const Nif::NiSphericalCollider* collider);
|
||||||
|
SphericalCollider();
|
||||||
|
SphericalCollider(const SphericalCollider& copy, const osg::CopyOp& copyop);
|
||||||
|
|
||||||
|
META_Object(NifOsg, SphericalCollider)
|
||||||
|
|
||||||
|
virtual void beginOperate(osgParticle::Program* program);
|
||||||
|
virtual void operate(osgParticle::Particle* particle, double dt);
|
||||||
|
private:
|
||||||
|
float mBounceFactor;
|
||||||
|
osg::BoundingSphere mSphere;
|
||||||
|
osg::BoundingSphere mSphereInParticleSpace;
|
||||||
|
};
|
||||||
|
|
||||||
class GrowFadeAffector : public osgParticle::Operator
|
class GrowFadeAffector : public osgParticle::Operator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -120,13 +120,17 @@ void RigGeometry::setSourceGeometry(osg::ref_ptr<osg::Geometry> sourceGeometry)
|
||||||
setVertexArray(vertexArray);
|
setVertexArray(vertexArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::ref_ptr<osg::Array> normalArray = osg::clone(from.getNormalArray(), osg::CopyOp::DEEP_COPY_ALL);
|
if (osg::Array* normals = from.getNormalArray())
|
||||||
if (normalArray)
|
|
||||||
{
|
{
|
||||||
normalArray->setVertexBufferObject(vbo);
|
osg::ref_ptr<osg::Array> normalArray = osg::clone(normals, osg::CopyOp::DEEP_COPY_ALL);
|
||||||
setNormalArray(normalArray, osg::Array::BIND_PER_VERTEX);
|
if (normalArray)
|
||||||
|
{
|
||||||
|
normalArray->setVertexBufferObject(vbo);
|
||||||
|
setNormalArray(normalArray, osg::Array::BIND_PER_VERTEX);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (osg::Vec4Array* tangents = dynamic_cast<osg::Vec4Array*>(from.getTexCoordArray(7)))
|
if (osg::Vec4Array* tangents = dynamic_cast<osg::Vec4Array*>(from.getTexCoordArray(7)))
|
||||||
{
|
{
|
||||||
mSourceTangents = tangents;
|
mSourceTangents = tangents;
|
||||||
|
@ -273,7 +277,8 @@ void RigGeometry::update(osg::NodeVisitor* nv)
|
||||||
{
|
{
|
||||||
unsigned short vertex = *vertexIt;
|
unsigned short vertex = *vertexIt;
|
||||||
(*positionDst)[vertex] = resultMat.preMult((*positionSrc)[vertex]);
|
(*positionDst)[vertex] = resultMat.preMult((*positionSrc)[vertex]);
|
||||||
(*normalDst)[vertex] = osg::Matrix::transform3x3((*normalSrc)[vertex], resultMat);
|
if (normalDst)
|
||||||
|
(*normalDst)[vertex] = osg::Matrix::transform3x3((*normalSrc)[vertex], resultMat);
|
||||||
if (tangentDst)
|
if (tangentDst)
|
||||||
{
|
{
|
||||||
osg::Vec4f srcTangent = (*tangentSrc)[vertex];
|
osg::Vec4f srcTangent = (*tangentSrc)[vertex];
|
||||||
|
@ -284,7 +289,8 @@ void RigGeometry::update(osg::NodeVisitor* nv)
|
||||||
}
|
}
|
||||||
|
|
||||||
positionDst->dirty();
|
positionDst->dirty();
|
||||||
normalDst->dirty();
|
if (normalDst)
|
||||||
|
normalDst->dirty();
|
||||||
if (tangentDst)
|
if (tangentDst)
|
||||||
tangentDst->dirty();
|
tangentDst->dirty();
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,6 +102,8 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr<osgViewer::Viewer> v
|
||||||
if (evt.key.keysym.sym == SDLK_F3)
|
if (evt.key.keysym.sym == SDLK_F3)
|
||||||
mViewer->getEventQueue()->keyRelease(osgGA::GUIEventAdapter::KEY_F3);
|
mViewer->getEventQueue()->keyRelease(osgGA::GUIEventAdapter::KEY_F3);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case SDL_TEXTEDITING:
|
||||||
break;
|
break;
|
||||||
case SDL_TEXTINPUT:
|
case SDL_TEXTINPUT:
|
||||||
mKeyboardListener->textInput(evt.text);
|
mKeyboardListener->textInput(evt.text);
|
||||||
|
|
|
@ -3,9 +3,9 @@ A Tour through OpenMW CS: making a magic ring
|
||||||
|
|
||||||
In this first chapter we will create a mod that adds a new ring with a simple
|
In this first chapter we will create a mod that adds a new ring with a simple
|
||||||
enchantment to the game. The ring will give its wearer a permanent Night Vision
|
enchantment to the game. The ring will give its wearer a permanent Night Vision
|
||||||
effect while being worn. You don't need prior knowledge about modding
|
effect while being worn. You do not need previous Morrowind modding experience,
|
||||||
Morrowind, but you should be familiar with the game itself. There will be no
|
but you should be familiar with the game itself. There will be no
|
||||||
scripting necessary, we chan achieve everything using just what the base game
|
scripting necessary, we can achieve everything using just what the base game
|
||||||
offers out of the box. Before continuing make sure that OpenMW is properly
|
offers out of the box. Before continuing make sure that OpenMW is properly
|
||||||
installed and playable.
|
installed and playable.
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ installed and playable.
|
||||||
Adding the ring to the game's records
|
Adding the ring to the game's records
|
||||||
*************************************
|
*************************************
|
||||||
|
|
||||||
In this first section we will define what our new ring is, what it looks like
|
In this first section we will define what our new ring is, what it looks like,
|
||||||
and what it does. Getting it to work is the first step before we go further.
|
and what it does. Getting it to work is the first step before we go further.
|
||||||
|
|
||||||
|
|
||||||
|
@ -28,11 +28,11 @@ options: create a new game, create a new addon, edit a content file.
|
||||||
:alt: Opening dialogue with three option and setting button (the wrench)
|
:alt: Opening dialogue with three option and setting button (the wrench)
|
||||||
|
|
||||||
The first option is for creating an entirely new game, that's not what we want.
|
The first option is for creating an entirely new game, that's not what we want.
|
||||||
We want to edit an existing game, so choose the second one. When you save your
|
We want to edit an existing game, so choose the second option. When you save your
|
||||||
addon you can use the third option to open it again.
|
addon you can use the third option to open it again.
|
||||||
|
|
||||||
You will be presented with another window where you get to chose the content to
|
You will be presented with another window where you get to choose the content to
|
||||||
edit and the name of your project. We have to chose at least a base game, and
|
edit and the name of your project. Then we have to select at least the base game and
|
||||||
optionally a number of other addons we want to depend on. The name of the
|
optionally a number of other addons we want to depend on. The name of the
|
||||||
project is arbitrary, it will be used to identify the addon later in the OpenMW
|
project is arbitrary, it will be used to identify the addon later in the OpenMW
|
||||||
launcher.
|
launcher.
|
||||||
|
@ -41,7 +41,7 @@ launcher.
|
||||||
:alt: Creation dialogue for a new project, pick content modules and name
|
:alt: Creation dialogue for a new project, pick content modules and name
|
||||||
|
|
||||||
Choose Morrowind as your content file and enter `Ring of Night Vision` as the
|
Choose Morrowind as your content file and enter `Ring of Night Vision` as the
|
||||||
name. We could also chose further content files as dependencies if we wanted
|
name. We could also choose further content files as dependencies if we wanted
|
||||||
to, but for this mod the base game is enough.
|
to, but for this mod the base game is enough.
|
||||||
|
|
||||||
Once the addon has been created you will be presented with a table. If you see
|
Once the addon has been created you will be presented with a table. If you see
|
||||||
|
@ -67,7 +67,7 @@ of the table are the attributes of each object.
|
||||||
Morrowind uses something called a *relational database* for game data. If you
|
Morrowind uses something called a *relational database* for game data. If you
|
||||||
are not familiar with the term, it means that every type of thing can be
|
are not familiar with the term, it means that every type of thing can be
|
||||||
expressed as a *table*: there is a table for objects, a table for enchantments,
|
expressed as a *table*: there is a table for objects, a table for enchantments,
|
||||||
a table for icons, one for meshes, and so on. Properties of an entry must be
|
a table for icons, one for meshes and so on. Properties of an entry must be
|
||||||
simple values, like numbers or text strings. If we want a more complicated
|
simple values, like numbers or text strings. If we want a more complicated
|
||||||
property we need to reference an entry from another table. There are a few
|
property we need to reference an entry from another table. There are a few
|
||||||
exceptions to this though, some tables do have subtables. The effects of
|
exceptions to this though, some tables do have subtables. The effects of
|
||||||
|
@ -95,7 +95,7 @@ holding Shift to edit it (this is a configurable shortcut), but there is a
|
||||||
better way: right-click the row of our new record and chose *Edit Record*, a
|
better way: right-click the row of our new record and chose *Edit Record*, a
|
||||||
new panel will open.
|
new panel will open.
|
||||||
|
|
||||||
We can right-click the row of our new record and chose *Edit Record*, a
|
We can right-click the row of our new record and select *Edit Record*, a
|
||||||
new panel will open. Alternatively we can also define a configurable shortcut
|
new panel will open. Alternatively we can also define a configurable shortcut
|
||||||
instead of using the context menu; the default is double-clicking while
|
instead of using the context menu; the default is double-clicking while
|
||||||
holding down the shift key.
|
holding down the shift key.
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
|
if (NOT DEFINED OPENMW_MYGUI_FILES_ROOT)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
# Copy resource files into the build directory
|
# Copy resource files into the build directory
|
||||||
set(SDIR ${CMAKE_CURRENT_SOURCE_DIR})
|
set(SDIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
set(DDIR ${OpenMW_BINARY_DIR}/resources/mygui)
|
set(DDIR ${OPENMW_MYGUI_FILES_ROOT}/resources/mygui)
|
||||||
|
|
||||||
set(MYGUI_FILES
|
set(MYGUI_FILES
|
||||||
core.skin
|
core.skin
|
||||||
|
|
|
@ -188,13 +188,13 @@ clamp lighting = true
|
||||||
|
|
||||||
# If this option is enabled, normal maps are automatically recognized and used if they are named appropriately
|
# If this option is enabled, normal maps are automatically recognized and used if they are named appropriately
|
||||||
# (see 'normal map pattern', e.g. for a base texture foo.dds, the normal map texture would have to be named foo_n.dds).
|
# (see 'normal map pattern', e.g. for a base texture foo.dds, the normal map texture would have to be named foo_n.dds).
|
||||||
# If this option is disabled, normal maps are only used if they are explicitely listed within the mesh file (.nif or .osg file).
|
# If this option is disabled, normal maps are only used if they are explicitly listed within the mesh file (.nif or .osg file).
|
||||||
# Affects objects.
|
# Affects objects.
|
||||||
auto use object normal maps = false
|
auto use object normal maps = false
|
||||||
|
|
||||||
# If this option is enabled, specular maps are automatically recognized and used if they are named appropriately
|
# If this option is enabled, specular maps are automatically recognized and used if they are named appropriately
|
||||||
# (see 'specular map pattern', e.g. for a base texture foo.dds, the specular map texture would have to be named foo_spec.dds).
|
# (see 'specular map pattern', e.g. for a base texture foo.dds, the specular map texture would have to be named foo_spec.dds).
|
||||||
# If this option is disabled, normal maps are only used if they are explicitely listed within the mesh file (.osg file, not supported in .nif files).
|
# If this option is disabled, normal maps are only used if they are explicitly listed within the mesh file (.osg file, not supported in .nif files).
|
||||||
# Affects objects.
|
# Affects objects.
|
||||||
auto use object specular maps = false
|
auto use object specular maps = false
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
|
if (NOT DEFINED OPENMW_SHADERS_ROOT)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
# Copy resource files into the build directory
|
# Copy resource files into the build directory
|
||||||
set(SDIR ${CMAKE_CURRENT_SOURCE_DIR})
|
set(SDIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
set(DDIR ${OpenMW_BINARY_DIR}/resources/shaders)
|
set(DDIR ${OPENMW_SHADERS_ROOT}/resources/shaders)
|
||||||
|
|
||||||
set(SHADER_FILES
|
set(SHADER_FILES
|
||||||
water_vertex.glsl
|
water_vertex.glsl
|
||||||
|
|
Loading…
Reference in a new issue