mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-03-01 18:19:39 +00:00
Add OpenMW commits up to 2 Dec 2018
# Conflicts: # .travis.yml # README.md
This commit is contained in:
commit
68886e7539
23 changed files with 131 additions and 106 deletions
|
@ -16,18 +16,18 @@ addons:
|
||||||
- sourceline: 'ppa:openmw/openmw'
|
- sourceline: 'ppa:openmw/openmw'
|
||||||
- sourceline: 'ppa:rakhimov/boost'
|
- sourceline: 'ppa:rakhimov/boost'
|
||||||
- ubuntu-toolchain-r-test
|
- ubuntu-toolchain-r-test
|
||||||
- llvm-toolchain-trusty-7
|
- llvm-toolchain-xenial-7
|
||||||
packages: [
|
packages: [
|
||||||
# Dev
|
# Dev
|
||||||
cmake, clang-7, clang-tools-7, gcc-8, g++-8,
|
cmake, clang-7, clang-tools-7, gcc-8, g++-8,
|
||||||
# Boost
|
# Boost
|
||||||
libboost-filesystem-dev, libboost-program-options-dev, libboost-system-dev,
|
libboost-filesystem-dev, libboost-program-options-dev, libboost-system-dev,
|
||||||
# FFmpeg
|
# FFmpeg
|
||||||
libavcodec-dev, libavformat-dev, libavutil-dev, libswscale-dev,
|
libavcodec-dev, libavformat-dev, libavutil-dev, libswresample-dev, libswscale-dev,
|
||||||
# Audio, Video and Misc. deps
|
# Audio, Video and Misc. deps
|
||||||
libsdl2-dev, libqt4-dev, libopenal-dev, libunshield-dev, libtinyxml-dev,
|
libsdl2-dev, libqt5opengl5-dev, libopenal-dev, libunshield-dev, libtinyxml-dev,
|
||||||
# The other ones from OpenMW ppa
|
# The other ones from OpenMW ppa
|
||||||
libbullet-dev, libswresample-dev, libopenscenegraph-3.4-dev, libmygui-dev,
|
libbullet-dev, libopenscenegraph-3.4-dev, libmygui-dev,
|
||||||
# tes3mp stuff
|
# tes3mp stuff
|
||||||
libboost-dev, libqt5opengl5-dev, libluajit-5.1-dev
|
libboost-dev, libqt5opengl5-dev, libluajit-5.1-dev
|
||||||
]
|
]
|
||||||
|
|
|
@ -4,6 +4,10 @@
|
||||||
Bug #3623: Fix HiDPI on Windows
|
Bug #3623: Fix HiDPI on Windows
|
||||||
Bug #4540: Rain delay when exiting water
|
Bug #4540: Rain delay when exiting water
|
||||||
Bug #4701: PrisonMarker record is not hardcoded like other markers
|
Bug #4701: PrisonMarker record is not hardcoded like other markers
|
||||||
|
Bug #4714: Crash upon game load in the repair menu while the "Your repair failed!" message is active
|
||||||
|
Bug #4715: "Cannot get class of an empty object" exception after pressing ESC in the dialogue mode
|
||||||
|
Bug #4720: Inventory avatar has shield with two-handed weapon during [un]equipping animation
|
||||||
|
Bug #4723: ResetActors command works incorrectly
|
||||||
Feature #2229: Improve pathfinding AI
|
Feature #2229: Improve pathfinding AI
|
||||||
Feature #3442: Default values for fallbacks from ini file
|
Feature #3442: Default values for fallbacks from ini file
|
||||||
Feature #4673: Weapon sheathing
|
Feature #4673: Weapon sheathing
|
||||||
|
|
|
@ -36,8 +36,9 @@ ${ANALYZE} cmake \
|
||||||
-DBUILD_BROWSER=ON \
|
-DBUILD_BROWSER=ON \
|
||||||
-DBUILD_MASTER=ON \
|
-DBUILD_MASTER=ON \
|
||||||
-DBUILD_WITH_CODE_COVERAGE=${CODE_COVERAGE} \
|
-DBUILD_WITH_CODE_COVERAGE=${CODE_COVERAGE} \
|
||||||
-DDESIRED_QT_VERSION=5 \
|
|
||||||
-DBUILD_UNITTESTS=1 \
|
-DBUILD_UNITTESTS=1 \
|
||||||
|
-DUSE_SYSTEM_TINYXML=1 \
|
||||||
|
-DDESIRED_QT_VERSION=5 \
|
||||||
-DCMAKE_INSTALL_PREFIX=/usr \
|
-DCMAKE_INSTALL_PREFIX=/usr \
|
||||||
-DBINDIR=/usr/games \
|
-DBINDIR=/usr/games \
|
||||||
-DCMAKE_BUILD_TYPE="None" \
|
-DCMAKE_BUILD_TYPE="None" \
|
||||||
|
|
|
@ -57,7 +57,7 @@ endif()
|
||||||
message(STATUS "Configuring OpenMW...")
|
message(STATUS "Configuring OpenMW...")
|
||||||
|
|
||||||
set(OPENMW_VERSION_MAJOR 0)
|
set(OPENMW_VERSION_MAJOR 0)
|
||||||
set(OPENMW_VERSION_MINOR 44)
|
set(OPENMW_VERSION_MINOR 46)
|
||||||
set(OPENMW_VERSION_RELEASE 0)
|
set(OPENMW_VERSION_RELEASE 0)
|
||||||
|
|
||||||
set(OPENMW_VERSION_COMMITHASH "")
|
set(OPENMW_VERSION_COMMITHASH "")
|
||||||
|
|
|
@ -9,7 +9,7 @@ Copyright (c) 2016-2019, Stanislav Zhukov & David Cernat
|
||||||
TES3MP is a project adding multiplayer functionality to [OpenMW](https://github.com/OpenMW/openmw), an open-source game engine that supports playing "The Elder Scrolls III: Morrowind" by Bethesda Softworks.
|
TES3MP is a project adding multiplayer functionality to [OpenMW](https://github.com/OpenMW/openmw), an open-source game engine that supports playing "The Elder Scrolls III: Morrowind" by Bethesda Softworks.
|
||||||
|
|
||||||
* TES3MP version: 0.7.1
|
* TES3MP version: 0.7.1
|
||||||
* OpenMW version: 0.44.0
|
* OpenMW version: 0.46.0
|
||||||
* License: GPLv3 (see [LICENSE](https://github.com/TES3MP/openmw-tes3mp/blob/master/LICENSE) for more information)
|
* License: GPLv3 (see [LICENSE](https://github.com/TES3MP/openmw-tes3mp/blob/master/LICENSE) for more information)
|
||||||
|
|
||||||
Font Licenses:
|
Font Licenses:
|
||||||
|
|
|
@ -123,14 +123,9 @@ bool parseOptions (int argc, char** argv, Arguments &info)
|
||||||
|
|
||||||
bpo::store(valid_opts, variables);
|
bpo::store(valid_opts, variables);
|
||||||
}
|
}
|
||||||
catch(boost::program_options::unknown_option & x)
|
catch(std::exception &e)
|
||||||
{
|
{
|
||||||
std::cerr << "ERROR: " << x.what() << std::endl;
|
std::cout << "ERROR parsing arguments: " << e.what() << std::endl;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
catch(boost::program_options::invalid_command_line_syntax & x)
|
|
||||||
{
|
|
||||||
std::cerr << "ERROR: " << x.what() << std::endl;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
#include <components/vfs/bsaarchive.hpp>
|
#include <components/vfs/bsaarchive.hpp>
|
||||||
#include <components/vfs/filesystemarchive.hpp>
|
#include <components/vfs/filesystemarchive.hpp>
|
||||||
|
|
||||||
#include <boost/exception/all.hpp>
|
|
||||||
#include <boost/program_options.hpp>
|
#include <boost/program_options.hpp>
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
|
@ -81,7 +80,7 @@ void readVFS(VFS::Archive* anArchive,std::string archivePath = "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> parseOptions (int argc, char** argv)
|
bool parseOptions (int argc, char** argv, std::vector<std::string>& files)
|
||||||
{
|
{
|
||||||
bpo::options_description desc("Ensure that OpenMW can use the provided NIF and BSA files\n\n"
|
bpo::options_description desc("Ensure that OpenMW can use the provided NIF and BSA files\n\n"
|
||||||
"Usages:\n"
|
"Usages:\n"
|
||||||
|
@ -108,37 +107,31 @@ std::vector<std::string> parseOptions (int argc, char** argv)
|
||||||
{
|
{
|
||||||
std::cout << "ERROR parsing arguments: " << e.what() << "\n\n"
|
std::cout << "ERROR parsing arguments: " << e.what() << "\n\n"
|
||||||
<< desc << std::endl;
|
<< desc << std::endl;
|
||||||
exit(1);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bpo::notify(variables);
|
bpo::notify(variables);
|
||||||
if (variables.count ("help"))
|
if (variables.count ("help"))
|
||||||
{
|
{
|
||||||
std::cout << desc << std::endl;
|
std::cout << desc << std::endl;
|
||||||
exit(1);
|
return false;
|
||||||
}
|
}
|
||||||
if (variables.count("input-file"))
|
if (variables.count("input-file"))
|
||||||
{
|
{
|
||||||
return variables["input-file"].as< std::vector<std::string> >();
|
files = variables["input-file"].as< std::vector<std::string> >();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "No input files or directories specified!" << std::endl;
|
std::cout << "No input files or directories specified!" << std::endl;
|
||||||
std::cout << desc << std::endl;
|
std::cout << desc << std::endl;
|
||||||
exit(1);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
std::vector<std::string> files;
|
std::vector<std::string> files;
|
||||||
try
|
if(!parseOptions (argc, argv, files))
|
||||||
{
|
return 1;
|
||||||
files = parseOptions (argc, argv);
|
|
||||||
}
|
|
||||||
catch( boost::exception &e )
|
|
||||||
{
|
|
||||||
std::cout << "ERROR parsing arguments: " << boost::diagnostic_information(e) << std::endl;
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// std::cout << "Reading Files" << std::endl;
|
// std::cout << "Reading Files" << std::endl;
|
||||||
for(std::vector<std::string>::const_iterator it=files.begin(); it!=files.end(); ++it)
|
for(std::vector<std::string>::const_iterator it=files.begin(); it!=files.end(); ++it)
|
||||||
|
|
|
@ -198,12 +198,7 @@ CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelI
|
||||||
|
|
||||||
if (mIndex.parent().isValid())
|
if (mIndex.parent().isValid())
|
||||||
{
|
{
|
||||||
CSMWorld::IdTree* tree = dynamic_cast<CSMWorld::IdTree*>(mModel);
|
CSMWorld::IdTree* tree = &dynamic_cast<CSMWorld::IdTree&>(*mModel);
|
||||||
if (tree == nullptr)
|
|
||||||
{
|
|
||||||
throw std::logic_error("CSMWorld::ModifyCommand: Attempt to add nested values to the non-nested model");
|
|
||||||
}
|
|
||||||
|
|
||||||
setText ("Modify " + tree->nestedHeaderData (
|
setText ("Modify " + tree->nestedHeaderData (
|
||||||
mIndex.parent().column(), mIndex.column(), Qt::Horizontal, Qt::DisplayRole).toString());
|
mIndex.parent().column(), mIndex.column(), Qt::Horizontal, Qt::DisplayRole).toString());
|
||||||
}
|
}
|
||||||
|
@ -249,12 +244,7 @@ void CSMWorld::CreateCommand::applyModifications()
|
||||||
{
|
{
|
||||||
if (!mNestedValues.empty())
|
if (!mNestedValues.empty())
|
||||||
{
|
{
|
||||||
CSMWorld::IdTree *tree = dynamic_cast<CSMWorld::IdTree *>(&mModel);
|
CSMWorld::IdTree* tree = &dynamic_cast<CSMWorld::IdTree&>(mModel);
|
||||||
if (tree == nullptr)
|
|
||||||
{
|
|
||||||
throw std::logic_error("CSMWorld::CreateCommand: Attempt to add nested values to the non-nested model");
|
|
||||||
}
|
|
||||||
|
|
||||||
std::map<int, std::pair<int, QVariant> >::const_iterator current = mNestedValues.begin();
|
std::map<int, std::pair<int, QVariant> >::const_iterator current = mNestedValues.begin();
|
||||||
std::map<int, std::pair<int, QVariant> >::const_iterator end = mNestedValues.end();
|
std::map<int, std::pair<int, QVariant> >::const_iterator end = mNestedValues.end();
|
||||||
for (; current != end; ++current)
|
for (; current != end; ++current)
|
||||||
|
|
|
@ -224,11 +224,7 @@ namespace CSVRender
|
||||||
|
|
||||||
void Pathgrid::applyPoint(CSMWorld::CommandMacro& commands, const osg::Vec3d& worldPos)
|
void Pathgrid::applyPoint(CSMWorld::CommandMacro& commands, const osg::Vec3d& worldPos)
|
||||||
{
|
{
|
||||||
CSMWorld::IdTree* model = dynamic_cast<CSMWorld::IdTree*>(mData.getTableModel(CSMWorld::UniversalId::Type_Pathgrids));
|
CSMWorld::IdTree* model = &dynamic_cast<CSMWorld::IdTree&>(*mData.getTableModel(CSMWorld::UniversalId::Type_Pathgrids));
|
||||||
if (model == nullptr)
|
|
||||||
{
|
|
||||||
throw std::logic_error("CSVRender::Pathgrid: Attempt to add nested values to the non-nested model");
|
|
||||||
}
|
|
||||||
|
|
||||||
const CSMWorld::Pathgrid* source = getPathgridSource();
|
const CSMWorld::Pathgrid* source = getPathgridSource();
|
||||||
if (source)
|
if (source)
|
||||||
|
@ -360,11 +356,7 @@ namespace CSVRender
|
||||||
const CSMWorld::Pathgrid* source = getPathgridSource();
|
const CSMWorld::Pathgrid* source = getPathgridSource();
|
||||||
if (source)
|
if (source)
|
||||||
{
|
{
|
||||||
CSMWorld::IdTree* model = dynamic_cast<CSMWorld::IdTree*>(mData.getTableModel(CSMWorld::UniversalId::Type_Pathgrids));
|
CSMWorld::IdTree* model = &dynamic_cast<CSMWorld::IdTree&>(*mData.getTableModel(CSMWorld::UniversalId::Type_Pathgrids));
|
||||||
if (model == nullptr)
|
|
||||||
{
|
|
||||||
throw std::logic_error("CSVRender::Pathgrid: Attempt to add nested values to the non-nested model");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Want to remove nodes from end of list first
|
// Want to remove nodes from end of list first
|
||||||
std::sort(mSelected.begin(), mSelected.end(), std::greater<int>());
|
std::sort(mSelected.begin(), mSelected.end(), std::greater<int>());
|
||||||
|
@ -464,12 +456,7 @@ namespace CSVRender
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMWorld::IdTree* model = dynamic_cast<CSMWorld::IdTree*>(mData.getTableModel(CSMWorld::UniversalId::Type_Pathgrids));
|
CSMWorld::IdTree* model = &dynamic_cast<CSMWorld::IdTree&>(*mData.getTableModel(CSMWorld::UniversalId::Type_Pathgrids));
|
||||||
if (model == nullptr)
|
|
||||||
{
|
|
||||||
throw std::logic_error("CSVRender::Pathgrid: Attempt to add nested values to the non-nested model");
|
|
||||||
}
|
|
||||||
|
|
||||||
int parentColumn = mPathgridCollection.findColumnIndex(CSMWorld::Columns::ColumnId_PathgridEdges);
|
int parentColumn = mPathgridCollection.findColumnIndex(CSMWorld::Columns::ColumnId_PathgridEdges);
|
||||||
|
|
||||||
std::set<int, std::greater<int> >::iterator row;
|
std::set<int, std::greater<int> >::iterator row;
|
||||||
|
@ -642,11 +629,7 @@ namespace CSVRender
|
||||||
void Pathgrid::addEdge(CSMWorld::CommandMacro& commands, const CSMWorld::Pathgrid& source, unsigned short node1,
|
void Pathgrid::addEdge(CSMWorld::CommandMacro& commands, const CSMWorld::Pathgrid& source, unsigned short node1,
|
||||||
unsigned short node2)
|
unsigned short node2)
|
||||||
{
|
{
|
||||||
CSMWorld::IdTree* model = dynamic_cast<CSMWorld::IdTree*>(mData.getTableModel(CSMWorld::UniversalId::Type_Pathgrids));
|
CSMWorld::IdTree* model = &dynamic_cast<CSMWorld::IdTree&>(*mData.getTableModel(CSMWorld::UniversalId::Type_Pathgrids));
|
||||||
if (model == nullptr)
|
|
||||||
{
|
|
||||||
throw std::logic_error("CSVRender::Pathgrid: Attempt to add nested values to the non-nested model");
|
|
||||||
}
|
|
||||||
|
|
||||||
int recordIndex = mPathgridCollection.getIndex(mId);
|
int recordIndex = mPathgridCollection.getIndex(mId);
|
||||||
int parentColumn = mPathgridCollection.findColumnIndex(CSMWorld::Columns::ColumnId_PathgridEdges);
|
int parentColumn = mPathgridCollection.findColumnIndex(CSMWorld::Columns::ColumnId_PathgridEdges);
|
||||||
|
|
|
@ -24,11 +24,7 @@ std::string CSVWorld::CellCreator::getId() const
|
||||||
|
|
||||||
void CSVWorld::CellCreator::configureCreateCommand(CSMWorld::CreateCommand& command) const
|
void CSVWorld::CellCreator::configureCreateCommand(CSMWorld::CreateCommand& command) const
|
||||||
{
|
{
|
||||||
CSMWorld::IdTree *model = dynamic_cast<CSMWorld::IdTree *>(getData().getTableModel(getCollectionId()));
|
CSMWorld::IdTree* model = &dynamic_cast<CSMWorld::IdTree&>(*getData().getTableModel(getCollectionId()));
|
||||||
if (model == nullptr)
|
|
||||||
{
|
|
||||||
throw std::logic_error("CSVWorld::CellCreator: Attempt to add nested values to the non-nested model");
|
|
||||||
}
|
|
||||||
|
|
||||||
int parentIndex = model->findColumnIndex(CSMWorld::Columns::ColumnId_Cell);
|
int parentIndex = model->findColumnIndex(CSMWorld::Columns::ColumnId_Cell);
|
||||||
int index = model->findNestedColumnIndex(parentIndex, CSMWorld::Columns::ColumnId_Interior);
|
int index = model->findNestedColumnIndex(parentIndex, CSMWorld::Columns::ColumnId_Interior);
|
||||||
|
|
|
@ -555,12 +555,7 @@ void CSVWorld::EditWidget::remake(int row)
|
||||||
if (mTable->hasChildren(mTable->index(row, i)) &&
|
if (mTable->hasChildren(mTable->index(row, i)) &&
|
||||||
!(flags & CSMWorld::ColumnBase::Flag_Dialogue_List))
|
!(flags & CSMWorld::ColumnBase::Flag_Dialogue_List))
|
||||||
{
|
{
|
||||||
CSMWorld::IdTree *innerTable = dynamic_cast<CSMWorld::IdTree*>(mTable);
|
CSMWorld::IdTree* innerTable = &dynamic_cast<CSMWorld::IdTree&>(*mTable);
|
||||||
if (innerTable == nullptr)
|
|
||||||
{
|
|
||||||
throw std::logic_error("CSVWorld::EditWidget: Attempt to add nested values to the non-nested model");
|
|
||||||
}
|
|
||||||
|
|
||||||
mNestedModels.push_back(new CSMWorld::NestedTableProxyModel (mTable->index(row, i), display, innerTable));
|
mNestedModels.push_back(new CSMWorld::NestedTableProxyModel (mTable->index(row, i), display, innerTable));
|
||||||
|
|
||||||
int idColumn = mTable->findColumnIndex (CSMWorld::Columns::ColumnId_Id);
|
int idColumn = mTable->findColumnIndex (CSMWorld::Columns::ColumnId_Id);
|
||||||
|
|
|
@ -740,6 +740,9 @@ namespace MWGui
|
||||||
|
|
||||||
bool DialogueWindow::isCompanion(const MWWorld::Ptr& actor)
|
bool DialogueWindow::isCompanion(const MWWorld::Ptr& actor)
|
||||||
{
|
{
|
||||||
|
if (actor.isEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
return !actor.getClass().getScript(actor).empty()
|
return !actor.getClass().getScript(actor).empty()
|
||||||
&& actor.getRefData().getLocals().getIntVar(actor.getClass().getScript(actor), "companion");
|
&& actor.getRefData().getLocals().getIntVar(actor.getClass().getScript(actor), "companion");
|
||||||
}
|
}
|
||||||
|
|
|
@ -330,6 +330,21 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ToolTips::clear()
|
||||||
|
{
|
||||||
|
mFocusObject = MWWorld::Ptr();
|
||||||
|
|
||||||
|
while (mDynamicToolTipBox->getChildCount())
|
||||||
|
{
|
||||||
|
MyGUI::Gui::getInstance().destroyWidget(mDynamicToolTipBox->getChildAt(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int i=0; i < mMainWidget->getChildCount(); ++i)
|
||||||
|
{
|
||||||
|
mMainWidget->getChildAt(i)->setVisible(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ToolTips::setFocusObject(const MWWorld::Ptr& focus)
|
void ToolTips::setFocusObject(const MWWorld::Ptr& focus)
|
||||||
{
|
{
|
||||||
mFocusObject = focus;
|
mFocusObject = focus;
|
||||||
|
|
|
@ -59,6 +59,8 @@ namespace MWGui
|
||||||
|
|
||||||
void setDelay(float delay);
|
void setDelay(float delay);
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
|
||||||
void setFocusObject(const MWWorld::Ptr& focus);
|
void setFocusObject(const MWWorld::Ptr& focus);
|
||||||
void setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y);
|
void setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y);
|
||||||
///< set the screen-space position of the tooltip for focused object
|
///< set the screen-space position of the tooltip for focused object
|
||||||
|
|
|
@ -1857,7 +1857,7 @@ namespace MWGui
|
||||||
|
|
||||||
mMessageBoxManager->clear();
|
mMessageBoxManager->clear();
|
||||||
|
|
||||||
mToolTips->setFocusObject(MWWorld::Ptr());
|
mToolTips->clear();
|
||||||
|
|
||||||
mSelectedSpell.clear();
|
mSelectedSpell.clear();
|
||||||
mCustomMarkers.clear();
|
mCustomMarkers.clear();
|
||||||
|
|
|
@ -462,11 +462,10 @@ void CharacterController::refreshMovementAnims(const WeaponInfo* weap, Character
|
||||||
|
|
||||||
if(!mAnimation->hasAnimation(movementAnimName))
|
if(!mAnimation->hasAnimation(movementAnimName))
|
||||||
{
|
{
|
||||||
movemask = MWRender::Animation::BlendMask_LowerBody;
|
|
||||||
movementAnimName = movestate->groupname;
|
movementAnimName = movestate->groupname;
|
||||||
|
|
||||||
if (swimpos == std::string::npos)
|
if (swimpos == std::string::npos)
|
||||||
{
|
{
|
||||||
|
movemask = MWRender::Animation::BlendMask_LowerBody;
|
||||||
// Since we apply movement only for lower body, do not reset idle animations.
|
// Since we apply movement only for lower body, do not reset idle animations.
|
||||||
// For upper body there will be idle animation.
|
// For upper body there will be idle animation.
|
||||||
if (idle == CharState_None)
|
if (idle == CharState_None)
|
||||||
|
@ -478,7 +477,11 @@ void CharacterController::refreshMovementAnims(const WeaponInfo* weap, Character
|
||||||
}
|
}
|
||||||
else if (idle == CharState_None)
|
else if (idle == CharState_None)
|
||||||
{
|
{
|
||||||
idle = CharState_IdleSwim;
|
// In the 1st-person mode use ground idle animations as fallback
|
||||||
|
if (mPtr == getPlayer() && MWBase::Environment::get().getWorld()->isFirstPerson())
|
||||||
|
idle = CharState_Idle;
|
||||||
|
else
|
||||||
|
idle = CharState_IdleSwim;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1307,6 +1310,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
||||||
|
|
||||||
std::string upSoundId;
|
std::string upSoundId;
|
||||||
std::string downSoundId;
|
std::string downSoundId;
|
||||||
|
bool weaponChanged = false;
|
||||||
if (mPtr.getClass().hasInventoryStore(mPtr))
|
if (mPtr.getClass().hasInventoryStore(mPtr))
|
||||||
{
|
{
|
||||||
MWWorld::InventoryStore &inv = cls.getInventoryStore(mPtr);
|
MWWorld::InventoryStore &inv = cls.getInventoryStore(mPtr);
|
||||||
|
@ -1324,7 +1328,13 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
||||||
if(weapon == inv.end() && !mWeapon.isEmpty() && weaptype == WeapType_HandToHand && mWeaponType != WeapType_Spell)
|
if(weapon == inv.end() && !mWeapon.isEmpty() && weaptype == WeapType_HandToHand && mWeaponType != WeapType_Spell)
|
||||||
downSoundId = mWeapon.getClass().getDownSoundId(mWeapon);
|
downSoundId = mWeapon.getClass().getDownSoundId(mWeapon);
|
||||||
|
|
||||||
mWeapon = weapon != inv.end() ? *weapon : MWWorld::Ptr();
|
MWWorld::Ptr newWeapon = weapon != inv.end() ? *weapon : MWWorld::Ptr();
|
||||||
|
|
||||||
|
if (mWeapon != newWeapon)
|
||||||
|
{
|
||||||
|
mWeapon = newWeapon;
|
||||||
|
weaponChanged = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use blending only with 3d-person movement animations for bipedal actors
|
// Use blending only with 3d-person movement animations for bipedal actors
|
||||||
|
@ -1359,9 +1369,8 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
||||||
&& mUpperBodyState != UpperCharState_UnEquipingWeap
|
&& mUpperBodyState != UpperCharState_UnEquipingWeap
|
||||||
&& !isStillWeapon)
|
&& !isStillWeapon)
|
||||||
{
|
{
|
||||||
// We can not play un-equip animation when we switch to HtH
|
// We can not play un-equip animation if weapon changed since last update
|
||||||
// because we already un-equipped weapon
|
if (!weaponChanged)
|
||||||
if (weaptype != WeapType_HandToHand || mWeaponType == WeapType_Spell)
|
|
||||||
{
|
{
|
||||||
// Note: we do not disable unequipping animation automatically to avoid body desync
|
// Note: we do not disable unequipping animation automatically to avoid body desync
|
||||||
getWeaponGroup(mWeaponType, weapgroup);
|
getWeaponGroup(mWeaponType, weapgroup);
|
||||||
|
@ -1707,8 +1716,12 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
||||||
idle = CharState_None;
|
idle = CharState_None;
|
||||||
|
|
||||||
// In other cases we should not break swim and sneak animations
|
// In other cases we should not break swim and sneak animations
|
||||||
if (resetIdle && mIdleState != CharState_IdleSneak && mIdleState != CharState_IdleSwim)
|
if (resetIdle &&
|
||||||
|
idle != CharState_IdleSneak && idle != CharState_IdleSwim &&
|
||||||
|
mIdleState != CharState_IdleSneak && mIdleState != CharState_IdleSwim)
|
||||||
|
{
|
||||||
idle = CharState_None;
|
idle = CharState_None;
|
||||||
|
}
|
||||||
|
|
||||||
animPlaying = mAnimation->getInfo(mCurrentWeapon, &complete);
|
animPlaying = mAnimation->getInfo(mCurrentWeapon, &complete);
|
||||||
if(mUpperBodyState == UpperCharState_MinAttackToMaxAttack && !isKnockedDown())
|
if(mUpperBodyState == UpperCharState_MinAttackToMaxAttack && !isKnockedDown())
|
||||||
|
@ -2115,6 +2128,7 @@ void CharacterController::update(float duration, bool animationOnly)
|
||||||
vec.z() = 0.0f;
|
vec.z() = 0.0f;
|
||||||
|
|
||||||
bool inJump = true;
|
bool inJump = true;
|
||||||
|
bool playLandingSound = false;
|
||||||
if(!onground && !flying && !inwater)
|
if(!onground && !flying && !inwater)
|
||||||
{
|
{
|
||||||
// In the air (either getting up —ascending part of jump— or falling).
|
// In the air (either getting up —ascending part of jump— or falling).
|
||||||
|
@ -2202,20 +2216,14 @@ void CharacterController::update(float duration, bool animationOnly)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Play landing sound for NPCs
|
|
||||||
if (mPtr.getClass().isNpc())
|
if (mPtr.getClass().isNpc())
|
||||||
{
|
playLandingSound = true;
|
||||||
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
|
||||||
std::string sound = "DefaultLand";
|
|
||||||
osg::Vec3f pos(mPtr.getRefData().getPosition().asVec3());
|
|
||||||
if (world->isUnderwater(mPtr.getCell(), pos) || world->isWalkingOnWater(mPtr))
|
|
||||||
sound = "DefaultLandWater";
|
|
||||||
|
|
||||||
sndMgr->playSound3D(mPtr, sound, 1.f, 1.f, MWSound::Type::Foot, MWSound::PlayMode::NoPlayerLocal);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if(mPtr.getClass().isNpc() && mJumpState == JumpState_InAir && !flying)
|
||||||
|
playLandingSound = true;
|
||||||
|
|
||||||
jumpstate = mAnimation->isPlaying(mCurrentJump) ? JumpState_Landing : JumpState_None;
|
jumpstate = mAnimation->isPlaying(mCurrentJump) ? JumpState_Landing : JumpState_None;
|
||||||
|
|
||||||
vec.z() = 0.0f;
|
vec.z() = 0.0f;
|
||||||
|
@ -2265,6 +2273,17 @@ void CharacterController::update(float duration, bool animationOnly)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (playLandingSound)
|
||||||
|
{
|
||||||
|
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
||||||
|
std::string sound = "DefaultLand";
|
||||||
|
osg::Vec3f pos(mPtr.getRefData().getPosition().asVec3());
|
||||||
|
if (world->isUnderwater(mPtr.getCell(), pos) || world->isWalkingOnWater(mPtr))
|
||||||
|
sound = "DefaultLandWater";
|
||||||
|
|
||||||
|
sndMgr->playSound3D(mPtr, sound, 1.f, 1.f, MWSound::Type::Foot, MWSound::PlayMode::NoPlayerLocal);
|
||||||
|
}
|
||||||
|
|
||||||
// Player can not use smooth turning as NPCs, so we play turning animation a bit to avoid jittering
|
// Player can not use smooth turning as NPCs, so we play turning animation a bit to avoid jittering
|
||||||
if (isPlayer)
|
if (isPlayer)
|
||||||
{
|
{
|
||||||
|
|
|
@ -355,10 +355,6 @@ void ActorAnimation::updateQuiver()
|
||||||
addGlow(arrow, glowColor);
|
addGlow(arrow, glowColor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// recreate shaders for invisible actors, otherwise new nodes will be visible
|
|
||||||
if (mAlpha != 1.f)
|
|
||||||
mResourceSystem->getSceneManager()->recreateShaders(mObjectRoot);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ActorAnimation::itemAdded(const MWWorld::ConstPtr& item, int /*count*/)
|
void ActorAnimation::itemAdded(const MWWorld::ConstPtr& item, int /*count*/)
|
||||||
|
|
|
@ -305,24 +305,37 @@ namespace MWRender
|
||||||
type == ESM::Weapon::LongBladeOneHand ||
|
type == ESM::Weapon::LongBladeOneHand ||
|
||||||
type == ESM::Weapon::BluntOneHand ||
|
type == ESM::Weapon::BluntOneHand ||
|
||||||
type == ESM::Weapon::AxeOneHand ||
|
type == ESM::Weapon::AxeOneHand ||
|
||||||
type == ESM::Weapon::MarksmanThrown ||
|
type == ESM::Weapon::MarksmanThrown)
|
||||||
type == ESM::Weapon::MarksmanCrossbow ||
|
{
|
||||||
type == ESM::Weapon::MarksmanBow)
|
|
||||||
groupname = "inventoryweapononehand";
|
groupname = "inventoryweapononehand";
|
||||||
|
}
|
||||||
|
else if(type == ESM::Weapon::MarksmanCrossbow ||
|
||||||
|
type == ESM::Weapon::MarksmanBow)
|
||||||
|
{
|
||||||
|
groupname = "inventoryweapononehand";
|
||||||
|
showCarriedLeft = false;
|
||||||
|
}
|
||||||
else if(type == ESM::Weapon::LongBladeTwoHand ||
|
else if(type == ESM::Weapon::LongBladeTwoHand ||
|
||||||
type == ESM::Weapon::BluntTwoClose ||
|
type == ESM::Weapon::BluntTwoClose ||
|
||||||
type == ESM::Weapon::AxeTwoHand)
|
type == ESM::Weapon::AxeTwoHand)
|
||||||
|
{
|
||||||
groupname = "inventoryweapontwohand";
|
groupname = "inventoryweapontwohand";
|
||||||
|
showCarriedLeft = false;
|
||||||
|
}
|
||||||
else if(type == ESM::Weapon::BluntTwoWide ||
|
else if(type == ESM::Weapon::BluntTwoWide ||
|
||||||
type == ESM::Weapon::SpearTwoWide)
|
type == ESM::Weapon::SpearTwoWide)
|
||||||
|
{
|
||||||
groupname = "inventoryweapontwowide";
|
groupname = "inventoryweapontwowide";
|
||||||
|
showCarriedLeft = false;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
groupname = "inventoryhandtohand";
|
groupname = "inventoryhandtohand";
|
||||||
|
showCarriedLeft = false;
|
||||||
showCarriedLeft = (iter->getClass().canBeEquipped(*iter, mCharacter).first != 2);
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
groupname = "inventoryhandtohand";
|
groupname = "inventoryhandtohand";
|
||||||
}
|
}
|
||||||
|
|
||||||
mAnimation->showCarriedLeft(showCarriedLeft);
|
mAnimation->showCarriedLeft(showCarriedLeft);
|
||||||
|
|
|
@ -925,6 +925,10 @@ void NpcAnimation::showWeapons(bool showWeapon)
|
||||||
|
|
||||||
updateHolsteredWeapon(!mShowWeapons);
|
updateHolsteredWeapon(!mShowWeapons);
|
||||||
updateQuiver();
|
updateQuiver();
|
||||||
|
|
||||||
|
// Recreate shaders for invisible actors, otherwise sheath nodes will be visible
|
||||||
|
if (mAlpha != 1.f && mWeaponSheathing)
|
||||||
|
mResourceSystem->getSceneManager()->recreateShaders(mObjectRoot);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NpcAnimation::showCarriedLeft(bool show)
|
void NpcAnimation::showCarriedLeft(bool show)
|
||||||
|
|
|
@ -404,6 +404,17 @@ namespace MWWorld
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CellStore::movedHere(const MWWorld::Ptr& ptr) const
|
||||||
|
{
|
||||||
|
if (ptr.isEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (mMovedHere.find(ptr.getBase()) != mMovedHere.end())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
CellStore::CellStore (const ESM::Cell *cell, const MWWorld::ESMStore& esmStore, std::vector<ESM::ESMReader>& readerList)
|
CellStore::CellStore (const ESM::Cell *cell, const MWWorld::ESMStore& esmStore, std::vector<ESM::ESMReader>& readerList)
|
||||||
: mStore(esmStore), mReader(readerList), mCell (cell), mState (State_Unloaded), mHasState (false), mLastRespawn(0,0)
|
: mStore(esmStore), mReader(readerList), mCell (cell), mState (State_Unloaded), mHasState (false), mLastRespawn(0,0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -293,6 +293,8 @@ namespace MWWorld
|
||||||
|
|
||||||
float getWaterLevel() const;
|
float getWaterLevel() const;
|
||||||
|
|
||||||
|
bool movedHere(const MWWorld::Ptr& ptr) const;
|
||||||
|
|
||||||
void setWaterLevel (float level);
|
void setWaterLevel (float level);
|
||||||
|
|
||||||
void setFog (ESM::FogState* fog);
|
void setFog (ESM::FogState* fog);
|
||||||
|
|
|
@ -4130,10 +4130,13 @@ namespace MWWorld
|
||||||
{
|
{
|
||||||
if (ptr.getClass().isActor() && ptr.getCellRef().hasContentFile())
|
if (ptr.getClass().isActor() && ptr.getCellRef().hasContentFile())
|
||||||
{
|
{
|
||||||
|
if (ptr.getCell()->movedHere(ptr))
|
||||||
|
return true;
|
||||||
|
|
||||||
const ESM::Position& origPos = ptr.getCellRef().getPosition();
|
const ESM::Position& origPos = ptr.getCellRef().getPosition();
|
||||||
MWBase::Environment::get().getWorld()->moveObject(ptr, origPos.pos[0], origPos.pos[1], origPos.pos[2]);
|
MWBase::Environment::get().getWorld()->moveObject(ptr, origPos.pos[0], origPos.pos[1], origPos.pos[2]);
|
||||||
MWBase::Environment::get().getWorld()->rotateObject(ptr, origPos.rot[0], origPos.rot[1], origPos.rot[2]);
|
MWBase::Environment::get().getWorld()->rotateObject(ptr, origPos.rot[0], origPos.rot[1], origPos.rot[2]);
|
||||||
ptr.getClass().adjustPosition(ptr, false);
|
ptr.getClass().adjustPosition(ptr, true);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ Copyright 2017 Bret Curtis <psi29a@gmail.com>
|
||||||
<category>RolePlaying</category>
|
<category>RolePlaying</category>
|
||||||
</categories>
|
</categories>
|
||||||
<releases>
|
<releases>
|
||||||
<release version="0.43.0" date="2017-12-05"/>
|
<release version="0.46.0" date="2017-12-05"/>
|
||||||
</releases>
|
</releases>
|
||||||
<url type="homepage">https://openmw.org</url>
|
<url type="homepage">https://openmw.org</url>
|
||||||
<url type="bugtracker">https://bugs.openmw.org/</url>
|
<url type="bugtracker">https://bugs.openmw.org/</url>
|
||||||
|
|
Loading…
Reference in a new issue