forked from mirror/openmw-tes3mp
Update to upstream/master. Resolve merge conflicts in MWWorld::Store
This commit is contained in:
commit
2ed182b144
72 changed files with 2329 additions and 1570 deletions
|
@ -18,8 +18,8 @@ addons:
|
||||||
name: "OpenMW/openmw"
|
name: "OpenMW/openmw"
|
||||||
description: "<Your project description here>"
|
description: "<Your project description here>"
|
||||||
notification_email: scrawl@baseoftrash.de
|
notification_email: scrawl@baseoftrash.de
|
||||||
build_command_prepend: "cmake ."
|
build_command_prepend: "cmake . -DBUILD_UNITTESTS=FALSE -DBUILD_OPENCS=FALSE"
|
||||||
build_command: "make -j3"
|
build_command: "make"
|
||||||
branch_pattern: coverity_scan
|
branch_pattern: coverity_scan
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
|
|
|
@ -10,9 +10,10 @@ fi
|
||||||
|
|
||||||
echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse"
|
echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse"
|
||||||
echo "yes" | sudo apt-add-repository ppa:openmw/openmw
|
echo "yes" | sudo apt-add-repository ppa:openmw/openmw
|
||||||
|
echo "yes" | sudo apt-add-repository ppa:boost-latest/ppa
|
||||||
sudo apt-get update -qq
|
sudo apt-get update -qq
|
||||||
sudo apt-get install -qq libgtest-dev google-mock
|
sudo apt-get install -qq libgtest-dev google-mock
|
||||||
sudo apt-get install -qq libboost-filesystem-dev libboost-program-options-dev libboost-system-dev libboost-thread-dev
|
sudo apt-get install -qq libboost-filesystem1.55-dev libboost-program-options1.55-dev libboost-system1.55-dev libboost-thread1.55-dev
|
||||||
sudo apt-get install -qq libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libavresample-dev
|
sudo apt-get install -qq libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libavresample-dev
|
||||||
sudo apt-get install -qq libbullet-dev libopenscenegraph-dev libmygui-dev libsdl2-dev libunshield-dev libtinyxml-dev libopenal-dev libqt4-dev
|
sudo apt-get install -qq libbullet-dev libopenscenegraph-dev libmygui-dev libsdl2-dev libunshield-dev libtinyxml-dev libopenal-dev libqt4-dev
|
||||||
sudo apt-get install -qq cmake-data #workaround for broken osgqt cmake script in ubuntu 12.04
|
sudo apt-get install -qq cmake-data #workaround for broken osgqt cmake script in ubuntu 12.04
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "convertplayer.hpp"
|
#include "convertplayer.hpp"
|
||||||
|
|
||||||
|
#include <components/misc/stringops.hpp>
|
||||||
|
|
||||||
namespace ESSImport
|
namespace ESSImport
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
@ -166,7 +166,9 @@ namespace ESSImport
|
||||||
|
|
||||||
if (i >= file2.mRecords.size())
|
if (i >= file2.mRecords.size())
|
||||||
{
|
{
|
||||||
|
std::ios::fmtflags f(std::cout.flags());
|
||||||
std::cout << "Record in file1 not present in file2: (1) 0x" << std::hex << rec.mFileOffset << std::endl;
|
std::cout << "Record in file1 not present in file2: (1) 0x" << std::hex << rec.mFileOffset << std::endl;
|
||||||
|
std::cout.flags(f);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,7 +176,9 @@ namespace ESSImport
|
||||||
|
|
||||||
if (rec.mName != rec2.mName)
|
if (rec.mName != rec2.mName)
|
||||||
{
|
{
|
||||||
|
std::ios::fmtflags f(std::cout.flags());
|
||||||
std::cout << "Different record name at (2) 0x" << std::hex << rec2.mFileOffset << std::endl;
|
std::cout << "Different record name at (2) 0x" << std::hex << rec2.mFileOffset << std::endl;
|
||||||
|
std::cout.flags(f);
|
||||||
return; // TODO: try to recover
|
return; // TODO: try to recover
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,7 +189,9 @@ namespace ESSImport
|
||||||
|
|
||||||
if (j >= rec2.mSubrecords.size())
|
if (j >= rec2.mSubrecords.size())
|
||||||
{
|
{
|
||||||
|
std::ios::fmtflags f(std::cout.flags());
|
||||||
std::cout << "Subrecord in file1 not present in file2: (1) 0x" << std::hex << sub.mFileOffset << std::endl;
|
std::cout << "Subrecord in file1 not present in file2: (1) 0x" << std::hex << sub.mFileOffset << std::endl;
|
||||||
|
std::cout.flags(f);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,8 +199,10 @@ namespace ESSImport
|
||||||
|
|
||||||
if (sub.mName != sub2.mName)
|
if (sub.mName != sub2.mName)
|
||||||
{
|
{
|
||||||
|
std::ios::fmtflags f(std::cout.flags());
|
||||||
std::cout << "Different subrecord name (" << rec.mName << "." << sub.mName << " vs. " << sub2.mName << ") at (1) 0x" << std::hex << sub.mFileOffset
|
std::cout << "Different subrecord name (" << rec.mName << "." << sub.mName << " vs. " << sub2.mName << ") at (1) 0x" << std::hex << sub.mFileOffset
|
||||||
<< " (2) 0x" << sub2.mFileOffset << std::endl;
|
<< " (2) 0x" << sub2.mFileOffset << std::endl;
|
||||||
|
std::cout.flags(f);
|
||||||
break; // TODO: try to recover
|
break; // TODO: try to recover
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,6 +211,8 @@ namespace ESSImport
|
||||||
if (blacklist.find(std::make_pair(rec.mName, sub.mName)) != blacklist.end())
|
if (blacklist.find(std::make_pair(rec.mName, sub.mName)) != blacklist.end())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
std::ios::fmtflags f(std::cout.flags());
|
||||||
|
|
||||||
std::cout << "Different subrecord data for " << rec.mName << "." << sub.mName << " at (1) 0x" << std::hex << sub.mFileOffset
|
std::cout << "Different subrecord data for " << rec.mName << "." << sub.mName << " at (1) 0x" << std::hex << sub.mFileOffset
|
||||||
<< " (2) 0x" << sub2.mFileOffset << std::endl;
|
<< " (2) 0x" << sub2.mFileOffset << std::endl;
|
||||||
|
|
||||||
|
@ -235,6 +245,7 @@ namespace ESSImport
|
||||||
std::cout << "\033[0m";
|
std::cout << "\033[0m";
|
||||||
}
|
}
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
|
std::cout.flags(f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -319,7 +330,11 @@ namespace ESSImport
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (unknownRecords.insert(n.val).second)
|
if (unknownRecords.insert(n.val).second)
|
||||||
|
{
|
||||||
|
std::ios::fmtflags f(std::cerr.flags());
|
||||||
std::cerr << "unknown record " << n.toString() << " (0x" << std::hex << esm.getFileOffset() << ")" << std::endl;
|
std::cerr << "unknown record " << n.toString() << " (0x" << std::hex << esm.getFileOffset() << ")" << std::endl;
|
||||||
|
std::cerr.flags(f);
|
||||||
|
}
|
||||||
|
|
||||||
esm.skipRecord();
|
esm.skipRecord();
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,10 @@ namespace ESSImport
|
||||||
std::map<std::string, ESM::NPC> mNpcs;
|
std::map<std::string, ESM::NPC> mNpcs;
|
||||||
|
|
||||||
Context()
|
Context()
|
||||||
|
: mDay(0)
|
||||||
|
, mMonth(0)
|
||||||
|
, mYear(0)
|
||||||
|
, mHour(0.f)
|
||||||
{
|
{
|
||||||
mPlayer.mAutoMove = 0;
|
mPlayer.mAutoMove = 0;
|
||||||
ESM::CellId playerCellId;
|
ESM::CellId playerCellId;
|
||||||
|
|
|
@ -64,7 +64,7 @@ opencs_units (view/world
|
||||||
table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator
|
table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator
|
||||||
cellcreator referenceablecreator referencecreator scenesubview
|
cellcreator referenceablecreator referencecreator scenesubview
|
||||||
infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable
|
infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable
|
||||||
dialoguespinbox recordbuttonbar
|
dialoguespinbox recordbuttonbar tableeditidaction
|
||||||
)
|
)
|
||||||
|
|
||||||
opencs_units_noqt (view/world
|
opencs_units_noqt (view/world
|
||||||
|
|
|
@ -92,7 +92,7 @@ namespace CSMWorld
|
||||||
{ ColumnId_Trainer, "Trainer" },
|
{ ColumnId_Trainer, "Trainer" },
|
||||||
{ ColumnId_Spellmaking, "Spellmaking" },
|
{ ColumnId_Spellmaking, "Spellmaking" },
|
||||||
{ ColumnId_EnchantingService, "Enchanting Service" },
|
{ ColumnId_EnchantingService, "Enchanting Service" },
|
||||||
{ ColumnId_RepairService, "Repair Serivce" },
|
{ ColumnId_RepairService, "Repair Service" },
|
||||||
{ ColumnId_ApparatusType, "Apparatus Type" },
|
{ ColumnId_ApparatusType, "Apparatus Type" },
|
||||||
{ ColumnId_ArmorType, "Armor Type" },
|
{ ColumnId_ArmorType, "Armor Type" },
|
||||||
{ ColumnId_Health, "Health" },
|
{ ColumnId_Health, "Health" },
|
||||||
|
|
|
@ -161,8 +161,19 @@ namespace CSMWorld
|
||||||
template<typename ESXRecordT, typename IdAccessorT>
|
template<typename ESXRecordT, typename IdAccessorT>
|
||||||
int NestedIdCollection<ESXRecordT, IdAccessorT>::getNestedColumnsCount(int row, int column) const
|
int NestedIdCollection<ESXRecordT, IdAccessorT>::getNestedColumnsCount(int row, int column) const
|
||||||
{
|
{
|
||||||
return getAdapter(Collection<ESXRecordT, IdAccessorT>::getColumn(column)).getColumnsCount(
|
const ColumnBase &nestedColumn = Collection<ESXRecordT, IdAccessorT>::getColumn(column);
|
||||||
Collection<ESXRecordT, IdAccessorT>::getRecord(row));
|
int numRecords = Collection<ESXRecordT, IdAccessorT>::getSize();
|
||||||
|
if (row >= 0 && row < numRecords)
|
||||||
|
{
|
||||||
|
const Record<ESXRecordT>& record = Collection<ESXRecordT, IdAccessorT>::getRecord(row);
|
||||||
|
return getAdapter(nestedColumn).getColumnsCount(record);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If the row is invalid (or there no records), retrieve the column count using a blank record
|
||||||
|
const Record<ESXRecordT> record;
|
||||||
|
return getAdapter(nestedColumn).getColumnsCount(record);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ESXRecordT, typename IdAccessorT>
|
template<typename ESXRecordT, typename IdAccessorT>
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QContextMenuEvent>
|
#include <QContextMenuEvent>
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
|
#include <QSortFilterProxyModel>
|
||||||
|
|
||||||
#include "../../model/tools/reportmodel.hpp"
|
#include "../../model/tools/reportmodel.hpp"
|
||||||
|
|
||||||
|
@ -23,7 +24,7 @@ namespace CSVTools
|
||||||
public:
|
public:
|
||||||
|
|
||||||
RichTextDelegate (QObject *parent = 0);
|
RichTextDelegate (QObject *parent = 0);
|
||||||
|
|
||||||
virtual void paint(QPainter *painter, const QStyleOptionViewItem& option,
|
virtual void paint(QPainter *painter, const QStyleOptionViewItem& option,
|
||||||
const QModelIndex& index) const;
|
const QModelIndex& index) const;
|
||||||
};
|
};
|
||||||
|
@ -63,7 +64,7 @@ void CSVTools::ReportTable::contextMenuEvent (QContextMenuEvent *event)
|
||||||
for (QModelIndexList::const_iterator iter (selectedRows.begin());
|
for (QModelIndexList::const_iterator iter (selectedRows.begin());
|
||||||
iter!=selectedRows.end(); ++iter)
|
iter!=selectedRows.end(); ++iter)
|
||||||
{
|
{
|
||||||
QString hint = mModel->data (mModel->index (iter->row(), 2)).toString();
|
QString hint = mProxyModel->data (mProxyModel->index (iter->row(), 2)).toString();
|
||||||
|
|
||||||
if (!hint.isEmpty() && hint[0]=='R')
|
if (!hint.isEmpty() && hint[0]=='R')
|
||||||
{
|
{
|
||||||
|
@ -78,7 +79,7 @@ void CSVTools::ReportTable::contextMenuEvent (QContextMenuEvent *event)
|
||||||
|
|
||||||
if (mRefreshAction)
|
if (mRefreshAction)
|
||||||
menu.addAction (mRefreshAction);
|
menu.addAction (mRefreshAction);
|
||||||
|
|
||||||
menu.exec (event->globalPos());
|
menu.exec (event->globalPos());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,14 +107,14 @@ void CSVTools::ReportTable::mouseDoubleClickEvent (QMouseEvent *event)
|
||||||
event->accept();
|
event->accept();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (iter->second)
|
switch (iter->second)
|
||||||
{
|
{
|
||||||
case Action_None:
|
case Action_None:
|
||||||
|
|
||||||
event->accept();
|
event->accept();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Action_Edit:
|
case Action_Edit:
|
||||||
|
|
||||||
event->accept();
|
event->accept();
|
||||||
|
@ -152,7 +153,10 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document,
|
||||||
setSelectionBehavior (QAbstractItemView::SelectRows);
|
setSelectionBehavior (QAbstractItemView::SelectRows);
|
||||||
setSelectionMode (QAbstractItemView::ExtendedSelection);
|
setSelectionMode (QAbstractItemView::ExtendedSelection);
|
||||||
|
|
||||||
setModel (mModel);
|
mProxyModel = new QSortFilterProxyModel (this);
|
||||||
|
mProxyModel->setSourceModel (mModel);
|
||||||
|
|
||||||
|
setModel (mProxyModel);
|
||||||
setColumnHidden (2, true);
|
setColumnHidden (2, true);
|
||||||
|
|
||||||
mIdTypeDelegate = CSVWorld::IdTypeDelegateFactory().makeDelegate (0,
|
mIdTypeDelegate = CSVWorld::IdTypeDelegateFactory().makeDelegate (0,
|
||||||
|
@ -162,7 +166,7 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document,
|
||||||
|
|
||||||
if (richTextDescription)
|
if (richTextDescription)
|
||||||
setItemDelegateForColumn (mModel->columnCount()-1, new RichTextDelegate (this));
|
setItemDelegateForColumn (mModel->columnCount()-1, new RichTextDelegate (this));
|
||||||
|
|
||||||
mShowAction = new QAction (tr ("Show"), this);
|
mShowAction = new QAction (tr ("Show"), this);
|
||||||
connect (mShowAction, SIGNAL (triggered()), this, SLOT (showSelection()));
|
connect (mShowAction, SIGNAL (triggered()), this, SLOT (showSelection()));
|
||||||
addAction (mShowAction);
|
addAction (mShowAction);
|
||||||
|
@ -182,10 +186,10 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document,
|
||||||
connect (mRefreshAction, SIGNAL (triggered()), this, SIGNAL (refreshRequest()));
|
connect (mRefreshAction, SIGNAL (triggered()), this, SIGNAL (refreshRequest()));
|
||||||
addAction (mRefreshAction);
|
addAction (mRefreshAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
mDoubleClickActions.insert (std::make_pair (Qt::NoModifier, Action_Edit));
|
mDoubleClickActions.insert (std::make_pair (Qt::NoModifier, Action_Edit));
|
||||||
mDoubleClickActions.insert (std::make_pair (Qt::ShiftModifier, Action_Remove));
|
mDoubleClickActions.insert (std::make_pair (Qt::ShiftModifier, Action_Remove));
|
||||||
mDoubleClickActions.insert (std::make_pair (Qt::ControlModifier, Action_EditAndRemove));
|
mDoubleClickActions.insert (std::make_pair (Qt::ControlModifier, Action_EditAndRemove));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<CSMWorld::UniversalId> CSVTools::ReportTable::getDraggedRecords() const
|
std::vector<CSMWorld::UniversalId> CSVTools::ReportTable::getDraggedRecords() const
|
||||||
|
@ -197,7 +201,7 @@ std::vector<CSMWorld::UniversalId> CSVTools::ReportTable::getDraggedRecords() co
|
||||||
for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end();
|
for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end();
|
||||||
++iter)
|
++iter)
|
||||||
{
|
{
|
||||||
ids.push_back (mModel->getUniversalId (iter->row()));
|
ids.push_back (mModel->getUniversalId (mProxyModel->mapToSource (*iter).row()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return ids;
|
return ids;
|
||||||
|
@ -234,7 +238,7 @@ void CSVTools::ReportTable::updateUserSetting (const QString& name, const QStrin
|
||||||
mDoubleClickActions[modifiers] = action;
|
mDoubleClickActions[modifiers] = action;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<int> CSVTools::ReportTable::getReplaceIndices (bool selection) const
|
std::vector<int> CSVTools::ReportTable::getReplaceIndices (bool selection) const
|
||||||
|
@ -245,13 +249,22 @@ std::vector<int> CSVTools::ReportTable::getReplaceIndices (bool selection) const
|
||||||
{
|
{
|
||||||
QModelIndexList selectedRows = selectionModel()->selectedRows();
|
QModelIndexList selectedRows = selectionModel()->selectedRows();
|
||||||
|
|
||||||
|
std::vector<int> rows;
|
||||||
|
|
||||||
for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end();
|
for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end();
|
||||||
++iter)
|
++iter)
|
||||||
{
|
{
|
||||||
QString hint = mModel->data (mModel->index (iter->row(), 2)).toString();
|
rows.push_back (mProxyModel->mapToSource (*iter).row());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort (rows.begin(), rows.end());
|
||||||
|
|
||||||
|
for (std::vector<int>::const_iterator iter (rows.begin()); iter!=rows.end(); ++iter)
|
||||||
|
{
|
||||||
|
QString hint = mModel->data (mModel->index (*iter, 2)).toString();
|
||||||
|
|
||||||
if (!hint.isEmpty() && hint[0]=='R')
|
if (!hint.isEmpty() && hint[0]=='R')
|
||||||
indices.push_back (iter->row());
|
indices.push_back (*iter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -272,25 +285,35 @@ void CSVTools::ReportTable::flagAsReplaced (int index)
|
||||||
{
|
{
|
||||||
mModel->flagAsReplaced (index);
|
mModel->flagAsReplaced (index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVTools::ReportTable::showSelection()
|
void CSVTools::ReportTable::showSelection()
|
||||||
{
|
{
|
||||||
QModelIndexList selectedRows = selectionModel()->selectedRows();
|
QModelIndexList selectedRows = selectionModel()->selectedRows();
|
||||||
|
|
||||||
for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end();
|
for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end();
|
||||||
++iter)
|
++iter)
|
||||||
emit editRequest (mModel->getUniversalId (iter->row()), mModel->getHint (iter->row()));
|
{
|
||||||
|
int row = mProxyModel->mapToSource (*iter).row();
|
||||||
|
emit editRequest (mModel->getUniversalId (row), mModel->getHint (row));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVTools::ReportTable::removeSelection()
|
void CSVTools::ReportTable::removeSelection()
|
||||||
{
|
{
|
||||||
QModelIndexList selectedRows = selectionModel()->selectedRows();
|
QModelIndexList selectedRows = selectionModel()->selectedRows();
|
||||||
|
|
||||||
std::reverse (selectedRows.begin(), selectedRows.end());
|
std::vector<int> rows;
|
||||||
|
|
||||||
for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end();
|
for (QModelIndexList::iterator iter (selectedRows.begin()); iter!=selectedRows.end();
|
||||||
++iter)
|
++iter)
|
||||||
mModel->removeRows (iter->row(), 1);
|
{
|
||||||
|
rows.push_back (mProxyModel->mapToSource (*iter).row());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort (rows.begin(), rows.end());
|
||||||
|
|
||||||
|
for (std::vector<int>::const_reverse_iterator iter (rows.rbegin()); iter!=rows.rend(); ++iter)
|
||||||
|
mProxyModel->removeRows (*iter, 1);
|
||||||
|
|
||||||
selectionModel()->clear();
|
selectionModel()->clear();
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "../world/dragrecordtable.hpp"
|
#include "../world/dragrecordtable.hpp"
|
||||||
|
|
||||||
class QAction;
|
class QAction;
|
||||||
|
class QSortFilterProxyModel;
|
||||||
|
|
||||||
namespace CSMTools
|
namespace CSMTools
|
||||||
{
|
{
|
||||||
|
@ -30,7 +31,8 @@ namespace CSVTools
|
||||||
Action_Remove,
|
Action_Remove,
|
||||||
Action_EditAndRemove
|
Action_EditAndRemove
|
||||||
};
|
};
|
||||||
|
|
||||||
|
QSortFilterProxyModel *mProxyModel;
|
||||||
CSMTools::ReportModel *mModel;
|
CSMTools::ReportModel *mModel;
|
||||||
CSVWorld::CommandDelegate *mIdTypeDelegate;
|
CSVWorld::CommandDelegate *mIdTypeDelegate;
|
||||||
QAction *mShowAction;
|
QAction *mShowAction;
|
||||||
|
@ -63,11 +65,14 @@ namespace CSVTools
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
// Return indices of rows that are suitable for replacement.
|
/// Return indices of rows that are suitable for replacement.
|
||||||
//
|
///
|
||||||
// \param selection Only list selected rows.
|
/// \param selection Only list selected rows.
|
||||||
|
///
|
||||||
|
/// \return rows in the original model
|
||||||
std::vector<int> getReplaceIndices (bool selection) const;
|
std::vector<int> getReplaceIndices (bool selection) const;
|
||||||
|
|
||||||
|
/// \param index row in the original model
|
||||||
void flagAsReplaced (int index);
|
void flagAsReplaced (int index);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
@ -78,8 +83,8 @@ namespace CSVTools
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
void stateChanged (int state, CSMDoc::Document *document);
|
void stateChanged (int state, CSMDoc::Document *document);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
void editRequest (const CSMWorld::UniversalId& id, const std::string& hint);
|
void editRequest (const CSMWorld::UniversalId& id, const std::string& hint);
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
#include <QHeaderView>
|
#include <QHeaderView>
|
||||||
#include <QScrollBar>
|
#include <QScrollBar>
|
||||||
|
#include <QMenu>
|
||||||
|
|
||||||
#include "../../model/world/nestedtableproxymodel.hpp"
|
#include "../../model/world/nestedtableproxymodel.hpp"
|
||||||
#include "../../model/world/columnbase.hpp"
|
#include "../../model/world/columnbase.hpp"
|
||||||
|
@ -314,10 +315,141 @@ CSVWorld::DialogueDelegateDispatcher::~DialogueDelegateDispatcher()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CSVWorld::IdContextMenu::IdContextMenu(QWidget *widget, CSMWorld::ColumnBase::Display display)
|
||||||
|
: QObject(widget),
|
||||||
|
mWidget(widget),
|
||||||
|
mIdType(CSMWorld::TableMimeData::convertEnums(display))
|
||||||
|
{
|
||||||
|
Q_ASSERT(mWidget != NULL);
|
||||||
|
Q_ASSERT(CSMWorld::ColumnBase::isId(display));
|
||||||
|
Q_ASSERT(mIdType != CSMWorld::UniversalId::Type_None);
|
||||||
|
|
||||||
|
mWidget->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
|
connect(mWidget,
|
||||||
|
SIGNAL(customContextMenuRequested(const QPoint &)),
|
||||||
|
this,
|
||||||
|
SLOT(showContextMenu(const QPoint &)));
|
||||||
|
|
||||||
|
mEditIdAction = new QAction(this);
|
||||||
|
connect(mEditIdAction, SIGNAL(triggered()), this, SLOT(editIdRequest()));
|
||||||
|
|
||||||
|
QLineEdit *lineEdit = qobject_cast<QLineEdit *>(mWidget);
|
||||||
|
if (lineEdit != NULL)
|
||||||
|
{
|
||||||
|
mContextMenu = lineEdit->createStandardContextMenu();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mContextMenu = new QMenu(mWidget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVWorld::IdContextMenu::excludeId(const std::string &id)
|
||||||
|
{
|
||||||
|
mExcludedIds.insert(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString CSVWorld::IdContextMenu::getWidgetValue() const
|
||||||
|
{
|
||||||
|
QLineEdit *lineEdit = qobject_cast<QLineEdit *>(mWidget);
|
||||||
|
QLabel *label = qobject_cast<QLabel *>(mWidget);
|
||||||
|
|
||||||
|
QString value = "";
|
||||||
|
if (lineEdit != NULL)
|
||||||
|
{
|
||||||
|
value = lineEdit->text();
|
||||||
|
}
|
||||||
|
else if (label != NULL)
|
||||||
|
{
|
||||||
|
value = label->text();
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVWorld::IdContextMenu::addEditIdActionToMenu(const QString &text)
|
||||||
|
{
|
||||||
|
mEditIdAction->setText(text);
|
||||||
|
if (mContextMenu->actions().isEmpty())
|
||||||
|
{
|
||||||
|
mContextMenu->addAction(mEditIdAction);
|
||||||
|
}
|
||||||
|
else if (mContextMenu->actions().first() != mEditIdAction)
|
||||||
|
{
|
||||||
|
QAction *action = mContextMenu->actions().first();
|
||||||
|
mContextMenu->insertAction(action, mEditIdAction);
|
||||||
|
mContextMenu->insertSeparator(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVWorld::IdContextMenu::removeEditIdActionFromMenu()
|
||||||
|
{
|
||||||
|
if (mContextMenu->actions().isEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mContextMenu->actions().first() == mEditIdAction)
|
||||||
|
{
|
||||||
|
mContextMenu->removeAction(mEditIdAction);
|
||||||
|
if (!mContextMenu->actions().isEmpty() && mContextMenu->actions().first()->isSeparator())
|
||||||
|
{
|
||||||
|
mContextMenu->removeAction(mContextMenu->actions().first());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVWorld::IdContextMenu::showContextMenu(const QPoint &pos)
|
||||||
|
{
|
||||||
|
QString value = getWidgetValue();
|
||||||
|
bool isExcludedId = mExcludedIds.find(value.toUtf8().constData()) != mExcludedIds.end();
|
||||||
|
if (!value.isEmpty() && !isExcludedId)
|
||||||
|
{
|
||||||
|
addEditIdActionToMenu("Edit '" + value + "'");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
removeEditIdActionFromMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mContextMenu->actions().isEmpty())
|
||||||
|
{
|
||||||
|
mContextMenu->exec(mWidget->mapToGlobal(pos));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVWorld::IdContextMenu::editIdRequest()
|
||||||
|
{
|
||||||
|
CSMWorld::UniversalId editId(mIdType, getWidgetValue().toUtf8().constData());
|
||||||
|
emit editIdRequest(editId, "");
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=============================================================EditWidget=====================================================
|
=============================================================EditWidget=====================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
void CSVWorld::EditWidget::createEditorContextMenu(QWidget *editor,
|
||||||
|
CSMWorld::ColumnBase::Display display,
|
||||||
|
int currentRow) const
|
||||||
|
{
|
||||||
|
Q_ASSERT(editor != NULL);
|
||||||
|
|
||||||
|
if (CSMWorld::ColumnBase::isId(display) &&
|
||||||
|
CSMWorld::TableMimeData::convertEnums(display) != CSMWorld::UniversalId::Type_None)
|
||||||
|
{
|
||||||
|
int idColumn = mTable->findColumnIndex(CSMWorld::Columns::ColumnId_Id);
|
||||||
|
QString id = mTable->data(mTable->index(currentRow, idColumn)).toString();
|
||||||
|
|
||||||
|
IdContextMenu *menu = new IdContextMenu(editor, display);
|
||||||
|
// Current ID is already opened, so no need to create Edit 'ID' action for it
|
||||||
|
menu->excludeId(id.toUtf8().constData());
|
||||||
|
connect(menu,
|
||||||
|
SIGNAL(editIdRequest(const CSMWorld::UniversalId &, const std::string &)),
|
||||||
|
this,
|
||||||
|
SIGNAL(editIdRequest(const CSMWorld::UniversalId &, const std::string &)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CSVWorld::EditWidget::~EditWidget()
|
CSVWorld::EditWidget::~EditWidget()
|
||||||
{
|
{
|
||||||
for (unsigned i = 0; i < mNestedModels.size(); ++i)
|
for (unsigned i = 0; i < mNestedModels.size(); ++i)
|
||||||
|
@ -455,6 +587,11 @@ void CSVWorld::EditWidget::remake(int row)
|
||||||
|
|
||||||
tablesLayout->addWidget(label);
|
tablesLayout->addWidget(label);
|
||||||
tablesLayout->addWidget(table);
|
tablesLayout->addWidget(table);
|
||||||
|
|
||||||
|
connect(table,
|
||||||
|
SIGNAL(editRequest(const CSMWorld::UniversalId &, const std::string &)),
|
||||||
|
this,
|
||||||
|
SIGNAL(editIdRequest(const CSMWorld::UniversalId &, const std::string &)));
|
||||||
}
|
}
|
||||||
else if (!(flags & CSMWorld::ColumnBase::Flag_Dialogue_List))
|
else if (!(flags & CSMWorld::ColumnBase::Flag_Dialogue_List))
|
||||||
{
|
{
|
||||||
|
@ -488,6 +625,8 @@ void CSVWorld::EditWidget::remake(int row)
|
||||||
editor->setEnabled(false);
|
editor->setEnabled(false);
|
||||||
label->setEnabled(false);
|
label->setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createEditorContextMenu(editor, display, row);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -539,6 +678,8 @@ void CSVWorld::EditWidget::remake(int row)
|
||||||
editor->setEnabled(false);
|
editor->setEnabled(false);
|
||||||
label->setEnabled(false);
|
label->setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createEditorContextMenu(editor, display, row);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mNestedTableMapper->setCurrentModelIndex(tree->index(0, 0, tree->index(row, i)));
|
mNestedTableMapper->setCurrentModelIndex(tree->index(0, 0, tree->index(row, i)));
|
||||||
|
@ -607,6 +748,11 @@ CSVWorld::SimpleDialogueSubView::SimpleDialogueSubView (const CSMWorld::Universa
|
||||||
mEditWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
|
mEditWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
|
||||||
|
|
||||||
dataChanged(mTable->getModelIndex (getUniversalId().getId(), 0));
|
dataChanged(mTable->getModelIndex (getUniversalId().getId(), 0));
|
||||||
|
|
||||||
|
connect(mEditWidget,
|
||||||
|
SIGNAL(editIdRequest(const CSMWorld::UniversalId &, const std::string &)),
|
||||||
|
this,
|
||||||
|
SIGNAL(focusId(const CSMWorld::UniversalId &, const std::string &)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVWorld::SimpleDialogueSubView::setEditLock (bool locked)
|
void CSVWorld::SimpleDialogueSubView::setEditLock (bool locked)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef CSV_WORLD_DIALOGUESUBVIEW_H
|
#ifndef CSV_WORLD_DIALOGUESUBVIEW_H
|
||||||
#define CSV_WORLD_DIALOGUESUBVIEW_H
|
#define CSV_WORLD_DIALOGUESUBVIEW_H
|
||||||
|
|
||||||
|
#include <set>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
@ -11,12 +12,14 @@
|
||||||
|
|
||||||
#include "../../model/world/columnbase.hpp"
|
#include "../../model/world/columnbase.hpp"
|
||||||
#include "../../model/world/commanddispatcher.hpp"
|
#include "../../model/world/commanddispatcher.hpp"
|
||||||
|
#include "../../model/world/universalid.hpp"
|
||||||
|
|
||||||
class QDataWidgetMapper;
|
class QDataWidgetMapper;
|
||||||
class QSize;
|
class QSize;
|
||||||
class QEvent;
|
class QEvent;
|
||||||
class QLabel;
|
class QLabel;
|
||||||
class QVBoxLayout;
|
class QVBoxLayout;
|
||||||
|
class QMenu;
|
||||||
|
|
||||||
namespace CSMWorld
|
namespace CSMWorld
|
||||||
{
|
{
|
||||||
|
@ -149,6 +152,36 @@ namespace CSVWorld
|
||||||
CSMWorld::ColumnBase::Display display);
|
CSMWorld::ColumnBase::Display display);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// A context menu with "Edit 'ID'" action for editors in the dialogue subview
|
||||||
|
class IdContextMenu : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
QWidget *mWidget;
|
||||||
|
CSMWorld::UniversalId::Type mIdType;
|
||||||
|
std::set<std::string> mExcludedIds;
|
||||||
|
///< A list of IDs that should not have the Edit 'ID' action.
|
||||||
|
|
||||||
|
QMenu *mContextMenu;
|
||||||
|
QAction *mEditIdAction;
|
||||||
|
|
||||||
|
QString getWidgetValue() const;
|
||||||
|
void addEditIdActionToMenu(const QString &text);
|
||||||
|
void removeEditIdActionFromMenu();
|
||||||
|
|
||||||
|
public:
|
||||||
|
IdContextMenu(QWidget *widget, CSMWorld::ColumnBase::Display display);
|
||||||
|
|
||||||
|
void excludeId(const std::string &id);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void showContextMenu(const QPoint &pos);
|
||||||
|
void editIdRequest();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void editIdRequest(const CSMWorld::UniversalId &id, const std::string &hint);
|
||||||
|
};
|
||||||
|
|
||||||
class EditWidget : public QScrollArea
|
class EditWidget : public QScrollArea
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -162,6 +195,9 @@ namespace CSVWorld
|
||||||
CSMDoc::Document& mDocument;
|
CSMDoc::Document& mDocument;
|
||||||
std::vector<CSMWorld::NestedTableProxyModel*> mNestedModels; //Plain, raw C pointers, deleted in the dtor
|
std::vector<CSMWorld::NestedTableProxyModel*> mNestedModels; //Plain, raw C pointers, deleted in the dtor
|
||||||
|
|
||||||
|
void createEditorContextMenu(QWidget *editor,
|
||||||
|
CSMWorld::ColumnBase::Display display,
|
||||||
|
int currentRow) const;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
EditWidget (QWidget *parent, int row, CSMWorld::IdTable* table,
|
EditWidget (QWidget *parent, int row, CSMWorld::IdTable* table,
|
||||||
|
@ -171,6 +207,9 @@ namespace CSVWorld
|
||||||
virtual ~EditWidget();
|
virtual ~EditWidget();
|
||||||
|
|
||||||
void remake(int row);
|
void remake(int row);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void editIdRequest(const CSMWorld::UniversalId &id, const std::string &hint);
|
||||||
};
|
};
|
||||||
|
|
||||||
class SimpleDialogueSubView : public CSVDoc::SubView
|
class SimpleDialogueSubView : public CSVDoc::SubView
|
||||||
|
|
|
@ -1,15 +1,18 @@
|
||||||
#include "nestedtable.hpp"
|
#include "nestedtable.hpp"
|
||||||
#include "../../model/world/nestedtableproxymodel.hpp"
|
|
||||||
#include "../../model/world/universalid.hpp"
|
|
||||||
#include "../../model/world/commands.hpp"
|
|
||||||
#include "../../model/world/commanddispatcher.hpp"
|
|
||||||
#include "util.hpp"
|
|
||||||
|
|
||||||
#include <QHeaderView>
|
#include <QHeaderView>
|
||||||
#include <QContextMenuEvent>
|
#include <QContextMenuEvent>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
|
#include "../../model/world/nestedtableproxymodel.hpp"
|
||||||
|
#include "../../model/world/universalid.hpp"
|
||||||
|
#include "../../model/world/commands.hpp"
|
||||||
|
#include "../../model/world/commanddispatcher.hpp"
|
||||||
|
|
||||||
|
#include "tableeditidaction.hpp"
|
||||||
|
#include "util.hpp"
|
||||||
|
|
||||||
CSVWorld::NestedTable::NestedTable(CSMDoc::Document& document,
|
CSVWorld::NestedTable::NestedTable(CSMDoc::Document& document,
|
||||||
CSMWorld::UniversalId id,
|
CSMWorld::UniversalId id,
|
||||||
CSMWorld::NestedTableProxyModel* model,
|
CSMWorld::NestedTableProxyModel* model,
|
||||||
|
@ -55,6 +58,9 @@ CSVWorld::NestedTable::NestedTable(CSMDoc::Document& document,
|
||||||
|
|
||||||
connect(mRemoveRowAction, SIGNAL(triggered()),
|
connect(mRemoveRowAction, SIGNAL(triggered()),
|
||||||
this, SLOT(removeRowActionTriggered()));
|
this, SLOT(removeRowActionTriggered()));
|
||||||
|
|
||||||
|
mEditIdAction = new TableEditIdAction(*this, this);
|
||||||
|
connect(mEditIdAction, SIGNAL(triggered()), this, SLOT(editCell()));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<CSMWorld::UniversalId> CSVWorld::NestedTable::getDraggedRecords() const
|
std::vector<CSMWorld::UniversalId> CSVWorld::NestedTable::getDraggedRecords() const
|
||||||
|
@ -69,6 +75,15 @@ void CSVWorld::NestedTable::contextMenuEvent (QContextMenuEvent *event)
|
||||||
|
|
||||||
QMenu menu(this);
|
QMenu menu(this);
|
||||||
|
|
||||||
|
int currentRow = rowAt(event->y());
|
||||||
|
int currentColumn = columnAt(event->x());
|
||||||
|
if (mEditIdAction->isValidIdCell(currentRow, currentColumn))
|
||||||
|
{
|
||||||
|
mEditIdAction->setCell(currentRow, currentColumn);
|
||||||
|
menu.addAction(mEditIdAction);
|
||||||
|
menu.addSeparator();
|
||||||
|
}
|
||||||
|
|
||||||
if (selectionModel()->selectedRows().size() == 1)
|
if (selectionModel()->selectedRows().size() == 1)
|
||||||
menu.addAction(mRemoveRowAction);
|
menu.addAction(mRemoveRowAction);
|
||||||
|
|
||||||
|
@ -92,3 +107,8 @@ void CSVWorld::NestedTable::addNewRowActionTriggered()
|
||||||
selectionModel()->selectedRows().size(),
|
selectionModel()->selectedRows().size(),
|
||||||
mModel->getParentColumn()));
|
mModel->getParentColumn()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVWorld::NestedTable::editCell()
|
||||||
|
{
|
||||||
|
emit editRequest(mEditIdAction->getCurrentId(), "");
|
||||||
|
}
|
||||||
|
|
|
@ -22,12 +22,15 @@ namespace CSMDoc
|
||||||
|
|
||||||
namespace CSVWorld
|
namespace CSVWorld
|
||||||
{
|
{
|
||||||
|
class TableEditIdAction;
|
||||||
|
|
||||||
class NestedTable : public DragRecordTable
|
class NestedTable : public DragRecordTable
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
QAction *mAddNewRowAction;
|
QAction *mAddNewRowAction;
|
||||||
QAction *mRemoveRowAction;
|
QAction *mRemoveRowAction;
|
||||||
|
TableEditIdAction *mEditIdAction;
|
||||||
CSMWorld::NestedTableProxyModel* mModel;
|
CSMWorld::NestedTableProxyModel* mModel;
|
||||||
CSMWorld::CommandDispatcher *mDispatcher;
|
CSMWorld::CommandDispatcher *mDispatcher;
|
||||||
|
|
||||||
|
@ -46,6 +49,11 @@ namespace CSVWorld
|
||||||
void removeRowActionTriggered();
|
void removeRowActionTriggered();
|
||||||
|
|
||||||
void addNewRowActionTriggered();
|
void addNewRowActionTriggered();
|
||||||
|
|
||||||
|
void editCell();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void editRequest(const CSMWorld::UniversalId &id, const std::string &hint);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -276,11 +276,11 @@ void CSVWorld::ScriptEdit::lineNumberAreaPaintEvent(QPaintEvent *event)
|
||||||
if(textCursor().hasSelection())
|
if(textCursor().hasSelection())
|
||||||
{
|
{
|
||||||
QString str = textCursor().selection().toPlainText();
|
QString str = textCursor().selection().toPlainText();
|
||||||
int selectedLines = str.count("\n")+1;
|
int offset = str.count("\n");
|
||||||
if(textCursor().position() < textCursor().anchor())
|
if(textCursor().position() < textCursor().anchor())
|
||||||
endBlock += selectedLines;
|
endBlock += offset;
|
||||||
else
|
else
|
||||||
startBlock -= selectedLines;
|
startBlock -= offset;
|
||||||
}
|
}
|
||||||
painter.setBackgroundMode(Qt::OpaqueMode);
|
painter.setBackgroundMode(Qt::OpaqueMode);
|
||||||
QFont font = painter.font();
|
QFont font = painter.font();
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include "../../model/settings/usersettings.hpp"
|
#include "../../model/settings/usersettings.hpp"
|
||||||
|
|
||||||
#include "recordstatusdelegate.hpp"
|
#include "recordstatusdelegate.hpp"
|
||||||
|
#include "tableeditidaction.hpp"
|
||||||
#include "util.hpp"
|
#include "util.hpp"
|
||||||
|
|
||||||
void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event)
|
void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event)
|
||||||
|
@ -58,33 +59,13 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event)
|
||||||
|
|
||||||
/// \todo add menu items for select all and clear selection
|
/// \todo add menu items for select all and clear selection
|
||||||
|
|
||||||
|
int currentRow = rowAt(event->y());
|
||||||
|
int currentColumn = columnAt(event->x());
|
||||||
|
if (mEditIdAction->isValidIdCell(currentRow, currentColumn))
|
||||||
{
|
{
|
||||||
// Request UniversalId editing from table columns.
|
mEditIdAction->setCell(currentRow, currentColumn);
|
||||||
|
menu.addAction(mEditIdAction);
|
||||||
int currRow = rowAt( event->y() ),
|
menu.addSeparator();
|
||||||
currCol = columnAt( event->x() );
|
|
||||||
|
|
||||||
currRow = mProxyModel->mapToSource(mProxyModel->index( currRow, 0 )).row();
|
|
||||||
|
|
||||||
CSMWorld::ColumnBase::Display colDisplay =
|
|
||||||
static_cast<CSMWorld::ColumnBase::Display>(
|
|
||||||
mModel->headerData(
|
|
||||||
currCol,
|
|
||||||
Qt::Horizontal,
|
|
||||||
CSMWorld::ColumnBase::Role_Display ).toInt());
|
|
||||||
|
|
||||||
QString cellData = mModel->data(mModel->index( currRow, currCol )).toString();
|
|
||||||
CSMWorld::UniversalId::Type colType = CSMWorld::TableMimeData::convertEnums( colDisplay );
|
|
||||||
|
|
||||||
if ( !cellData.isEmpty()
|
|
||||||
&& colType != CSMWorld::UniversalId::Type_None )
|
|
||||||
{
|
|
||||||
mEditCellAction->setText(tr("Edit '").append(cellData).append("'"));
|
|
||||||
|
|
||||||
menu.addAction( mEditCellAction );
|
|
||||||
|
|
||||||
mEditCellId = CSMWorld::UniversalId( colType, cellData.toUtf8().constData() );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mEditLock && !(mModel->getFeatures() & CSMWorld::IdTableBase::Feature_Constant))
|
if (!mEditLock && !(mModel->getFeatures() & CSMWorld::IdTableBase::Feature_Constant))
|
||||||
|
@ -363,10 +344,6 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id,
|
||||||
connect (mMoveDownAction, SIGNAL (triggered()), this, SLOT (moveDownRecord()));
|
connect (mMoveDownAction, SIGNAL (triggered()), this, SLOT (moveDownRecord()));
|
||||||
addAction (mMoveDownAction);
|
addAction (mMoveDownAction);
|
||||||
|
|
||||||
mEditCellAction = new QAction( tr("Edit Cell"), this );
|
|
||||||
connect( mEditCellAction, SIGNAL(triggered()), this, SLOT(editCell()) );
|
|
||||||
addAction( mEditCellAction );
|
|
||||||
|
|
||||||
mViewAction = new QAction (tr ("View"), this);
|
mViewAction = new QAction (tr ("View"), this);
|
||||||
connect (mViewAction, SIGNAL (triggered()), this, SLOT (viewRecord()));
|
connect (mViewAction, SIGNAL (triggered()), this, SLOT (viewRecord()));
|
||||||
addAction (mViewAction);
|
addAction (mViewAction);
|
||||||
|
@ -387,6 +364,10 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id,
|
||||||
connect (mExtendedRevertAction, SIGNAL (triggered()), mDispatcher, SLOT (executeExtendedRevert()));
|
connect (mExtendedRevertAction, SIGNAL (triggered()), mDispatcher, SLOT (executeExtendedRevert()));
|
||||||
addAction (mExtendedRevertAction);
|
addAction (mExtendedRevertAction);
|
||||||
|
|
||||||
|
mEditIdAction = new TableEditIdAction (*this, this);
|
||||||
|
connect (mEditIdAction, SIGNAL (triggered()), this, SLOT (editCell()));
|
||||||
|
addAction (mEditIdAction);
|
||||||
|
|
||||||
connect (mProxyModel, SIGNAL (rowsRemoved (const QModelIndex&, int, int)),
|
connect (mProxyModel, SIGNAL (rowsRemoved (const QModelIndex&, int, int)),
|
||||||
this, SLOT (tableSizeUpdate()));
|
this, SLOT (tableSizeUpdate()));
|
||||||
|
|
||||||
|
@ -522,7 +503,7 @@ void CSVWorld::Table::moveDownRecord()
|
||||||
|
|
||||||
void CSVWorld::Table::editCell()
|
void CSVWorld::Table::editCell()
|
||||||
{
|
{
|
||||||
emit editRequest( mEditCellId, std::string() );
|
emit editRequest(mEditIdAction->getCurrentId(), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVWorld::Table::viewRecord()
|
void CSVWorld::Table::viewRecord()
|
||||||
|
|
|
@ -30,6 +30,7 @@ namespace CSMWorld
|
||||||
namespace CSVWorld
|
namespace CSVWorld
|
||||||
{
|
{
|
||||||
class CommandDelegate;
|
class CommandDelegate;
|
||||||
|
class TableEditIdAction;
|
||||||
|
|
||||||
///< Table widget
|
///< Table widget
|
||||||
class Table : public DragRecordTable
|
class Table : public DragRecordTable
|
||||||
|
@ -57,15 +58,14 @@ namespace CSVWorld
|
||||||
QAction *mMoveUpAction;
|
QAction *mMoveUpAction;
|
||||||
QAction *mMoveDownAction;
|
QAction *mMoveDownAction;
|
||||||
QAction *mViewAction;
|
QAction *mViewAction;
|
||||||
QAction *mEditCellAction;
|
|
||||||
QAction *mPreviewAction;
|
QAction *mPreviewAction;
|
||||||
QAction *mExtendedDeleteAction;
|
QAction *mExtendedDeleteAction;
|
||||||
QAction *mExtendedRevertAction;
|
QAction *mExtendedRevertAction;
|
||||||
|
TableEditIdAction *mEditIdAction;
|
||||||
CSMWorld::IdTableProxyModel *mProxyModel;
|
CSMWorld::IdTableProxyModel *mProxyModel;
|
||||||
CSMWorld::IdTableBase *mModel;
|
CSMWorld::IdTableBase *mModel;
|
||||||
int mRecordStatusDisplay;
|
int mRecordStatusDisplay;
|
||||||
CSMWorld::CommandDispatcher *mDispatcher;
|
CSMWorld::CommandDispatcher *mDispatcher;
|
||||||
CSMWorld::UniversalId mEditCellId;
|
|
||||||
std::map<Qt::KeyboardModifiers, DoubleClickAction> mDoubleClickActions;
|
std::map<Qt::KeyboardModifiers, DoubleClickAction> mDoubleClickActions;
|
||||||
bool mJumpToAddedRecord;
|
bool mJumpToAddedRecord;
|
||||||
bool mUnselectAfterJump;
|
bool mUnselectAfterJump;
|
||||||
|
|
49
apps/opencs/view/world/tableeditidaction.cpp
Normal file
49
apps/opencs/view/world/tableeditidaction.cpp
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
#include "tableeditidaction.hpp"
|
||||||
|
|
||||||
|
#include <QTableView>
|
||||||
|
|
||||||
|
#include "../../model/world/tablemimedata.hpp"
|
||||||
|
|
||||||
|
CSVWorld::TableEditIdAction::CellData CSVWorld::TableEditIdAction::getCellData(int row, int column) const
|
||||||
|
{
|
||||||
|
QModelIndex index = mTable.model()->index(row, column);
|
||||||
|
if (index.isValid())
|
||||||
|
{
|
||||||
|
QVariant display = mTable.model()->data(index, CSMWorld::ColumnBase::Role_Display);
|
||||||
|
QString value = mTable.model()->data(index).toString();
|
||||||
|
return std::make_pair(static_cast<CSMWorld::ColumnBase::Display>(display.toInt()), value);
|
||||||
|
}
|
||||||
|
return std::make_pair(CSMWorld::ColumnBase::Display_None, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
CSVWorld::TableEditIdAction::TableEditIdAction(const QTableView &table, QWidget *parent)
|
||||||
|
: QAction(parent),
|
||||||
|
mTable(table),
|
||||||
|
mCurrentId(CSMWorld::UniversalId::Type_None)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void CSVWorld::TableEditIdAction::setCell(int row, int column)
|
||||||
|
{
|
||||||
|
CellData data = getCellData(row, column);
|
||||||
|
CSMWorld::UniversalId::Type idType = CSMWorld::TableMimeData::convertEnums(data.first);
|
||||||
|
|
||||||
|
if (idType != CSMWorld::UniversalId::Type_None)
|
||||||
|
{
|
||||||
|
mCurrentId = CSMWorld::UniversalId(idType, data.second.toUtf8().constData());
|
||||||
|
setText("Edit '" + data.second + "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CSMWorld::UniversalId CSVWorld::TableEditIdAction::getCurrentId() const
|
||||||
|
{
|
||||||
|
return mCurrentId;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CSVWorld::TableEditIdAction::isValidIdCell(int row, int column) const
|
||||||
|
{
|
||||||
|
CellData data = getCellData(row, column);
|
||||||
|
CSMWorld::UniversalId::Type idType = CSMWorld::TableMimeData::convertEnums(data.first);
|
||||||
|
return CSMWorld::ColumnBase::isId(data.first) &&
|
||||||
|
idType != CSMWorld::UniversalId::Type_None &&
|
||||||
|
!data.second.isEmpty();
|
||||||
|
}
|
31
apps/opencs/view/world/tableeditidaction.hpp
Normal file
31
apps/opencs/view/world/tableeditidaction.hpp
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
#ifndef CSVWORLD_TABLEEDITIDACTION_HPP
|
||||||
|
#define CSVWORLD_TABLEEDITIDACTION_HPP
|
||||||
|
|
||||||
|
#include <QAction>
|
||||||
|
|
||||||
|
#include "../../model/world/columnbase.hpp"
|
||||||
|
#include "../../model/world/universalid.hpp"
|
||||||
|
|
||||||
|
class QTableView;
|
||||||
|
|
||||||
|
namespace CSVWorld
|
||||||
|
{
|
||||||
|
class TableEditIdAction : public QAction
|
||||||
|
{
|
||||||
|
const QTableView &mTable;
|
||||||
|
CSMWorld::UniversalId mCurrentId;
|
||||||
|
|
||||||
|
typedef std::pair<CSMWorld::ColumnBase::Display, QString> CellData;
|
||||||
|
CellData getCellData(int row, int column) const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
TableEditIdAction(const QTableView &table, QWidget *parent = 0);
|
||||||
|
|
||||||
|
void setCell(int row, int column);
|
||||||
|
|
||||||
|
CSMWorld::UniversalId getCurrentId() const;
|
||||||
|
bool isValidIdCell(int row, int column) const;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -14,7 +14,9 @@
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
// For OutputDebugString
|
// For OutputDebugString
|
||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#endif
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
// makes __argc and __argv available on windows
|
// makes __argc and __argv available on windows
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <components/esm/loaddial.hpp>
|
#include <components/esm/loaddial.hpp>
|
||||||
#include <components/esm/loadinfo.hpp>
|
#include <components/esm/loadinfo.hpp>
|
||||||
#include <components/esm/dialoguestate.hpp>
|
#include <components/esm/dialoguestate.hpp>
|
||||||
|
#include <components/esm/esmwriter.hpp>
|
||||||
|
|
||||||
#include <components/compiler/exception.hpp>
|
#include <components/compiler/exception.hpp>
|
||||||
#include <components/compiler/errorhandler.hpp>
|
#include <components/compiler/errorhandler.hpp>
|
||||||
|
|
|
@ -203,6 +203,8 @@ bool MWDialogue::Filter::testSelectStructNumeric (const SelectWrapper& select) c
|
||||||
return false; // script does not have a variable of this name.
|
return false; // script does not have a variable of this name.
|
||||||
|
|
||||||
int index = localDefs.getIndex (name);
|
int index = localDefs.getIndex (name);
|
||||||
|
if (index < 0)
|
||||||
|
return false; // shouldn't happen, we checked that variable has a type above, so must exist
|
||||||
|
|
||||||
const MWScript::Locals& locals = mActor.getRefData().getLocals();
|
const MWScript::Locals& locals = mActor.getRefData().getLocals();
|
||||||
|
|
||||||
|
|
|
@ -10,10 +10,14 @@
|
||||||
|
|
||||||
#include <osg/Texture2D>
|
#include <osg/Texture2D>
|
||||||
|
|
||||||
|
#include <components/misc/stringops.hpp>
|
||||||
|
|
||||||
#include <components/myguiplatform/myguitexture.hpp>
|
#include <components/myguiplatform/myguitexture.hpp>
|
||||||
|
|
||||||
#include <components/settings/settings.hpp>
|
#include <components/settings/settings.hpp>
|
||||||
|
|
||||||
|
#include <components/misc/stringops.hpp>
|
||||||
|
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/soundmanager.hpp"
|
#include "../mwbase/soundmanager.hpp"
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <MyGUI_FactoryManager.h>
|
#include <MyGUI_FactoryManager.h>
|
||||||
|
|
||||||
#include <components/esm/globalmap.hpp>
|
#include <components/esm/globalmap.hpp>
|
||||||
|
#include <components/esm/esmwriter.hpp>
|
||||||
#include <components/settings/settings.hpp>
|
#include <components/settings/settings.hpp>
|
||||||
#include <components/myguiplatform/myguitexture.hpp>
|
#include <components/myguiplatform/myguitexture.hpp>
|
||||||
|
|
||||||
|
|
|
@ -72,6 +72,11 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
MarkerUserData(MWRender::LocalMap* map)
|
MarkerUserData(MWRender::LocalMap* map)
|
||||||
: mLocalMapRender(map)
|
: mLocalMapRender(map)
|
||||||
|
, interior(false)
|
||||||
|
, cellX(0)
|
||||||
|
, cellY(0)
|
||||||
|
, nX(0.f)
|
||||||
|
, nY(0.f)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <MyGUI_Gui.h>
|
#include <MyGUI_Gui.h>
|
||||||
#include <MyGUI_ImageBox.h>
|
#include <MyGUI_ImageBox.h>
|
||||||
|
|
||||||
|
#include <components/esm/esmwriter.hpp>
|
||||||
#include <components/esm/quickkeys.hpp>
|
#include <components/esm/quickkeys.hpp>
|
||||||
|
|
||||||
#include "../mwworld/inventorystore.hpp"
|
#include "../mwworld/inventorystore.hpp"
|
||||||
|
|
|
@ -22,6 +22,9 @@
|
||||||
|
|
||||||
#include <components/sdlutil/sdlcursormanager.hpp>
|
#include <components/sdlutil/sdlcursormanager.hpp>
|
||||||
|
|
||||||
|
#include <components/esm/esmreader.hpp>
|
||||||
|
#include <components/esm/esmwriter.hpp>
|
||||||
|
|
||||||
#include <components/fontloader/fontloader.hpp>
|
#include <components/fontloader/fontloader.hpp>
|
||||||
|
|
||||||
#include <components/resource/resourcesystem.hpp>
|
#include <components/resource/resourcesystem.hpp>
|
||||||
|
@ -893,6 +896,9 @@ namespace MWGui
|
||||||
|
|
||||||
void WindowManager::updateMap()
|
void WindowManager::updateMap()
|
||||||
{
|
{
|
||||||
|
if (!mLocalMapRender)
|
||||||
|
return;
|
||||||
|
|
||||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||||
|
|
||||||
osg::Vec3f playerPosition = player.getRefData().getPosition().asVec3();
|
osg::Vec3f playerPosition = player.getRefData().getPosition().asVec3();
|
||||||
|
|
|
@ -4,7 +4,10 @@
|
||||||
|
|
||||||
#include <osg/PositionAttitudeTransform>
|
#include <osg/PositionAttitudeTransform>
|
||||||
|
|
||||||
|
#include <components/esm/esmreader.hpp>
|
||||||
|
#include <components/esm/esmwriter.hpp>
|
||||||
#include <components/esm/loadnpc.hpp>
|
#include <components/esm/loadnpc.hpp>
|
||||||
|
#include <components/esm/esmreader.hpp>
|
||||||
|
|
||||||
#include "../mwworld/esmstore.hpp"
|
#include "../mwworld/esmstore.hpp"
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
|
|
|
@ -31,8 +31,6 @@ namespace
|
||||||
//chooses an attack depending on probability to avoid uniformity
|
//chooses an attack depending on probability to avoid uniformity
|
||||||
ESM::Weapon::AttackType chooseBestAttack(const ESM::Weapon* weapon, MWMechanics::Movement &movement);
|
ESM::Weapon::AttackType chooseBestAttack(const ESM::Weapon* weapon, MWMechanics::Movement &movement);
|
||||||
|
|
||||||
void getMinMaxAttackDuration(const MWWorld::Ptr& actor, float (*fMinMaxDurations)[2]);
|
|
||||||
|
|
||||||
osg::Vec3f AimDirToMovingTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, const osg::Vec3f& vLastTargetPos,
|
osg::Vec3f AimDirToMovingTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, const osg::Vec3f& vLastTargetPos,
|
||||||
float duration, int weapType, float strength);
|
float duration, int weapType, float strength);
|
||||||
|
|
||||||
|
@ -83,7 +81,7 @@ namespace MWMechanics
|
||||||
/// \brief This class holds the variables AiCombat needs which are deleted if the package becomes inactive.
|
/// \brief This class holds the variables AiCombat needs which are deleted if the package becomes inactive.
|
||||||
struct AiCombatStorage : AiTemporaryBase
|
struct AiCombatStorage : AiTemporaryBase
|
||||||
{
|
{
|
||||||
float mTimerAttack;
|
float mAttackCooldown;
|
||||||
float mTimerReact;
|
float mTimerReact;
|
||||||
float mTimerCombatMove;
|
float mTimerCombatMove;
|
||||||
bool mReadyToAttack;
|
bool mReadyToAttack;
|
||||||
|
@ -95,15 +93,13 @@ namespace MWMechanics
|
||||||
boost::shared_ptr<Action> mCurrentAction;
|
boost::shared_ptr<Action> mCurrentAction;
|
||||||
float mActionCooldown;
|
float mActionCooldown;
|
||||||
float mStrength;
|
float mStrength;
|
||||||
float mMinMaxAttackDuration[3][2];
|
|
||||||
bool mMinMaxAttackDurationInitialised;
|
|
||||||
bool mForceNoShortcut;
|
bool mForceNoShortcut;
|
||||||
ESM::Position mShortcutFailPos;
|
ESM::Position mShortcutFailPos;
|
||||||
osg::Vec3f mLastActorPos;
|
osg::Vec3f mLastActorPos;
|
||||||
MWMechanics::Movement mMovement;
|
MWMechanics::Movement mMovement;
|
||||||
|
|
||||||
AiCombatStorage():
|
AiCombatStorage():
|
||||||
mTimerAttack(0),
|
mAttackCooldown(0),
|
||||||
mTimerReact(0),
|
mTimerReact(0),
|
||||||
mTimerCombatMove(0),
|
mTimerCombatMove(0),
|
||||||
mReadyToAttack(false),
|
mReadyToAttack(false),
|
||||||
|
@ -115,7 +111,6 @@ namespace MWMechanics
|
||||||
mCurrentAction(),
|
mCurrentAction(),
|
||||||
mActionCooldown(0),
|
mActionCooldown(0),
|
||||||
mStrength(),
|
mStrength(),
|
||||||
mMinMaxAttackDurationInitialised(false),
|
|
||||||
mForceNoShortcut(false),
|
mForceNoShortcut(false),
|
||||||
mLastActorPos(0,0,0),
|
mLastActorPos(0,0,0),
|
||||||
mMovement(){}
|
mMovement(){}
|
||||||
|
@ -233,41 +228,12 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
if(smoothTurn(actor, osg::DegreesToRadians(movement.mRotation[0]), 0)) movement.mRotation[0] = 0;
|
if(smoothTurn(actor, osg::DegreesToRadians(movement.mRotation[0]), 0)) movement.mRotation[0] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
float attacksPeriod = 1.0f;
|
|
||||||
|
|
||||||
ESM::Weapon::AttackType attackType;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool& attack = storage.mAttack;
|
bool& attack = storage.mAttack;
|
||||||
bool& readyToAttack = storage.mReadyToAttack;
|
bool& readyToAttack = storage.mReadyToAttack;
|
||||||
float& timerAttack = storage.mTimerAttack;
|
|
||||||
|
|
||||||
bool& minMaxAttackDurationInitialised = storage.mMinMaxAttackDurationInitialised;
|
|
||||||
float (&minMaxAttackDuration)[3][2] = storage.mMinMaxAttackDuration;
|
|
||||||
|
|
||||||
if(readyToAttack)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!minMaxAttackDurationInitialised)
|
if (attack && (characterController.getAttackStrength() >= storage.mStrength || characterController.readyToPrepareAttack()))
|
||||||
{
|
|
||||||
// TODO: this must be updated when a different weapon is equipped
|
|
||||||
// TODO: it would be much easier to ask the CharacterController about the current % completion of the weapon wind-up animation
|
|
||||||
getMinMaxAttackDuration(actor, minMaxAttackDuration);
|
|
||||||
minMaxAttackDurationInitialised = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (timerAttack < 0) attack = false;
|
|
||||||
|
|
||||||
timerAttack -= duration;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
timerAttack = -attacksPeriod;
|
|
||||||
attack = false;
|
attack = false;
|
||||||
}
|
|
||||||
|
|
||||||
characterController.setAttackingOrSpell(attack);
|
characterController.setAttackingOrSpell(attack);
|
||||||
|
|
||||||
|
@ -300,10 +266,6 @@ namespace MWMechanics
|
||||||
currentCell = actor.getCell();
|
currentCell = actor.getCell();
|
||||||
}
|
}
|
||||||
|
|
||||||
MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(actor);
|
|
||||||
if (!anim) // shouldn't happen
|
|
||||||
return false;
|
|
||||||
|
|
||||||
actorClass.getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true);
|
actorClass.getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true);
|
||||||
|
|
||||||
if (actionCooldown > 0)
|
if (actionCooldown > 0)
|
||||||
|
@ -312,11 +274,7 @@ namespace MWMechanics
|
||||||
float rangeAttack = 0;
|
float rangeAttack = 0;
|
||||||
float rangeFollow = 0;
|
float rangeFollow = 0;
|
||||||
boost::shared_ptr<Action>& currentAction = storage.mCurrentAction;
|
boost::shared_ptr<Action>& currentAction = storage.mCurrentAction;
|
||||||
// TODO: upperBodyReady() works fine for checking if we can start an attack,
|
if (characterController.readyToPrepareAttack())
|
||||||
// but doesn't work properly for checking if the attack is finished (as things like hit recovery or knockdown also play on the upper body)
|
|
||||||
// Only a minor problem, but can mess with the actionCooldown timer.
|
|
||||||
// To fix this the AI needs to be brought closer to the CharacterController, so we can simply check if a weapon animation is playing.
|
|
||||||
if (anim->upperBodyReady())
|
|
||||||
{
|
{
|
||||||
currentAction = prepareNextAction(actor, target);
|
currentAction = prepareNextAction(actor, target);
|
||||||
actionCooldown = currentAction->getActionCooldown();
|
actionCooldown = currentAction->getActionCooldown();
|
||||||
|
@ -333,9 +291,6 @@ namespace MWMechanics
|
||||||
// Get weapon characteristics
|
// Get weapon characteristics
|
||||||
if (actorClass.hasInventoryStore(actor))
|
if (actorClass.hasInventoryStore(actor))
|
||||||
{
|
{
|
||||||
// TODO: Check equipped weapon and equip a different one if we can't attack with it
|
|
||||||
// (e.g. no ammunition, or wrong type of ammunition equipped, etc. autoEquip is not very smart in this regard))
|
|
||||||
|
|
||||||
//Get weapon speed and range
|
//Get weapon speed and range
|
||||||
MWWorld::ContainerStoreIterator weaponSlot =
|
MWWorld::ContainerStoreIterator weaponSlot =
|
||||||
MWMechanics::getActiveWeapon(actorClass.getCreatureStats(actor), actorClass.getInventoryStore(actor), &weaptype);
|
MWMechanics::getActiveWeapon(actorClass.getCreatureStats(actor), actorClass.getInventoryStore(actor), &weaptype);
|
||||||
|
@ -383,34 +338,38 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
float& strength = storage.mStrength;
|
float& strength = storage.mStrength;
|
||||||
// start new attack
|
// start new attack
|
||||||
if(readyToAttack)
|
if(readyToAttack && characterController.readyToStartAttack())
|
||||||
{
|
{
|
||||||
if(timerAttack <= -attacksPeriod)
|
if (storage.mAttackCooldown <= 0)
|
||||||
{
|
{
|
||||||
attack = true; // attack starts just now
|
attack = true; // attack starts just now
|
||||||
|
characterController.setAttackingOrSpell(attack);
|
||||||
|
|
||||||
if (!distantCombat) attackType = chooseBestAttack(weapon, movement);
|
if (!distantCombat)
|
||||||
else attackType = ESM::Weapon::AT_Chop; // cause it's =0
|
chooseBestAttack(weapon, movement);
|
||||||
|
|
||||||
strength = Misc::Rng::rollClosedProbability();
|
strength = Misc::Rng::rollClosedProbability();
|
||||||
|
|
||||||
// Note: may be 0 for some animations
|
const MWWorld::ESMStore &store = world->getStore();
|
||||||
timerAttack = minMaxAttackDuration[attackType][0] +
|
|
||||||
(minMaxAttackDuration[attackType][1] - minMaxAttackDuration[attackType][0]) * strength;
|
|
||||||
|
|
||||||
//say a provoking combat phrase
|
//say a provoking combat phrase
|
||||||
if (actor.getClass().isNpc())
|
if (actor.getClass().isNpc())
|
||||||
{
|
{
|
||||||
const MWWorld::ESMStore &store = world->getStore();
|
|
||||||
int chance = store.get<ESM::GameSetting>().find("iVoiceAttackOdds")->getInt();
|
int chance = store.get<ESM::GameSetting>().find("iVoiceAttackOdds")->getInt();
|
||||||
if (Misc::Rng::roll0to99() < chance)
|
if (Misc::Rng::roll0to99() < chance)
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getDialogueManager()->say(actor, "attack");
|
MWBase::Environment::get().getDialogueManager()->say(actor, "attack");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
float baseDelay = store.get<ESM::GameSetting>().find("fCombatDelayCreature")->getFloat();
|
||||||
|
if (actor.getClass().isNpc())
|
||||||
|
baseDelay = store.get<ESM::GameSetting>().find("fCombatDelayNPC")->getFloat();
|
||||||
|
storage.mAttackCooldown = std::min(baseDelay + 0.01 * Misc::Rng::roll0to99(), baseDelay + 0.9);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
storage.mAttackCooldown -= tReaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -618,57 +577,6 @@ namespace MWMechanics
|
||||||
readyToAttack = false;
|
readyToAttack = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!isStuck && distToTarget > rangeAttack && !distantCombat)
|
|
||||||
{
|
|
||||||
//special run attack; it shouldn't affect melee combat tactics
|
|
||||||
if(actorClass.getMovementSettings(actor).mPosition[1] == 1)
|
|
||||||
{
|
|
||||||
/* check if actor can overcome the distance = distToTarget - attackerWeapRange
|
|
||||||
less than in time of swinging with weapon (t_swing), then start attacking
|
|
||||||
*/
|
|
||||||
float speed1 = actorClass.getSpeed(actor);
|
|
||||||
float speed2 = target.getClass().getSpeed(target);
|
|
||||||
if(target.getClass().getMovementSettings(target).mPosition[0] == 0
|
|
||||||
&& target.getClass().getMovementSettings(target).mPosition[1] == 0)
|
|
||||||
speed2 = 0;
|
|
||||||
|
|
||||||
float s1 = distToTarget - weapRange;
|
|
||||||
float t = s1/speed1;
|
|
||||||
float s2 = speed2 * t;
|
|
||||||
float t_swing =
|
|
||||||
minMaxAttackDuration[ESM::Weapon::AT_Thrust][0] +
|
|
||||||
(minMaxAttackDuration[ESM::Weapon::AT_Thrust][1] - minMaxAttackDuration[ESM::Weapon::AT_Thrust][0]) * Misc::Rng::rollClosedProbability();
|
|
||||||
|
|
||||||
if (t + s2/speed1 <= t_swing)
|
|
||||||
{
|
|
||||||
readyToAttack = true;
|
|
||||||
if(timerAttack <= -attacksPeriod)
|
|
||||||
{
|
|
||||||
timerAttack = t_swing;
|
|
||||||
attack = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Add a parameter to vary DURATION_SAME_SPOT?
|
|
||||||
if((distToTarget > rangeAttack || followTarget) &&
|
|
||||||
mObstacleCheck.check(actor, tReaction)) // check if evasive action needed
|
|
||||||
{
|
|
||||||
// probably walking into another NPC TODO: untested in combat situation
|
|
||||||
// TODO: diagonal should have same animation as walk forward
|
|
||||||
// but doesn't seem to do that?
|
|
||||||
actor.getClass().getMovementSettings(actor).mPosition[0] = 1;
|
|
||||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 0.1f;
|
|
||||||
// change the angle a bit, too
|
|
||||||
if(mPathFinder.isPathConstructed())
|
|
||||||
zTurn(actor, osg::DegreesToRadians(mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1])));
|
|
||||||
|
|
||||||
if(followTarget)
|
|
||||||
followTarget = false;
|
|
||||||
// FIXME: can fool actors to stay behind doors, etc.
|
|
||||||
// Related to Bug#1102 and to some degree #1155 as well
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -794,70 +702,6 @@ ESM::Weapon::AttackType chooseBestAttack(const ESM::Weapon* weapon, MWMechanics:
|
||||||
return attackType;
|
return attackType;
|
||||||
}
|
}
|
||||||
|
|
||||||
void getMinMaxAttackDuration(const MWWorld::Ptr& actor, float (*fMinMaxDurations)[2])
|
|
||||||
{
|
|
||||||
if (!actor.getClass().hasInventoryStore(actor)) // creatures
|
|
||||||
{
|
|
||||||
fMinMaxDurations[0][0] = fMinMaxDurations[0][1] = 0.1f;
|
|
||||||
fMinMaxDurations[1][0] = fMinMaxDurations[1][1] = 0.1f;
|
|
||||||
fMinMaxDurations[2][0] = fMinMaxDurations[2][1] = 0.1f;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get weapon information: type and speed
|
|
||||||
const ESM::Weapon *weapon = NULL;
|
|
||||||
MWMechanics::WeaponType weaptype = MWMechanics::WeapType_None;
|
|
||||||
|
|
||||||
MWWorld::ContainerStoreIterator weaponSlot =
|
|
||||||
MWMechanics::getActiveWeapon(actor.getClass().getCreatureStats(actor), actor.getClass().getInventoryStore(actor), &weaptype);
|
|
||||||
|
|
||||||
float weapSpeed;
|
|
||||||
if (weaptype != MWMechanics::WeapType_HandToHand
|
|
||||||
&& weaptype != MWMechanics::WeapType_Spell
|
|
||||||
&& weaptype != MWMechanics::WeapType_None)
|
|
||||||
{
|
|
||||||
weapon = weaponSlot->get<ESM::Weapon>()->mBase;
|
|
||||||
weapSpeed = weapon->mData.mSpeed;
|
|
||||||
}
|
|
||||||
else weapSpeed = 1.0f;
|
|
||||||
|
|
||||||
MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(actor);
|
|
||||||
|
|
||||||
std::string weapGroup;
|
|
||||||
MWMechanics::getWeaponGroup(weaptype, weapGroup);
|
|
||||||
weapGroup = weapGroup + ": ";
|
|
||||||
|
|
||||||
bool bRangedWeap = (weaptype >= MWMechanics::WeapType_BowAndArrow && weaptype <= MWMechanics::WeapType_Thrown);
|
|
||||||
|
|
||||||
const char *attackType[] = {"chop ", "slash ", "thrust ", "shoot "};
|
|
||||||
|
|
||||||
std::string textKey = "start";
|
|
||||||
std::string textKey2;
|
|
||||||
|
|
||||||
// get durations for each attack type
|
|
||||||
for (int i = 0; i < (bRangedWeap ? 1 : 3); i++)
|
|
||||||
{
|
|
||||||
float start1 = anim->getTextKeyTime(weapGroup + (bRangedWeap ? attackType[3] : attackType[i]) + textKey);
|
|
||||||
|
|
||||||
if (start1 < 0)
|
|
||||||
{
|
|
||||||
fMinMaxDurations[i][0] = fMinMaxDurations[i][1] = 0.1f;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
textKey2 = "min attack";
|
|
||||||
float start2 = anim->getTextKeyTime(weapGroup + (bRangedWeap ? attackType[3] : attackType[i]) + textKey2);
|
|
||||||
|
|
||||||
fMinMaxDurations[i][0] = (start2 - start1) / weapSpeed;
|
|
||||||
|
|
||||||
textKey2 = "max attack";
|
|
||||||
start1 = anim->getTextKeyTime(weapGroup + (bRangedWeap ? attackType[3] : attackType[i]) + textKey2);
|
|
||||||
|
|
||||||
fMinMaxDurations[i][1] = fMinMaxDurations[i][0] + (start1 - start2) / weapSpeed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
osg::Vec3f AimDirToMovingTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, const osg::Vec3f& vLastTargetPos,
|
osg::Vec3f AimDirToMovingTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, const osg::Vec3f& vLastTargetPos,
|
||||||
float duration, int weapType, float strength)
|
float duration, int weapType, float strength)
|
||||||
{
|
{
|
||||||
|
|
|
@ -184,6 +184,11 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac
|
||||||
const ESM::Position &targetPos = target.getRefData().getPosition();
|
const ESM::Position &targetPos = target.getRefData().getPosition();
|
||||||
|
|
||||||
float distTo = (targetPos.asVec3() - vActorPos).length();
|
float distTo = (targetPos.asVec3() - vActorPos).length();
|
||||||
|
|
||||||
|
// Small threshold for changing target
|
||||||
|
if (it == mPackages.begin())
|
||||||
|
distTo = std::max(0.f, distTo - 50.f);
|
||||||
|
|
||||||
if (distTo < nearestDist)
|
if (distTo < nearestDist)
|
||||||
{
|
{
|
||||||
nearestDist = distTo;
|
nearestDist = distTo;
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "aiwander.hpp"
|
#include "aiwander.hpp"
|
||||||
|
|
||||||
|
#include <cfloat>
|
||||||
|
|
||||||
#include <components/misc/rng.hpp>
|
#include <components/misc/rng.hpp>
|
||||||
|
|
||||||
#include <components/esm/aisequence.hpp>
|
#include <components/esm/aisequence.hpp>
|
||||||
|
@ -28,6 +30,12 @@ namespace MWMechanics
|
||||||
static const int GREETING_SHOULD_START = 4; //how many reaction intervals should pass before NPC can greet player
|
static const int GREETING_SHOULD_START = 4; //how many reaction intervals should pass before NPC can greet player
|
||||||
static const int GREETING_SHOULD_END = 10;
|
static const int GREETING_SHOULD_END = 10;
|
||||||
|
|
||||||
|
// to prevent overcrowding
|
||||||
|
static const int DESTINATION_TOLERANCE = 64;
|
||||||
|
|
||||||
|
// distance must be long enough that NPC will need to move to get there.
|
||||||
|
static const int MINIMUM_WANDER_DISTANCE = DESTINATION_TOLERANCE * 2;
|
||||||
|
|
||||||
const std::string AiWander::sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1] =
|
const std::string AiWander::sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1] =
|
||||||
{
|
{
|
||||||
std::string("idle2"),
|
std::string("idle2"),
|
||||||
|
@ -214,7 +222,7 @@ namespace MWMechanics
|
||||||
// Are we there yet?
|
// Are we there yet?
|
||||||
bool& chooseAction = storage.mChooseAction;
|
bool& chooseAction = storage.mChooseAction;
|
||||||
if(walking &&
|
if(walking &&
|
||||||
storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], 64.f))
|
storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], DESTINATION_TOLERANCE))
|
||||||
{
|
{
|
||||||
stopWalking(actor, storage);
|
stopWalking(actor, storage);
|
||||||
moveNow = false;
|
moveNow = false;
|
||||||
|
@ -267,6 +275,7 @@ namespace MWMechanics
|
||||||
moveNow = false;
|
moveNow = false;
|
||||||
walking = false;
|
walking = false;
|
||||||
chooseAction = true;
|
chooseAction = true;
|
||||||
|
mStuckCount = 0;
|
||||||
}
|
}
|
||||||
//#endif
|
//#endif
|
||||||
}
|
}
|
||||||
|
@ -410,7 +419,7 @@ namespace MWMechanics
|
||||||
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
|
||||||
storage.mPathFinder.buildPath(start, dest, actor.getCell(), false);
|
storage.mPathFinder.buildSyncedPath(start, dest, actor.getCell(), false);
|
||||||
|
|
||||||
if(storage.mPathFinder.isPathConstructed())
|
if(storage.mPathFinder.isPathConstructed())
|
||||||
{
|
{
|
||||||
|
@ -497,30 +506,17 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
assert(mAllowedNodes.size());
|
assert(mAllowedNodes.size());
|
||||||
unsigned int randNode = Misc::Rng::rollDice(mAllowedNodes.size());
|
unsigned int randNode = Misc::Rng::rollDice(mAllowedNodes.size());
|
||||||
// NOTE: initially constructed with local (i.e. cell) co-ordinates
|
|
||||||
// convert dest to use world co-ordinates
|
|
||||||
ESM::Pathgrid::Point dest(mAllowedNodes[randNode]);
|
ESM::Pathgrid::Point dest(mAllowedNodes[randNode]);
|
||||||
if (currentCell->getCell()->isExterior())
|
ToWorldCoordinates(dest, currentCell->getCell());
|
||||||
{
|
|
||||||
dest.mX += currentCell->getCell()->mData.mX * ESM::Land::REAL_SIZE;
|
|
||||||
dest.mY += currentCell->getCell()->mData.mY * ESM::Land::REAL_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// actor position is already in world co-ordinates
|
// actor position is already in world co-ordinates
|
||||||
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
|
||||||
storage.mPathFinder.buildPath(start, dest, actor.getCell(), false);
|
storage.mPathFinder.buildSyncedPath(start, dest, actor.getCell(), false);
|
||||||
|
|
||||||
if(storage.mPathFinder.isPathConstructed())
|
if(storage.mPathFinder.isPathConstructed())
|
||||||
{
|
{
|
||||||
// buildPath inserts dest in case it is not a pathgraph point
|
|
||||||
// index which is a duplicate for AiWander. However below code
|
|
||||||
// does not work since getPath() returns a copy of path not a
|
|
||||||
// reference
|
|
||||||
//if(storage.mPathFinder.getPathSize() > 1)
|
|
||||||
//storage.mPathFinder.getPath().pop_back();
|
|
||||||
|
|
||||||
// Remove this node as an option and add back the previously used node (stops NPC from picking the same node):
|
// Remove this node as an option and add back the previously used node (stops NPC from picking the same node):
|
||||||
ESM::Pathgrid::Point temp = mAllowedNodes[randNode];
|
ESM::Pathgrid::Point temp = mAllowedNodes[randNode];
|
||||||
mAllowedNodes.erase(mAllowedNodes.begin() + randNode);
|
mAllowedNodes.erase(mAllowedNodes.begin() + randNode);
|
||||||
|
@ -543,6 +539,15 @@ namespace MWMechanics
|
||||||
return false; // AiWander package not yet completed
|
return false; // AiWander package not yet completed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AiWander::ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::Cell * cell)
|
||||||
|
{
|
||||||
|
if (cell->isExterior())
|
||||||
|
{
|
||||||
|
point.mX += cell->mData.mX * ESM::Land::REAL_SIZE;
|
||||||
|
point.mY += cell->mData.mY * ESM::Land::REAL_SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AiWander::trimAllowedNodes(std::vector<ESM::Pathgrid::Point>& nodes,
|
void AiWander::trimAllowedNodes(std::vector<ESM::Pathgrid::Point>& nodes,
|
||||||
const PathFinder& pathfinder)
|
const PathFinder& pathfinder)
|
||||||
{
|
{
|
||||||
|
@ -646,15 +651,9 @@ namespace MWMechanics
|
||||||
int index = Misc::Rng::rollDice(mAllowedNodes.size());
|
int index = Misc::Rng::rollDice(mAllowedNodes.size());
|
||||||
ESM::Pathgrid::Point dest = mAllowedNodes[index];
|
ESM::Pathgrid::Point dest = mAllowedNodes[index];
|
||||||
|
|
||||||
// apply a slight offset to prevent overcrowding
|
dest.mX += OffsetToPreventOvercrowding();
|
||||||
dest.mX += static_cast<int>(Misc::Rng::rollProbability() * 128 - 64);
|
dest.mY += OffsetToPreventOvercrowding();
|
||||||
dest.mY += static_cast<int>(Misc::Rng::rollProbability() * 128 - 64);
|
ToWorldCoordinates(dest, actor.getCell()->getCell());
|
||||||
|
|
||||||
if (actor.getCell()->isExterior())
|
|
||||||
{
|
|
||||||
dest.mX += actor.getCell()->getCell()->mData.mX * ESM::Land::REAL_SIZE;
|
|
||||||
dest.mY += actor.getCell()->getCell()->mData.mY * ESM::Land::REAL_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
MWBase::Environment::get().getWorld()->moveObject(actor, static_cast<float>(dest.mX),
|
MWBase::Environment::get().getWorld()->moveObject(actor, static_cast<float>(dest.mX),
|
||||||
static_cast<float>(dest.mY), static_cast<float>(dest.mZ));
|
static_cast<float>(dest.mY), static_cast<float>(dest.mZ));
|
||||||
|
@ -664,6 +663,11 @@ namespace MWMechanics
|
||||||
mStoredAvailableNodes = false;
|
mStoredAvailableNodes = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int AiWander::OffsetToPreventOvercrowding()
|
||||||
|
{
|
||||||
|
return static_cast<int>(DESTINATION_TOLERANCE * (Misc::Rng::rollProbability() * 2.0f - 1.0f));
|
||||||
|
}
|
||||||
|
|
||||||
void AiWander::getAllowedNodes(const MWWorld::Ptr& actor, const ESM::Cell* cell)
|
void AiWander::getAllowedNodes(const MWWorld::Ptr& actor, const ESM::Cell* cell)
|
||||||
{
|
{
|
||||||
if (!mStoredInitialActorPosition)
|
if (!mStoredInitialActorPosition)
|
||||||
|
@ -690,70 +694,85 @@ namespace MWMechanics
|
||||||
// ... pathgrids don't usually include water, so swimmers ignore them
|
// ... pathgrids don't usually include water, so swimmers ignore them
|
||||||
if (mDistance && !actor.getClass().isPureWaterCreature(actor))
|
if (mDistance && !actor.getClass().isPureWaterCreature(actor))
|
||||||
{
|
{
|
||||||
float cellXOffset = 0;
|
// get NPC's position in local (i.e. cell) co-ordinates
|
||||||
float cellYOffset = 0;
|
osg::Vec3f npcPos(mInitialActorPosition);
|
||||||
if(cell->isExterior())
|
if(cell->isExterior())
|
||||||
{
|
{
|
||||||
cellXOffset = static_cast<float>(cell->mData.mX * ESM::Land::REAL_SIZE);
|
npcPos[0] = npcPos[0] - static_cast<float>(cell->mData.mX * ESM::Land::REAL_SIZE);
|
||||||
cellYOffset = static_cast<float>(cell->mData.mY * ESM::Land::REAL_SIZE);
|
npcPos[1] = npcPos[1] - static_cast<float>(cell->mData.mY * ESM::Land::REAL_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert npcPos to local (i.e. cell) co-ordinates
|
|
||||||
osg::Vec3f npcPos(mInitialActorPosition);
|
|
||||||
npcPos[0] = npcPos[0] - cellXOffset;
|
|
||||||
npcPos[1] = npcPos[1] - cellYOffset;
|
|
||||||
|
|
||||||
// mAllowedNodes for this actor with pathgrid point indexes based on mDistance
|
// mAllowedNodes for this actor with pathgrid point indexes based on mDistance
|
||||||
// NOTE: mPoints and mAllowedNodes are in local co-ordinates
|
// NOTE: mPoints and mAllowedNodes are in local co-ordinates
|
||||||
|
int pointIndex = 0;
|
||||||
for(unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++)
|
for(unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++)
|
||||||
{
|
{
|
||||||
osg::Vec3f nodePos(PathFinder::MakeOsgVec3(pathgrid->mPoints[counter]));
|
osg::Vec3f nodePos(PathFinder::MakeOsgVec3(pathgrid->mPoints[counter]));
|
||||||
if((npcPos - nodePos).length2() <= mDistance * mDistance)
|
if((npcPos - nodePos).length2() <= mDistance * mDistance)
|
||||||
|
{
|
||||||
mAllowedNodes.push_back(pathgrid->mPoints[counter]);
|
mAllowedNodes.push_back(pathgrid->mPoints[counter]);
|
||||||
|
pointIndex = counter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mAllowedNodes.size() == 1)
|
||||||
|
{
|
||||||
|
AddNonPathGridAllowedPoints(npcPos, pathgrid, pointIndex);
|
||||||
}
|
}
|
||||||
if(!mAllowedNodes.empty())
|
if(!mAllowedNodes.empty())
|
||||||
{
|
{
|
||||||
osg::Vec3f firstNodePos(PathFinder::MakeOsgVec3(mAllowedNodes[0]));
|
SetCurrentNodeToClosestAllowedNode(npcPos);
|
||||||
float closestNode = (npcPos - firstNodePos).length2();
|
|
||||||
unsigned int index = 0;
|
|
||||||
for(unsigned int counterThree = 1; counterThree < mAllowedNodes.size(); counterThree++)
|
|
||||||
{
|
|
||||||
osg::Vec3f nodePos(PathFinder::MakeOsgVec3(mAllowedNodes[counterThree]));
|
|
||||||
float tempDist = (npcPos - nodePos).length2();
|
|
||||||
if(tempDist < closestNode)
|
|
||||||
index = counterThree;
|
|
||||||
}
|
|
||||||
mCurrentNode = mAllowedNodes[index];
|
|
||||||
mAllowedNodes.erase(mAllowedNodes.begin() + index);
|
|
||||||
}
|
|
||||||
|
|
||||||
// In vanilla Morrowind, sometimes distance is too small to include at least two points,
|
|
||||||
// in which case, we will take the two closest points regardless of the wander distance
|
|
||||||
// This is a backup option, as std::sort is potentially O(n^2) in time.
|
|
||||||
if (mAllowedNodes.empty())
|
|
||||||
{
|
|
||||||
// Start with list of PathGrid nodes, sorted by distance from actor
|
|
||||||
std::vector<PathDistance> nodeDistances;
|
|
||||||
for (unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++)
|
|
||||||
{
|
|
||||||
float distance = (npcPos - PathFinder::MakeOsgVec3(pathgrid->mPoints[counter])).length2();
|
|
||||||
nodeDistances.push_back(std::make_pair(distance, &pathgrid->mPoints.at(counter)));
|
|
||||||
}
|
|
||||||
std::sort(nodeDistances.begin(), nodeDistances.end(), sortByDistance);
|
|
||||||
|
|
||||||
// make closest node the current node
|
|
||||||
mCurrentNode = *nodeDistances[0].second;
|
|
||||||
|
|
||||||
// give Actor a 2nd node to walk to
|
|
||||||
mAllowedNodes.push_back(*nodeDistances[1].second);
|
|
||||||
}
|
}
|
||||||
mStoredAvailableNodes = true; // set only if successful in finding allowed nodes
|
mStoredAvailableNodes = true; // set only if successful in finding allowed nodes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AiWander::sortByDistance(const PathDistance& left, const PathDistance& right)
|
// When only one path grid point in wander distance,
|
||||||
|
// additional points for NPC to wander to are:
|
||||||
|
// 1. NPC's initial location
|
||||||
|
// 2. Partway along the path between the point and its connected points.
|
||||||
|
void AiWander::AddNonPathGridAllowedPoints(osg::Vec3f npcPos, const ESM::Pathgrid * pathGrid, int pointIndex)
|
||||||
{
|
{
|
||||||
return left.first < right.first;
|
mAllowedNodes.push_back(PathFinder::MakePathgridPoint(npcPos));
|
||||||
|
for (std::vector<ESM::Pathgrid::Edge>::const_iterator it = pathGrid->mEdges.begin(); it != pathGrid->mEdges.end(); ++it)
|
||||||
|
{
|
||||||
|
if (it->mV0 == pointIndex)
|
||||||
|
{
|
||||||
|
AddPointBetweenPathGridPoints(pathGrid->mPoints[it->mV0], pathGrid->mPoints[it->mV1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AiWander::AddPointBetweenPathGridPoints(const ESM::Pathgrid::Point& start, const ESM::Pathgrid::Point& end)
|
||||||
|
{
|
||||||
|
osg::Vec3f vectorStart = PathFinder::MakeOsgVec3(start);
|
||||||
|
osg::Vec3f delta = PathFinder::MakeOsgVec3(end) - vectorStart;
|
||||||
|
float length = delta.length();
|
||||||
|
delta.normalize();
|
||||||
|
|
||||||
|
int distance = std::max(mDistance / 2, MINIMUM_WANDER_DISTANCE);
|
||||||
|
|
||||||
|
// must not travel longer than distance between waypoints or NPC goes past waypoint
|
||||||
|
distance = std::min(distance, static_cast<int>(length));
|
||||||
|
delta *= distance;
|
||||||
|
mAllowedNodes.push_back(PathFinder::MakePathgridPoint(vectorStart + delta));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AiWander::SetCurrentNodeToClosestAllowedNode(osg::Vec3f npcPos)
|
||||||
|
{
|
||||||
|
float distanceToClosestNode = FLT_MAX;
|
||||||
|
unsigned int index = 0;
|
||||||
|
for (unsigned int counterThree = 0; counterThree < mAllowedNodes.size(); counterThree++)
|
||||||
|
{
|
||||||
|
osg::Vec3f nodePos(PathFinder::MakeOsgVec3(mAllowedNodes[counterThree]));
|
||||||
|
float tempDist = (npcPos - nodePos).length2();
|
||||||
|
if (tempDist < distanceToClosestNode)
|
||||||
|
{
|
||||||
|
index = counterThree;
|
||||||
|
distanceToClosestNode = tempDist;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mCurrentNode = mAllowedNodes[index];
|
||||||
|
mAllowedNodes.erase(mAllowedNodes.begin() + index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AiWander::writeState(ESM::AiSequence::AiSequence &sequence) const
|
void AiWander::writeState(ESM::AiSequence::AiSequence &sequence) const
|
||||||
|
|
|
@ -118,15 +118,19 @@ namespace MWMechanics
|
||||||
GroupIndex_MaxIdle = 9
|
GroupIndex_MaxIdle = 9
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// convert point from local (i.e. cell) to world co-ordinates
|
||||||
|
void ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::Cell * cell);
|
||||||
|
|
||||||
|
void SetCurrentNodeToClosestAllowedNode(osg::Vec3f npcPos);
|
||||||
|
|
||||||
|
void AddNonPathGridAllowedPoints(osg::Vec3f npcPos, const ESM::Pathgrid * pathGrid, int pointIndex);
|
||||||
|
|
||||||
|
void AddPointBetweenPathGridPoints(const ESM::Pathgrid::Point& start, const ESM::Pathgrid::Point& end);
|
||||||
|
|
||||||
/// lookup table for converting idleSelect value to groupName
|
/// lookup table for converting idleSelect value to groupName
|
||||||
static const std::string sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1];
|
static const std::string sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1];
|
||||||
|
|
||||||
/// record distances of pathgrid point nodes to actor
|
static int OffsetToPreventOvercrowding();
|
||||||
/// first value is distance between actor and node, second value is PathGrid node
|
|
||||||
typedef std::pair<float, const ESM::Pathgrid::Point*> PathDistance;
|
|
||||||
|
|
||||||
/// used to sort array of PathDistance objects into ascending order
|
|
||||||
static bool sortByDistance(const PathDistance& left, const PathDistance& right);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1259,6 +1259,8 @@ bool CharacterController::updateWeaponState()
|
||||||
}
|
}
|
||||||
|
|
||||||
animPlaying = mAnimation->getInfo(mCurrentWeapon, &complete);
|
animPlaying = mAnimation->getInfo(mCurrentWeapon, &complete);
|
||||||
|
if(mUpperBodyState == UpperCharState_MinAttackToMaxAttack && mHitState != CharState_KnockDown)
|
||||||
|
mAttackStrength = complete;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1789,7 +1791,8 @@ void CharacterController::update(float duration)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(cls.isBipedal(mPtr))
|
// bipedal means hand-to-hand could be used (which is handled in updateWeaponState). an existing InventoryStore means an actual weapon could be used.
|
||||||
|
if(cls.isBipedal(mPtr) || cls.hasInventoryStore(mPtr))
|
||||||
forcestateupdate = updateWeaponState() || forcestateupdate;
|
forcestateupdate = updateWeaponState() || forcestateupdate;
|
||||||
else
|
else
|
||||||
forcestateupdate = updateCreatureState() || forcestateupdate;
|
forcestateupdate = updateCreatureState() || forcestateupdate;
|
||||||
|
@ -2047,6 +2050,27 @@ void CharacterController::setAttackingOrSpell(bool attackingOrSpell)
|
||||||
mAttackingOrSpell = attackingOrSpell;
|
mAttackingOrSpell = attackingOrSpell;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CharacterController::readyToPrepareAttack() const
|
||||||
|
{
|
||||||
|
return mHitState == CharState_None && mUpperBodyState <= UpperCharState_WeapEquiped;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CharacterController::readyToStartAttack() const
|
||||||
|
{
|
||||||
|
if (mHitState != CharState_None)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (mPtr.getClass().hasInventoryStore(mPtr) || mPtr.getClass().isBipedal(mPtr))
|
||||||
|
return mUpperBodyState == UpperCharState_WeapEquiped;
|
||||||
|
else
|
||||||
|
return mUpperBodyState == UpperCharState_Nothing;
|
||||||
|
}
|
||||||
|
|
||||||
|
float CharacterController::getAttackStrength() const
|
||||||
|
{
|
||||||
|
return mAttackStrength;
|
||||||
|
}
|
||||||
|
|
||||||
void CharacterController::setActive(bool active)
|
void CharacterController::setActive(bool active)
|
||||||
{
|
{
|
||||||
mAnimation->setActive(active);
|
mAnimation->setActive(active);
|
||||||
|
|
|
@ -240,6 +240,11 @@ public:
|
||||||
|
|
||||||
void setAttackingOrSpell(bool attackingOrSpell);
|
void setAttackingOrSpell(bool attackingOrSpell);
|
||||||
|
|
||||||
|
bool readyToPrepareAttack() const;
|
||||||
|
bool readyToStartAttack() const;
|
||||||
|
|
||||||
|
float getAttackStrength() const;
|
||||||
|
|
||||||
/// @see Animation::setActive
|
/// @see Animation::setActive
|
||||||
void setActive(bool active);
|
void setActive(bool active);
|
||||||
|
|
||||||
|
@ -247,7 +252,6 @@ public:
|
||||||
void setHeadTrackTarget(const MWWorld::Ptr& target);
|
void setHeadTrackTarget(const MWWorld::Ptr& target);
|
||||||
};
|
};
|
||||||
|
|
||||||
void getWeaponGroup(WeaponType weaptype, std::string &group);
|
|
||||||
MWWorld::ContainerStoreIterator getActiveWeapon(CreatureStats &stats, MWWorld::InventoryStore &inv, WeaponType *weaptype);
|
MWWorld::ContainerStoreIterator getActiveWeapon(CreatureStats &stats, MWWorld::InventoryStore &inv, WeaponType *weaptype);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include <components/esm/creaturestats.hpp>
|
#include <components/esm/creaturestats.hpp>
|
||||||
|
#include <components/esm/esmreader.hpp>
|
||||||
|
#include <components/esm/esmwriter.hpp>
|
||||||
|
|
||||||
#include "../mwworld/esmstore.hpp"
|
#include "../mwworld/esmstore.hpp"
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include <components/misc/rng.hpp>
|
#include <components/misc/rng.hpp>
|
||||||
|
|
||||||
|
#include <components/esm/esmwriter.hpp>
|
||||||
#include <components/esm/stolenitems.hpp>
|
#include <components/esm/stolenitems.hpp>
|
||||||
|
|
||||||
#include "../mwworld/esmstore.hpp"
|
#include "../mwworld/esmstore.hpp"
|
||||||
|
|
|
@ -19,6 +19,8 @@ namespace MWMechanics
|
||||||
public:
|
public:
|
||||||
PathFinder();
|
PathFinder();
|
||||||
|
|
||||||
|
static const int PathTolerance = 32;
|
||||||
|
|
||||||
static float sgn(float val)
|
static float sgn(float val)
|
||||||
{
|
{
|
||||||
if(val > 0)
|
if(val > 0)
|
||||||
|
@ -35,10 +37,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
void clearPath();
|
void clearPath();
|
||||||
|
|
||||||
void buildPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint,
|
bool checkPathCompleted(float x, float y, float tolerance = PathTolerance);
|
||||||
const MWWorld::CellStore* cell, bool allowShortcuts = true);
|
|
||||||
|
|
||||||
bool checkPathCompleted(float x, float y, float tolerance=32.f);
|
|
||||||
///< \Returns true if we are within \a tolerance units of the last path point.
|
///< \Returns true if we are within \a tolerance units of the last path point.
|
||||||
|
|
||||||
/// In degrees
|
/// In degrees
|
||||||
|
@ -92,6 +91,8 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void buildPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint,
|
||||||
|
const MWWorld::CellStore* cell, bool allowShortcuts = true);
|
||||||
|
|
||||||
std::list<ESM::Pathgrid::Point> mPath;
|
std::list<ESM::Pathgrid::Point> mPath;
|
||||||
|
|
||||||
|
|
|
@ -313,27 +313,27 @@ namespace MWMechanics
|
||||||
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 world co-ordinates
|
// reconstruct path to return, using world co-ordinates
|
||||||
float xCell = 0;
|
int xCell = 0;
|
||||||
float yCell = 0;
|
int yCell = 0;
|
||||||
if (mIsExterior)
|
if (mIsExterior)
|
||||||
{
|
{
|
||||||
xCell = static_cast<float>(mPathgrid->mData.mX * ESM::Land::REAL_SIZE);
|
xCell = mPathgrid->mData.mX * ESM::Land::REAL_SIZE;
|
||||||
yCell = static_cast<float>(mPathgrid->mData.mY * ESM::Land::REAL_SIZE);
|
yCell = mPathgrid->mData.mY * ESM::Land::REAL_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
while(graphParent[current] != -1)
|
while(graphParent[current] != -1)
|
||||||
{
|
{
|
||||||
ESM::Pathgrid::Point pt = mPathgrid->mPoints[current];
|
ESM::Pathgrid::Point pt = mPathgrid->mPoints[current];
|
||||||
pt.mX += static_cast<int>(xCell);
|
pt.mX += xCell;
|
||||||
pt.mY += static_cast<int>(yCell);
|
pt.mY += yCell;
|
||||||
path.push_front(pt);
|
path.push_front(pt);
|
||||||
current = graphParent[current];
|
current = graphParent[current];
|
||||||
}
|
}
|
||||||
|
|
||||||
// add first node to path explicitly
|
// add first node to path explicitly
|
||||||
ESM::Pathgrid::Point pt = mPathgrid->mPoints[start];
|
ESM::Pathgrid::Point pt = mPathgrid->mPoints[start];
|
||||||
pt.mX += static_cast<int>(xCell);
|
pt.mX += xCell;
|
||||||
pt.mY += static_cast<int>(yCell);
|
pt.mY += yCell;
|
||||||
path.push_front(pt);
|
path.push_front(pt);
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include <components/esm/loadspel.hpp>
|
#include <components/esm/loadspel.hpp>
|
||||||
#include <components/esm/spellstate.hpp>
|
#include <components/esm/spellstate.hpp>
|
||||||
|
#include <components/misc/rng.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
|
|
@ -1,28 +1,276 @@
|
||||||
|
|
||||||
#include "stat.hpp"
|
#include "stat.hpp"
|
||||||
|
|
||||||
void MWMechanics::AttributeValue::writeState (ESM::StatState<int>& state) const
|
#include <components/esm/statstate.hpp>
|
||||||
|
|
||||||
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
state.mBase = mBase;
|
template<typename T>
|
||||||
state.mMod = mModifier;
|
Stat<T>::Stat() : mBase (0), mModified (0) {}
|
||||||
state.mDamage = mDamage;
|
template<typename T>
|
||||||
|
Stat<T>::Stat(T base) : mBase (base), mModified (base) {}
|
||||||
|
template<typename T>
|
||||||
|
Stat<T>::Stat(T base, T modified) : mBase (base), mModified (modified) {}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
const T& Stat<T>::getBase() const
|
||||||
|
{
|
||||||
|
return mBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T Stat<T>::getModified() const
|
||||||
|
{
|
||||||
|
return std::max(static_cast<T>(0), mModified);
|
||||||
|
}
|
||||||
|
template<typename T>
|
||||||
|
T Stat<T>::getModifier() const
|
||||||
|
{
|
||||||
|
return mModified-mBase;
|
||||||
|
}
|
||||||
|
template<typename T>
|
||||||
|
void Stat<T>::set (const T& value)
|
||||||
|
{
|
||||||
|
mBase = mModified = value;
|
||||||
|
}
|
||||||
|
template<typename T>
|
||||||
|
void Stat<T>::modify(const T& diff)
|
||||||
|
{
|
||||||
|
mBase += diff;
|
||||||
|
if(mBase >= static_cast<T>(0))
|
||||||
|
mModified += diff;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mModified += diff - mBase;
|
||||||
|
mBase = static_cast<T>(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
template<typename T>
|
||||||
|
void Stat<T>::setBase (const T& value)
|
||||||
|
{
|
||||||
|
T diff = value - mBase;
|
||||||
|
mBase = value;
|
||||||
|
mModified += diff;
|
||||||
|
}
|
||||||
|
template<typename T>
|
||||||
|
void Stat<T>::setModified (T value, const T& min, const T& max)
|
||||||
|
{
|
||||||
|
T diff = value - mModified;
|
||||||
|
|
||||||
|
if (mBase+diff<min)
|
||||||
|
{
|
||||||
|
value = min + (mModified - mBase);
|
||||||
|
diff = value - mModified;
|
||||||
|
}
|
||||||
|
else if (mBase+diff>max)
|
||||||
|
{
|
||||||
|
value = max + (mModified - mBase);
|
||||||
|
diff = value - mModified;
|
||||||
|
}
|
||||||
|
|
||||||
|
mModified = value;
|
||||||
|
mBase += diff;
|
||||||
|
}
|
||||||
|
template<typename T>
|
||||||
|
void Stat<T>::setModifier (const T& modifier)
|
||||||
|
{
|
||||||
|
mModified = mBase + modifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void Stat<T>::writeState (ESM::StatState<T>& state) const
|
||||||
|
{
|
||||||
|
state.mBase = mBase;
|
||||||
|
state.mMod = mModified;
|
||||||
|
}
|
||||||
|
template<typename T>
|
||||||
|
void Stat<T>::readState (const ESM::StatState<T>& state)
|
||||||
|
{
|
||||||
|
mBase = state.mBase;
|
||||||
|
mModified = state.mMod;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
DynamicStat<T>::DynamicStat() : mStatic (0), mCurrent (0) {}
|
||||||
|
template<typename T>
|
||||||
|
DynamicStat<T>::DynamicStat(T base) : mStatic (base), mCurrent (base) {}
|
||||||
|
template<typename T>
|
||||||
|
DynamicStat<T>::DynamicStat(T base, T modified, T current) : mStatic(base, modified), mCurrent (current) {}
|
||||||
|
template<typename T>
|
||||||
|
DynamicStat<T>::DynamicStat(const Stat<T> &stat, T current) : mStatic(stat), mCurrent (current) {}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
const T& DynamicStat<T>::getBase() const
|
||||||
|
{
|
||||||
|
return mStatic.getBase();
|
||||||
|
}
|
||||||
|
template<typename T>
|
||||||
|
T DynamicStat<T>::getModified() const
|
||||||
|
{
|
||||||
|
return mStatic.getModified();
|
||||||
|
}
|
||||||
|
template<typename T>
|
||||||
|
const T& DynamicStat<T>::getCurrent() const
|
||||||
|
{
|
||||||
|
return mCurrent;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void DynamicStat<T>::set (const T& value)
|
||||||
|
{
|
||||||
|
mStatic.set (value);
|
||||||
|
mCurrent = value;
|
||||||
|
}
|
||||||
|
template<typename T>
|
||||||
|
void DynamicStat<T>::setBase (const T& value)
|
||||||
|
{
|
||||||
|
mStatic.setBase (value);
|
||||||
|
|
||||||
|
if (mCurrent>getModified())
|
||||||
|
mCurrent = getModified();
|
||||||
|
}
|
||||||
|
template<typename T>
|
||||||
|
void DynamicStat<T>::setModified (T value, const T& min, const T& max)
|
||||||
|
{
|
||||||
|
mStatic.setModified (value, min, max);
|
||||||
|
|
||||||
|
if (mCurrent>getModified())
|
||||||
|
mCurrent = getModified();
|
||||||
|
}
|
||||||
|
template<typename T>
|
||||||
|
void DynamicStat<T>::modify (const T& diff, bool allowCurrentDecreaseBelowZero)
|
||||||
|
{
|
||||||
|
mStatic.modify (diff);
|
||||||
|
setCurrent (getCurrent()+diff, allowCurrentDecreaseBelowZero);
|
||||||
|
}
|
||||||
|
template<typename T>
|
||||||
|
void DynamicStat<T>::setCurrent (const T& value, bool allowDecreaseBelowZero)
|
||||||
|
{
|
||||||
|
if (value > mCurrent)
|
||||||
|
{
|
||||||
|
// increase
|
||||||
|
mCurrent = value;
|
||||||
|
|
||||||
|
if (mCurrent > getModified())
|
||||||
|
mCurrent = getModified();
|
||||||
|
}
|
||||||
|
else if (value > 0 || allowDecreaseBelowZero)
|
||||||
|
{
|
||||||
|
// allowed decrease
|
||||||
|
mCurrent = value;
|
||||||
|
}
|
||||||
|
else if (mCurrent > 0)
|
||||||
|
{
|
||||||
|
// capped decrease
|
||||||
|
mCurrent = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
template<typename T>
|
||||||
|
void DynamicStat<T>::setModifier (const T& modifier, bool allowCurrentDecreaseBelowZero)
|
||||||
|
{
|
||||||
|
T diff = modifier - mStatic.getModifier();
|
||||||
|
mStatic.setModifier (modifier);
|
||||||
|
setCurrent (getCurrent()+diff, allowCurrentDecreaseBelowZero);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void DynamicStat<T>::writeState (ESM::StatState<T>& state) const
|
||||||
|
{
|
||||||
|
mStatic.writeState (state);
|
||||||
|
state.mCurrent = mCurrent;
|
||||||
|
}
|
||||||
|
template<typename T>
|
||||||
|
void DynamicStat<T>::readState (const ESM::StatState<T>& state)
|
||||||
|
{
|
||||||
|
mStatic.readState (state);
|
||||||
|
mCurrent = state.mCurrent;
|
||||||
|
}
|
||||||
|
|
||||||
|
AttributeValue::AttributeValue() :
|
||||||
|
mBase(0), mModifier(0), mDamage(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int AttributeValue::getModified() const
|
||||||
|
{
|
||||||
|
return std::max(0, mBase - (int) mDamage + mModifier);
|
||||||
|
}
|
||||||
|
int AttributeValue::getBase() const
|
||||||
|
{
|
||||||
|
return mBase;
|
||||||
|
}
|
||||||
|
int AttributeValue::getModifier() const
|
||||||
|
{
|
||||||
|
return mModifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AttributeValue::setBase(int base)
|
||||||
|
{
|
||||||
|
mBase = std::max(0, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AttributeValue::setModifier(int mod)
|
||||||
|
{
|
||||||
|
mModifier = mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AttributeValue::damage(float damage)
|
||||||
|
{
|
||||||
|
mDamage += std::min(damage, (float)getModified());
|
||||||
|
}
|
||||||
|
void AttributeValue::restore(float amount)
|
||||||
|
{
|
||||||
|
mDamage -= std::min(mDamage, amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
float AttributeValue::getDamage() const
|
||||||
|
{
|
||||||
|
return mDamage;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AttributeValue::writeState (ESM::StatState<int>& state) const
|
||||||
|
{
|
||||||
|
state.mBase = mBase;
|
||||||
|
state.mMod = mModifier;
|
||||||
|
state.mDamage = mDamage;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AttributeValue::readState (const ESM::StatState<int>& state)
|
||||||
|
{
|
||||||
|
mBase = state.mBase;
|
||||||
|
mModifier = state.mMod;
|
||||||
|
mDamage = state.mDamage;
|
||||||
|
}
|
||||||
|
|
||||||
|
SkillValue::SkillValue() :
|
||||||
|
mProgress(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
float SkillValue::getProgress() const
|
||||||
|
{
|
||||||
|
return mProgress;
|
||||||
|
}
|
||||||
|
void SkillValue::setProgress(float progress)
|
||||||
|
{
|
||||||
|
mProgress = progress;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SkillValue::writeState (ESM::StatState<int>& state) const
|
||||||
|
{
|
||||||
|
AttributeValue::writeState (state);
|
||||||
|
state.mProgress = mProgress;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SkillValue::readState (const ESM::StatState<int>& state)
|
||||||
|
{
|
||||||
|
AttributeValue::readState (state);
|
||||||
|
mProgress = state.mProgress;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MWMechanics::AttributeValue::readState (const ESM::StatState<int>& state)
|
template class MWMechanics::Stat<int>;
|
||||||
{
|
template class MWMechanics::Stat<float>;
|
||||||
mBase = state.mBase;
|
template class MWMechanics::DynamicStat<int>;
|
||||||
mModifier = state.mMod;
|
template class MWMechanics::DynamicStat<float>;
|
||||||
mDamage = state.mDamage;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MWMechanics::SkillValue::writeState (ESM::StatState<int>& state) const
|
|
||||||
{
|
|
||||||
AttributeValue::writeState (state);
|
|
||||||
state.mProgress = mProgress;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MWMechanics::SkillValue::readState (const ESM::StatState<int>& state)
|
|
||||||
{
|
|
||||||
AttributeValue::readState (state);
|
|
||||||
mProgress = state.mProgress;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,9 +1,14 @@
|
||||||
#ifndef GAME_MWMECHANICS_STAT_H
|
#ifndef GAME_MWMECHANICS_STAT_H
|
||||||
#define GAME_MWMECHANICS_STAT_H
|
#define GAME_MWMECHANICS_STAT_H
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
#include <components/esm/statstate.hpp>
|
namespace ESM
|
||||||
|
{
|
||||||
|
template<typename T>
|
||||||
|
struct StatState;
|
||||||
|
}
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
@ -16,87 +21,28 @@ namespace MWMechanics
|
||||||
public:
|
public:
|
||||||
typedef T Type;
|
typedef T Type;
|
||||||
|
|
||||||
Stat() : mBase (0), mModified (0) {}
|
Stat();
|
||||||
Stat(T base) : mBase (base), mModified (base) {}
|
Stat(T base);
|
||||||
Stat(T base, T modified) : mBase (base), mModified (modified) {}
|
Stat(T base, T modified);
|
||||||
|
|
||||||
const T& getBase() const
|
const T& getBase() const;
|
||||||
{
|
|
||||||
return mBase;
|
|
||||||
}
|
|
||||||
|
|
||||||
T getModified() const
|
T getModified() const;
|
||||||
{
|
T getModifier() const;
|
||||||
return std::max(static_cast<T>(0), mModified);
|
|
||||||
}
|
|
||||||
|
|
||||||
T getModifier() const
|
|
||||||
{
|
|
||||||
return mModified-mBase;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set base and modified to \a value.
|
/// Set base and modified to \a value.
|
||||||
void set (const T& value)
|
void set (const T& value);
|
||||||
{
|
void modify(const T& diff);
|
||||||
mBase = mModified = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void modify(const T& diff)
|
|
||||||
{
|
|
||||||
mBase += diff;
|
|
||||||
if(mBase >= static_cast<T>(0))
|
|
||||||
mModified += diff;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mModified += diff - mBase;
|
|
||||||
mBase = static_cast<T>(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set base and adjust modified accordingly.
|
/// Set base and adjust modified accordingly.
|
||||||
void setBase (const T& value)
|
void setBase (const T& value);
|
||||||
{
|
|
||||||
T diff = value - mBase;
|
|
||||||
mBase = value;
|
|
||||||
mModified += diff;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set modified value an adjust base accordingly.
|
/// Set modified value an adjust base accordingly.
|
||||||
void setModified (T value, const T& min, const T& max = std::numeric_limits<T>::max())
|
void setModified (T value, const T& min, const T& max = std::numeric_limits<T>::max());
|
||||||
{
|
void setModifier (const T& modifier);
|
||||||
T diff = value - mModified;
|
|
||||||
|
|
||||||
if (mBase+diff<min)
|
void writeState (ESM::StatState<T>& state) const;
|
||||||
{
|
void readState (const ESM::StatState<T>& state);
|
||||||
value = min + (mModified - mBase);
|
|
||||||
diff = value - mModified;
|
|
||||||
}
|
|
||||||
else if (mBase+diff>max)
|
|
||||||
{
|
|
||||||
value = max + (mModified - mBase);
|
|
||||||
diff = value - mModified;
|
|
||||||
}
|
|
||||||
|
|
||||||
mModified = value;
|
|
||||||
mBase += diff;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setModifier (const T& modifier)
|
|
||||||
{
|
|
||||||
mModified = mBase + modifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
void writeState (ESM::StatState<T>& state) const
|
|
||||||
{
|
|
||||||
state.mBase = mBase;
|
|
||||||
state.mMod = mModified;
|
|
||||||
}
|
|
||||||
|
|
||||||
void readState (const ESM::StatState<T>& state)
|
|
||||||
{
|
|
||||||
mBase = state.mBase;
|
|
||||||
mModified = state.mMod;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
@ -121,98 +67,32 @@ namespace MWMechanics
|
||||||
public:
|
public:
|
||||||
typedef T Type;
|
typedef T Type;
|
||||||
|
|
||||||
DynamicStat() : mStatic (0), mCurrent (0) {}
|
DynamicStat();
|
||||||
DynamicStat(T base) : mStatic (base), mCurrent (base) {}
|
DynamicStat(T base);
|
||||||
DynamicStat(T base, T modified, T current) : mStatic(base, modified), mCurrent (current) {}
|
DynamicStat(T base, T modified, T current);
|
||||||
DynamicStat(const Stat<T> &stat, T current) : mStatic(stat), mCurrent (current) {}
|
DynamicStat(const Stat<T> &stat, T current);
|
||||||
|
|
||||||
const T& getBase() const
|
const T& getBase() const;
|
||||||
{
|
T getModified() const;
|
||||||
return mStatic.getBase();
|
const T& getCurrent() const;
|
||||||
}
|
|
||||||
|
|
||||||
T getModified() const
|
|
||||||
{
|
|
||||||
return mStatic.getModified();
|
|
||||||
}
|
|
||||||
|
|
||||||
const T& getCurrent() const
|
|
||||||
{
|
|
||||||
return mCurrent;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set base, modified and current to \a value.
|
/// Set base, modified and current to \a value.
|
||||||
void set (const T& value)
|
void set (const T& value);
|
||||||
{
|
|
||||||
mStatic.set (value);
|
|
||||||
mCurrent = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set base and adjust modified accordingly.
|
/// Set base and adjust modified accordingly.
|
||||||
void setBase (const T& value)
|
void setBase (const T& value);
|
||||||
{
|
|
||||||
mStatic.setBase (value);
|
|
||||||
|
|
||||||
if (mCurrent>getModified())
|
|
||||||
mCurrent = getModified();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set modified value an adjust base accordingly.
|
/// Set modified value an adjust base accordingly.
|
||||||
void setModified (T value, const T& min, const T& max = std::numeric_limits<T>::max())
|
void setModified (T value, const T& min, const T& max = std::numeric_limits<T>::max());
|
||||||
{
|
|
||||||
mStatic.setModified (value, min, max);
|
|
||||||
|
|
||||||
if (mCurrent>getModified())
|
|
||||||
mCurrent = getModified();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Change modified relatively.
|
/// Change modified relatively.
|
||||||
void modify (const T& diff, bool allowCurrentDecreaseBelowZero=false)
|
void modify (const T& diff, bool allowCurrentDecreaseBelowZero=false);
|
||||||
{
|
|
||||||
mStatic.modify (diff);
|
|
||||||
setCurrent (getCurrent()+diff, allowCurrentDecreaseBelowZero);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setCurrent (const T& value, bool allowDecreaseBelowZero = false)
|
void setCurrent (const T& value, bool allowDecreaseBelowZero = false);
|
||||||
{
|
void setModifier (const T& modifier, bool allowCurrentDecreaseBelowZero=false);
|
||||||
if (value > mCurrent)
|
|
||||||
{
|
|
||||||
// increase
|
|
||||||
mCurrent = value;
|
|
||||||
|
|
||||||
if (mCurrent > getModified())
|
void writeState (ESM::StatState<T>& state) const;
|
||||||
mCurrent = getModified();
|
void readState (const ESM::StatState<T>& state);
|
||||||
}
|
|
||||||
else if (value > 0 || allowDecreaseBelowZero)
|
|
||||||
{
|
|
||||||
// allowed decrease
|
|
||||||
mCurrent = value;
|
|
||||||
}
|
|
||||||
else if (mCurrent > 0)
|
|
||||||
{
|
|
||||||
// capped decrease
|
|
||||||
mCurrent = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void setModifier (const T& modifier, bool allowCurrentDecreaseBelowZero=false)
|
|
||||||
{
|
|
||||||
T diff = modifier - mStatic.getModifier();
|
|
||||||
mStatic.setModifier (modifier);
|
|
||||||
setCurrent (getCurrent()+diff, allowCurrentDecreaseBelowZero);
|
|
||||||
}
|
|
||||||
|
|
||||||
void writeState (ESM::StatState<T>& state) const
|
|
||||||
{
|
|
||||||
mStatic.writeState (state);
|
|
||||||
state.mCurrent = mCurrent;
|
|
||||||
}
|
|
||||||
|
|
||||||
void readState (const ESM::StatState<T>& state)
|
|
||||||
{
|
|
||||||
mStatic.readState (state);
|
|
||||||
mCurrent = state.mCurrent;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
@ -236,26 +116,25 @@ namespace MWMechanics
|
||||||
float mDamage; // needs to be float to allow continuous damage
|
float mDamage; // needs to be float to allow continuous damage
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AttributeValue() : mBase(0), mModifier(0), mDamage(0) {}
|
AttributeValue();
|
||||||
|
|
||||||
int getModified() const { return std::max(0, mBase - (int) mDamage + mModifier); }
|
int getModified() const;
|
||||||
int getBase() const { return mBase; }
|
int getBase() const;
|
||||||
int getModifier() const { return mModifier; }
|
int getModifier() const;
|
||||||
|
|
||||||
void setBase(int base) { mBase = std::max(0, base); }
|
void setBase(int base);
|
||||||
|
|
||||||
void setModifier(int mod) { mModifier = mod; }
|
void setModifier(int mod);
|
||||||
|
|
||||||
// Maximum attribute damage is limited to the modified value.
|
// Maximum attribute damage is limited to the modified value.
|
||||||
// Note: I think MW applies damage directly to mModified, since you can also
|
// Note: I think MW applies damage directly to mModified, since you can also
|
||||||
// "restore" drained attributes. We need to rewrite the magic effect system to support this.
|
// "restore" drained attributes. We need to rewrite the magic effect system to support this.
|
||||||
void damage(float damage) { mDamage += std::min(damage, (float)getModified()); }
|
void damage(float damage);
|
||||||
void restore(float amount) { mDamage -= std::min(mDamage, amount); }
|
void restore(float amount);
|
||||||
|
|
||||||
float getDamage() const { return mDamage; }
|
float getDamage() const;
|
||||||
|
|
||||||
void writeState (ESM::StatState<int>& state) const;
|
void writeState (ESM::StatState<int>& state) const;
|
||||||
|
|
||||||
void readState (const ESM::StatState<int>& state);
|
void readState (const ESM::StatState<int>& state);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -263,12 +142,11 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
float mProgress;
|
float mProgress;
|
||||||
public:
|
public:
|
||||||
SkillValue() : mProgress(0) {}
|
SkillValue();
|
||||||
float getProgress() const { return mProgress; }
|
float getProgress() const;
|
||||||
void setProgress(float progress) { mProgress = progress; }
|
void setProgress(float progress);
|
||||||
|
|
||||||
void writeState (ESM::StatState<int>& state) const;
|
void writeState (ESM::StatState<int>& state) const;
|
||||||
|
|
||||||
void readState (const ESM::StatState<int>& state);
|
void readState (const ESM::StatState<int>& state);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -267,6 +267,8 @@ namespace MWRender
|
||||||
|
|
||||||
Animation::~Animation()
|
Animation::~Animation()
|
||||||
{
|
{
|
||||||
|
setLightEffect(0.f);
|
||||||
|
|
||||||
if (mObjectRoot)
|
if (mObjectRoot)
|
||||||
mInsert->removeChild(mObjectRoot);
|
mInsert->removeChild(mObjectRoot);
|
||||||
}
|
}
|
||||||
|
@ -1224,6 +1226,36 @@ namespace MWRender
|
||||||
return found->second;
|
return found->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Animation::setLightEffect(float effect)
|
||||||
|
{
|
||||||
|
if (effect == 0)
|
||||||
|
{
|
||||||
|
if (mGlowLight)
|
||||||
|
{
|
||||||
|
mInsert->removeChild(mGlowLight);
|
||||||
|
mGlowLight = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!mGlowLight)
|
||||||
|
{
|
||||||
|
mGlowLight = new SceneUtil::LightSource;
|
||||||
|
mGlowLight->setLight(new osg::Light);
|
||||||
|
osg::Light* light = mGlowLight->getLight();
|
||||||
|
light->setDiffuse(osg::Vec4f(0,0,0,0));
|
||||||
|
light->setSpecular(osg::Vec4f(0,0,0,0));
|
||||||
|
light->setAmbient(osg::Vec4f(1.5f,1.5f,1.5f,1.f));
|
||||||
|
mInsert->addChild(mGlowLight);
|
||||||
|
}
|
||||||
|
|
||||||
|
effect += 3;
|
||||||
|
osg::Light* light = mGlowLight->getLight();
|
||||||
|
mGlowLight->setRadius(effect * 66.f);
|
||||||
|
light->setLinearAttenuation(0.5f/effect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Animation::addControllers()
|
void Animation::addControllers()
|
||||||
{
|
{
|
||||||
mHeadController = NULL;
|
mHeadController = NULL;
|
||||||
|
|
|
@ -21,6 +21,11 @@ namespace NifOsg
|
||||||
class KeyframeController;
|
class KeyframeController;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace SceneUtil
|
||||||
|
{
|
||||||
|
class LightSource;
|
||||||
|
}
|
||||||
|
|
||||||
namespace MWRender
|
namespace MWRender
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -202,6 +207,8 @@ protected:
|
||||||
float mHeadYawRadians;
|
float mHeadYawRadians;
|
||||||
float mHeadPitchRadians;
|
float mHeadPitchRadians;
|
||||||
|
|
||||||
|
osg::ref_ptr<SceneUtil::LightSource> mGlowLight;
|
||||||
|
|
||||||
/* Sets the appropriate animations on the bone groups based on priority.
|
/* Sets the appropriate animations on the bone groups based on priority.
|
||||||
*/
|
*/
|
||||||
void resetActiveGroups();
|
void resetActiveGroups();
|
||||||
|
@ -377,7 +384,7 @@ public:
|
||||||
// TODO: move outside of this class
|
// TODO: move outside of this class
|
||||||
/// Makes this object glow, by placing a Light in its center.
|
/// Makes this object glow, by placing a Light in its center.
|
||||||
/// @param effect Controls the radius and intensity of the light.
|
/// @param effect Controls the radius and intensity of the light.
|
||||||
virtual void setLightEffect(float effect) {}
|
virtual void setLightEffect(float effect);
|
||||||
|
|
||||||
virtual void setHeadPitch(float pitchRadians);
|
virtual void setHeadPitch(float pitchRadians);
|
||||||
virtual void setHeadYaw(float yawRadians);
|
virtual void setHeadYaw(float yawRadians);
|
||||||
|
|
|
@ -88,7 +88,8 @@ namespace MWRender
|
||||||
struct ImageDest
|
struct ImageDest
|
||||||
{
|
{
|
||||||
ImageDest()
|
ImageDest()
|
||||||
: mFramesUntilDone(3) // wait an extra frame to ensure the draw thread has completed its frame.
|
: mX(0), mY(0)
|
||||||
|
, mFramesUntilDone(3) // wait an extra frame to ensure the draw thread has completed its frame.
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -459,7 +459,7 @@ void NpcAnimation::updateParts()
|
||||||
};
|
};
|
||||||
static const size_t slotlistsize = sizeof(slotlist)/sizeof(slotlist[0]);
|
static const size_t slotlistsize = sizeof(slotlist)/sizeof(slotlist[0]);
|
||||||
|
|
||||||
bool wasArrowAttached = 0;//(mAmmunition.get() != NULL);
|
bool wasArrowAttached = (mAmmunition.get() != NULL);
|
||||||
|
|
||||||
MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr);
|
MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr);
|
||||||
for(size_t i = 0;i < slotlistsize && mViewMode != VM_HeadOnly;i++)
|
for(size_t i = 0;i < slotlistsize && mViewMode != VM_HeadOnly;i++)
|
||||||
|
@ -622,7 +622,7 @@ void NpcAnimation::updateParts()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mNpc->isMale() != (bodypart.mData.mFlags & ESM::BodyPart::BPF_Female))
|
if ((!mNpc->isMale()) != (bodypart.mData.mFlags & ESM::BodyPart::BPF_Female))
|
||||||
{
|
{
|
||||||
// Allow opposite gender's parts as fallback if parts for our gender are missing
|
// Allow opposite gender's parts as fallback if parts for our gender are missing
|
||||||
BodyPartMapType::const_iterator bIt = sBodyPartMap.lower_bound(BodyPartMapType::key_type(bodypart.mData.mPart));
|
BodyPartMapType::const_iterator bIt = sBodyPartMap.lower_bound(BodyPartMapType::key_type(bodypart.mData.mPart));
|
||||||
|
@ -850,7 +850,6 @@ void NpcAnimation::addControllers()
|
||||||
Animation::addControllers();
|
Animation::addControllers();
|
||||||
|
|
||||||
mFirstPersonNeckController = NULL;
|
mFirstPersonNeckController = NULL;
|
||||||
mHeadController = NULL;
|
|
||||||
WeaponAnimation::deleteControllers();
|
WeaponAnimation::deleteControllers();
|
||||||
|
|
||||||
if (mViewMode == VM_FirstPerson)
|
if (mViewMode == VM_FirstPerson)
|
||||||
|
|
|
@ -46,7 +46,8 @@ namespace MWRender
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
StateUpdater()
|
StateUpdater()
|
||||||
: mFogEnd(0.f)
|
: mFogStart(0.f)
|
||||||
|
, mFogEnd(0.f)
|
||||||
, mWireframe(false)
|
, mWireframe(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -56,7 +57,6 @@ namespace MWRender
|
||||||
osg::LightModel* lightModel = new osg::LightModel;
|
osg::LightModel* lightModel = new osg::LightModel;
|
||||||
stateset->setAttribute(lightModel, osg::StateAttribute::ON);
|
stateset->setAttribute(lightModel, osg::StateAttribute::ON);
|
||||||
osg::Fog* fog = new osg::Fog;
|
osg::Fog* fog = new osg::Fog;
|
||||||
fog->setStart(1);
|
|
||||||
fog->setMode(osg::Fog::LINEAR);
|
fog->setMode(osg::Fog::LINEAR);
|
||||||
stateset->setAttributeAndModes(fog, osg::StateAttribute::ON);
|
stateset->setAttributeAndModes(fog, osg::StateAttribute::ON);
|
||||||
if (mWireframe)
|
if (mWireframe)
|
||||||
|
@ -75,6 +75,7 @@ namespace MWRender
|
||||||
lightModel->setAmbientIntensity(mAmbientColor);
|
lightModel->setAmbientIntensity(mAmbientColor);
|
||||||
osg::Fog* fog = static_cast<osg::Fog*>(stateset->getAttribute(osg::StateAttribute::FOG));
|
osg::Fog* fog = static_cast<osg::Fog*>(stateset->getAttribute(osg::StateAttribute::FOG));
|
||||||
fog->setColor(mFogColor);
|
fog->setColor(mFogColor);
|
||||||
|
fog->setStart(mFogStart);
|
||||||
fog->setEnd(mFogEnd);
|
fog->setEnd(mFogEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,6 +89,11 @@ namespace MWRender
|
||||||
mFogColor = col;
|
mFogColor = col;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setFogStart(float start)
|
||||||
|
{
|
||||||
|
mFogStart = start;
|
||||||
|
}
|
||||||
|
|
||||||
void setFogEnd(float end)
|
void setFogEnd(float end)
|
||||||
{
|
{
|
||||||
mFogEnd = end;
|
mFogEnd = end;
|
||||||
|
@ -110,6 +116,7 @@ namespace MWRender
|
||||||
private:
|
private:
|
||||||
osg::Vec4f mAmbientColor;
|
osg::Vec4f mAmbientColor;
|
||||||
osg::Vec4f mFogColor;
|
osg::Vec4f mFogColor;
|
||||||
|
float mFogStart;
|
||||||
float mFogEnd;
|
float mFogEnd;
|
||||||
bool mWireframe;
|
bool mWireframe;
|
||||||
};
|
};
|
||||||
|
@ -118,6 +125,7 @@ namespace MWRender
|
||||||
: mViewer(viewer)
|
: mViewer(viewer)
|
||||||
, mRootNode(rootNode)
|
, mRootNode(rootNode)
|
||||||
, mResourceSystem(resourceSystem)
|
, mResourceSystem(resourceSystem)
|
||||||
|
, mFogDepth(0.f)
|
||||||
, mNightEyeFactor(0.f)
|
, mNightEyeFactor(0.f)
|
||||||
{
|
{
|
||||||
osg::ref_ptr<SceneUtil::LightManager> lightRoot = new SceneUtil::LightManager;
|
osg::ref_ptr<SceneUtil::LightManager> lightRoot = new SceneUtil::LightManager;
|
||||||
|
@ -338,8 +346,9 @@ namespace MWRender
|
||||||
configureFog (cell->mAmbi.mFogDensity, color);
|
configureFog (cell->mAmbi.mFogDensity, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderingManager::configureFog(float /* fogDepth */, const osg::Vec4f &color)
|
void RenderingManager::configureFog(float fogDepth, const osg::Vec4f &color)
|
||||||
{
|
{
|
||||||
|
mFogDepth = fogDepth;
|
||||||
mFogColor = color;
|
mFogColor = color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -364,11 +373,13 @@ namespace MWRender
|
||||||
if (mWater->isUnderwater(cameraPos))
|
if (mWater->isUnderwater(cameraPos))
|
||||||
{
|
{
|
||||||
setFogColor(osg::Vec4f(0.090195f, 0.115685f, 0.12745f, 1.f));
|
setFogColor(osg::Vec4f(0.090195f, 0.115685f, 0.12745f, 1.f));
|
||||||
|
mStateUpdater->setFogStart(0.f);
|
||||||
mStateUpdater->setFogEnd(1000);
|
mStateUpdater->setFogEnd(1000);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
setFogColor(mFogColor);
|
setFogColor(mFogColor);
|
||||||
|
mStateUpdater->setFogStart(mViewDistance * (1 - mFogDepth));
|
||||||
mStateUpdater->setFogEnd(mViewDistance);
|
mStateUpdater->setFogEnd(mViewDistance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -190,6 +190,7 @@ namespace MWRender
|
||||||
|
|
||||||
osg::ref_ptr<StateUpdater> mStateUpdater;
|
osg::ref_ptr<StateUpdater> mStateUpdater;
|
||||||
|
|
||||||
|
float mFogDepth;
|
||||||
osg::Vec4f mFogColor;
|
osg::Vec4f mFogColor;
|
||||||
|
|
||||||
osg::Vec4f mAmbientColor;
|
osg::Vec4f mAmbientColor;
|
||||||
|
|
|
@ -59,16 +59,11 @@ namespace MWRender
|
||||||
|
|
||||||
private:
|
private:
|
||||||
osg::ref_ptr<osg::Group> mParent;
|
osg::ref_ptr<osg::Group> mParent;
|
||||||
Resource::ResourceSystem* mResourceSystem;
|
|
||||||
|
|
||||||
osg::ref_ptr<osgParticle::ParticleSystem> mParticleSystem;
|
osg::ref_ptr<osgParticle::ParticleSystem> mParticleSystem;
|
||||||
osg::ref_ptr<osg::PositionAttitudeTransform> mParticleNode;
|
osg::ref_ptr<osg::PositionAttitudeTransform> mParticleNode;
|
||||||
|
|
||||||
std::vector<Emitter> mEmitters;
|
std::vector<Emitter> mEmitters;
|
||||||
|
|
||||||
float mRippleLifeTime;
|
|
||||||
float mRippleRotSpeed;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <osg/PositionAttitudeTransform>
|
#include <osg/PositionAttitudeTransform>
|
||||||
#include <osg/TexEnvCombine>
|
#include <osg/TexEnvCombine>
|
||||||
#include <osg/TexMat>
|
#include <osg/TexMat>
|
||||||
|
#include <osg/Version>
|
||||||
|
|
||||||
#include <osgParticle/ParticleSystem>
|
#include <osgParticle/ParticleSystem>
|
||||||
#include <osgParticle/ParticleSystemUpdater>
|
#include <osgParticle/ParticleSystemUpdater>
|
||||||
|
@ -162,6 +163,12 @@ protected:
|
||||||
class CloudUpdater : public SceneUtil::StateSetUpdater
|
class CloudUpdater : public SceneUtil::StateSetUpdater
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
CloudUpdater()
|
||||||
|
: mAnimationTimer(0.f)
|
||||||
|
, mOpacity(0.f)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void setAnimationTimer(float timer)
|
void setAnimationTimer(float timer)
|
||||||
{
|
{
|
||||||
mAnimationTimer = timer;
|
mAnimationTimer = timer;
|
||||||
|
@ -721,7 +728,11 @@ public:
|
||||||
if (stateset->getAttribute(osg::StateAttribute::MATERIAL))
|
if (stateset->getAttribute(osg::StateAttribute::MATERIAL))
|
||||||
{
|
{
|
||||||
SceneUtil::CompositeStateSetUpdater* composite = NULL;
|
SceneUtil::CompositeStateSetUpdater* composite = NULL;
|
||||||
|
#if OSG_MIN_VERSION_REQUIRED(3,3,3)
|
||||||
|
osg::Callback* callback = node.getUpdateCallback();
|
||||||
|
#else
|
||||||
osg::NodeCallback* callback = node.getUpdateCallback();
|
osg::NodeCallback* callback = node.getUpdateCallback();
|
||||||
|
#endif
|
||||||
while (callback)
|
while (callback)
|
||||||
{
|
{
|
||||||
if ((composite = dynamic_cast<SceneUtil::CompositeStateSetUpdater*>(callback)))
|
if ((composite = dynamic_cast<SceneUtil::CompositeStateSetUpdater*>(callback)))
|
||||||
|
@ -762,9 +773,6 @@ public:
|
||||||
mat->setColorMode(osg::Material::OFF);
|
mat->setColorMode(osg::Material::OFF);
|
||||||
stateset->setAttributeAndModes(mat, osg::StateAttribute::ON);
|
stateset->setAttributeAndModes(mat, osg::StateAttribute::ON);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
float mAlpha;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void SkyManager::createRain()
|
void SkyManager::createRain()
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include <components/misc/stringops.hpp>
|
#include <components/misc/stringops.hpp>
|
||||||
|
#include <components/esm/esmwriter.hpp>
|
||||||
#include <components/esm/globalscript.hpp>
|
#include <components/esm/globalscript.hpp>
|
||||||
|
|
||||||
#include "../mwworld/esmstore.hpp"
|
#include "../mwworld/esmstore.hpp"
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
#include <components/esm/cellid.hpp>
|
#include <components/esm/cellid.hpp>
|
||||||
#include <components/esm/loadcell.hpp>
|
#include <components/esm/loadcell.hpp>
|
||||||
|
|
||||||
|
#include <components/loadinglistener/loadinglistener.hpp>
|
||||||
|
|
||||||
#include <components/misc/stringops.hpp>
|
#include <components/misc/stringops.hpp>
|
||||||
|
|
||||||
#include <components/settings/settings.hpp>
|
#include <components/settings/settings.hpp>
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <components/esm/esmwriter.hpp>
|
#include <components/esm/esmwriter.hpp>
|
||||||
#include <components/esm/defs.hpp>
|
#include <components/esm/defs.hpp>
|
||||||
#include <components/esm/cellstate.hpp>
|
#include <components/esm/cellstate.hpp>
|
||||||
|
#include <components/loadinglistener/loadinglistener.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include <components/esm/cellstate.hpp>
|
#include <components/esm/cellstate.hpp>
|
||||||
#include <components/esm/cellid.hpp>
|
#include <components/esm/cellid.hpp>
|
||||||
|
#include <components/esm/esmreader.hpp>
|
||||||
#include <components/esm/esmwriter.hpp>
|
#include <components/esm/esmwriter.hpp>
|
||||||
#include <components/esm/objectstate.hpp>
|
#include <components/esm/objectstate.hpp>
|
||||||
#include <components/esm/containerstate.hpp>
|
#include <components/esm/containerstate.hpp>
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <components/loadinglistener/loadinglistener.hpp>
|
#include <components/loadinglistener/loadinglistener.hpp>
|
||||||
|
|
||||||
#include <components/esm/esmreader.hpp>
|
#include <components/esm/esmreader.hpp>
|
||||||
|
#include <components/esm/esmwriter.hpp>
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef OPENMW_MWWORLD_ESMSTORE_H
|
#ifndef OPENMW_MWWORLD_ESMSTORE_H
|
||||||
#define OPENMW_MWWORLD_ESMSTORE_H
|
#define OPENMW_MWWORLD_ESMSTORE_H
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <components/esm/records.hpp>
|
#include <components/esm/records.hpp>
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include <components/esm/loadench.hpp>
|
#include <components/esm/loadench.hpp>
|
||||||
#include <components/esm/inventorystate.hpp>
|
#include <components/esm/inventorystate.hpp>
|
||||||
|
#include <components/misc/rng.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include <osg/PositionAttitudeTransform>
|
#include <osg/PositionAttitudeTransform>
|
||||||
|
|
||||||
|
#include <components/esm/esmwriter.hpp>
|
||||||
#include <components/esm/projectilestate.hpp>
|
#include <components/esm/projectilestate.hpp>
|
||||||
#include <components/resource/resourcesystem.hpp>
|
#include <components/resource/resourcesystem.hpp>
|
||||||
#include <components/resource/scenemanager.hpp>
|
#include <components/resource/scenemanager.hpp>
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
#include <components/nif/niffile.hpp>
|
#include <components/nif/niffile.hpp>
|
||||||
|
#include <components/loadinglistener/loadinglistener.hpp>
|
||||||
#include <components/misc/resourcehelpers.hpp>
|
#include <components/misc/resourcehelpers.hpp>
|
||||||
#include <components/settings/settings.hpp>
|
#include <components/settings/settings.hpp>
|
||||||
#include <components/resource/resourcesystem.hpp>
|
#include <components/resource/resourcesystem.hpp>
|
||||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include <components/misc/rng.hpp>
|
#include <components/misc/rng.hpp>
|
||||||
|
|
||||||
|
#include <components/esm/esmwriter.hpp>
|
||||||
#include <components/esm/weatherstate.hpp>
|
#include <components/esm/weatherstate.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
|
@ -66,6 +67,10 @@ void WeatherManager::setFallbackWeather(Weather& weather,const std::string& name
|
||||||
weather.mGlareView = mFallback->getFallbackFloat("Weather_"+upper+"_Glare_View");
|
weather.mGlareView = mFallback->getFallbackFloat("Weather_"+upper+"_Glare_View");
|
||||||
weather.mCloudTexture = mFallback->getFallbackString("Weather_"+upper+"_Cloud_Texture");
|
weather.mCloudTexture = mFallback->getFallbackString("Weather_"+upper+"_Cloud_Texture");
|
||||||
|
|
||||||
|
static const float fStromWindSpeed = mStore->get<ESM::GameSetting>().find("fStromWindSpeed")->getFloat();
|
||||||
|
|
||||||
|
weather.mIsStorm = weather.mWindSpeed > fStromWindSpeed;
|
||||||
|
|
||||||
bool usesPrecip = mFallback->getFallbackBool("Weather_"+upper+"_Using_Precip");
|
bool usesPrecip = mFallback->getFallbackBool("Weather_"+upper+"_Using_Precip");
|
||||||
if (usesPrecip)
|
if (usesPrecip)
|
||||||
weather.mRainEffect = "meshes\\raindrop.nif";
|
weather.mRainEffect = "meshes\\raindrop.nif";
|
||||||
|
@ -79,7 +84,6 @@ Rain Height Max=700 ?
|
||||||
Rain Threshold=0.6 ?
|
Rain Threshold=0.6 ?
|
||||||
Max Raindrops=650 ?
|
Max Raindrops=650 ?
|
||||||
*/
|
*/
|
||||||
weather.mIsStorm = (name == "ashstorm" || name == "blight");
|
|
||||||
|
|
||||||
mWeatherSettings[name] = weather;
|
mWeatherSettings[name] = weather;
|
||||||
}
|
}
|
||||||
|
@ -112,8 +116,8 @@ float WeatherManager::calculateAngleFade (const std::string& moonName, float ang
|
||||||
return 1.f;
|
return 1.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
WeatherManager::WeatherManager(MWRender::RenderingManager* rendering,MWWorld::Fallback* fallback) :
|
WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, MWWorld::Fallback* fallback, MWWorld::ESMStore* store) :
|
||||||
mHour(14), mWindSpeed(0.f), mIsStorm(false), mStormDirection(0,1,0), mFallback(fallback),
|
mHour(14), mWindSpeed(0.f), mIsStorm(false), mStormDirection(0,1,0), mFallback(fallback), mStore(store),
|
||||||
mRendering(rendering), mCurrentWeather("clear"), mNextWeather(""), mFirstUpdate(true),
|
mRendering(rendering), mCurrentWeather("clear"), mNextWeather(""), mFirstUpdate(true),
|
||||||
mRemainingTransitionTime(0), mThunderFlash(0), mThunderChance(0), mThunderChanceNeeded(50),
|
mRemainingTransitionTime(0), mThunderFlash(0), mThunderChance(0), mThunderChanceNeeded(50),
|
||||||
mTimePassed(0), mWeatherUpdateTime(0), mThunderSoundDelay(0)
|
mTimePassed(0), mWeatherUpdateTime(0), mThunderSoundDelay(0)
|
||||||
|
|
|
@ -156,7 +156,8 @@ namespace MWWorld
|
||||||
class WeatherManager
|
class WeatherManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
WeatherManager(MWRender::RenderingManager*,MWWorld::Fallback* fallback);
|
// Have to pass fallback and Store, can't use singleton since World isn't fully constructed yet at the time
|
||||||
|
WeatherManager(MWRender::RenderingManager*, MWWorld::Fallback* fallback, MWWorld::ESMStore* store);
|
||||||
~WeatherManager();
|
~WeatherManager();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -210,6 +211,7 @@ namespace MWWorld
|
||||||
std::string mPlayingSoundID;
|
std::string mPlayingSoundID;
|
||||||
|
|
||||||
MWWorld::Fallback* mFallback;
|
MWWorld::Fallback* mFallback;
|
||||||
|
MWWorld::ESMStore* mStore;
|
||||||
void setFallbackWeather(Weather& weather,const std::string& name);
|
void setFallbackWeather(Weather& weather,const std::string& name);
|
||||||
MWRender::RenderingManager* mRendering;
|
MWRender::RenderingManager* mRendering;
|
||||||
|
|
||||||
|
|
|
@ -12,11 +12,15 @@
|
||||||
#include <osg/ComputeBoundsVisitor>
|
#include <osg/ComputeBoundsVisitor>
|
||||||
#include <osg/PositionAttitudeTransform>
|
#include <osg/PositionAttitudeTransform>
|
||||||
|
|
||||||
|
#include <components/esm/esmreader.hpp>
|
||||||
|
#include <components/esm/esmwriter.hpp>
|
||||||
|
|
||||||
#include <components/misc/rng.hpp>
|
#include <components/misc/rng.hpp>
|
||||||
|
|
||||||
#include <components/files/collections.hpp>
|
#include <components/files/collections.hpp>
|
||||||
#include <components/compiler/locals.hpp>
|
#include <components/compiler/locals.hpp>
|
||||||
#include <components/esm/cellid.hpp>
|
#include <components/esm/cellid.hpp>
|
||||||
|
#include <components/esm/esmreader.hpp>
|
||||||
#include <components/misc/resourcehelpers.hpp>
|
#include <components/misc/resourcehelpers.hpp>
|
||||||
#include <components/resource/resourcesystem.hpp>
|
#include <components/resource/resourcesystem.hpp>
|
||||||
|
|
||||||
|
@ -163,8 +167,6 @@ namespace MWWorld
|
||||||
mProjectileManager.reset(new ProjectileManager(rootNode, resourceSystem, mPhysics));
|
mProjectileManager.reset(new ProjectileManager(rootNode, resourceSystem, mPhysics));
|
||||||
mRendering = new MWRender::RenderingManager(viewer, rootNode, resourceSystem, &mFallback);
|
mRendering = new MWRender::RenderingManager(viewer, rootNode, resourceSystem, &mFallback);
|
||||||
|
|
||||||
mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback);
|
|
||||||
|
|
||||||
mEsm.resize(contentFiles.size());
|
mEsm.resize(contentFiles.size());
|
||||||
Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();
|
Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();
|
||||||
listener->loadingOn();
|
listener->loadingOn();
|
||||||
|
@ -193,6 +195,8 @@ namespace MWWorld
|
||||||
|
|
||||||
mGlobalVariables.fill (mStore);
|
mGlobalVariables.fill (mStore);
|
||||||
|
|
||||||
|
mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback,&mStore);
|
||||||
|
|
||||||
mWorldScene = new Scene(*mRendering, mPhysics);
|
mWorldScene = new Scene(*mRendering, mPhysics);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,7 +269,7 @@ namespace MWWorld
|
||||||
// we don't want old weather to persist on a new game
|
// we don't want old weather to persist on a new game
|
||||||
delete mWeatherManager;
|
delete mWeatherManager;
|
||||||
mWeatherManager = 0;
|
mWeatherManager = 0;
|
||||||
mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback);
|
mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback,&mStore);
|
||||||
|
|
||||||
if (!mStartupScript.empty())
|
if (!mStartupScript.empty())
|
||||||
MWBase::Environment::get().getWindowManager()->executeInConsole(mStartupScript);
|
MWBase::Environment::get().getWindowManager()->executeInConsole(mStartupScript);
|
||||||
|
|
|
@ -52,6 +52,11 @@ namespace MWRender
|
||||||
class Camera;
|
class Camera;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace ToUTF8
|
||||||
|
{
|
||||||
|
class Utf8Encoder;
|
||||||
|
}
|
||||||
|
|
||||||
struct ContentLoader;
|
struct ContentLoader;
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
#include "creaturestats.hpp"
|
#include "creaturestats.hpp"
|
||||||
|
#include "esmreader.hpp"
|
||||||
|
#include "esmwriter.hpp"
|
||||||
|
|
||||||
void ESM::CreatureStats::load (ESMReader &esm)
|
void ESM::CreatureStats::load (ESMReader &esm)
|
||||||
{
|
{
|
||||||
|
|
52
components/esm/statstate.cpp
Normal file
52
components/esm/statstate.cpp
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
#include "statstate.hpp"
|
||||||
|
|
||||||
|
#include "esmreader.hpp"
|
||||||
|
#include "esmwriter.hpp"
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
template<typename T>
|
||||||
|
StatState<T>::StatState() : mBase(0), mMod(0), mCurrent(0), mDamage(0), mProgress(0) {}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void StatState<T>::load(ESMReader &esm)
|
||||||
|
{
|
||||||
|
esm.getHNT(mBase, "STBA");
|
||||||
|
|
||||||
|
mMod = 0;
|
||||||
|
esm.getHNOT(mMod, "STMO");
|
||||||
|
mCurrent = 0;
|
||||||
|
esm.getHNOT(mCurrent, "STCU");
|
||||||
|
|
||||||
|
// mDamage was changed to a float; ensure backwards compatibility
|
||||||
|
T oldDamage = 0;
|
||||||
|
esm.getHNOT(oldDamage, "STDA");
|
||||||
|
mDamage = static_cast<float>(oldDamage);
|
||||||
|
|
||||||
|
esm.getHNOT(mDamage, "STDF");
|
||||||
|
|
||||||
|
mProgress = 0;
|
||||||
|
esm.getHNOT(mProgress, "STPR");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void StatState<T>::save(ESMWriter &esm) const
|
||||||
|
{
|
||||||
|
esm.writeHNT("STBA", mBase);
|
||||||
|
|
||||||
|
if (mMod != 0)
|
||||||
|
esm.writeHNT("STMO", mMod);
|
||||||
|
|
||||||
|
if (mCurrent)
|
||||||
|
esm.writeHNT("STCU", mCurrent);
|
||||||
|
|
||||||
|
if (mDamage)
|
||||||
|
esm.writeHNT("STDF", mDamage);
|
||||||
|
|
||||||
|
if (mProgress)
|
||||||
|
esm.writeHNT("STPR", mProgress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template struct ESM::StatState<int>;
|
||||||
|
template struct ESM::StatState<float>;
|
|
@ -1,11 +1,11 @@
|
||||||
#ifndef OPENMW_ESM_STATSTATE_H
|
#ifndef OPENMW_ESM_STATSTATE_H
|
||||||
#define OPENMW_ESM_STATSTATE_H
|
#define OPENMW_ESM_STATSTATE_H
|
||||||
|
|
||||||
#include "esmreader.hpp"
|
|
||||||
#include "esmwriter.hpp"
|
|
||||||
|
|
||||||
namespace ESM
|
namespace ESM
|
||||||
{
|
{
|
||||||
|
class ESMReader;
|
||||||
|
class ESMWriter;
|
||||||
|
|
||||||
// format 0, saved games only
|
// format 0, saved games only
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
@ -23,48 +23,6 @@ namespace ESM
|
||||||
void load (ESMReader &esm);
|
void load (ESMReader &esm);
|
||||||
void save (ESMWriter &esm) const;
|
void save (ESMWriter &esm) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
StatState<T>::StatState() : mBase (0), mMod (0), mCurrent (0), mDamage (0), mProgress (0) {}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
void StatState<T>::load (ESMReader &esm)
|
|
||||||
{
|
|
||||||
esm.getHNT (mBase, "STBA");
|
|
||||||
|
|
||||||
mMod = 0;
|
|
||||||
esm.getHNOT (mMod, "STMO");
|
|
||||||
mCurrent = 0;
|
|
||||||
esm.getHNOT (mCurrent, "STCU");
|
|
||||||
|
|
||||||
// mDamage was changed to a float; ensure backwards compatibility
|
|
||||||
T oldDamage = 0;
|
|
||||||
esm.getHNOT(oldDamage, "STDA");
|
|
||||||
mDamage = static_cast<float>(oldDamage);
|
|
||||||
|
|
||||||
esm.getHNOT (mDamage, "STDF");
|
|
||||||
|
|
||||||
mProgress = 0;
|
|
||||||
esm.getHNOT (mProgress, "STPR");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
void StatState<T>::save (ESMWriter &esm) const
|
|
||||||
{
|
|
||||||
esm.writeHNT ("STBA", mBase);
|
|
||||||
|
|
||||||
if (mMod != 0)
|
|
||||||
esm.writeHNT ("STMO", mMod);
|
|
||||||
|
|
||||||
if (mCurrent)
|
|
||||||
esm.writeHNT ("STCU", mCurrent);
|
|
||||||
|
|
||||||
if (mDamage)
|
|
||||||
esm.writeHNT ("STDF", mDamage);
|
|
||||||
|
|
||||||
if (mProgress)
|
|
||||||
esm.writeHNT ("STPR", mProgress);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -119,7 +119,7 @@ class Drawable : public osg::Drawable {
|
||||||
|
|
||||||
// VBOs disabled due to crash in OSG: http://forum.openscenegraph.org/viewtopic.php?t=14909
|
// VBOs disabled due to crash in OSG: http://forum.openscenegraph.org/viewtopic.php?t=14909
|
||||||
osg::GLBufferObject* bufferobject = 0;//state->isVertexBufferObjectSupported() ? vbo->getOrCreateGLBufferObject(state->getContextID()) : 0;
|
osg::GLBufferObject* bufferobject = 0;//state->isVertexBufferObjectSupported() ? vbo->getOrCreateGLBufferObject(state->getContextID()) : 0;
|
||||||
if (bufferobject)
|
if (0)//bufferobject)
|
||||||
{
|
{
|
||||||
state->bindVertexBufferObject(bufferobject);
|
state->bindVertexBufferObject(bufferobject);
|
||||||
|
|
||||||
|
@ -165,6 +165,8 @@ public:
|
||||||
Drawable(const Drawable ©, const osg::CopyOp ©op=osg::CopyOp::SHALLOW_COPY)
|
Drawable(const Drawable ©, const osg::CopyOp ©op=osg::CopyOp::SHALLOW_COPY)
|
||||||
: osg::Drawable(copy, copyop)
|
: osg::Drawable(copy, copyop)
|
||||||
, mParent(copy.mParent)
|
, mParent(copy.mParent)
|
||||||
|
, mWriteTo(0)
|
||||||
|
, mReadFrom(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -521,12 +523,8 @@ void RenderManager::destroyAllResources()
|
||||||
|
|
||||||
bool RenderManager::checkTexture(MyGUI::ITexture* _texture)
|
bool RenderManager::checkTexture(MyGUI::ITexture* _texture)
|
||||||
{
|
{
|
||||||
for (MapTexture::const_iterator item = mTextures.begin(); item != mTextures.end(); ++item)
|
// We support external textures that aren't registered via this manager, so can't implement this method sensibly.
|
||||||
{
|
return true;
|
||||||
if (item->second == _texture)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -407,6 +407,8 @@ FlipController::FlipController(int texSlot, float delta, std::vector<osg::ref_pt
|
||||||
}
|
}
|
||||||
|
|
||||||
FlipController::FlipController()
|
FlipController::FlipController()
|
||||||
|
: mTexSlot(0)
|
||||||
|
, mDelta(0.f)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -434,6 +436,7 @@ ParticleSystemController::ParticleSystemController(const Nif::NiParticleSystemCo
|
||||||
}
|
}
|
||||||
|
|
||||||
ParticleSystemController::ParticleSystemController()
|
ParticleSystemController::ParticleSystemController()
|
||||||
|
: mEmitStart(0.f), mEmitStop(0.f)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ void InverseWorldMatrix::operator()(osg::Node *node, osg::NodeVisitor *nv)
|
||||||
osg::NodePath path = nv->getNodePath();
|
osg::NodePath path = nv->getNodePath();
|
||||||
path.pop_back();
|
path.pop_back();
|
||||||
|
|
||||||
osg::MatrixTransform* trans = dynamic_cast<osg::MatrixTransform*>(node);
|
osg::MatrixTransform* trans = static_cast<osg::MatrixTransform*>(node);
|
||||||
|
|
||||||
osg::Matrix mat = osg::computeLocalToWorld( path );
|
osg::Matrix mat = osg::computeLocalToWorld( path );
|
||||||
mat.orthoNormalize(mat); // don't undo the scale
|
mat.orthoNormalize(mat); // don't undo the scale
|
||||||
|
|
|
@ -11,6 +11,7 @@ namespace SceneUtil
|
||||||
class ControllerSource
|
class ControllerSource
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
virtual ~ControllerSource() { }
|
||||||
virtual float getValue(osg::NodeVisitor* nv) = 0;
|
virtual float getValue(osg::NodeVisitor* nv) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -244,7 +244,7 @@ namespace SceneUtil
|
||||||
|
|
||||||
bool sortLights (const LightManager::LightSourceTransform* left, const LightManager::LightSourceTransform* right)
|
bool sortLights (const LightManager::LightSourceTransform* left, const LightManager::LightSourceTransform* right)
|
||||||
{
|
{
|
||||||
return left->mViewBound.center().length2() < right->mViewBound.center().length2();
|
return left->mViewBound.center().length2() - left->mViewBound.radius2()/4.f < right->mViewBound.center().length2() - right->mViewBound.radius2()/4.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LightListCallback::operator()(osg::Node *node, osg::NodeVisitor *nv)
|
void LightListCallback::operator()(osg::Node *node, osg::NodeVisitor *nv)
|
||||||
|
|
Loading…
Reference in a new issue