forked from teamnwah/openmw-tes3coop
Merge branch 'master' of https://github.com/zinnschlag/openmw.git into MeleeCombat2
Conflicts: apps/openmw/mwmechanics/character.cpp apps/openmw/mwmechanics/character.hpp
This commit is contained in:
commit
ee47e99dad
43 changed files with 1473 additions and 484 deletions
|
@ -18,7 +18,7 @@ opencs_hdrs_noqt (model/doc
|
||||||
|
|
||||||
|
|
||||||
opencs_units (model/world
|
opencs_units (model/world
|
||||||
idtable idtableproxymodel
|
idtable idtableproxymodel regionmap
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ opencs_hdrs_noqt (view/doc
|
||||||
|
|
||||||
|
|
||||||
opencs_units (view/world
|
opencs_units (view/world
|
||||||
table tablesubview scriptsubview util
|
table tablesubview scriptsubview util regionmapsubview
|
||||||
)
|
)
|
||||||
|
|
||||||
opencs_units_noqt (view/world
|
opencs_units_noqt (view/world
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include "idtable.hpp"
|
#include "idtable.hpp"
|
||||||
#include "columns.hpp"
|
#include "columns.hpp"
|
||||||
|
#include "regionmap.hpp"
|
||||||
|
|
||||||
void CSMWorld::Data::addModel (QAbstractItemModel *model, UniversalId::Type type1,
|
void CSMWorld::Data::addModel (QAbstractItemModel *model, UniversalId::Type type1,
|
||||||
UniversalId::Type type2)
|
UniversalId::Type type2)
|
||||||
|
@ -304,7 +305,20 @@ QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id)
|
||||||
std::map<UniversalId::Type, QAbstractItemModel *>::iterator iter = mModelIndex.find (id.getType());
|
std::map<UniversalId::Type, QAbstractItemModel *>::iterator iter = mModelIndex.find (id.getType());
|
||||||
|
|
||||||
if (iter==mModelIndex.end())
|
if (iter==mModelIndex.end())
|
||||||
|
{
|
||||||
|
// try creating missing (secondary) tables on the fly
|
||||||
|
//
|
||||||
|
// Note: We create these tables here so we don't have to deal with them during load/initial
|
||||||
|
// construction of the ESX data where no update signals are available.
|
||||||
|
if (id.getType()==UniversalId::Type_RegionMap)
|
||||||
|
{
|
||||||
|
RegionMap *table = 0;
|
||||||
|
addModel (table = new RegionMap (*this), UniversalId::Type_RegionMap,
|
||||||
|
UniversalId::Type_None);
|
||||||
|
return table;
|
||||||
|
}
|
||||||
throw std::logic_error ("No table model available for " + id.toString());
|
throw std::logic_error ("No table model available for " + id.toString());
|
||||||
|
}
|
||||||
|
|
||||||
return iter->second;
|
return iter->second;
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ namespace CSMWorld
|
||||||
{
|
{
|
||||||
Record<ESXRecordT> record = Collection<ESXRecordT, IdAccessorT>::getRecord (index);
|
Record<ESXRecordT> record = Collection<ESXRecordT, IdAccessorT>::getRecord (index);
|
||||||
record.mState = RecordBase::State_Deleted;
|
record.mState = RecordBase::State_Deleted;
|
||||||
setRecord (index, record);
|
this->setRecord (index, record);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -56,7 +56,7 @@ namespace CSMWorld
|
||||||
IdAccessorT().getId (record) = id;
|
IdAccessorT().getId (record) = id;
|
||||||
record.load (reader);
|
record.load (reader);
|
||||||
|
|
||||||
int index = searchId (IdAccessorT().getId (record));
|
int index = this->searchId (IdAccessorT().getId (record));
|
||||||
|
|
||||||
if (index==-1)
|
if (index==-1)
|
||||||
{
|
{
|
||||||
|
@ -65,7 +65,7 @@ namespace CSMWorld
|
||||||
record2.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly;
|
record2.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly;
|
||||||
(base ? record2.mBase : record2.mModified) = record;
|
(base ? record2.mBase : record2.mModified) = record;
|
||||||
|
|
||||||
appendRecord (record2);
|
this->appendRecord (record2);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -77,7 +77,7 @@ namespace CSMWorld
|
||||||
else
|
else
|
||||||
record2.setModified (record);
|
record2.setModified (record);
|
||||||
|
|
||||||
setRecord (index, record2);
|
this->setRecord (index, record2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,8 +16,6 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool
|
||||||
|
|
||||||
Cell& cell2 = base ? cell.mBase : cell.mModified;
|
Cell& cell2 = base ? cell.mBase : cell.mModified;
|
||||||
|
|
||||||
cell2.restore (reader, 0); /// \todo fix the index
|
|
||||||
|
|
||||||
CellRef ref;
|
CellRef ref;
|
||||||
|
|
||||||
while (cell2.getNextRef (reader, ref))
|
while (cell2.getNextRef (reader, ref))
|
||||||
|
|
513
apps/opencs/model/world/regionmap.cpp
Normal file
513
apps/opencs/model/world/regionmap.cpp
Normal file
|
@ -0,0 +1,513 @@
|
||||||
|
|
||||||
|
#include "regionmap.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <QBrush>
|
||||||
|
|
||||||
|
#include <components/misc/stringops.hpp>
|
||||||
|
|
||||||
|
#include "data.hpp"
|
||||||
|
#include "universalid.hpp"
|
||||||
|
|
||||||
|
CSMWorld::RegionMap::CellDescription::CellDescription() : mDeleted (false) {}
|
||||||
|
|
||||||
|
CSMWorld::RegionMap::CellDescription::CellDescription (const Record<Cell>& cell)
|
||||||
|
{
|
||||||
|
const Cell& cell2 = cell.get();
|
||||||
|
|
||||||
|
if (!cell2.isExterior())
|
||||||
|
throw std::logic_error ("Interior cell in region map");
|
||||||
|
|
||||||
|
mDeleted = cell.isDeleted();
|
||||||
|
|
||||||
|
mRegion = cell2.mRegion;
|
||||||
|
mName = cell2.mName;
|
||||||
|
}
|
||||||
|
|
||||||
|
CSMWorld::RegionMap::CellIndex CSMWorld::RegionMap::getIndex (const QModelIndex& index) const
|
||||||
|
{
|
||||||
|
return CellIndex (index.column()+mMin.first,
|
||||||
|
(mMax.second-mMin.second - index.row()-1)+mMin.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex CSMWorld::RegionMap::getIndex (const CellIndex& index) const
|
||||||
|
{
|
||||||
|
// I hate you, Qt API naming scheme!
|
||||||
|
return QAbstractTableModel::index (mMax.second-mMin.second - (index.second-mMin.second)-1,
|
||||||
|
index.first-mMin.first);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::RegionMap::buildRegions()
|
||||||
|
{
|
||||||
|
const IdCollection<ESM::Region>& regions = mData.getRegions();
|
||||||
|
|
||||||
|
int size = regions.getSize();
|
||||||
|
|
||||||
|
for (int i=0; i<size; ++i)
|
||||||
|
{
|
||||||
|
const Record<ESM::Region>& region = regions.getRecord (i);
|
||||||
|
|
||||||
|
if (!region.isDeleted())
|
||||||
|
mColours.insert (std::make_pair (Misc::StringUtils::lowerCase (region.get().mId),
|
||||||
|
region.get().mMapColor));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::RegionMap::buildMap()
|
||||||
|
{
|
||||||
|
const IdCollection<Cell>& cells = mData.getCells();
|
||||||
|
|
||||||
|
int size = cells.getSize();
|
||||||
|
|
||||||
|
for (int i=0; i<size; ++i)
|
||||||
|
{
|
||||||
|
const Record<Cell>& cell = cells.getRecord (i);
|
||||||
|
|
||||||
|
const Cell& cell2 = cell.get();
|
||||||
|
|
||||||
|
if (cell2.isExterior())
|
||||||
|
{
|
||||||
|
CellDescription description (cell);
|
||||||
|
|
||||||
|
CellIndex index (cell2.mData.mX, cell2.mData.mY);
|
||||||
|
|
||||||
|
mMap.insert (std::make_pair (index, description));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<CellIndex, CellIndex> mapSize = getSize();
|
||||||
|
|
||||||
|
mMin = mapSize.first;
|
||||||
|
mMax = mapSize.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::RegionMap::addCell (const CellIndex& index, const CellDescription& description)
|
||||||
|
{
|
||||||
|
std::map<CellIndex, CellDescription>::iterator cell = mMap.find (index);
|
||||||
|
|
||||||
|
if (cell!=mMap.end())
|
||||||
|
{
|
||||||
|
cell->second = description;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
updateSize();
|
||||||
|
|
||||||
|
mMap.insert (std::make_pair (index, description));
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex index2 = getIndex (index);
|
||||||
|
|
||||||
|
dataChanged (index2, index2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::RegionMap::addCells (int start, int end)
|
||||||
|
{
|
||||||
|
const IdCollection<Cell>& cells = mData.getCells();
|
||||||
|
|
||||||
|
for (int i=start; i<=end; ++i)
|
||||||
|
{
|
||||||
|
const Record<Cell>& cell = cells.getRecord (i);
|
||||||
|
|
||||||
|
const Cell& cell2 = cell.get();
|
||||||
|
|
||||||
|
if (cell2.isExterior())
|
||||||
|
{
|
||||||
|
CellIndex index (cell2.mData.mX, cell2.mData.mY);
|
||||||
|
|
||||||
|
CellDescription description (cell);
|
||||||
|
|
||||||
|
addCell (index, description);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::RegionMap::removeCell (const CellIndex& index)
|
||||||
|
{
|
||||||
|
std::map<CellIndex, CellDescription>::iterator cell = mMap.find (index);
|
||||||
|
|
||||||
|
if (cell!=mMap.end())
|
||||||
|
{
|
||||||
|
mMap.erase (cell);
|
||||||
|
|
||||||
|
QModelIndex index2 = getIndex (index);
|
||||||
|
|
||||||
|
dataChanged (index2, index2);
|
||||||
|
|
||||||
|
updateSize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::RegionMap::addRegion (const std::string& region, unsigned int colour)
|
||||||
|
{
|
||||||
|
mColours[Misc::StringUtils::lowerCase (region)] = colour;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::RegionMap::removeRegion (const std::string& region)
|
||||||
|
{
|
||||||
|
std::map<std::string, unsigned int>::iterator iter (
|
||||||
|
mColours.find (Misc::StringUtils::lowerCase (region)));
|
||||||
|
|
||||||
|
if (iter!=mColours.end())
|
||||||
|
mColours.erase (iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::RegionMap::updateRegions (const std::vector<std::string>& regions)
|
||||||
|
{
|
||||||
|
std::vector<std::string> regions2 (regions);
|
||||||
|
|
||||||
|
std::for_each (regions2.begin(), regions2.end(), &Misc::StringUtils::lowerCase);
|
||||||
|
std::sort (regions2.begin(), regions2.end());
|
||||||
|
|
||||||
|
for (std::map<CellIndex, CellDescription>::const_iterator iter (mMap.begin());
|
||||||
|
iter!=mMap.end(); ++iter)
|
||||||
|
{
|
||||||
|
if (!iter->second.mRegion.empty() &&
|
||||||
|
std::find (regions2.begin(), regions2.end(),
|
||||||
|
Misc::StringUtils::lowerCase (iter->second.mRegion))!=regions2.end())
|
||||||
|
{
|
||||||
|
QModelIndex index = getIndex (iter->first);
|
||||||
|
|
||||||
|
dataChanged (index, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::RegionMap::updateSize()
|
||||||
|
{
|
||||||
|
std::pair<CellIndex, CellIndex> size = getSize();
|
||||||
|
|
||||||
|
{
|
||||||
|
int diff = size.first.first - mMin.first;
|
||||||
|
|
||||||
|
if (diff<0)
|
||||||
|
{
|
||||||
|
beginInsertColumns (QModelIndex(), 0, -diff-1);
|
||||||
|
mMin.first = size.first.first;
|
||||||
|
endInsertColumns();
|
||||||
|
}
|
||||||
|
else if (diff>0)
|
||||||
|
{
|
||||||
|
beginRemoveColumns (QModelIndex(), 0, diff-1);
|
||||||
|
mMin.first = size.first.first;
|
||||||
|
endRemoveColumns();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
int diff = size.first.second - mMin.second;
|
||||||
|
|
||||||
|
if (diff<0)
|
||||||
|
{
|
||||||
|
beginInsertRows (QModelIndex(), 0, -diff-1);
|
||||||
|
mMin.second = size.first.second;
|
||||||
|
endInsertRows();
|
||||||
|
}
|
||||||
|
else if (diff>0)
|
||||||
|
{
|
||||||
|
beginRemoveRows (QModelIndex(), 0, diff-1);
|
||||||
|
mMin.second = size.first.second;
|
||||||
|
endRemoveRows();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
int diff = size.second.first - mMax.first;
|
||||||
|
|
||||||
|
if (diff>0)
|
||||||
|
{
|
||||||
|
int columns = columnCount();
|
||||||
|
beginInsertColumns (QModelIndex(), columns, columns+diff-1);
|
||||||
|
mMax.first = size.second.first;
|
||||||
|
endInsertColumns();
|
||||||
|
}
|
||||||
|
else if (diff<0)
|
||||||
|
{
|
||||||
|
int columns = columnCount();
|
||||||
|
beginRemoveColumns (QModelIndex(), columns+diff, columns-1);
|
||||||
|
mMax.first = size.second.first;
|
||||||
|
endRemoveColumns();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
int diff = size.second.second - mMax.second;
|
||||||
|
|
||||||
|
if (diff>0)
|
||||||
|
{
|
||||||
|
int rows = rowCount();
|
||||||
|
beginInsertRows (QModelIndex(), rows, rows+diff-1);
|
||||||
|
mMax.second = size.second.second;
|
||||||
|
endInsertRows();
|
||||||
|
}
|
||||||
|
else if (diff<0)
|
||||||
|
{
|
||||||
|
int rows = rowCount();
|
||||||
|
beginRemoveRows (QModelIndex(), rows+diff, rows-1);
|
||||||
|
mMax.second = size.second.second;
|
||||||
|
endRemoveRows();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<CSMWorld::RegionMap::CellIndex, CSMWorld::RegionMap::CellIndex> CSMWorld::RegionMap::getSize()
|
||||||
|
const
|
||||||
|
{
|
||||||
|
const IdCollection<Cell>& cells = mData.getCells();
|
||||||
|
|
||||||
|
int size = cells.getSize();
|
||||||
|
|
||||||
|
CellIndex min (0, 0);
|
||||||
|
CellIndex max (0, 0);
|
||||||
|
|
||||||
|
for (int i=0; i<size; ++i)
|
||||||
|
{
|
||||||
|
const Record<Cell>& cell = cells.getRecord (i);
|
||||||
|
|
||||||
|
const Cell& cell2 = cell.get();
|
||||||
|
|
||||||
|
if (cell2.isExterior())
|
||||||
|
{
|
||||||
|
CellIndex index (cell2.mData.mX, cell2.mData.mY);
|
||||||
|
|
||||||
|
if (min==max)
|
||||||
|
{
|
||||||
|
min = index;
|
||||||
|
max = std::make_pair (min.first+1, min.second+1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (index.first<min.first)
|
||||||
|
min.first = index.first;
|
||||||
|
else if (index.first>=max.first)
|
||||||
|
max.first = index.first + 1;
|
||||||
|
|
||||||
|
if (index.second<min.second)
|
||||||
|
min.second = index.second;
|
||||||
|
else if (index.second>=max.second)
|
||||||
|
max.second = index.second + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_pair (min, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
CSMWorld::RegionMap::RegionMap (Data& data) : mData (data)
|
||||||
|
{
|
||||||
|
buildRegions();
|
||||||
|
buildMap();
|
||||||
|
|
||||||
|
QAbstractItemModel *regions = data.getTableModel (UniversalId (UniversalId::Type_Regions));
|
||||||
|
|
||||||
|
connect (regions, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)),
|
||||||
|
this, SLOT (regionsAboutToBeRemoved (const QModelIndex&, int, int)));
|
||||||
|
connect (regions, SIGNAL (rowsInserted (const QModelIndex&, int, int)),
|
||||||
|
this, SLOT (regionsInserted (const QModelIndex&, int, int)));
|
||||||
|
connect (regions, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)),
|
||||||
|
this, SLOT (regionsChanged (const QModelIndex&, const QModelIndex&)));
|
||||||
|
|
||||||
|
QAbstractItemModel *cells = data.getTableModel (UniversalId (UniversalId::Type_Cells));
|
||||||
|
|
||||||
|
connect (cells, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)),
|
||||||
|
this, SLOT (cellsAboutToBeRemoved (const QModelIndex&, int, int)));
|
||||||
|
connect (cells, SIGNAL (rowsInserted (const QModelIndex&, int, int)),
|
||||||
|
this, SLOT (cellsInserted (const QModelIndex&, int, int)));
|
||||||
|
connect (cells, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)),
|
||||||
|
this, SLOT (cellsChanged (const QModelIndex&, const QModelIndex&)));
|
||||||
|
}
|
||||||
|
|
||||||
|
int CSMWorld::RegionMap::rowCount (const QModelIndex& parent) const
|
||||||
|
{
|
||||||
|
if (parent.isValid())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return mMax.second-mMin.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CSMWorld::RegionMap::columnCount (const QModelIndex& parent) const
|
||||||
|
{
|
||||||
|
if (parent.isValid())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return mMax.first-mMin.first;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant CSMWorld::RegionMap::data (const QModelIndex& index, int role) const
|
||||||
|
{
|
||||||
|
if (role==Qt::SizeHintRole)
|
||||||
|
return QSize (16, 16);
|
||||||
|
|
||||||
|
if (role==Qt::BackgroundRole)
|
||||||
|
{
|
||||||
|
/// \todo GUI class in non-GUI code. Needs to be addressed eventually.
|
||||||
|
|
||||||
|
std::map<CellIndex, CellDescription>::const_iterator cell =
|
||||||
|
mMap.find (getIndex (index));
|
||||||
|
|
||||||
|
if (cell!=mMap.end())
|
||||||
|
{
|
||||||
|
if (cell->second.mDeleted)
|
||||||
|
return QBrush (Qt::red, Qt::DiagCrossPattern);
|
||||||
|
|
||||||
|
std::map<std::string, unsigned int>::const_iterator iter =
|
||||||
|
mColours.find (Misc::StringUtils::lowerCase (cell->second.mRegion));
|
||||||
|
|
||||||
|
if (iter!=mColours.end())
|
||||||
|
return QBrush (
|
||||||
|
QColor (iter->second>>24, (iter->second>>16) & 255, (iter->second>>8) & 255,
|
||||||
|
iter->second & 255));
|
||||||
|
|
||||||
|
if (cell->second.mRegion.empty())
|
||||||
|
return QBrush (Qt::Dense6Pattern); // no region
|
||||||
|
|
||||||
|
return QBrush (Qt::red, Qt::Dense6Pattern); // invalid region
|
||||||
|
}
|
||||||
|
|
||||||
|
return QBrush (Qt::DiagCrossPattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (role==Qt::ToolTipRole)
|
||||||
|
{
|
||||||
|
CellIndex cellIndex = getIndex (index);
|
||||||
|
|
||||||
|
std::ostringstream stream;
|
||||||
|
|
||||||
|
stream << cellIndex.first << ", " << cellIndex.second;
|
||||||
|
|
||||||
|
std::map<CellIndex, CellDescription>::const_iterator cell =
|
||||||
|
mMap.find (cellIndex);
|
||||||
|
|
||||||
|
if (cell!=mMap.end())
|
||||||
|
{
|
||||||
|
if (!cell->second.mName.empty())
|
||||||
|
stream << " " << cell->second.mName;
|
||||||
|
|
||||||
|
if (cell->second.mDeleted)
|
||||||
|
stream << " (deleted)";
|
||||||
|
|
||||||
|
if (!cell->second.mRegion.empty())
|
||||||
|
{
|
||||||
|
stream << "<br>";
|
||||||
|
|
||||||
|
std::map<std::string, unsigned int>::const_iterator iter =
|
||||||
|
mColours.find (Misc::StringUtils::lowerCase (cell->second.mRegion));
|
||||||
|
|
||||||
|
if (iter!=mColours.end())
|
||||||
|
stream << cell->second.mRegion;
|
||||||
|
else
|
||||||
|
stream << "<font color=red>" << cell->second.mRegion << "</font>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
stream << " (no cell)";
|
||||||
|
|
||||||
|
return QString::fromUtf8 (stream.str().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::ItemFlags CSMWorld::RegionMap::flags (const QModelIndex& index) const
|
||||||
|
{
|
||||||
|
if (mMap.find (getIndex (index))!=mMap.end())
|
||||||
|
return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::RegionMap::regionsAboutToBeRemoved (const QModelIndex& parent, int start, int end)
|
||||||
|
{
|
||||||
|
std::vector<std::string> update;
|
||||||
|
|
||||||
|
const IdCollection<ESM::Region>& regions = mData.getRegions();
|
||||||
|
|
||||||
|
for (int i=start; i<=end; ++i)
|
||||||
|
{
|
||||||
|
const Record<ESM::Region>& region = regions.getRecord (i);
|
||||||
|
|
||||||
|
update.push_back (region.get().mId);
|
||||||
|
|
||||||
|
removeRegion (region.get().mId);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateRegions (update);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::RegionMap::regionsInserted (const QModelIndex& parent, int start, int end)
|
||||||
|
{
|
||||||
|
std::vector<std::string> update;
|
||||||
|
|
||||||
|
const IdCollection<ESM::Region>& regions = mData.getRegions();
|
||||||
|
|
||||||
|
for (int i=start; i<=end; ++i)
|
||||||
|
{
|
||||||
|
const Record<ESM::Region>& region = regions.getRecord (i);
|
||||||
|
|
||||||
|
if (!region.isDeleted())
|
||||||
|
{
|
||||||
|
update.push_back (region.get().mId);
|
||||||
|
|
||||||
|
addRegion (region.get().mId, region.get().mMapColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateRegions (update);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::RegionMap::regionsChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight)
|
||||||
|
{
|
||||||
|
// Note: At this point an additional check could be inserted to see if there is any change to the
|
||||||
|
// columns we are interested in. If not we can exit the function here and avoid all updating.
|
||||||
|
|
||||||
|
std::vector<std::string> update;
|
||||||
|
|
||||||
|
const IdCollection<ESM::Region>& regions = mData.getRegions();
|
||||||
|
|
||||||
|
for (int i=topLeft.row(); i<=bottomRight.column(); ++i)
|
||||||
|
{
|
||||||
|
const Record<ESM::Region>& region = regions.getRecord (i);
|
||||||
|
|
||||||
|
update.push_back (region.get().mId);
|
||||||
|
|
||||||
|
if (!region.isDeleted())
|
||||||
|
addRegion (region.get().mId, region.get().mMapColor);
|
||||||
|
else
|
||||||
|
removeRegion (region.get().mId);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateRegions (update);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::RegionMap::cellsAboutToBeRemoved (const QModelIndex& parent, int start, int end)
|
||||||
|
{
|
||||||
|
const IdCollection<Cell>& cells = mData.getCells();
|
||||||
|
|
||||||
|
for (int i=start; i<=end; ++i)
|
||||||
|
{
|
||||||
|
const Record<Cell>& cell = cells.getRecord (i);
|
||||||
|
|
||||||
|
const Cell& cell2 = cell.get();
|
||||||
|
|
||||||
|
if (cell2.isExterior())
|
||||||
|
{
|
||||||
|
CellIndex index (cell2.mData.mX, cell2.mData.mY);
|
||||||
|
|
||||||
|
removeCell (index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::RegionMap::cellsInserted (const QModelIndex& parent, int start, int end)
|
||||||
|
{
|
||||||
|
addCells (start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::RegionMap::cellsChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight)
|
||||||
|
{
|
||||||
|
// Note: At this point an additional check could be inserted to see if there is any change to the
|
||||||
|
// columns we are interested in. If not we can exit the function here and avoid all updating.
|
||||||
|
|
||||||
|
addCells (topLeft.row(), bottomRight.row());
|
||||||
|
}
|
111
apps/opencs/model/world/regionmap.hpp
Normal file
111
apps/opencs/model/world/regionmap.hpp
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
#ifndef CSM_WOLRD_REGIONMAP_H
|
||||||
|
#define CSM_WOLRD_REGIONMAP_H
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <QAbstractTableModel>
|
||||||
|
|
||||||
|
#include "record.hpp"
|
||||||
|
#include "cell.hpp"
|
||||||
|
|
||||||
|
namespace CSMWorld
|
||||||
|
{
|
||||||
|
class Data;
|
||||||
|
|
||||||
|
/// \brief Model for the region map
|
||||||
|
///
|
||||||
|
/// This class does not holds any record data (other than for the purpose of buffering).
|
||||||
|
class RegionMap : public QAbstractTableModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
typedef std::pair<int, int> CellIndex;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
struct CellDescription
|
||||||
|
{
|
||||||
|
bool mDeleted;
|
||||||
|
std::string mRegion;
|
||||||
|
std::string mName;
|
||||||
|
|
||||||
|
CellDescription();
|
||||||
|
|
||||||
|
CellDescription (const Record<Cell>& cell);
|
||||||
|
};
|
||||||
|
|
||||||
|
Data& mData;
|
||||||
|
std::map<CellIndex, CellDescription> mMap;
|
||||||
|
CellIndex mMin; ///< inclusive
|
||||||
|
CellIndex mMax; ///< exclusive
|
||||||
|
std::map<std::string, unsigned int> mColours; ///< region ID, colour (RGBA)
|
||||||
|
|
||||||
|
CellIndex getIndex (const QModelIndex& index) const;
|
||||||
|
///< Translates a Qt model index into a cell index (which can contain negative components)
|
||||||
|
|
||||||
|
QModelIndex getIndex (const CellIndex& index) const;
|
||||||
|
|
||||||
|
void buildRegions();
|
||||||
|
|
||||||
|
void buildMap();
|
||||||
|
|
||||||
|
void addCell (const CellIndex& index, const CellDescription& description);
|
||||||
|
///< May be called on a cell that is already in the map (in which case an update is
|
||||||
|
// performed)
|
||||||
|
|
||||||
|
void addCells (int start, int end);
|
||||||
|
|
||||||
|
void removeCell (const CellIndex& index);
|
||||||
|
///< May be called on a cell that is not in the map (in which case the call is ignored)
|
||||||
|
|
||||||
|
void addRegion (const std::string& region, unsigned int colour);
|
||||||
|
///< May be called on a region that is already listed (in which case an update is
|
||||||
|
/// performed)
|
||||||
|
///
|
||||||
|
/// \note This function does not update the region map.
|
||||||
|
|
||||||
|
void removeRegion (const std::string& region);
|
||||||
|
///< May be called on a region that is not listed (in which case the call is ignored)
|
||||||
|
///
|
||||||
|
/// \note This function does not update the region map.
|
||||||
|
|
||||||
|
void updateRegions (const std::vector<std::string>& regions);
|
||||||
|
///< Update cells affected by the listed regions
|
||||||
|
|
||||||
|
void updateSize();
|
||||||
|
|
||||||
|
std::pair<CellIndex, CellIndex> getSize() const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
RegionMap (Data& data);
|
||||||
|
|
||||||
|
virtual int rowCount (const QModelIndex& parent = QModelIndex()) const;
|
||||||
|
|
||||||
|
virtual int columnCount (const QModelIndex& parent = QModelIndex()) const;
|
||||||
|
|
||||||
|
virtual QVariant data (const QModelIndex& index, int role = Qt::DisplayRole) const;
|
||||||
|
|
||||||
|
virtual Qt::ItemFlags flags (const QModelIndex& index) const;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
|
||||||
|
void regionsAboutToBeRemoved (const QModelIndex& parent, int start, int end);
|
||||||
|
|
||||||
|
void regionsInserted (const QModelIndex& parent, int start, int end);
|
||||||
|
|
||||||
|
void regionsChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight);
|
||||||
|
|
||||||
|
void cellsAboutToBeRemoved (const QModelIndex& parent, int start, int end);
|
||||||
|
|
||||||
|
void cellsInserted (const QModelIndex& parent, int start, int end);
|
||||||
|
|
||||||
|
void cellsChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -33,6 +33,8 @@ namespace
|
||||||
"Referenceables" },
|
"Referenceables" },
|
||||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_References,
|
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_References,
|
||||||
"References" },
|
"References" },
|
||||||
|
{ CSMWorld::UniversalId::Class_NonRecord, CSMWorld::UniversalId::Type_RegionMap,
|
||||||
|
"Region Map" },
|
||||||
|
|
||||||
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker
|
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker
|
||||||
};
|
};
|
||||||
|
|
|
@ -81,7 +81,8 @@ namespace CSMWorld
|
||||||
Type_Static,
|
Type_Static,
|
||||||
Type_Weapon,
|
Type_Weapon,
|
||||||
Type_References,
|
Type_References,
|
||||||
Type_Reference
|
Type_Reference,
|
||||||
|
Type_RegionMap
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -139,6 +139,10 @@ void CSVDoc::View::setupWorldMenu()
|
||||||
QAction *references = new QAction (tr ("References"), this);
|
QAction *references = new QAction (tr ("References"), this);
|
||||||
connect (references, SIGNAL (triggered()), this, SLOT (addReferencesSubView()));
|
connect (references, SIGNAL (triggered()), this, SLOT (addReferencesSubView()));
|
||||||
world->addAction (references);
|
world->addAction (references);
|
||||||
|
|
||||||
|
QAction *regionMap = new QAction (tr ("Region Map"), this);
|
||||||
|
connect (regionMap, SIGNAL (triggered()), this, SLOT (addRegionMapSubView()));
|
||||||
|
world->addAction (regionMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVDoc::View::setupUi()
|
void CSVDoc::View::setupUi()
|
||||||
|
@ -362,6 +366,11 @@ void CSVDoc::View::addReferencesSubView()
|
||||||
addSubView (CSMWorld::UniversalId::Type_References);
|
addSubView (CSMWorld::UniversalId::Type_References);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVDoc::View::addRegionMapSubView()
|
||||||
|
{
|
||||||
|
addSubView (CSMWorld::UniversalId::Type_RegionMap);
|
||||||
|
}
|
||||||
|
|
||||||
void CSVDoc::View::abortOperation (int type)
|
void CSVDoc::View::abortOperation (int type)
|
||||||
{
|
{
|
||||||
mDocument->abortOperation (type);
|
mDocument->abortOperation (type);
|
||||||
|
|
|
@ -151,6 +151,8 @@ namespace CSVDoc
|
||||||
|
|
||||||
void addReferencesSubView();
|
void addReferencesSubView();
|
||||||
|
|
||||||
|
void addRegionMapSubView();
|
||||||
|
|
||||||
void showUserSettings();
|
void showUserSettings();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
29
apps/opencs/view/world/regionmapsubview.cpp
Normal file
29
apps/opencs/view/world/regionmapsubview.cpp
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
|
||||||
|
#include "regionmapsubview.hpp"
|
||||||
|
|
||||||
|
#include <QTableView>
|
||||||
|
#include <QHeaderView>
|
||||||
|
|
||||||
|
CSVWorld::RegionMapSubView::RegionMapSubView (CSMWorld::UniversalId universalId,
|
||||||
|
CSMDoc::Document& document)
|
||||||
|
: CSVDoc::SubView (universalId)
|
||||||
|
{
|
||||||
|
mTable = new QTableView (this);
|
||||||
|
|
||||||
|
mTable->verticalHeader()->hide();
|
||||||
|
mTable->horizontalHeader()->hide();
|
||||||
|
|
||||||
|
mTable->setSelectionMode (QAbstractItemView::ExtendedSelection);
|
||||||
|
|
||||||
|
mTable->setModel (document.getData().getTableModel (universalId));
|
||||||
|
|
||||||
|
mTable->resizeColumnsToContents();
|
||||||
|
mTable->resizeRowsToContents();
|
||||||
|
|
||||||
|
setWidget (mTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVWorld::RegionMapSubView::setEditLock (bool locked)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
27
apps/opencs/view/world/regionmapsubview.hpp
Normal file
27
apps/opencs/view/world/regionmapsubview.hpp
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#ifndef CSV_WORLD_REGIONMAPSUBVIEW_H
|
||||||
|
#define CSV_WORLD_REGIONMAPSUBVIEW_H
|
||||||
|
|
||||||
|
#include "../doc/subview.hpp"
|
||||||
|
|
||||||
|
class QTableView;
|
||||||
|
|
||||||
|
namespace CSMDoc
|
||||||
|
{
|
||||||
|
class Document;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace CSVWorld
|
||||||
|
{
|
||||||
|
class RegionMapSubView : public CSVDoc::SubView
|
||||||
|
{
|
||||||
|
QTableView *mTable;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
RegionMapSubView (CSMWorld::UniversalId universalId, CSMDoc::Document& document);
|
||||||
|
|
||||||
|
virtual void setEditLock (bool locked);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -6,6 +6,7 @@
|
||||||
#include "tablesubview.hpp"
|
#include "tablesubview.hpp"
|
||||||
#include "dialoguesubview.hpp"
|
#include "dialoguesubview.hpp"
|
||||||
#include "scriptsubview.hpp"
|
#include "scriptsubview.hpp"
|
||||||
|
#include "regionmapsubview.hpp"
|
||||||
|
|
||||||
void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
|
void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
|
||||||
{
|
{
|
||||||
|
@ -38,6 +39,8 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
|
||||||
|
|
||||||
manager.add (CSMWorld::UniversalId::Type_Script, new CSVDoc::SubViewFactory<ScriptSubView>);
|
manager.add (CSMWorld::UniversalId::Type_Script, new CSVDoc::SubViewFactory<ScriptSubView>);
|
||||||
|
|
||||||
|
manager.add (CSMWorld::UniversalId::Type_RegionMap, new CSVDoc::SubViewFactory<RegionMapSubView>);
|
||||||
|
|
||||||
// manager.add (CSMWorld::UniversalId::Type_Global,
|
// manager.add (CSMWorld::UniversalId::Type_Global,
|
||||||
// new CSVDoc::SubViewFactoryWithCreateFlag<DialogueSubView> (true));
|
// new CSVDoc::SubViewFactoryWithCreateFlag<DialogueSubView> (true));
|
||||||
}
|
}
|
|
@ -215,4 +215,27 @@ namespace MWClass
|
||||||
ptr.get<ESM::Light>();
|
ptr.get<ESM::Light>();
|
||||||
return ref->mBase->mData.mWeight;
|
return ref->mBase->mData.mWeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::pair<int, std::string> Light::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const
|
||||||
|
{
|
||||||
|
MWWorld::InventoryStore& invStore = MWWorld::Class::get(npc).getInventoryStore(npc);
|
||||||
|
MWWorld::ContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||||
|
|
||||||
|
if(weapon == invStore.end())
|
||||||
|
return std::make_pair(1,"");
|
||||||
|
|
||||||
|
/// \todo the 2h check is repeated many times; put it in a function
|
||||||
|
if(weapon->getTypeName() == typeid(ESM::Weapon).name() &&
|
||||||
|
(weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand ||
|
||||||
|
weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::BluntTwoClose ||
|
||||||
|
weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::BluntTwoWide ||
|
||||||
|
weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::SpearTwoWide ||
|
||||||
|
weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::AxeTwoHand ||
|
||||||
|
weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanBow ||
|
||||||
|
weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow))
|
||||||
|
{
|
||||||
|
return std::make_pair(3,"");
|
||||||
|
}
|
||||||
|
return std::make_pair(1,"");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,8 @@ namespace MWClass
|
||||||
virtual float getWeight (const MWWorld::Ptr& ptr) const;
|
virtual float getWeight (const MWWorld::Ptr& ptr) const;
|
||||||
|
|
||||||
virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const;
|
virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const;
|
||||||
|
|
||||||
|
std::pair<int, std::string> canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -101,59 +101,58 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
|
|
||||||
Console::Console(int w, int h, bool consoleOnlyScripts)
|
Console::Console(int w, int h, bool consoleOnlyScripts)
|
||||||
: Layout("openmw_console.layout"),
|
: WindowBase("openmw_console.layout"),
|
||||||
mCompilerContext (MWScript::CompilerContext::Type_Console),
|
mCompilerContext (MWScript::CompilerContext::Type_Console),
|
||||||
mConsoleOnlyScripts (consoleOnlyScripts)
|
mConsoleOnlyScripts (consoleOnlyScripts)
|
||||||
{
|
{
|
||||||
setCoord(10,10, w-10, h/2);
|
setCoord(10,10, w-10, h/2);
|
||||||
|
|
||||||
getWidget(command, "edit_Command");
|
getWidget(mCommandLine, "edit_Command");
|
||||||
getWidget(history, "list_History");
|
getWidget(mHistory, "list_History");
|
||||||
|
|
||||||
// Set up the command line box
|
// Set up the command line box
|
||||||
command->eventEditSelectAccept +=
|
mCommandLine->eventEditSelectAccept +=
|
||||||
newDelegate(this, &Console::acceptCommand);
|
newDelegate(this, &Console::acceptCommand);
|
||||||
command->eventKeyButtonPressed +=
|
mCommandLine->eventKeyButtonPressed +=
|
||||||
newDelegate(this, &Console::keyPress);
|
newDelegate(this, &Console::keyPress);
|
||||||
|
|
||||||
// Set up the log window
|
// Set up the log window
|
||||||
history->setOverflowToTheLeft(true);
|
mHistory->setOverflowToTheLeft(true);
|
||||||
history->setEditStatic(true);
|
mHistory->setEditStatic(true);
|
||||||
history->setVisibleVScroll(true);
|
mHistory->setVisibleVScroll(true);
|
||||||
|
|
||||||
// compiler
|
// compiler
|
||||||
MWScript::registerExtensions (mExtensions, mConsoleOnlyScripts);
|
MWScript::registerExtensions (mExtensions, mConsoleOnlyScripts);
|
||||||
mCompilerContext.setExtensions (&mExtensions);
|
mCompilerContext.setExtensions (&mExtensions);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Console::enable()
|
void Console::open()
|
||||||
{
|
{
|
||||||
setVisible(true);
|
|
||||||
|
|
||||||
// Give keyboard focus to the combo box whenever the console is
|
// Give keyboard focus to the combo box whenever the console is
|
||||||
// turned on
|
// turned on
|
||||||
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(command);
|
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCommandLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Console::disable()
|
void Console::close()
|
||||||
{
|
{
|
||||||
setVisible(false);
|
// Apparently, hidden widgets can retain key focus
|
||||||
|
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Console::setFont(const std::string &fntName)
|
void Console::setFont(const std::string &fntName)
|
||||||
{
|
{
|
||||||
history->setFontName(fntName);
|
mHistory->setFontName(fntName);
|
||||||
command->setFontName(fntName);
|
mCommandLine->setFontName(fntName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Console::clearHistory()
|
void Console::clearHistory()
|
||||||
{
|
{
|
||||||
history->setCaption("");
|
mHistory->setCaption("");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Console::print(const std::string &msg)
|
void Console::print(const std::string &msg)
|
||||||
{
|
{
|
||||||
history->addText(msg);
|
mHistory->addText(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Console::printOK(const std::string &msg)
|
void Console::printOK(const std::string &msg)
|
||||||
|
@ -215,7 +214,7 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
std::vector<std::string> matches;
|
std::vector<std::string> matches;
|
||||||
listNames();
|
listNames();
|
||||||
command->setCaption(complete( command->getCaption(), matches ));
|
mCommandLine->setCaption(complete( mCommandLine->getCaption(), matches ));
|
||||||
#if 0
|
#if 0
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for(std::vector<std::string>::iterator it=matches.begin(); it < matches.end(); it++,i++ )
|
for(std::vector<std::string>::iterator it=matches.begin(); it < matches.end(); it++,i++ )
|
||||||
|
@ -227,50 +226,50 @@ namespace MWGui
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if(command_history.empty()) return;
|
if(mCommandHistory.empty()) return;
|
||||||
|
|
||||||
// Traverse history with up and down arrows
|
// Traverse history with up and down arrows
|
||||||
if(key == MyGUI::KeyCode::ArrowUp)
|
if(key == MyGUI::KeyCode::ArrowUp)
|
||||||
{
|
{
|
||||||
// If the user was editing a string, store it for later
|
// If the user was editing a string, store it for later
|
||||||
if(current == command_history.end())
|
if(mCurrent == mCommandHistory.end())
|
||||||
editString = command->getCaption();
|
mEditString = mCommandLine->getCaption();
|
||||||
|
|
||||||
if(current != command_history.begin())
|
if(mCurrent != mCommandHistory.begin())
|
||||||
{
|
{
|
||||||
current--;
|
mCurrent--;
|
||||||
command->setCaption(*current);
|
mCommandLine->setCaption(*mCurrent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(key == MyGUI::KeyCode::ArrowDown)
|
else if(key == MyGUI::KeyCode::ArrowDown)
|
||||||
{
|
{
|
||||||
if(current != command_history.end())
|
if(mCurrent != mCommandHistory.end())
|
||||||
{
|
{
|
||||||
current++;
|
mCurrent++;
|
||||||
|
|
||||||
if(current != command_history.end())
|
if(mCurrent != mCommandHistory.end())
|
||||||
command->setCaption(*current);
|
mCommandLine->setCaption(*mCurrent);
|
||||||
else
|
else
|
||||||
// Restore the edit string
|
// Restore the edit string
|
||||||
command->setCaption(editString);
|
mCommandLine->setCaption(mEditString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Console::acceptCommand(MyGUI::EditBox* _sender)
|
void Console::acceptCommand(MyGUI::EditBox* _sender)
|
||||||
{
|
{
|
||||||
const std::string &cm = command->getCaption();
|
const std::string &cm = mCommandLine->getCaption();
|
||||||
if(cm.empty()) return;
|
if(cm.empty()) return;
|
||||||
|
|
||||||
// Add the command to the history, and set the current pointer to
|
// Add the command to the history, and set the current pointer to
|
||||||
// the end of the list
|
// the end of the list
|
||||||
command_history.push_back(cm);
|
mCommandHistory.push_back(cm);
|
||||||
current = command_history.end();
|
mCurrent = mCommandHistory.end();
|
||||||
editString.clear();
|
mEditString.clear();
|
||||||
|
|
||||||
execute (cm);
|
execute (cm);
|
||||||
|
|
||||||
command->setCaption("");
|
mCommandLine->setCaption("");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Console::complete( std::string input, std::vector<std::string> &matches )
|
std::string Console::complete( std::string input, std::vector<std::string> &matches )
|
||||||
|
@ -412,7 +411,7 @@ namespace MWGui
|
||||||
setTitle("#{sConsoleTitle}");
|
setTitle("#{sConsoleTitle}");
|
||||||
mPtr = MWWorld::Ptr();
|
mPtr = MWWorld::Ptr();
|
||||||
}
|
}
|
||||||
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(command);
|
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCommandLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Console::onReferenceUnavailable()
|
void Console::onReferenceUnavailable()
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#ifndef MWGUI_CONSOLE_H
|
#ifndef MWGUI_CONSOLE_H
|
||||||
#define MWGUI_CONSOLE_H
|
#define MWGUI_CONSOLE_H
|
||||||
|
|
||||||
#include <openengine/gui/layout.hpp>
|
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -18,10 +17,11 @@
|
||||||
#include "../mwscript/interpretercontext.hpp"
|
#include "../mwscript/interpretercontext.hpp"
|
||||||
|
|
||||||
#include "referenceinterface.hpp"
|
#include "referenceinterface.hpp"
|
||||||
|
#include "windowbase.hpp"
|
||||||
|
|
||||||
namespace MWGui
|
namespace MWGui
|
||||||
{
|
{
|
||||||
class Console : private OEngine::GUI::Layout, private Compiler::ErrorHandler, public ReferenceInterface
|
class Console : public WindowBase, private Compiler::ErrorHandler, public ReferenceInterface
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -55,21 +55,20 @@ namespace MWGui
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MyGUI::EditBox* command;
|
MyGUI::EditBox* mCommandLine;
|
||||||
MyGUI::EditBox* history;
|
MyGUI::EditBox* mHistory;
|
||||||
|
|
||||||
typedef std::list<std::string> StringList;
|
typedef std::list<std::string> StringList;
|
||||||
|
|
||||||
// History of previous entered commands
|
// History of previous entered commands
|
||||||
StringList command_history;
|
StringList mCommandHistory;
|
||||||
StringList::iterator current;
|
StringList::iterator mCurrent;
|
||||||
std::string editString;
|
std::string mEditString;
|
||||||
|
|
||||||
Console(int w, int h, bool consoleOnlyScripts);
|
Console(int w, int h, bool consoleOnlyScripts);
|
||||||
|
|
||||||
void enable();
|
virtual void open();
|
||||||
|
virtual void close();
|
||||||
void disable();
|
|
||||||
|
|
||||||
void setFont(const std::string &fntName);
|
void setFont(const std::string &fntName);
|
||||||
|
|
||||||
|
@ -91,7 +90,7 @@ namespace MWGui
|
||||||
|
|
||||||
void execute (const std::string& command);
|
void execute (const std::string& command);
|
||||||
|
|
||||||
void executeFile (const std::string& command);
|
void executeFile (const std::string& path);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
|
@ -329,7 +329,7 @@ namespace MWGui
|
||||||
mMap->setVisible(false);
|
mMap->setVisible(false);
|
||||||
mMenu->setVisible(false);
|
mMenu->setVisible(false);
|
||||||
mStatsWindow->setVisible(false);
|
mStatsWindow->setVisible(false);
|
||||||
mConsole->disable();
|
mConsole->setVisible(false);
|
||||||
mJournal->setVisible(false);
|
mJournal->setVisible(false);
|
||||||
mDialogueWindow->setVisible(false);
|
mDialogueWindow->setVisible(false);
|
||||||
mContainerWindow->setVisible(false);
|
mContainerWindow->setVisible(false);
|
||||||
|
@ -398,7 +398,7 @@ namespace MWGui
|
||||||
mInventoryWindow->setVisible(mInventoryWindow->pinned());
|
mInventoryWindow->setVisible(mInventoryWindow->pinned());
|
||||||
mSpellWindow->setVisible(mSpellWindow->pinned());
|
mSpellWindow->setVisible(mSpellWindow->pinned());
|
||||||
|
|
||||||
mConsole->enable();
|
mConsole->setVisible(true);
|
||||||
break;
|
break;
|
||||||
case GM_Scroll:
|
case GM_Scroll:
|
||||||
mScrollWindow->setVisible(true);
|
mScrollWindow->setVisible(true);
|
||||||
|
|
|
@ -183,11 +183,14 @@ namespace MWInput
|
||||||
break;
|
break;
|
||||||
case A_Activate:
|
case A_Activate:
|
||||||
resetIdleTime();
|
resetIdleTime();
|
||||||
if( MWBase::Environment::get().getWindowManager()->isGuiMode()) {
|
|
||||||
// Pressing the activation key when a messagebox is prompting for "ok" will activate the ok button
|
if (mWindows.getMode() == MWGui::GM_Container) {
|
||||||
|
toggleContainer ();
|
||||||
|
} else if (MWBase::Environment::get().getWindowManager()->isGuiMode()) {
|
||||||
MWBase::Environment::get().getWindowManager()->enterPressed();
|
MWBase::Environment::get().getWindowManager()->enterPressed();
|
||||||
}
|
} else {
|
||||||
activate();
|
activate();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case A_Journal:
|
case A_Journal:
|
||||||
toggleJournal ();
|
toggleJournal ();
|
||||||
|
@ -678,6 +681,24 @@ namespace MWInput
|
||||||
// .. but don't touch any other mode, except container.
|
// .. but don't touch any other mode, except container.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InputManager::toggleContainer()
|
||||||
|
{
|
||||||
|
if (MyGUI::InputManager::getInstance ().isModalAny())
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool gameMode = !mWindows.isGuiMode();
|
||||||
|
|
||||||
|
if(!gameMode)
|
||||||
|
{
|
||||||
|
if (mWindows.getMode() == MWGui::GM_Container)
|
||||||
|
mWindows.popGuiMode();
|
||||||
|
else
|
||||||
|
mWindows.pushGuiMode(MWGui::GM_Container);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void InputManager::toggleConsole()
|
void InputManager::toggleConsole()
|
||||||
{
|
{
|
||||||
if (MyGUI::InputManager::getInstance ().isModalAny())
|
if (MyGUI::InputManager::getInstance ().isModalAny())
|
||||||
|
|
|
@ -170,6 +170,7 @@ namespace MWInput
|
||||||
void toggleSpell();
|
void toggleSpell();
|
||||||
void toggleWeapon();
|
void toggleWeapon();
|
||||||
void toggleInventory();
|
void toggleInventory();
|
||||||
|
void toggleContainer();
|
||||||
void toggleConsole();
|
void toggleConsole();
|
||||||
void screenshot();
|
void screenshot();
|
||||||
void toggleJournal();
|
void toggleJournal();
|
||||||
|
|
|
@ -168,31 +168,31 @@ namespace MWMechanics
|
||||||
void Actors::addActor (const MWWorld::Ptr& ptr)
|
void Actors::addActor (const MWWorld::Ptr& ptr)
|
||||||
{
|
{
|
||||||
// erase previous death events since we are currently only tracking them while in an active cell
|
// erase previous death events since we are currently only tracking them while in an active cell
|
||||||
MWWorld::Class::get (ptr).getCreatureStats (ptr).clearHasDied();
|
MWWorld::Class::get(ptr).getCreatureStats(ptr).clearHasDied();
|
||||||
|
|
||||||
MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr);
|
MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr);
|
||||||
if(!MWWorld::Class::get(ptr).getCreatureStats(ptr).isDead())
|
mActors.insert(std::make_pair(ptr, new CharacterController(ptr, anim)));
|
||||||
mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle)));
|
|
||||||
else
|
|
||||||
mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Death1)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Actors::removeActor (const MWWorld::Ptr& ptr)
|
void Actors::removeActor (const MWWorld::Ptr& ptr)
|
||||||
{
|
{
|
||||||
PtrControllerMap::iterator iter = mActors.find(ptr);
|
PtrControllerMap::iterator iter = mActors.find(ptr);
|
||||||
if(iter != mActors.end())
|
if(iter != mActors.end())
|
||||||
|
{
|
||||||
|
delete iter->second;
|
||||||
mActors.erase(iter);
|
mActors.erase(iter);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Actors::updateActor(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr)
|
void Actors::updateActor(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr)
|
||||||
{
|
{
|
||||||
PtrControllerMap::iterator iter = mActors.find(old);
|
PtrControllerMap::iterator iter = mActors.find(old);
|
||||||
if(iter != mActors.end())
|
if(iter != mActors.end())
|
||||||
{
|
{
|
||||||
CharacterController ctrl = iter->second;
|
CharacterController *ctrl = iter->second;
|
||||||
mActors.erase(iter);
|
mActors.erase(iter);
|
||||||
|
|
||||||
ctrl.updatePtr(ptr);
|
ctrl->updatePtr(ptr);
|
||||||
mActors.insert(std::make_pair(ptr, ctrl));
|
mActors.insert(std::make_pair(ptr, ctrl));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -203,7 +203,10 @@ namespace MWMechanics
|
||||||
while(iter != mActors.end())
|
while(iter != mActors.end())
|
||||||
{
|
{
|
||||||
if(iter->first.getCell()==cellStore)
|
if(iter->first.getCell()==cellStore)
|
||||||
|
{
|
||||||
|
delete iter->second;
|
||||||
mActors.erase(iter++);
|
mActors.erase(iter++);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
++iter;
|
++iter;
|
||||||
}
|
}
|
||||||
|
@ -222,8 +225,8 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
if(!MWWorld::Class::get(iter->first).getCreatureStats(iter->first).isDead())
|
if(!MWWorld::Class::get(iter->first).getCreatureStats(iter->first).isDead())
|
||||||
{
|
{
|
||||||
if(iter->second.getState() >= CharState_Death1)
|
if(iter->second->isDead())
|
||||||
iter->second.setState(CharState_Idle);
|
iter->second->resurrect();
|
||||||
|
|
||||||
updateActor(iter->first, totalDuration);
|
updateActor(iter->first, totalDuration);
|
||||||
if(iter->first.getTypeName() == typeid(ESM::NPC).name())
|
if(iter->first.getTypeName() == typeid(ESM::NPC).name())
|
||||||
|
@ -250,10 +253,10 @@ namespace MWMechanics
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(iter->second.getState() >= CharState_Death1)
|
if(iter->second->isDead())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
iter->second.setState(CharState_Death1);
|
iter->second->kill();
|
||||||
|
|
||||||
++mDeathCount[MWWorld::Class::get(iter->first).getId(iter->first)];
|
++mDeathCount[MWWorld::Class::get(iter->first).getId(iter->first)];
|
||||||
|
|
||||||
|
@ -270,7 +273,7 @@ namespace MWMechanics
|
||||||
for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
|
for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
|
||||||
{
|
{
|
||||||
Movement movement;
|
Movement movement;
|
||||||
iter->second.update(duration, movement);
|
iter->second->update(duration, movement);
|
||||||
mMovement.push_back(std::make_pair(iter->first, movement));
|
mMovement.push_back(std::make_pair(iter->first, movement));
|
||||||
}
|
}
|
||||||
MWBase::Environment::get().getWorld()->doPhysics(mMovement, duration);
|
MWBase::Environment::get().getWorld()->doPhysics(mMovement, duration);
|
||||||
|
@ -297,27 +300,27 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
PtrControllerMap::iterator iter = mActors.find(ptr);
|
PtrControllerMap::iterator iter = mActors.find(ptr);
|
||||||
if(iter != mActors.end())
|
if(iter != mActors.end())
|
||||||
iter->second.forceStateUpdate();
|
iter->second->forceStateUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Actors::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number)
|
void Actors::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number)
|
||||||
{
|
{
|
||||||
PtrControllerMap::iterator iter = mActors.find(ptr);
|
PtrControllerMap::iterator iter = mActors.find(ptr);
|
||||||
if(iter != mActors.end())
|
if(iter != mActors.end())
|
||||||
iter->second.playGroup(groupName, mode, number);
|
iter->second->playGroup(groupName, mode, number);
|
||||||
}
|
}
|
||||||
void Actors::skipAnimation(const MWWorld::Ptr& ptr)
|
void Actors::skipAnimation(const MWWorld::Ptr& ptr)
|
||||||
{
|
{
|
||||||
PtrControllerMap::iterator iter = mActors.find(ptr);
|
PtrControllerMap::iterator iter = mActors.find(ptr);
|
||||||
if(iter != mActors.end())
|
if(iter != mActors.end())
|
||||||
iter->second.skipAnim();
|
iter->second->skipAnim();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Actors::checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName)
|
bool Actors::checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName)
|
||||||
{
|
{
|
||||||
PtrControllerMap::iterator iter = mActors.find(ptr);
|
PtrControllerMap::iterator iter = mActors.find(ptr);
|
||||||
if(iter != mActors.end())
|
if(iter != mActors.end())
|
||||||
return iter->second.isAnimPlaying(groupName);
|
return iter->second->isAnimPlaying(groupName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
class Actors
|
class Actors
|
||||||
{
|
{
|
||||||
typedef std::map<MWWorld::Ptr,CharacterController> PtrControllerMap;
|
typedef std::map<MWWorld::Ptr,CharacterController*> PtrControllerMap;
|
||||||
PtrControllerMap mActors;
|
PtrControllerMap mActors;
|
||||||
|
|
||||||
MWWorld::PtrMovementList mMovement;
|
MWWorld::PtrMovementList mMovement;
|
||||||
|
|
|
@ -39,62 +39,65 @@
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
|
||||||
static const struct StateInfo {
|
struct StateInfo {
|
||||||
CharacterState state;
|
CharacterState state;
|
||||||
const char groupname[32];
|
const char groupname[32];
|
||||||
Priority priority;
|
};
|
||||||
bool loops;
|
|
||||||
} sStateList[] = {
|
|
||||||
{ CharState_Idle, "idle", Priority_Default, true },
|
|
||||||
{ CharState_Idle2, "idle2", Priority_Default, true },
|
|
||||||
{ CharState_Idle3, "idle3", Priority_Default, true },
|
|
||||||
{ CharState_Idle4, "idle4", Priority_Default, true },
|
|
||||||
{ CharState_Idle5, "idle5", Priority_Default, true },
|
|
||||||
{ CharState_Idle6, "idle6", Priority_Default, true },
|
|
||||||
{ CharState_Idle7, "idle7", Priority_Default, true },
|
|
||||||
{ CharState_Idle8, "idle8", Priority_Default, true },
|
|
||||||
{ CharState_Idle9, "idle9", Priority_Default, true },
|
|
||||||
{ CharState_IdleSwim, "idleswim", Priority_Default, true },
|
|
||||||
{ CharState_IdleSneak, "idlesneak", Priority_Default, true },
|
|
||||||
|
|
||||||
{ CharState_WalkForward, "walkforward", Priority_Default, true },
|
static const StateInfo sStateList[] = {
|
||||||
{ CharState_WalkBack, "walkback", Priority_Default, true },
|
{ CharState_Idle, "idle" },
|
||||||
{ CharState_WalkLeft, "walkleft", Priority_Default, true },
|
{ CharState_Idle2, "idle2" },
|
||||||
{ CharState_WalkRight, "walkright", Priority_Default, true },
|
{ CharState_Idle3, "idle3" },
|
||||||
|
{ CharState_Idle4, "idle4" },
|
||||||
|
{ CharState_Idle5, "idle5" },
|
||||||
|
{ CharState_Idle6, "idle6" },
|
||||||
|
{ CharState_Idle7, "idle7" },
|
||||||
|
{ CharState_Idle8, "idle8" },
|
||||||
|
{ CharState_Idle9, "idle9" },
|
||||||
|
{ CharState_IdleSwim, "idleswim" },
|
||||||
|
{ CharState_IdleSneak, "idlesneak" },
|
||||||
|
|
||||||
{ CharState_SwimWalkForward, "swimwalkforward", Priority_Default, true },
|
{ CharState_Death1, "death1" },
|
||||||
{ CharState_SwimWalkBack, "swimwalkback", Priority_Default, true },
|
{ CharState_Death2, "death2" },
|
||||||
{ CharState_SwimWalkLeft, "swimwalkleft", Priority_Default, true },
|
{ CharState_Death3, "death3" },
|
||||||
{ CharState_SwimWalkRight, "swimwalkright", Priority_Default, true },
|
{ CharState_Death4, "death4" },
|
||||||
|
{ CharState_Death5, "death5" },
|
||||||
{ CharState_RunForward, "runforward", Priority_Default, true },
|
|
||||||
{ CharState_RunBack, "runback", Priority_Default, true },
|
|
||||||
{ CharState_RunLeft, "runleft", Priority_Default, true },
|
|
||||||
{ CharState_RunRight, "runright", Priority_Default, true },
|
|
||||||
|
|
||||||
{ CharState_SwimRunForward, "swimrunforward", Priority_Default, true },
|
|
||||||
{ CharState_SwimRunBack, "swimrunback", Priority_Default, true },
|
|
||||||
{ CharState_SwimRunLeft, "swimrunleft", Priority_Default, true },
|
|
||||||
{ CharState_SwimRunRight, "swimrunright", Priority_Default, true },
|
|
||||||
|
|
||||||
{ CharState_SneakForward, "sneakforward", Priority_Default, true },
|
|
||||||
{ CharState_SneakBack, "sneakback", Priority_Default, true },
|
|
||||||
{ CharState_SneakLeft, "sneakleft", Priority_Default, true },
|
|
||||||
{ CharState_SneakRight, "sneakright", Priority_Default, true },
|
|
||||||
|
|
||||||
{ CharState_TurnLeft, "turnleft", Priority_Default, true },
|
|
||||||
{ CharState_TurnRight, "turnright", Priority_Default, true },
|
|
||||||
|
|
||||||
{ CharState_Jump, "jump", Priority_Default, true },
|
|
||||||
|
|
||||||
{ CharState_Death1, "death1", Priority_Death, false },
|
|
||||||
{ CharState_Death2, "death2", Priority_Death, false },
|
|
||||||
{ CharState_Death3, "death3", Priority_Death, false },
|
|
||||||
{ CharState_Death4, "death4", Priority_Death, false },
|
|
||||||
{ CharState_Death5, "death5", Priority_Death, false },
|
|
||||||
};
|
};
|
||||||
static const StateInfo *sStateListEnd = &sStateList[sizeof(sStateList)/sizeof(sStateList[0])];
|
static const StateInfo *sStateListEnd = &sStateList[sizeof(sStateList)/sizeof(sStateList[0])];
|
||||||
|
|
||||||
|
|
||||||
|
static const StateInfo sMovementList[] = {
|
||||||
|
{ CharState_WalkForward, "walkforward" },
|
||||||
|
{ CharState_WalkBack, "walkback" },
|
||||||
|
{ CharState_WalkLeft, "walkleft" },
|
||||||
|
{ CharState_WalkRight, "walkright" },
|
||||||
|
|
||||||
|
{ CharState_SwimWalkForward, "swimwalkforward" },
|
||||||
|
{ CharState_SwimWalkBack, "swimwalkback" },
|
||||||
|
{ CharState_SwimWalkLeft, "swimwalkleft" },
|
||||||
|
{ CharState_SwimWalkRight, "swimwalkright" },
|
||||||
|
|
||||||
|
{ CharState_RunForward, "runforward" },
|
||||||
|
{ CharState_RunBack, "runback" },
|
||||||
|
{ CharState_RunLeft, "runleft" },
|
||||||
|
{ CharState_RunRight, "runright" },
|
||||||
|
|
||||||
|
{ CharState_SwimRunForward, "swimrunforward" },
|
||||||
|
{ CharState_SwimRunBack, "swimrunback" },
|
||||||
|
{ CharState_SwimRunLeft, "swimrunleft" },
|
||||||
|
{ CharState_SwimRunRight, "swimrunright" },
|
||||||
|
|
||||||
|
{ CharState_SneakForward, "sneakforward" },
|
||||||
|
{ CharState_SneakBack, "sneakback" },
|
||||||
|
{ CharState_SneakLeft, "sneakleft" },
|
||||||
|
{ CharState_SneakRight, "sneakright" },
|
||||||
|
|
||||||
|
{ CharState_TurnLeft, "turnleft" },
|
||||||
|
{ CharState_TurnRight, "turnright" },
|
||||||
|
};
|
||||||
|
static const StateInfo *sMovementListEnd = &sMovementList[sizeof(sMovementList)/sizeof(sMovementList[0])];
|
||||||
|
|
||||||
|
|
||||||
class FindCharState {
|
class FindCharState {
|
||||||
CharacterState state;
|
CharacterState state;
|
||||||
|
|
||||||
|
@ -108,19 +111,18 @@ public:
|
||||||
|
|
||||||
static const struct WeaponInfo {
|
static const struct WeaponInfo {
|
||||||
WeaponType type;
|
WeaponType type;
|
||||||
const char idlegroup[16];
|
const char shortgroup[16];
|
||||||
const char movementgroup[16];
|
const char longgroup[16];
|
||||||
const char actiongroup[16];
|
|
||||||
} sWeaponTypeList[] = {
|
} sWeaponTypeList[] = {
|
||||||
{ WeapType_HandToHand, "hh", "hh", "handtohand" },
|
{ WeapType_HandToHand, "hh", "handtohand" },
|
||||||
{ WeapType_OneHand, "1h", "1h", "weapononehand" },
|
{ WeapType_OneHand, "1h", "weapononehand" },
|
||||||
{ WeapType_TwoHand, "2c", "2c", "weapontwohand" },
|
{ WeapType_TwoHand, "2c", "weapontwohand" },
|
||||||
{ WeapType_TwoWide, "2w", "2w", "weapontwowide" },
|
{ WeapType_TwoWide, "2w", "weapontwowide" },
|
||||||
{ WeapType_BowAndArrow, "1h", "1h", "bowandarrow" },
|
{ WeapType_BowAndArrow, "1h", "bowandarrow" },
|
||||||
{ WeapType_Crossbow, "crossbow", "1h", "crossbow" },
|
{ WeapType_Crossbow, "crossbow", "crossbow" },
|
||||||
{ WeapType_ThowWeapon, "1h", "1h", "throwweapon" },
|
{ WeapType_ThowWeapon, "1h", "throwweapon" },
|
||||||
{ WeapType_PickProbe, "1h", "1h", "pickprobe" },
|
{ WeapType_PickProbe, "1h", "pickprobe" },
|
||||||
{ WeapType_Spell, "spell", "", "spellcast" },
|
{ WeapType_Spell, "spell", "spellcast" },
|
||||||
};
|
};
|
||||||
static const WeaponInfo *sWeaponTypeListEnd = &sWeaponTypeList[sizeof(sWeaponTypeList)/sizeof(sWeaponTypeList[0])];
|
static const WeaponInfo *sWeaponTypeListEnd = &sWeaponTypeList[sizeof(sWeaponTypeList)/sizeof(sWeaponTypeList[0])];
|
||||||
|
|
||||||
|
@ -135,31 +137,84 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
void CharacterController::getCurrentGroup(std::string &group, Priority &priority, bool &loops) const
|
void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterState movement, bool force)
|
||||||
{
|
{
|
||||||
std::string name;
|
|
||||||
const StateInfo *state = std::find_if(sStateList, sStateListEnd, FindCharState(mCharState));
|
|
||||||
if(state == sStateListEnd)
|
|
||||||
throw std::runtime_error("Failed to find character state "+Ogre::StringConverter::toString(mCharState));
|
|
||||||
|
|
||||||
name = state->groupname;
|
|
||||||
priority = state->priority;
|
|
||||||
loops = state->loops;
|
|
||||||
|
|
||||||
if(!(mCharState >= CharState_Death1) && mWeaponType != WeapType_None)
|
|
||||||
{
|
|
||||||
const WeaponInfo *weap = std::find_if(sWeaponTypeList, sWeaponTypeListEnd, FindWeaponType(mWeaponType));
|
const WeaponInfo *weap = std::find_if(sWeaponTypeList, sWeaponTypeListEnd, FindWeaponType(mWeaponType));
|
||||||
|
|
||||||
|
if(force || idle != mIdleState)
|
||||||
|
{
|
||||||
|
mIdleState = idle;
|
||||||
|
|
||||||
|
std::string idle;
|
||||||
|
// Only play "idleswim" or "idlesneak" if they exist. Otherwise, fallback to
|
||||||
|
// "idle"+weapon or "idle".
|
||||||
|
if(mIdleState == CharState_IdleSwim && mAnimation->hasAnimation("idleswim"))
|
||||||
|
idle = "idleswim";
|
||||||
|
else if(mIdleState == CharState_IdleSneak && mAnimation->hasAnimation("idlesneak"))
|
||||||
|
idle = "idlesneak";
|
||||||
|
else
|
||||||
|
{
|
||||||
|
idle = "idle";
|
||||||
if(weap != sWeaponTypeListEnd)
|
if(weap != sWeaponTypeListEnd)
|
||||||
{
|
{
|
||||||
if(mCharState == CharState_Idle)
|
idle += weap->shortgroup;
|
||||||
(group=name) += weap->idlegroup;
|
if(!mAnimation->hasAnimation(idle))
|
||||||
else
|
idle = "idle";
|
||||||
(group=name) += weap->movementgroup;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(group.empty() || !mAnimation->hasAnimation(group))
|
mAnimation->disable(mCurrentIdle);
|
||||||
group = (mAnimation->hasAnimation(name) ? name : std::string());
|
mCurrentIdle = idle;
|
||||||
|
mAnimation->play(mCurrentIdle, Priority_Default, MWRender::Animation::Group_All, false,
|
||||||
|
1.0f, "start", "stop", 0.0f, ~0ul);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(force || movement != mMovementState)
|
||||||
|
{
|
||||||
|
mMovementState = movement;
|
||||||
|
|
||||||
|
std::string movement;
|
||||||
|
MWRender::Animation::Group movegroup = MWRender::Animation::Group_All;
|
||||||
|
const StateInfo *movestate = std::find_if(sMovementList, sMovementListEnd, FindCharState(mMovementState));
|
||||||
|
if(movestate != sMovementListEnd)
|
||||||
|
{
|
||||||
|
movement = movestate->groupname;
|
||||||
|
if(weap != sWeaponTypeListEnd && movement.find("swim") == std::string::npos)
|
||||||
|
{
|
||||||
|
movement += weap->shortgroup;
|
||||||
|
if(!mAnimation->hasAnimation(movement))
|
||||||
|
{
|
||||||
|
movegroup = MWRender::Animation::Group_LowerBody;
|
||||||
|
movement = movestate->groupname;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!mAnimation->hasAnimation(movement))
|
||||||
|
{
|
||||||
|
std::string::size_type sneakpos = movement.find("sneak");
|
||||||
|
if(sneakpos == std::string::npos)
|
||||||
|
movement.clear();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
movegroup = MWRender::Animation::Group_LowerBody;
|
||||||
|
movement.erase(sneakpos, 5);
|
||||||
|
if(!mAnimation->hasAnimation(movement))
|
||||||
|
movement.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mAnimation->disable(mCurrentMovement);
|
||||||
|
mCurrentMovement = movement;
|
||||||
|
if(!mCurrentMovement.empty())
|
||||||
|
{
|
||||||
|
float vel, speed = 0.0f;
|
||||||
|
if(mMovementSpeed > 0.0f && (vel=mAnimation->getVelocity(mCurrentMovement)) > 1.0f)
|
||||||
|
speed = mMovementSpeed / vel;
|
||||||
|
mAnimation->play(mCurrentMovement, Priority_Movement, movegroup, false,
|
||||||
|
speed, "start", "stop", 0.0f, ~0ul);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -167,14 +222,17 @@ void CharacterController::getWeaponGroup(WeaponType weaptype, std::string &group
|
||||||
{
|
{
|
||||||
const WeaponInfo *info = std::find_if(sWeaponTypeList, sWeaponTypeListEnd, FindWeaponType(weaptype));
|
const WeaponInfo *info = std::find_if(sWeaponTypeList, sWeaponTypeListEnd, FindWeaponType(weaptype));
|
||||||
if(info != sWeaponTypeListEnd)
|
if(info != sWeaponTypeListEnd)
|
||||||
group = info->actiongroup;
|
group = info->longgroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state)
|
CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim)
|
||||||
: mPtr(ptr)
|
: mPtr(ptr)
|
||||||
, mAnimation(anim)
|
, mAnimation(anim)
|
||||||
, mCharState(state)
|
, mIdleState(CharState_Idle)
|
||||||
|
, mMovementState(CharState_None)
|
||||||
|
, mMovementSpeed(0.0f)
|
||||||
|
, mDeathState(CharState_None)
|
||||||
, mUpperBodyState(UpperCharState_Nothing)
|
, mUpperBodyState(UpperCharState_Nothing)
|
||||||
, mWeaponType(WeapType_None)
|
, mWeaponType(WeapType_None)
|
||||||
, mSkipAnim(false)
|
, mSkipAnim(false)
|
||||||
|
@ -190,6 +248,12 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim
|
||||||
/* Accumulate along X/Y only for now, until we can figure out how we should
|
/* Accumulate along X/Y only for now, until we can figure out how we should
|
||||||
* handle knockout and death which moves the character down. */
|
* handle knockout and death which moves the character down. */
|
||||||
mAnimation->setAccumulation(Ogre::Vector3(1.0f, 1.0f, 0.0f));
|
mAnimation->setAccumulation(Ogre::Vector3(1.0f, 1.0f, 0.0f));
|
||||||
|
|
||||||
|
if(MWWorld::Class::get(mPtr).getCreatureStats(mPtr).isDead())
|
||||||
|
{
|
||||||
|
/* FIXME: Get the actual death state used. */
|
||||||
|
mDeathState = CharState_Death1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -197,12 +261,17 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim
|
||||||
mAnimation->setAccumulation(Ogre::Vector3(0.0f));
|
mAnimation->setAccumulation(Ogre::Vector3(0.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string group;
|
refreshCurrentAnims(mIdleState, mMovementState, true);
|
||||||
Priority prio;
|
if(mDeathState != CharState_None)
|
||||||
bool loops;
|
{
|
||||||
getCurrentGroup(group, prio, loops);
|
const StateInfo *state = std::find_if(sStateList, sStateListEnd, FindCharState(mDeathState));
|
||||||
mAnimation->play(group, prio, MWRender::Animation::Group_All, false,
|
if(state == sStateListEnd)
|
||||||
"start", "stop", 1.0f, loops ? (~(size_t)0) : 0);
|
throw std::runtime_error("Failed to find character state "+Ogre::StringConverter::toString(mDeathState));
|
||||||
|
|
||||||
|
mCurrentDeath = state->groupname;
|
||||||
|
mAnimation->play(mCurrentDeath, Priority_Death, MWRender::Animation::Group_All,
|
||||||
|
false, 1.0f, "start", "stop", 1.0f, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CharacterController::~CharacterController()
|
CharacterController::~CharacterController()
|
||||||
|
@ -219,7 +288,6 @@ void CharacterController::updatePtr(const MWWorld::Ptr &ptr)
|
||||||
void CharacterController::update(float duration, Movement &movement)
|
void CharacterController::update(float duration, Movement &movement)
|
||||||
{
|
{
|
||||||
const MWWorld::Class &cls = MWWorld::Class::get(mPtr);
|
const MWWorld::Class &cls = MWWorld::Class::get(mPtr);
|
||||||
float speed = 0.0f;
|
|
||||||
|
|
||||||
if(!cls.isActor())
|
if(!cls.isActor())
|
||||||
{
|
{
|
||||||
|
@ -232,32 +300,12 @@ void CharacterController::update(float duration, Movement &movement)
|
||||||
|
|
||||||
mAnimation->play(mAnimQueue.front().first, Priority_Default,
|
mAnimation->play(mAnimQueue.front().first, Priority_Default,
|
||||||
MWRender::Animation::Group_All, false,
|
MWRender::Animation::Group_All, false,
|
||||||
"start", "stop", 0.0f, mAnimQueue.front().second);
|
1.0f, "start", "stop", 0.0f, mAnimQueue.front().second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(!cls.getCreatureStats(mPtr).isDead())
|
else if(!cls.getCreatureStats(mPtr).isDead())
|
||||||
{
|
{
|
||||||
/*std::list<std::pair<std::string,std::string>> lastKeys = cls.getCreatureStats(mPtr).getLastAnimKey();
|
|
||||||
for(std::list<std::pair<std::string,std::string>>::iterator it = cls.getCreatureStats(mPtr).getLastAnimKey().begin();
|
|
||||||
it!=cls.getCreatureStats(mPtr).getLastAnimKey().end();)
|
|
||||||
{
|
|
||||||
std::cout << "NE";
|
|
||||||
std::pair<std::string,std::string> lastKey = *it;
|
|
||||||
if(!lastKey.first.empty())
|
|
||||||
{
|
|
||||||
std::cout << lastKey.first << " " << lastKey.second << " ";
|
|
||||||
//const std::string &evt = key->second;
|
|
||||||
size_t off = lastKey.second.size()+2;
|
|
||||||
size_t len = lastKey.first.size() - off;
|
|
||||||
|
|
||||||
if(lastKey.first.compare(off, len, "equip stop") == 0) mUpperBodyState = UpperCharState_WeapEquiped;
|
|
||||||
if(lastKey.first.compare(off, len, "unequip stop") == 0) mUpperBodyState = UpperCharState_Nothing;
|
|
||||||
if(lastKey.first.compare(off, len, "chop large follow stop") == 0){ mUpperBodyState = UpperCharState_WeapEquiped;std::cout << "FINISHED";}
|
|
||||||
}
|
|
||||||
it = cls.getCreatureStats(mPtr).getLastAnimKey().erase(it);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||||
|
|
||||||
bool onground = world->isOnGround(mPtr);
|
bool onground = world->isOnGround(mPtr);
|
||||||
|
@ -266,12 +314,12 @@ void CharacterController::update(float duration, Movement &movement)
|
||||||
bool sneak = cls.getStance(mPtr, MWWorld::Class::Sneak);
|
bool sneak = cls.getStance(mPtr, MWWorld::Class::Sneak);
|
||||||
Ogre::Vector3 vec = cls.getMovementVector(mPtr);
|
Ogre::Vector3 vec = cls.getMovementVector(mPtr);
|
||||||
Ogre::Vector3 rot = cls.getRotationVector(mPtr);
|
Ogre::Vector3 rot = cls.getRotationVector(mPtr);
|
||||||
speed = cls.getSpeed(mPtr);
|
mMovementSpeed = cls.getSpeed(mPtr);
|
||||||
|
|
||||||
// advance athletics
|
// advance athletics
|
||||||
if (vec.squaredLength() > 0 && mPtr.getRefData().getHandle() == "player")
|
if(vec.squaredLength() > 0 && mPtr.getRefData().getHandle() == "player")
|
||||||
{
|
{
|
||||||
if (inwater)
|
if(inwater)
|
||||||
{
|
{
|
||||||
mSecondsOfSwimming += duration;
|
mSecondsOfSwimming += duration;
|
||||||
while(mSecondsOfSwimming > 1)
|
while(mSecondsOfSwimming > 1)
|
||||||
|
@ -280,7 +328,7 @@ void CharacterController::update(float duration, Movement &movement)
|
||||||
mSecondsOfSwimming -= 1;
|
mSecondsOfSwimming -= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (isrunning)
|
else if(isrunning)
|
||||||
{
|
{
|
||||||
mSecondsOfRunning += duration;
|
mSecondsOfRunning += duration;
|
||||||
while(mSecondsOfRunning > 1)
|
while(mSecondsOfRunning > 1)
|
||||||
|
@ -313,40 +361,49 @@ void CharacterController::update(float duration, Movement &movement)
|
||||||
//decrease fatigue by fFatigueJumpBase + (1 - normalizedEncumbrance) * fFatigueJumpMult;
|
//decrease fatigue by fFatigueJumpBase + (1 - normalizedEncumbrance) * fFatigueJumpMult;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(std::abs(vec.x/2.0f) > std::abs(vec.y) && speed > 0.0f)
|
vec.x *= mMovementSpeed;
|
||||||
|
vec.y *= mMovementSpeed;
|
||||||
|
|
||||||
|
CharacterState movestate = CharState_None;
|
||||||
|
CharacterState idlestate = CharState_SpecialIdle;
|
||||||
|
bool forcestateupdate = false;
|
||||||
|
|
||||||
|
if(std::abs(vec.x/2.0f) > std::abs(vec.y))
|
||||||
{
|
{
|
||||||
if(vec.x > 0.0f)
|
if(vec.x > 0.0f)
|
||||||
setState(inwater ? (isrunning ? CharState_SwimRunRight : CharState_SwimWalkRight)
|
movestate = (inwater ? (isrunning ? CharState_SwimRunRight : CharState_SwimWalkRight)
|
||||||
: (sneak ? CharState_SneakRight : (isrunning ? CharState_RunRight : CharState_WalkRight)));
|
: (sneak ? CharState_SneakRight
|
||||||
|
: (isrunning ? CharState_RunRight : CharState_WalkRight)));
|
||||||
else if(vec.x < 0.0f)
|
else if(vec.x < 0.0f)
|
||||||
setState(inwater ? (isrunning ? CharState_SwimRunLeft : CharState_SwimWalkLeft)
|
movestate = (inwater ? (isrunning ? CharState_SwimRunLeft : CharState_SwimWalkLeft)
|
||||||
: (sneak ? CharState_SneakLeft : (isrunning ? CharState_RunLeft : CharState_WalkLeft)));
|
: (sneak ? CharState_SneakLeft
|
||||||
|
: (isrunning ? CharState_RunLeft : CharState_WalkLeft)));
|
||||||
vec.x *= speed;
|
|
||||||
vec.y *= speed;
|
|
||||||
}
|
}
|
||||||
else if(vec.y != 0.0f && speed > 0.0f)
|
else if(vec.y != 0.0f)
|
||||||
{
|
{
|
||||||
if(vec.y > 0.0f)
|
if(vec.y > 0.0f)
|
||||||
setState(inwater ? (isrunning ? CharState_SwimRunForward : CharState_SwimWalkForward)
|
movestate = (inwater ? (isrunning ? CharState_SwimRunForward : CharState_SwimWalkForward)
|
||||||
: (sneak ? CharState_SneakForward : (isrunning ? CharState_RunForward : CharState_WalkForward)));
|
: (sneak ? CharState_SneakForward
|
||||||
|
: (isrunning ? CharState_RunForward : CharState_WalkForward)));
|
||||||
else if(vec.y < 0.0f)
|
else if(vec.y < 0.0f)
|
||||||
setState(inwater ? (isrunning ? CharState_SwimRunBack : CharState_SwimWalkBack)
|
movestate = (inwater ? (isrunning ? CharState_SwimRunBack : CharState_SwimWalkBack)
|
||||||
: (sneak ? CharState_SneakBack : (isrunning ? CharState_RunBack : CharState_WalkBack)));
|
: (sneak ? CharState_SneakBack
|
||||||
|
: (isrunning ? CharState_RunBack : CharState_WalkBack)));
|
||||||
vec.x *= speed;
|
|
||||||
vec.y *= speed;
|
|
||||||
}
|
}
|
||||||
else if(rot.z != 0.0f && !inwater && !sneak)
|
else if(rot.z != 0.0f && !inwater && !sneak)
|
||||||
{
|
{
|
||||||
if(rot.z > 0.0f)
|
if(rot.z > 0.0f)
|
||||||
setState(CharState_TurnRight);
|
movestate = CharState_TurnRight;
|
||||||
else if(rot.z < 0.0f)
|
else if(rot.z < 0.0f)
|
||||||
setState(CharState_TurnLeft);
|
movestate = CharState_TurnLeft;
|
||||||
}
|
}
|
||||||
else if(mAnimQueue.size() > 0)
|
|
||||||
{
|
if(movestate != CharState_None)
|
||||||
if(mAnimQueue.size() > 1)
|
clearAnimQueue();
|
||||||
|
|
||||||
|
if(mAnimQueue.size() == 0)
|
||||||
|
idlestate = (inwater ? CharState_IdleSwim : (sneak ? CharState_IdleSneak : CharState_Idle));
|
||||||
|
else if(mAnimQueue.size() > 1)
|
||||||
{
|
{
|
||||||
if(mAnimation->isPlaying(mAnimQueue.front().first) == false)
|
if(mAnimation->isPlaying(mAnimQueue.front().first) == false)
|
||||||
{
|
{
|
||||||
|
@ -354,13 +411,10 @@ void CharacterController::update(float duration, Movement &movement)
|
||||||
mAnimQueue.pop_front();
|
mAnimQueue.pop_front();
|
||||||
|
|
||||||
mAnimation->play(mAnimQueue.front().first, Priority_Default,
|
mAnimation->play(mAnimQueue.front().first, Priority_Default,
|
||||||
MWRender::Animation::Group_All, true,
|
MWRender::Animation::Group_All, false,
|
||||||
"start", "stop", 0.0f, mAnimQueue.front().second);
|
1.0f, "start", "stop", 0.0f, mAnimQueue.front().second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
setState((inwater ? CharState_IdleSwim : (sneak ? CharState_IdleSneak : CharState_Idle)));
|
|
||||||
|
|
||||||
vec *= duration;
|
vec *= duration;
|
||||||
movement.mPosition[0] += vec.x;
|
movement.mPosition[0] += vec.x;
|
||||||
|
@ -431,20 +485,22 @@ void CharacterController::update(float duration, Movement &movement)
|
||||||
|
|
||||||
if(mUpdateWeapon)
|
if(mUpdateWeapon)
|
||||||
{
|
{
|
||||||
|
forcestateupdate = (mWeaponType != weaptype);
|
||||||
mWeaponType = weaptype;
|
mWeaponType = weaptype;
|
||||||
forceStateUpdate();
|
|
||||||
mUpdateWeapon = false;
|
mUpdateWeapon = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(weaptype != mWeaponType)
|
if(weaptype != mWeaponType)
|
||||||
{
|
{
|
||||||
|
forcestateupdate = true;
|
||||||
|
|
||||||
std::string weapgroup;
|
std::string weapgroup;
|
||||||
if(weaptype == WeapType_None)
|
if(weaptype == WeapType_None)
|
||||||
{
|
{
|
||||||
getWeaponGroup(mWeaponType, weapgroup);
|
getWeaponGroup(mWeaponType, weapgroup);
|
||||||
mAnimation->play(weapgroup, Priority_Weapon,
|
mAnimation->play(weapgroup, Priority_Weapon,
|
||||||
MWRender::Animation::Group_UpperBody, true,
|
MWRender::Animation::Group_UpperBody, true,
|
||||||
"unequip start", "unequip stop", 0.0f, 0);
|
1.0f, "unequip start", "unequip stop", 0.0f, 0);
|
||||||
mUpperBodyState = UpperCharState_UnEquipingWeap;
|
mUpperBodyState = UpperCharState_UnEquipingWeap;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -453,12 +509,11 @@ void CharacterController::update(float duration, Movement &movement)
|
||||||
mAnimation->showWeapons(false);
|
mAnimation->showWeapons(false);
|
||||||
mAnimation->play(weapgroup, Priority_Weapon,
|
mAnimation->play(weapgroup, Priority_Weapon,
|
||||||
MWRender::Animation::Group_UpperBody, true,
|
MWRender::Animation::Group_UpperBody, true,
|
||||||
"equip start", "equip stop", 0.0f, 0);
|
1.0f, "equip start", "equip stop", 0.0f, 0);
|
||||||
mUpperBodyState = UpperCharState_EquipingWeap;
|
mUpperBodyState = UpperCharState_EquipingWeap;
|
||||||
}
|
}
|
||||||
|
|
||||||
mWeaponType = weaptype;
|
mWeaponType = weaptype;
|
||||||
forceStateUpdate();
|
|
||||||
|
|
||||||
if(weapon != inv.end())
|
if(weapon != inv.end())
|
||||||
{
|
{
|
||||||
|
@ -482,7 +537,7 @@ void CharacterController::update(float duration, Movement &movement)
|
||||||
getWeaponGroup(mWeaponType, weapgroup);
|
getWeaponGroup(mWeaponType, weapgroup);
|
||||||
mAnimation->play(weapgroup, Priority_Weapon,
|
mAnimation->play(weapgroup, Priority_Weapon,
|
||||||
MWRender::Animation::Group_UpperBody, false,
|
MWRender::Animation::Group_UpperBody, false,
|
||||||
"chop start", "chop min attack", 0.0f, 0);
|
1.0f,"chop start", "chop min attack", 0.0f, 0);
|
||||||
mUpperBodyState = UpperCharState_ChopStartToMinAttack;
|
mUpperBodyState = UpperCharState_ChopStartToMinAttack;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -501,13 +556,13 @@ void CharacterController::update(float duration, Movement &movement)
|
||||||
mAnimation->disable(weapgroup);
|
mAnimation->disable(weapgroup);
|
||||||
mAnimation->play(weapgroup, Priority_Weapon,
|
mAnimation->play(weapgroup, Priority_Weapon,
|
||||||
MWRender::Animation::Group_UpperBody, false,
|
MWRender::Animation::Group_UpperBody, false,
|
||||||
"chop max attack", "chop min hit", 1-complete, 0);
|
1.0f,"chop max attack", "chop min hit", 1-complete, 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mAnimation->play(weapgroup, Priority_Weapon,
|
mAnimation->play(weapgroup, Priority_Weapon,
|
||||||
MWRender::Animation::Group_UpperBody, false,
|
MWRender::Animation::Group_UpperBody, false,
|
||||||
"chop max attack", "chop min hit", 0, 0);
|
1.0f,"chop max attack", "chop min hit", 0, 0);
|
||||||
}
|
}
|
||||||
mUpperBodyState = UpperCharState_ChopMaxAttackToMinHit;
|
mUpperBodyState = UpperCharState_ChopMaxAttackToMinHit;
|
||||||
}
|
}
|
||||||
|
@ -560,24 +615,24 @@ void CharacterController::update(float duration, Movement &movement)
|
||||||
if(!mAnimation->isPlaying("torch"))
|
if(!mAnimation->isPlaying("torch"))
|
||||||
mAnimation->play("torch", Priority_Torch,
|
mAnimation->play("torch", Priority_Torch,
|
||||||
MWRender::Animation::Group_LeftArm, false,
|
MWRender::Animation::Group_LeftArm, false,
|
||||||
"start", "stop", 0.0f, (~(size_t)0));
|
1.0f, "start", "stop", 0.0f, (~(size_t)0));
|
||||||
}
|
}
|
||||||
else if(mAnimation->isPlaying("torch"))
|
else if(mAnimation->isPlaying("torch"))
|
||||||
mAnimation->disable("torch");
|
mAnimation->disable("torch");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
refreshCurrentAnims(idlestate, movestate, forcestateupdate);
|
||||||
}
|
}
|
||||||
else if (cls.getCreatureStats(mPtr).isDead())
|
else if(cls.getCreatureStats(mPtr).isDead())
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getWorld()->enableActorCollision(mPtr, false);
|
MWBase::Environment::get().getWorld()->enableActorCollision(mPtr, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mAnimation && !mSkipAnim)
|
if(mAnimation && !mSkipAnim)
|
||||||
{
|
{
|
||||||
mAnimation->setSpeed(speed);
|
|
||||||
|
|
||||||
Ogre::Vector3 moved = mAnimation->runAnimation(duration);
|
Ogre::Vector3 moved = mAnimation->runAnimation(duration);
|
||||||
// Ensure we're moving in generally the right direction
|
// Ensure we're moving in generally the right direction
|
||||||
if (speed > 0.f)
|
if(mMovementSpeed > 0.f)
|
||||||
{
|
{
|
||||||
if((movement.mPosition[0] < 0.0f && movement.mPosition[0] < moved.x*2.0f) ||
|
if((movement.mPosition[0] < 0.0f && movement.mPosition[0] < moved.x*2.0f) ||
|
||||||
(movement.mPosition[0] > 0.0f && movement.mPosition[0] > moved.x*2.0f))
|
(movement.mPosition[0] > 0.0f && movement.mPosition[0] > moved.x*2.0f))
|
||||||
|
@ -610,9 +665,12 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int
|
||||||
clearAnimQueue();
|
clearAnimQueue();
|
||||||
mAnimQueue.push_back(std::make_pair(groupname, count-1));
|
mAnimQueue.push_back(std::make_pair(groupname, count-1));
|
||||||
|
|
||||||
mCharState = CharState_SpecialIdle;
|
mAnimation->disable(mCurrentIdle);
|
||||||
|
mCurrentIdle.clear();
|
||||||
|
|
||||||
|
mIdleState = CharState_SpecialIdle;
|
||||||
mAnimation->play(groupname, Priority_Default,
|
mAnimation->play(groupname, Priority_Default,
|
||||||
MWRender::Animation::Group_All, false,
|
MWRender::Animation::Group_All, false, 1.0f,
|
||||||
((mode==2) ? "loop start" : "start"), "stop", 0.0f, count-1);
|
((mode==2) ? "loop start" : "start"), "stop", 0.0f, count-1);
|
||||||
}
|
}
|
||||||
else if(mode == 0)
|
else if(mode == 0)
|
||||||
|
@ -632,7 +690,6 @@ bool CharacterController::isAnimPlaying(const std::string &groupName)
|
||||||
{
|
{
|
||||||
if(mAnimation == NULL)
|
if(mAnimation == NULL)
|
||||||
return false;
|
return false;
|
||||||
else
|
|
||||||
return mAnimation->isPlaying(groupName);
|
return mAnimation->isPlaying(groupName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -645,27 +702,56 @@ void CharacterController::clearAnimQueue()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CharacterController::setState(CharacterState state)
|
|
||||||
{
|
|
||||||
if(mCharState == state)
|
|
||||||
return;
|
|
||||||
mCharState = state;
|
|
||||||
|
|
||||||
forceStateUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CharacterController::forceStateUpdate()
|
void CharacterController::forceStateUpdate()
|
||||||
{
|
{
|
||||||
if(!mAnimation)
|
if(!mAnimation)
|
||||||
return;
|
return;
|
||||||
clearAnimQueue();
|
clearAnimQueue();
|
||||||
|
|
||||||
std::string group;
|
refreshCurrentAnims(mIdleState, mMovementState, true);
|
||||||
Priority prio;
|
if(mDeathState != CharState_None)
|
||||||
bool loops;
|
{
|
||||||
getCurrentGroup(group, prio, loops);
|
const StateInfo *state = std::find_if(sStateList, sStateListEnd, FindCharState(mDeathState));
|
||||||
mAnimation->play(group, prio, MWRender::Animation::Group_All, false,
|
if(state == sStateListEnd)
|
||||||
"start", "stop", 0.0f, loops ? (~(size_t)0) : 0);
|
throw std::runtime_error("Failed to find character state "+Ogre::StringConverter::toString(mDeathState));
|
||||||
|
|
||||||
|
mCurrentDeath = state->groupname;
|
||||||
|
if(!mAnimation->getInfo(mCurrentDeath))
|
||||||
|
mAnimation->play(mCurrentDeath, Priority_Death, MWRender::Animation::Group_All,
|
||||||
|
false, 1.0f, "start", "stop", 0.0f, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CharacterController::kill()
|
||||||
|
{
|
||||||
|
static const CharacterState deathstates[] = {
|
||||||
|
CharState_Death1, CharState_Death2, CharState_Death3, CharState_Death4, CharState_Death5
|
||||||
|
};
|
||||||
|
|
||||||
|
if(mDeathState != CharState_None)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mDeathState = deathstates[(int)(rand()/((double)RAND_MAX+1.0)*5.0)];
|
||||||
|
const StateInfo *state = std::find_if(sStateList, sStateListEnd, FindCharState(mDeathState));
|
||||||
|
if(state == sStateListEnd)
|
||||||
|
throw std::runtime_error("Failed to find character state "+Ogre::StringConverter::toString(mDeathState));
|
||||||
|
|
||||||
|
mCurrentDeath = state->groupname;
|
||||||
|
if(mAnimation && !mAnimation->getInfo(mCurrentDeath))
|
||||||
|
mAnimation->play(mCurrentDeath, Priority_Death, MWRender::Animation::Group_All,
|
||||||
|
false, 1.0f, "start", "stop", 0.0f, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CharacterController::resurrect()
|
||||||
|
{
|
||||||
|
if(mDeathState == CharState_None)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(mAnimation)
|
||||||
|
mAnimation->disable(mCurrentDeath);
|
||||||
|
mCurrentDeath.empty();
|
||||||
|
mDeathState = CharState_None;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ class Movement;
|
||||||
|
|
||||||
enum Priority {
|
enum Priority {
|
||||||
Priority_Default,
|
Priority_Default,
|
||||||
|
Priority_Movement,
|
||||||
Priority_Weapon,
|
Priority_Weapon,
|
||||||
Priority_Torch,
|
Priority_Torch,
|
||||||
|
|
||||||
|
@ -26,6 +27,8 @@ enum Priority {
|
||||||
};
|
};
|
||||||
|
|
||||||
enum CharacterState {
|
enum CharacterState {
|
||||||
|
CharState_None,
|
||||||
|
|
||||||
CharState_SpecialIdle,
|
CharState_SpecialIdle,
|
||||||
CharState_Idle,
|
CharState_Idle,
|
||||||
CharState_Idle2,
|
CharState_Idle2,
|
||||||
|
@ -121,8 +124,18 @@ class CharacterController
|
||||||
typedef std::deque<std::pair<std::string,size_t> > AnimationQueue;
|
typedef std::deque<std::pair<std::string,size_t> > AnimationQueue;
|
||||||
AnimationQueue mAnimQueue;
|
AnimationQueue mAnimQueue;
|
||||||
|
|
||||||
CharacterState mCharState;
|
CharacterState mIdleState;
|
||||||
|
std::string mCurrentIdle;
|
||||||
|
|
||||||
|
CharacterState mMovementState;
|
||||||
|
std::string mCurrentMovement;
|
||||||
|
float mMovementSpeed;
|
||||||
|
|
||||||
|
CharacterState mDeathState;
|
||||||
|
std::string mCurrentDeath;
|
||||||
|
|
||||||
UpperBodyCharacterState mUpperBodyState;
|
UpperBodyCharacterState mUpperBodyState;
|
||||||
|
|
||||||
WeaponType mWeaponType;
|
WeaponType mWeaponType;
|
||||||
bool mSkipAnim;
|
bool mSkipAnim;
|
||||||
|
|
||||||
|
@ -133,15 +146,14 @@ class CharacterController
|
||||||
float mSecondsOfSwimming;
|
float mSecondsOfSwimming;
|
||||||
float mSecondsOfRunning;
|
float mSecondsOfRunning;
|
||||||
|
|
||||||
// Gets an animation group name from the current character state, and whether it should loop.
|
void refreshCurrentAnims(CharacterState idle, CharacterState movement, bool force=false);
|
||||||
void getCurrentGroup(std::string &group, Priority &prio, bool &loops) const;
|
|
||||||
|
|
||||||
static void getWeaponGroup(WeaponType weaptype, std::string &group);
|
static void getWeaponGroup(WeaponType weaptype, std::string &group);
|
||||||
|
|
||||||
void clearAnimQueue();
|
void clearAnimQueue();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state);
|
CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim);
|
||||||
virtual ~CharacterController();
|
virtual ~CharacterController();
|
||||||
|
|
||||||
void updatePtr(const MWWorld::Ptr &ptr);
|
void updatePtr(const MWWorld::Ptr &ptr);
|
||||||
|
@ -152,9 +164,10 @@ public:
|
||||||
void skipAnim();
|
void skipAnim();
|
||||||
bool isAnimPlaying(const std::string &groupName);
|
bool isAnimPlaying(const std::string &groupName);
|
||||||
|
|
||||||
void setState(CharacterState state);
|
void kill();
|
||||||
CharacterState getState() const
|
void resurrect();
|
||||||
{ return mCharState; }
|
bool isDead() const
|
||||||
|
{ return mDeathState != CharState_None; }
|
||||||
|
|
||||||
void forceStateUpdate();
|
void forceStateUpdate();
|
||||||
};
|
};
|
||||||
|
|
|
@ -17,15 +17,17 @@ Objects::Objects()
|
||||||
void Objects::addObject(const MWWorld::Ptr& ptr)
|
void Objects::addObject(const MWWorld::Ptr& ptr)
|
||||||
{
|
{
|
||||||
MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr);
|
MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr);
|
||||||
if(anim != NULL)
|
if(anim) mObjects.insert(std::make_pair(ptr, new CharacterController(ptr, anim)));
|
||||||
mObjects.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Objects::removeObject(const MWWorld::Ptr& ptr)
|
void Objects::removeObject(const MWWorld::Ptr& ptr)
|
||||||
{
|
{
|
||||||
PtrControllerMap::iterator iter = mObjects.find(ptr);
|
PtrControllerMap::iterator iter = mObjects.find(ptr);
|
||||||
if(iter != mObjects.end())
|
if(iter != mObjects.end())
|
||||||
|
{
|
||||||
|
delete iter->second;
|
||||||
mObjects.erase(iter);
|
mObjects.erase(iter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Objects::updateObject(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr)
|
void Objects::updateObject(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr)
|
||||||
|
@ -33,10 +35,10 @@ void Objects::updateObject(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr)
|
||||||
PtrControllerMap::iterator iter = mObjects.find(old);
|
PtrControllerMap::iterator iter = mObjects.find(old);
|
||||||
if(iter != mObjects.end())
|
if(iter != mObjects.end())
|
||||||
{
|
{
|
||||||
CharacterController ctrl = iter->second;
|
CharacterController *ctrl = iter->second;
|
||||||
mObjects.erase(iter);
|
mObjects.erase(iter);
|
||||||
|
|
||||||
ctrl.updatePtr(ptr);
|
ctrl->updatePtr(ptr);
|
||||||
mObjects.insert(std::make_pair(ptr, ctrl));
|
mObjects.insert(std::make_pair(ptr, ctrl));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,7 +49,10 @@ void Objects::dropObjects (const MWWorld::Ptr::CellStore *cellStore)
|
||||||
while(iter != mObjects.end())
|
while(iter != mObjects.end())
|
||||||
{
|
{
|
||||||
if(iter->first.getCell()==cellStore)
|
if(iter->first.getCell()==cellStore)
|
||||||
|
{
|
||||||
|
delete iter->second;
|
||||||
mObjects.erase(iter++);
|
mObjects.erase(iter++);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
++iter;
|
++iter;
|
||||||
}
|
}
|
||||||
|
@ -60,7 +65,7 @@ void Objects::update(float duration, bool paused)
|
||||||
for(PtrControllerMap::iterator iter(mObjects.begin());iter != mObjects.end();++iter)
|
for(PtrControllerMap::iterator iter(mObjects.begin());iter != mObjects.end();++iter)
|
||||||
{
|
{
|
||||||
Movement movement;
|
Movement movement;
|
||||||
iter->second.update(duration, movement);
|
iter->second->update(duration, movement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,13 +74,13 @@ void Objects::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& gro
|
||||||
{
|
{
|
||||||
PtrControllerMap::iterator iter = mObjects.find(ptr);
|
PtrControllerMap::iterator iter = mObjects.find(ptr);
|
||||||
if(iter != mObjects.end())
|
if(iter != mObjects.end())
|
||||||
iter->second.playGroup(groupName, mode, number);
|
iter->second->playGroup(groupName, mode, number);
|
||||||
}
|
}
|
||||||
void Objects::skipAnimation(const MWWorld::Ptr& ptr)
|
void Objects::skipAnimation(const MWWorld::Ptr& ptr)
|
||||||
{
|
{
|
||||||
PtrControllerMap::iterator iter = mObjects.find(ptr);
|
PtrControllerMap::iterator iter = mObjects.find(ptr);
|
||||||
if(iter != mObjects.end())
|
if(iter != mObjects.end())
|
||||||
iter->second.skipAnim();
|
iter->second->skipAnim();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
class Objects
|
class Objects
|
||||||
{
|
{
|
||||||
typedef std::map<MWWorld::Ptr,CharacterController> PtrControllerMap;
|
typedef std::map<MWWorld::Ptr,CharacterController*> PtrControllerMap;
|
||||||
PtrControllerMap mObjects;
|
PtrControllerMap mObjects;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -45,14 +45,13 @@ void Animation::destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectL
|
||||||
|
|
||||||
Animation::Animation(const MWWorld::Ptr &ptr)
|
Animation::Animation(const MWWorld::Ptr &ptr)
|
||||||
: mPtr(ptr)
|
: mPtr(ptr)
|
||||||
|
, mCamera(NULL)
|
||||||
, mInsert(NULL)
|
, mInsert(NULL)
|
||||||
, mSkelBase(NULL)
|
, mSkelBase(NULL)
|
||||||
, mAccumRoot(NULL)
|
, mAccumRoot(NULL)
|
||||||
, mNonAccumRoot(NULL)
|
, mNonAccumRoot(NULL)
|
||||||
, mNonAccumCtrl(NULL)
|
, mNonAccumCtrl(NULL)
|
||||||
, mAccumulate(0.0f)
|
, mAccumulate(0.0f)
|
||||||
, mAnimVelocity(0.0f)
|
|
||||||
, mAnimSpeedMult(1.0f)
|
|
||||||
{
|
{
|
||||||
for(size_t i = 0;i < sNumGroups;i++)
|
for(size_t i = 0;i < sNumGroups;i++)
|
||||||
mAnimationValuePtr[i].bind(OGRE_NEW AnimationValue(this));
|
mAnimationValuePtr[i].bind(OGRE_NEW AnimationValue(this));
|
||||||
|
@ -72,7 +71,8 @@ Animation::~Animation()
|
||||||
|
|
||||||
void Animation::setObjectRoot(Ogre::SceneNode *node, const std::string &model, bool baseonly)
|
void Animation::setObjectRoot(Ogre::SceneNode *node, const std::string &model, bool baseonly)
|
||||||
{
|
{
|
||||||
OgreAssert(!mInsert, "Object already has a root!");
|
OgreAssert(mAnimSources.size() == 0, "Setting object root while animation sources are set!");
|
||||||
|
if(!mInsert)
|
||||||
mInsert = node->createChildSceneNode();
|
mInsert = node->createChildSceneNode();
|
||||||
|
|
||||||
std::string mdlname = Misc::StringUtils::lowerCase(model);
|
std::string mdlname = Misc::StringUtils::lowerCase(model);
|
||||||
|
@ -89,6 +89,9 @@ void Animation::setObjectRoot(Ogre::SceneNode *node, const std::string &model, b
|
||||||
Misc::StringUtils::toLower(mdlname);
|
Misc::StringUtils::toLower(mdlname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mSkelBase = NULL;
|
||||||
|
destroyObjectList(mInsert->getCreator(), mObjectRoot);
|
||||||
|
|
||||||
mObjectRoot = (!baseonly ? NifOgre::Loader::createObjects(mInsert, mdlname) :
|
mObjectRoot = (!baseonly ? NifOgre::Loader::createObjects(mInsert, mdlname) :
|
||||||
NifOgre::Loader::createObjectBase(mInsert, mdlname));
|
NifOgre::Loader::createObjectBase(mInsert, mdlname));
|
||||||
if(mObjectRoot.mSkelBase)
|
if(mObjectRoot.mSkelBase)
|
||||||
|
@ -110,7 +113,23 @@ void Animation::setObjectRoot(Ogre::SceneNode *node, const std::string &model, b
|
||||||
Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator();
|
Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator();
|
||||||
while(boneiter.hasMoreElements())
|
while(boneiter.hasMoreElements())
|
||||||
boneiter.getNext()->setManuallyControlled(true);
|
boneiter.getNext()->setManuallyControlled(true);
|
||||||
|
|
||||||
|
// Reattach any objects that have been attached to this one
|
||||||
|
ObjectAttachMap::iterator iter = mAttachedObjects.begin();
|
||||||
|
while(iter != mAttachedObjects.end())
|
||||||
|
{
|
||||||
|
if(!skelinst->hasBone(iter->second))
|
||||||
|
mAttachedObjects.erase(iter++);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mSkelBase->attachObjectToBone(iter->second, iter->first);
|
||||||
|
iter++;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mAttachedObjects.clear();
|
||||||
|
|
||||||
for(size_t i = 0;i < mObjectRoot.mControllers.size();i++)
|
for(size_t i = 0;i < mObjectRoot.mControllers.size();i++)
|
||||||
{
|
{
|
||||||
if(mObjectRoot.mControllers[i].getSource().isNull())
|
if(mObjectRoot.mControllers[i].getSource().isNull())
|
||||||
|
@ -224,7 +243,6 @@ void Animation::clearAnimSources()
|
||||||
mAnimationValuePtr[i]->setAnimName(std::string());
|
mAnimationValuePtr[i]->setAnimName(std::string());
|
||||||
|
|
||||||
mNonAccumCtrl = NULL;
|
mNonAccumCtrl = NULL;
|
||||||
mAnimVelocity = 0.0f;
|
|
||||||
|
|
||||||
mAccumRoot = NULL;
|
mAccumRoot = NULL;
|
||||||
mNonAccumRoot = NULL;
|
mNonAccumRoot = NULL;
|
||||||
|
@ -277,13 +295,6 @@ void Animation::setAccumulation(const Ogre::Vector3 &accum)
|
||||||
mAccumulate = accum;
|
mAccumulate = accum;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Animation::setSpeed(float speed)
|
|
||||||
{
|
|
||||||
mAnimSpeedMult = 1.0f;
|
|
||||||
if(speed > 0.0f && mAnimVelocity > 1.0f)
|
|
||||||
mAnimSpeedMult = speed / mAnimVelocity;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Animation::updatePtr(const MWWorld::Ptr &ptr)
|
void Animation::updatePtr(const MWWorld::Ptr &ptr)
|
||||||
{
|
{
|
||||||
|
@ -323,6 +334,61 @@ float Animation::calcAnimVelocity(const NifOgre::TextKeyMap &keys, NifOgre::Node
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float Animation::getVelocity(const std::string &groupname) const
|
||||||
|
{
|
||||||
|
/* Look in reverse; last-inserted source has priority. */
|
||||||
|
AnimSourceList::const_reverse_iterator animsrc(mAnimSources.rbegin());
|
||||||
|
for(;animsrc != mAnimSources.rend();animsrc++)
|
||||||
|
{
|
||||||
|
const NifOgre::TextKeyMap &keys = (*animsrc)->mTextKeys;
|
||||||
|
if(findGroupStart(keys, groupname) != keys.end())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(animsrc == mAnimSources.rend())
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
float velocity = 0.0f;
|
||||||
|
const NifOgre::TextKeyMap &keys = (*animsrc)->mTextKeys;
|
||||||
|
const std::vector<Ogre::Controller<Ogre::Real> >&ctrls = (*animsrc)->mControllers[0];
|
||||||
|
for(size_t i = 0;i < ctrls.size();i++)
|
||||||
|
{
|
||||||
|
NifOgre::NodeTargetValue<Ogre::Real> *dstval;
|
||||||
|
dstval = static_cast<NifOgre::NodeTargetValue<Ogre::Real>*>(ctrls[i].getDestination().getPointer());
|
||||||
|
if(dstval->getNode() == mNonAccumRoot)
|
||||||
|
{
|
||||||
|
velocity = calcAnimVelocity(keys, dstval, mAccumulate, groupname);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there's no velocity, keep looking
|
||||||
|
if(!(velocity > 1.0f))
|
||||||
|
{
|
||||||
|
AnimSourceList::const_reverse_iterator animiter = mAnimSources.rbegin();
|
||||||
|
while(*animiter != *animsrc)
|
||||||
|
++animiter;
|
||||||
|
|
||||||
|
while(!(velocity > 1.0f) && ++animiter != mAnimSources.rend())
|
||||||
|
{
|
||||||
|
const NifOgre::TextKeyMap &keys = (*animiter)->mTextKeys;
|
||||||
|
const std::vector<Ogre::Controller<Ogre::Real> >&ctrls = (*animiter)->mControllers[0];
|
||||||
|
for(size_t i = 0;i < ctrls.size();i++)
|
||||||
|
{
|
||||||
|
NifOgre::NodeTargetValue<Ogre::Real> *dstval;
|
||||||
|
dstval = static_cast<NifOgre::NodeTargetValue<Ogre::Real>*>(ctrls[i].getDestination().getPointer());
|
||||||
|
if(dstval->getNode() == mNonAccumRoot)
|
||||||
|
{
|
||||||
|
velocity = calcAnimVelocity(keys, dstval, mAccumulate, groupname);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return velocity;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void updateBoneTree(const Ogre::SkeletonInstance *skelsrc, Ogre::Bone *bone)
|
static void updateBoneTree(const Ogre::SkeletonInstance *skelsrc, Ogre::Bone *bone)
|
||||||
{
|
{
|
||||||
if(skelsrc->hasBone(bone->getName()))
|
if(skelsrc->hasBone(bone->getName()))
|
||||||
|
@ -496,7 +562,7 @@ bool Animation::handleTextKey(AnimState &state, const std::string &groupname, co
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Animation::play(const std::string &groupname, int priority, int groups, bool autodisable, const std::string &start, const std::string &stop, float startpoint, size_t loops)
|
void Animation::play(const std::string &groupname, int priority, int groups, bool autodisable, float speedmult, const std::string &start, const std::string &stop, float startpoint, size_t loops)
|
||||||
{
|
{
|
||||||
if(!mSkelBase)
|
if(!mSkelBase)
|
||||||
return;
|
return;
|
||||||
|
@ -534,6 +600,7 @@ void Animation::play(const std::string &groupname, int priority, int groups, boo
|
||||||
if(reset(state, (*iter)->mTextKeys, groupname, start, stop, startpoint))
|
if(reset(state, (*iter)->mTextKeys, groupname, start, stop, startpoint))
|
||||||
{
|
{
|
||||||
state.mSource = *iter;
|
state.mSource = *iter;
|
||||||
|
state.mSpeedMult = speedmult;
|
||||||
state.mLoopCount = loops;
|
state.mLoopCount = loops;
|
||||||
state.mPlaying = true;
|
state.mPlaying = true;
|
||||||
state.mPriority = priority;
|
state.mPriority = priority;
|
||||||
|
@ -577,9 +644,7 @@ void Animation::resetActiveGroups()
|
||||||
mAnimationValuePtr[grp]->setAnimName((active == mStates.end()) ?
|
mAnimationValuePtr[grp]->setAnimName((active == mStates.end()) ?
|
||||||
std::string() : active->first);
|
std::string() : active->first);
|
||||||
}
|
}
|
||||||
|
|
||||||
mNonAccumCtrl = NULL;
|
mNonAccumCtrl = NULL;
|
||||||
mAnimVelocity = 0.0f;
|
|
||||||
|
|
||||||
if(!mNonAccumRoot || mAccumulate == Ogre::Vector3(0.0f))
|
if(!mNonAccumRoot || mAccumulate == Ogre::Vector3(0.0f))
|
||||||
return;
|
return;
|
||||||
|
@ -597,44 +662,20 @@ void Animation::resetActiveGroups()
|
||||||
dstval = static_cast<NifOgre::NodeTargetValue<Ogre::Real>*>(ctrls[i].getDestination().getPointer());
|
dstval = static_cast<NifOgre::NodeTargetValue<Ogre::Real>*>(ctrls[i].getDestination().getPointer());
|
||||||
if(dstval->getNode() == mNonAccumRoot)
|
if(dstval->getNode() == mNonAccumRoot)
|
||||||
{
|
{
|
||||||
mAnimVelocity = calcAnimVelocity(keys, dstval, mAccumulate, state->first);
|
|
||||||
mNonAccumCtrl = dstval;
|
mNonAccumCtrl = dstval;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there's no velocity, keep looking
|
|
||||||
if(!(mAnimVelocity > 1.0f))
|
|
||||||
{
|
|
||||||
AnimSourceList::const_reverse_iterator animiter = mAnimSources.rbegin();
|
|
||||||
while(*animiter != animsrc)
|
|
||||||
++animiter;
|
|
||||||
|
|
||||||
while(!(mAnimVelocity > 1.0f) && ++animiter != mAnimSources.rend())
|
|
||||||
{
|
|
||||||
const NifOgre::TextKeyMap &keys = (*animiter)->mTextKeys;
|
|
||||||
const std::vector<Ogre::Controller<Ogre::Real> >&ctrls = (*animiter)->mControllers[0];
|
|
||||||
for(size_t i = 0;i < ctrls.size();i++)
|
|
||||||
{
|
|
||||||
NifOgre::NodeTargetValue<Ogre::Real> *dstval;
|
|
||||||
dstval = static_cast<NifOgre::NodeTargetValue<Ogre::Real>*>(ctrls[i].getDestination().getPointer());
|
|
||||||
if(dstval->getNode() == mNonAccumRoot)
|
|
||||||
{
|
|
||||||
mAnimVelocity = calcAnimVelocity(keys, dstval, mAccumulate, state->first);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Animation::getInfo(const std::string &groupname, float *complete, std::string *start, std::string *stop) const
|
bool Animation::getInfo(const std::string &groupname, float *complete, float *speedmult, std::string *start, std::string *stop) const
|
||||||
{
|
{
|
||||||
AnimStateMap::const_iterator iter = mStates.find(groupname);
|
AnimStateMap::const_iterator iter = mStates.find(groupname);
|
||||||
if(iter == mStates.end())
|
if(iter == mStates.end())
|
||||||
{
|
{
|
||||||
if(complete) *complete = 0.0f;
|
if(complete) *complete = 0.0f;
|
||||||
|
if(speedmult) *speedmult = 0.0f;
|
||||||
if(start) *start = "";
|
if(start) *start = "";
|
||||||
if(stop) *stop = "";
|
if(stop) *stop = "";
|
||||||
return false;
|
return false;
|
||||||
|
@ -642,6 +683,7 @@ bool Animation::getInfo(const std::string &groupname, float *complete, std::stri
|
||||||
|
|
||||||
if(complete) *complete = (iter->second.mTime - iter->second.mStartKey->first) /
|
if(complete) *complete = (iter->second.mTime - iter->second.mStartKey->first) /
|
||||||
(iter->second.mStopKey->first - iter->second.mStartKey->first);
|
(iter->second.mStopKey->first - iter->second.mStartKey->first);
|
||||||
|
if(speedmult) *speedmult = iter->second.mSpeedMult;
|
||||||
if(start) *start = iter->second.mStartKey->second.substr(groupname.size()+2);
|
if(start) *start = iter->second.mStartKey->second.substr(groupname.size()+2);
|
||||||
if(stop) *stop = iter->second.mStopKey->second.substr(groupname.size()+2);
|
if(stop) *stop = iter->second.mStopKey->second.substr(groupname.size()+2);
|
||||||
return true;
|
return true;
|
||||||
|
@ -661,12 +703,11 @@ Ogre::Vector3 Animation::runAnimation(float duration)
|
||||||
{
|
{
|
||||||
Ogre::Vector3 movement(0.0f);
|
Ogre::Vector3 movement(0.0f);
|
||||||
|
|
||||||
duration *= mAnimSpeedMult;
|
|
||||||
AnimStateMap::iterator stateiter = mStates.begin();
|
AnimStateMap::iterator stateiter = mStates.begin();
|
||||||
while(stateiter != mStates.end())
|
while(stateiter != mStates.end())
|
||||||
{
|
{
|
||||||
AnimState &state = stateiter->second;
|
AnimState &state = stateiter->second;
|
||||||
float timepassed = duration;
|
float timepassed = duration * state.mSpeedMult;
|
||||||
while(state.mPlaying)
|
while(state.mPlaying)
|
||||||
{
|
{
|
||||||
float targetTime = state.mTime + timepassed;
|
float targetTime = state.mTime + timepassed;
|
||||||
|
@ -736,4 +777,24 @@ bool Animation::isPriorityActive(int priority) const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ogre::TagPoint *Animation::attachObjectToBone(const Ogre::String &bonename, Ogre::MovableObject *obj)
|
||||||
|
{
|
||||||
|
Ogre::TagPoint *tag = NULL;
|
||||||
|
Ogre::SkeletonInstance *skel = (mSkelBase ? mSkelBase->getSkeleton() : NULL);
|
||||||
|
if(skel && skel->hasBone(bonename))
|
||||||
|
{
|
||||||
|
tag = mSkelBase->attachObjectToBone(bonename, obj);
|
||||||
|
mAttachedObjects[obj] = bonename;
|
||||||
|
}
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Animation::detachObjectFromBone(Ogre::MovableObject *obj)
|
||||||
|
{
|
||||||
|
ObjectAttachMap::iterator iter = mAttachedObjects.find(obj);
|
||||||
|
if(iter != mAttachedObjects.end())
|
||||||
|
mAttachedObjects.erase(iter);
|
||||||
|
mSkelBase->detachObjectFromBone(obj);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
namespace MWRender
|
namespace MWRender
|
||||||
{
|
{
|
||||||
|
class Camera;
|
||||||
|
|
||||||
class Animation
|
class Animation
|
||||||
{
|
{
|
||||||
|
@ -65,6 +66,7 @@ protected:
|
||||||
NifOgre::TextKeyMap::const_iterator mNextKey;
|
NifOgre::TextKeyMap::const_iterator mNextKey;
|
||||||
|
|
||||||
float mTime;
|
float mTime;
|
||||||
|
float mSpeedMult;
|
||||||
|
|
||||||
bool mPlaying;
|
bool mPlaying;
|
||||||
size_t mLoopCount;
|
size_t mLoopCount;
|
||||||
|
@ -73,13 +75,16 @@ protected:
|
||||||
int mGroups;
|
int mGroups;
|
||||||
bool mAutoDisable;
|
bool mAutoDisable;
|
||||||
|
|
||||||
AnimState() : mTime(0.0f), mPlaying(false), mLoopCount(0),
|
AnimState() : mTime(0.0f), mSpeedMult(1.0f), mPlaying(false), mLoopCount(0),
|
||||||
mPriority(0), mGroups(0), mAutoDisable(true)
|
mPriority(0), mGroups(0), mAutoDisable(true)
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
typedef std::map<std::string,AnimState> AnimStateMap;
|
typedef std::map<std::string,AnimState> AnimStateMap;
|
||||||
|
|
||||||
|
typedef std::map<Ogre::MovableObject*,std::string> ObjectAttachMap;
|
||||||
|
|
||||||
MWWorld::Ptr mPtr;
|
MWWorld::Ptr mPtr;
|
||||||
|
Camera *mCamera;
|
||||||
|
|
||||||
Ogre::SceneNode *mInsert;
|
Ogre::SceneNode *mInsert;
|
||||||
Ogre::Entity *mSkelBase;
|
Ogre::Entity *mSkelBase;
|
||||||
|
@ -94,8 +99,7 @@ protected:
|
||||||
|
|
||||||
Ogre::SharedPtr<AnimationValue> mAnimationValuePtr[sNumGroups];
|
Ogre::SharedPtr<AnimationValue> mAnimationValuePtr[sNumGroups];
|
||||||
|
|
||||||
float mAnimVelocity;
|
ObjectAttachMap mAttachedObjects;
|
||||||
float mAnimSpeedMult;
|
|
||||||
|
|
||||||
/* Sets the appropriate animations on the bone groups based on priority.
|
/* Sets the appropriate animations on the bone groups based on priority.
|
||||||
*/
|
*/
|
||||||
|
@ -131,7 +135,18 @@ protected:
|
||||||
|
|
||||||
bool handleTextKey(AnimState &state, const std::string &groupname, const NifOgre::TextKeyMap::const_iterator &key);
|
bool handleTextKey(AnimState &state, const std::string &groupname, const NifOgre::TextKeyMap::const_iterator &key);
|
||||||
|
|
||||||
|
/* Sets the root model of the object. If 'baseonly' is true, then any meshes or particle
|
||||||
|
* systems in the model are ignored (useful for NPCs, where only the skeleton is needed for
|
||||||
|
* the root).
|
||||||
|
*
|
||||||
|
* Note that you must make sure all animation sources are cleared before reseting the object
|
||||||
|
* root. All nodes previously retrieved with getNode will also become invalidated.
|
||||||
|
*/
|
||||||
void setObjectRoot(Ogre::SceneNode *node, const std::string &model, bool baseonly);
|
void setObjectRoot(Ogre::SceneNode *node, const std::string &model, bool baseonly);
|
||||||
|
|
||||||
|
/* Adds the keyframe controllers in the specified model as a new animation source. Note that
|
||||||
|
* the filename portion of the provided model name will be prepended with 'x', and the .nif
|
||||||
|
* extension will be replaced with .kf. */
|
||||||
void addAnimSource(const std::string &model);
|
void addAnimSource(const std::string &model);
|
||||||
|
|
||||||
static void destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects);
|
static void destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects);
|
||||||
|
@ -156,8 +171,6 @@ public:
|
||||||
// should be on the scale of 0 to 1.
|
// should be on the scale of 0 to 1.
|
||||||
void setAccumulation(const Ogre::Vector3 &accum);
|
void setAccumulation(const Ogre::Vector3 &accum);
|
||||||
|
|
||||||
void setSpeed(float speed);
|
|
||||||
|
|
||||||
/** Plays an animation.
|
/** Plays an animation.
|
||||||
* \param groupname Name of the animation group to play.
|
* \param groupname Name of the animation group to play.
|
||||||
* \param priority Priority of the animation. The animation will play on
|
* \param priority Priority of the animation. The animation will play on
|
||||||
|
@ -166,6 +179,7 @@ public:
|
||||||
* \param groups Bone groups to play the animation on.
|
* \param groups Bone groups to play the animation on.
|
||||||
* \param autodisable Automatically disable the animation when it stops
|
* \param autodisable Automatically disable the animation when it stops
|
||||||
* playing.
|
* playing.
|
||||||
|
* \param speedmult Speed multiplier for the animation.
|
||||||
* \param start Key marker from which to start.
|
* \param start Key marker from which to start.
|
||||||
* \param stop Key marker to stop at.
|
* \param stop Key marker to stop at.
|
||||||
* \param startpoint How far in between the two markers to start. 0 starts
|
* \param startpoint How far in between the two markers to start. 0 starts
|
||||||
|
@ -175,7 +189,7 @@ public:
|
||||||
* otherwise it will use "start" and "stop".
|
* otherwise it will use "start" and "stop".
|
||||||
*/
|
*/
|
||||||
void play(const std::string &groupname, int priority, int groups, bool autodisable,
|
void play(const std::string &groupname, int priority, int groups, bool autodisable,
|
||||||
const std::string &start, const std::string &stop,
|
float speedmult, const std::string &start, const std::string &stop,
|
||||||
float startpoint, size_t loops);
|
float startpoint, size_t loops);
|
||||||
|
|
||||||
/** Returns true if the named animation group is playing. */
|
/** Returns true if the named animation group is playing. */
|
||||||
|
@ -184,22 +198,35 @@ public:
|
||||||
/** Gets info about the given animation group.
|
/** Gets info about the given animation group.
|
||||||
* \param groupname Animation group to check.
|
* \param groupname Animation group to check.
|
||||||
* \param complete Stores completion amount (0 = at start key, 0.5 = half way between start and stop keys), etc.
|
* \param complete Stores completion amount (0 = at start key, 0.5 = half way between start and stop keys), etc.
|
||||||
|
* \param speedmult Stores the animation speed multiplier
|
||||||
* \param start Stores the start key
|
* \param start Stores the start key
|
||||||
* \param stop Stores the stop key
|
* \param stop Stores the stop key
|
||||||
* \return True if the animation is active, false otherwise.
|
* \return True if the animation is active, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool getInfo(const std::string &groupname, float *complete=NULL, std::string *start=NULL, std::string *stop=NULL) const;
|
bool getInfo(const std::string &groupname, float *complete=NULL, float *speedmult=NULL, std::string *start=NULL, std::string *stop=NULL) const;
|
||||||
|
|
||||||
/** Disables the specified animation group;
|
/** Disables the specified animation group;
|
||||||
* \param groupname Animation group to disable.
|
* \param groupname Animation group to disable.
|
||||||
*/
|
*/
|
||||||
void disable(const std::string &groupname);
|
void disable(const std::string &groupname);
|
||||||
|
|
||||||
|
/** Retrieves the velocity (in units per second) that the animation will move. */
|
||||||
|
float getVelocity(const std::string &groupname) const;
|
||||||
|
|
||||||
virtual Ogre::Vector3 runAnimation(float duration);
|
virtual Ogre::Vector3 runAnimation(float duration);
|
||||||
|
|
||||||
virtual void showWeapons(bool showWeapon);
|
virtual void showWeapons(bool showWeapon);
|
||||||
|
|
||||||
|
void setCamera(Camera *cam)
|
||||||
|
{ mCamera = cam; }
|
||||||
|
|
||||||
Ogre::Node *getNode(const std::string &name);
|
Ogre::Node *getNode(const std::string &name);
|
||||||
|
|
||||||
|
// Attaches the given object to a bone on this object's base skeleton. If the bone doesn't
|
||||||
|
// exist, the object isn't attached and NULL is returned. The returned TagPoint is only
|
||||||
|
// valid until the next setObjectRoot call.
|
||||||
|
Ogre::TagPoint *attachObjectToBone(const Ogre::String &bonename, Ogre::MovableObject *obj);
|
||||||
|
void detachObjectFromBone(Ogre::MovableObject *obj);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <OgreSceneNode.h>
|
#include <OgreSceneNode.h>
|
||||||
#include <OgreCamera.h>
|
#include <OgreCamera.h>
|
||||||
#include <OgreSceneManager.h>
|
#include <OgreSceneManager.h>
|
||||||
|
#include <OgreTagPoint.h>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
@ -57,10 +58,10 @@ namespace MWRender
|
||||||
|
|
||||||
Ogre::Quaternion xr(Ogre::Radian(getPitch() + Ogre::Math::HALF_PI), Ogre::Vector3::UNIT_X);
|
Ogre::Quaternion xr(Ogre::Radian(getPitch() + Ogre::Math::HALF_PI), Ogre::Vector3::UNIT_X);
|
||||||
if (!mVanity.enabled && !mPreviewMode) {
|
if (!mVanity.enabled && !mPreviewMode) {
|
||||||
mCameraNode->setOrientation(xr);
|
mCamera->getParentNode()->setOrientation(xr);
|
||||||
} else {
|
} else {
|
||||||
Ogre::Quaternion zr(Ogre::Radian(getYaw()), Ogre::Vector3::NEGATIVE_UNIT_Z);
|
Ogre::Quaternion zr(Ogre::Radian(getYaw()), Ogre::Vector3::NEGATIVE_UNIT_Z);
|
||||||
mCameraNode->setOrientation(zr * xr);
|
mCamera->getParentNode()->setOrientation(zr * xr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,6 +82,7 @@ namespace MWRender
|
||||||
mCameraNode->getCreator()->destroySceneNode(mCameraNode);
|
mCameraNode->getCreator()->destroySceneNode(mCameraNode);
|
||||||
}
|
}
|
||||||
mCameraNode = node;
|
mCameraNode = node;
|
||||||
|
mCamera->detachFromParent();
|
||||||
mCameraNode->attachObject(mCamera);
|
mCameraNode->attachObject(mCamera);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,14 +114,12 @@ namespace MWRender
|
||||||
void Camera::toggleViewMode()
|
void Camera::toggleViewMode()
|
||||||
{
|
{
|
||||||
mFirstPersonView = !mFirstPersonView;
|
mFirstPersonView = !mFirstPersonView;
|
||||||
mAnimation->setViewMode(isFirstPerson() ? NpcAnimation::VM_FirstPerson :
|
processViewChange();
|
||||||
NpcAnimation::VM_Normal);
|
|
||||||
if (mFirstPersonView) {
|
if (mFirstPersonView) {
|
||||||
mCamera->setPosition(0.f, 0.f, 0.f);
|
mCamera->setPosition(0.f, 0.f, 0.f);
|
||||||
setLowHeight(false);
|
|
||||||
} else {
|
} else {
|
||||||
mCamera->setPosition(0.f, 0.f, mCameraDistance);
|
mCamera->setPosition(0.f, 0.f, mCameraDistance);
|
||||||
setLowHeight(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,21 +139,16 @@ namespace MWRender
|
||||||
return true;
|
return true;
|
||||||
mVanity.enabled = enable;
|
mVanity.enabled = enable;
|
||||||
|
|
||||||
mAnimation->setViewMode(isFirstPerson() ? NpcAnimation::VM_FirstPerson :
|
processViewChange();
|
||||||
NpcAnimation::VM_Normal);
|
|
||||||
|
|
||||||
float offset = mPreviewCam.offset;
|
float offset = mPreviewCam.offset;
|
||||||
Ogre::Vector3 rot(0.f, 0.f, 0.f);
|
Ogre::Vector3 rot(0.f, 0.f, 0.f);
|
||||||
if (mVanity.enabled) {
|
if (mVanity.enabled) {
|
||||||
rot.x = Ogre::Degree(-30.f).valueRadians();
|
rot.x = Ogre::Degree(-30.f).valueRadians();
|
||||||
mMainCam.offset = mCamera->getPosition().z;
|
mMainCam.offset = mCamera->getPosition().z;
|
||||||
|
|
||||||
setLowHeight(true);
|
|
||||||
} else {
|
} else {
|
||||||
rot.x = getPitch();
|
rot.x = getPitch();
|
||||||
offset = mMainCam.offset;
|
offset = mMainCam.offset;
|
||||||
|
|
||||||
setLowHeight(!mFirstPersonView);
|
|
||||||
}
|
}
|
||||||
rot.z = getYaw();
|
rot.z = getYaw();
|
||||||
|
|
||||||
|
@ -169,20 +164,15 @@ namespace MWRender
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mPreviewMode = enable;
|
mPreviewMode = enable;
|
||||||
mAnimation->setViewMode(isFirstPerson() ? NpcAnimation::VM_FirstPerson :
|
processViewChange();
|
||||||
NpcAnimation::VM_Normal);
|
|
||||||
|
|
||||||
float offset = mCamera->getPosition().z;
|
float offset = mCamera->getPosition().z;
|
||||||
if (mPreviewMode) {
|
if (mPreviewMode) {
|
||||||
mMainCam.offset = offset;
|
mMainCam.offset = offset;
|
||||||
offset = mPreviewCam.offset;
|
offset = mPreviewCam.offset;
|
||||||
|
|
||||||
setLowHeight(true);
|
|
||||||
} else {
|
} else {
|
||||||
mPreviewCam.offset = offset;
|
mPreviewCam.offset = offset;
|
||||||
offset = mMainCam.offset;
|
offset = mMainCam.offset;
|
||||||
|
|
||||||
setLowHeight(!mFirstPersonView);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mCamera->setPosition(0.f, 0.f, offset);
|
mCamera->setPosition(0.f, 0.f, offset);
|
||||||
|
@ -283,26 +273,48 @@ namespace MWRender
|
||||||
// If we're switching to a new NpcAnimation, ensure the old one is
|
// If we're switching to a new NpcAnimation, ensure the old one is
|
||||||
// using a normal view mode
|
// using a normal view mode
|
||||||
if(mAnimation && mAnimation != anim)
|
if(mAnimation && mAnimation != anim)
|
||||||
|
{
|
||||||
mAnimation->setViewMode(NpcAnimation::VM_Normal);
|
mAnimation->setViewMode(NpcAnimation::VM_Normal);
|
||||||
|
mAnimation->setCamera(NULL);
|
||||||
|
mAnimation->detachObjectFromBone(mCamera);
|
||||||
|
}
|
||||||
mAnimation = anim;
|
mAnimation = anim;
|
||||||
mAnimation->setViewMode(isFirstPerson() ? NpcAnimation::VM_FirstPerson :
|
mAnimation->setCamera(this);
|
||||||
NpcAnimation::VM_Normal);
|
|
||||||
|
processViewChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Camera::setHeight(float height)
|
void Camera::processViewChange()
|
||||||
{
|
{
|
||||||
mHeight = height;
|
mAnimation->detachObjectFromBone(mCamera);
|
||||||
mCameraNode->setPosition(0.f, 0.f, mHeight);
|
mCamera->detachFromParent();
|
||||||
|
|
||||||
|
if(isFirstPerson())
|
||||||
|
{
|
||||||
|
mAnimation->setViewMode(NpcAnimation::VM_FirstPerson);
|
||||||
|
Ogre::TagPoint *tag = mAnimation->attachObjectToBone("Head", mCamera);
|
||||||
|
tag->setInheritOrientation(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mAnimation->setViewMode(NpcAnimation::VM_Normal);
|
||||||
|
mCameraNode->attachObject(mCamera);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float Camera::getHeight()
|
float Camera::getHeight()
|
||||||
{
|
{
|
||||||
return mHeight * mTrackingPtr.getRefData().getBaseNode()->getScale().z;
|
if(mCamera->isParentTagPoint())
|
||||||
|
{
|
||||||
|
Ogre::TagPoint *tag = static_cast<Ogre::TagPoint*>(mCamera->getParentNode());
|
||||||
|
return tag->_getFullLocalTransform().getTrans().z;
|
||||||
|
}
|
||||||
|
return mCamera->getParentNode()->getPosition().z;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Camera::getPosition(Ogre::Vector3 &player, Ogre::Vector3 &camera)
|
bool Camera::getPosition(Ogre::Vector3 &player, Ogre::Vector3 &camera)
|
||||||
{
|
{
|
||||||
mCamera->getParentSceneNode ()->needUpdate(true);
|
mCamera->getParentSceneNode()->needUpdate(true);
|
||||||
camera = mCamera->getRealPosition();
|
camera = mCamera->getRealPosition();
|
||||||
player = mTrackingPtr.getRefData().getBaseNode()->getPosition();
|
player = mTrackingPtr.getRefData().getBaseNode()->getPosition();
|
||||||
|
|
||||||
|
@ -325,15 +337,6 @@ namespace MWRender
|
||||||
mFreeLook = enable;
|
mFreeLook = enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Camera::setLowHeight(bool low)
|
|
||||||
{
|
|
||||||
if (low) {
|
|
||||||
mCameraNode->setPosition(0.f, 0.f, mHeight * 0.85);
|
|
||||||
} else {
|
|
||||||
mCameraNode->setPosition(0.f, 0.f, mHeight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Camera::isVanityOrPreviewModeEnabled()
|
bool Camera::isVanityOrPreviewModeEnabled()
|
||||||
{
|
{
|
||||||
return mPreviewMode || mVanity.enabled;
|
return mPreviewMode || mVanity.enabled;
|
||||||
|
|
|
@ -46,8 +46,6 @@ namespace MWRender
|
||||||
/// Updates sound manager listener data
|
/// Updates sound manager listener data
|
||||||
void updateListener();
|
void updateListener();
|
||||||
|
|
||||||
void setLowHeight(bool low = true);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Camera(Ogre::Camera *camera);
|
Camera(Ogre::Camera *camera);
|
||||||
~Camera();
|
~Camera();
|
||||||
|
@ -80,6 +78,8 @@ namespace MWRender
|
||||||
bool isFirstPerson() const
|
bool isFirstPerson() const
|
||||||
{ return !(mVanity.enabled || mPreviewMode || !mFirstPersonView); }
|
{ return !(mVanity.enabled || mPreviewMode || !mFirstPersonView); }
|
||||||
|
|
||||||
|
void processViewChange();
|
||||||
|
|
||||||
void update(float duration);
|
void update(float duration);
|
||||||
|
|
||||||
/// Set camera distance for current mode. Don't work on 1st person view.
|
/// Set camera distance for current mode. Don't work on 1st person view.
|
||||||
|
@ -93,7 +93,6 @@ namespace MWRender
|
||||||
|
|
||||||
void setAnimation(NpcAnimation *anim);
|
void setAnimation(NpcAnimation *anim);
|
||||||
|
|
||||||
void setHeight(float height);
|
|
||||||
float getHeight();
|
float getHeight();
|
||||||
|
|
||||||
/// Stores player and camera world positions in passed arguments
|
/// Stores player and camera world positions in passed arguments
|
||||||
|
|
|
@ -44,9 +44,14 @@ namespace MWRender
|
||||||
{
|
{
|
||||||
mSceneMgr = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC);
|
mSceneMgr = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC);
|
||||||
|
|
||||||
/// \todo Read the fallback values from INIImporter (Inventory:Directional*)
|
// This is a dummy light to turn off shadows without having to use a separate set of shaders
|
||||||
Ogre::Light* l = mSceneMgr->createLight();
|
Ogre::Light* l = mSceneMgr->createLight();
|
||||||
l->setType (Ogre::Light::LT_DIRECTIONAL);
|
l->setType (Ogre::Light::LT_DIRECTIONAL);
|
||||||
|
l->setDiffuseColour (Ogre::ColourValue(0,0,0));
|
||||||
|
|
||||||
|
/// \todo Read the fallback values from INIImporter (Inventory:Directional*)
|
||||||
|
l = mSceneMgr->createLight();
|
||||||
|
l->setType (Ogre::Light::LT_DIRECTIONAL);
|
||||||
l->setDirection (Ogre::Vector3(0.3, -0.7, 0.3));
|
l->setDirection (Ogre::Vector3(0.3, -0.7, 0.3));
|
||||||
l->setDiffuseColour (Ogre::ColourValue(1,1,1));
|
l->setDiffuseColour (Ogre::ColourValue(1,1,1));
|
||||||
|
|
||||||
|
@ -172,7 +177,7 @@ namespace MWRender
|
||||||
if(groupname != mCurrentAnimGroup)
|
if(groupname != mCurrentAnimGroup)
|
||||||
{
|
{
|
||||||
mCurrentAnimGroup = groupname;
|
mCurrentAnimGroup = groupname;
|
||||||
mAnimation->play(mCurrentAnimGroup, 1, Animation::Group_All, false, "start", "stop", 0.0f, 0);
|
mAnimation->play(mCurrentAnimGroup, 1, Animation::Group_All, false, 1.0f, "start", "stop", 0.0f, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
MWWorld::ContainerStoreIterator torch = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft);
|
MWWorld::ContainerStoreIterator torch = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft);
|
||||||
|
@ -180,7 +185,7 @@ namespace MWRender
|
||||||
{
|
{
|
||||||
if(!mAnimation->getInfo("torch"))
|
if(!mAnimation->getInfo("torch"))
|
||||||
mAnimation->play("torch", 2, MWRender::Animation::Group_LeftArm, false,
|
mAnimation->play("torch", 2, MWRender::Animation::Group_LeftArm, false,
|
||||||
"start", "stop", 0.0f, (~(size_t)0));
|
1.0f, "start", "stop", 0.0f, ~0ul);
|
||||||
}
|
}
|
||||||
else if(mAnimation->getInfo("torch"))
|
else if(mAnimation->getInfo("torch"))
|
||||||
mAnimation->disable("torch");
|
mAnimation->disable("torch");
|
||||||
|
@ -210,7 +215,7 @@ namespace MWRender
|
||||||
mAnimation->showWeapons(true);
|
mAnimation->showWeapons(true);
|
||||||
|
|
||||||
mCurrentAnimGroup = "inventoryhandtohand";
|
mCurrentAnimGroup = "inventoryhandtohand";
|
||||||
mAnimation->play(mCurrentAnimGroup, 1, Animation::Group_All, false, "start", "stop", 0.0f, 0);
|
mAnimation->play(mCurrentAnimGroup, 1, Animation::Group_All, false, 1.0f, "start", "stop", 0.0f, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------------
|
||||||
|
@ -247,7 +252,7 @@ namespace MWRender
|
||||||
|
|
||||||
void RaceSelectionPreview::onSetup ()
|
void RaceSelectionPreview::onSetup ()
|
||||||
{
|
{
|
||||||
mAnimation->play("idle", 1, Animation::Group_All, false, "start", "stop", 0.0f, 0);
|
mAnimation->play("idle", 1, Animation::Group_All, false, 1.0f, "start", "stop", 0.0f, 0);
|
||||||
|
|
||||||
updateCamera();
|
updateCamera();
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "../mwbase/mechanicsmanager.hpp"
|
#include "../mwbase/mechanicsmanager.hpp"
|
||||||
|
|
||||||
#include "renderconst.hpp"
|
#include "renderconst.hpp"
|
||||||
|
#include "camera.hpp"
|
||||||
|
|
||||||
|
|
||||||
namespace MWRender
|
namespace MWRender
|
||||||
|
@ -98,9 +99,13 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor
|
||||||
Misc::StringUtils::toLower(mBodyPrefix);
|
Misc::StringUtils::toLower(mBodyPrefix);
|
||||||
|
|
||||||
bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0;
|
bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0;
|
||||||
std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif");
|
std::string smodel = (viewMode != VM_FirstPerson) ?
|
||||||
|
(!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif") :
|
||||||
|
(!isBeast ? "meshes\\base_anim.1st.nif" : "meshes\\base_animkna.1st.nif") ;
|
||||||
setObjectRoot(node, smodel, true);
|
setObjectRoot(node, smodel, true);
|
||||||
|
|
||||||
|
if(mViewMode != VM_FirstPerson)
|
||||||
|
{
|
||||||
addAnimSource(smodel);
|
addAnimSource(smodel);
|
||||||
if(mBodyPrefix.find("argonian") != std::string::npos)
|
if(mBodyPrefix.find("argonian") != std::string::npos)
|
||||||
addAnimSource("meshes\\argonian_swimkna.nif");
|
addAnimSource("meshes\\argonian_swimkna.nif");
|
||||||
|
@ -108,7 +113,8 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor
|
||||||
addAnimSource("meshes\\base_anim_female.nif");
|
addAnimSource("meshes\\base_anim_female.nif");
|
||||||
if(mNpc->mModel.length() > 0)
|
if(mNpc->mModel.length() > 0)
|
||||||
addAnimSource("meshes\\"+mNpc->mModel);
|
addAnimSource("meshes\\"+mNpc->mModel);
|
||||||
if(mViewMode == VM_FirstPerson)
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
/* A bit counter-intuitive, but unlike third-person anims, it seems
|
/* A bit counter-intuitive, but unlike third-person anims, it seems
|
||||||
* beast races get both base_anim.1st.nif and base_animkna.1st.nif.
|
* beast races get both base_anim.1st.nif and base_animkna.1st.nif.
|
||||||
|
@ -128,12 +134,19 @@ void NpcAnimation::setViewMode(NpcAnimation::ViewMode viewMode)
|
||||||
assert(viewMode != VM_HeadOnly);
|
assert(viewMode != VM_HeadOnly);
|
||||||
mViewMode = viewMode;
|
mViewMode = viewMode;
|
||||||
|
|
||||||
|
clearAnimSources();
|
||||||
|
|
||||||
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
||||||
const ESM::Race *race = store.get<ESM::Race>().find(mNpc->mRace);
|
const ESM::Race *race = store.get<ESM::Race>().find(mNpc->mRace);
|
||||||
bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0;
|
|
||||||
std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif");
|
|
||||||
|
|
||||||
clearAnimSources();
|
bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0;
|
||||||
|
std::string smodel = (viewMode != VM_FirstPerson) ?
|
||||||
|
(!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif") :
|
||||||
|
(!isBeast ? "meshes\\base_anim.1st.nif" : "meshes\\base_animkna.1st.nif") ;
|
||||||
|
setObjectRoot(mInsert->getParentSceneNode(), smodel, true);
|
||||||
|
|
||||||
|
if(mViewMode != VM_FirstPerson)
|
||||||
|
{
|
||||||
addAnimSource(smodel);
|
addAnimSource(smodel);
|
||||||
if(mBodyPrefix.find("argonian") != std::string::npos)
|
if(mBodyPrefix.find("argonian") != std::string::npos)
|
||||||
addAnimSource("meshes\\argonian_swimkna.nif");
|
addAnimSource("meshes\\argonian_swimkna.nif");
|
||||||
|
@ -141,7 +154,8 @@ void NpcAnimation::setViewMode(NpcAnimation::ViewMode viewMode)
|
||||||
addAnimSource("meshes\\base_anim_female.nif");
|
addAnimSource("meshes\\base_anim_female.nif");
|
||||||
if(mNpc->mModel.length() > 0)
|
if(mNpc->mModel.length() > 0)
|
||||||
addAnimSource("meshes\\"+mNpc->mModel);
|
addAnimSource("meshes\\"+mNpc->mModel);
|
||||||
if(mViewMode == VM_FirstPerson)
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
/* A bit counter-intuitive, but unlike third-person anims, it seems
|
/* A bit counter-intuitive, but unlike third-person anims, it seems
|
||||||
* beast races get both base_anim.1st.nif and base_animkna.1st.nif.
|
* beast races get both base_anim.1st.nif and base_animkna.1st.nif.
|
||||||
|
@ -197,19 +211,11 @@ void NpcAnimation::updateParts(bool forceupdate)
|
||||||
if(!forceupdate)
|
if(!forceupdate)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* FIXME: Remove this once we figure out how to show what in first-person */
|
|
||||||
if(mViewMode == VM_FirstPerson)
|
|
||||||
{
|
|
||||||
for(size_t i = 0;i < slotlistsize;i++)
|
|
||||||
this->*slotlist[i].mPart = inv.getSlot(slotlist[i].mSlot);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(size_t i = 0;i < slotlistsize && mViewMode != VM_HeadOnly;i++)
|
for(size_t i = 0;i < slotlistsize && mViewMode != VM_HeadOnly;i++)
|
||||||
{
|
{
|
||||||
MWWorld::ContainerStoreIterator iter = inv.getSlot(slotlist[i].mSlot);
|
MWWorld::ContainerStoreIterator store = inv.getSlot(slotlist[i].mSlot);
|
||||||
|
|
||||||
this->*slotlist[i].mPart = iter;
|
this->*slotlist[i].mPart = store;
|
||||||
removePartGroup(slotlist[i].mSlot);
|
removePartGroup(slotlist[i].mSlot);
|
||||||
|
|
||||||
if(this->*slotlist[i].mPart == inv.end())
|
if(this->*slotlist[i].mPart == inv.end())
|
||||||
|
@ -219,7 +225,6 @@ void NpcAnimation::updateParts(bool forceupdate)
|
||||||
removeIndividualPart(ESM::PRT_Hair);
|
removeIndividualPart(ESM::PRT_Hair);
|
||||||
|
|
||||||
int prio = 1;
|
int prio = 1;
|
||||||
MWWorld::ContainerStoreIterator &store = this->*slotlist[i].mPart;
|
|
||||||
if(store->getTypeName() == typeid(ESM::Clothing).name())
|
if(store->getTypeName() == typeid(ESM::Clothing).name())
|
||||||
{
|
{
|
||||||
prio = ((slotlist[i].mBasePriority+1)<<1) + 0;
|
prio = ((slotlist[i].mBasePriority+1)<<1) + 0;
|
||||||
|
@ -279,32 +284,34 @@ void NpcAnimation::updateParts(bool forceupdate)
|
||||||
std::pair<std::string, int> thisCombination = std::make_pair(race, flags);
|
std::pair<std::string, int> thisCombination = std::make_pair(race, flags);
|
||||||
if (sRaceMapping.find(thisCombination) == sRaceMapping.end())
|
if (sRaceMapping.find(thisCombination) == sRaceMapping.end())
|
||||||
{
|
{
|
||||||
static std::map<int, int> bodypartMap;
|
typedef std::multimap<ESM::BodyPart::MeshPart,ESM::PartReferenceType> BodyPartMapType;
|
||||||
if(bodypartMap.size() == 0)
|
static BodyPartMapType sBodyPartMap;
|
||||||
|
if(sBodyPartMap.size() == 0)
|
||||||
{
|
{
|
||||||
bodypartMap[ESM::PRT_Neck] = ESM::BodyPart::MP_Neck;
|
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Neck, ESM::PRT_Neck));
|
||||||
bodypartMap[ESM::PRT_Cuirass] = ESM::BodyPart::MP_Chest;
|
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Chest, ESM::PRT_Cuirass));
|
||||||
bodypartMap[ESM::PRT_Groin] = ESM::BodyPart::MP_Groin;
|
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Groin, ESM::PRT_Groin));
|
||||||
bodypartMap[ESM::PRT_RHand] = ESM::BodyPart::MP_Hand;
|
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Hand, ESM::PRT_RHand));
|
||||||
bodypartMap[ESM::PRT_LHand] = ESM::BodyPart::MP_Hand;
|
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Hand, ESM::PRT_LHand));
|
||||||
bodypartMap[ESM::PRT_RWrist] = ESM::BodyPart::MP_Wrist;
|
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Wrist, ESM::PRT_RWrist));
|
||||||
bodypartMap[ESM::PRT_LWrist] = ESM::BodyPart::MP_Wrist;
|
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Wrist, ESM::PRT_LWrist));
|
||||||
bodypartMap[ESM::PRT_RForearm] = ESM::BodyPart::MP_Forearm;
|
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Forearm, ESM::PRT_RForearm));
|
||||||
bodypartMap[ESM::PRT_LForearm] = ESM::BodyPart::MP_Forearm;
|
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Forearm, ESM::PRT_LForearm));
|
||||||
bodypartMap[ESM::PRT_RUpperarm] = ESM::BodyPart::MP_Upperarm;
|
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Upperarm, ESM::PRT_RUpperarm));
|
||||||
bodypartMap[ESM::PRT_LUpperarm] = ESM::BodyPart::MP_Upperarm;
|
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Upperarm, ESM::PRT_LUpperarm));
|
||||||
bodypartMap[ESM::PRT_RFoot] = ESM::BodyPart::MP_Foot;
|
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Foot, ESM::PRT_RFoot));
|
||||||
bodypartMap[ESM::PRT_LFoot] = ESM::BodyPart::MP_Foot;
|
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Foot, ESM::PRT_LFoot));
|
||||||
bodypartMap[ESM::PRT_RAnkle] = ESM::BodyPart::MP_Ankle;
|
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Ankle, ESM::PRT_RAnkle));
|
||||||
bodypartMap[ESM::PRT_LAnkle] = ESM::BodyPart::MP_Ankle;
|
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Ankle, ESM::PRT_LAnkle));
|
||||||
bodypartMap[ESM::PRT_RKnee] = ESM::BodyPart::MP_Knee;
|
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Knee, ESM::PRT_RKnee));
|
||||||
bodypartMap[ESM::PRT_LKnee] = ESM::BodyPart::MP_Knee;
|
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Knee, ESM::PRT_LKnee));
|
||||||
bodypartMap[ESM::PRT_RLeg] = ESM::BodyPart::MP_Upperleg;
|
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Upperleg, ESM::PRT_RLeg));
|
||||||
bodypartMap[ESM::PRT_LLeg] = ESM::BodyPart::MP_Upperleg;
|
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Upperleg, ESM::PRT_LLeg));
|
||||||
bodypartMap[ESM::PRT_Tail] = ESM::BodyPart::MP_Tail;
|
sBodyPartMap.insert(std::make_pair(ESM::BodyPart::MP_Tail, ESM::PRT_Tail));
|
||||||
}
|
}
|
||||||
|
|
||||||
sRaceMapping[thisCombination].resize(ESM::PRT_Count, NULL);
|
std::vector<const ESM::BodyPart*> &parts = sRaceMapping[thisCombination];
|
||||||
|
parts.resize(ESM::PRT_Count, NULL);
|
||||||
|
|
||||||
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
||||||
const MWWorld::Store<ESM::BodyPart> &partStore = store.get<ESM::BodyPart>();
|
const MWWorld::Store<ESM::BodyPart> &partStore = store.get<ESM::BodyPart>();
|
||||||
|
@ -325,29 +332,55 @@ void NpcAnimation::updateParts(bool forceupdate)
|
||||||
&& bodypart.mId[bodypart.mId.size()-3] == '1'
|
&& bodypart.mId[bodypart.mId.size()-3] == '1'
|
||||||
&& bodypart.mId[bodypart.mId.size()-2] == 's'
|
&& bodypart.mId[bodypart.mId.size()-2] == 's'
|
||||||
&& bodypart.mId[bodypart.mId.size()-1] == 't';
|
&& bodypart.mId[bodypart.mId.size()-1] == 't';
|
||||||
if (firstPerson != (mViewMode == VM_FirstPerson))
|
if(firstPerson != (mViewMode == VM_FirstPerson))
|
||||||
|
{
|
||||||
|
if(mViewMode == VM_FirstPerson && (bodypart.mData.mPart == ESM::BodyPart::MP_Hand ||
|
||||||
|
bodypart.mData.mPart == ESM::BodyPart::MP_Wrist ||
|
||||||
|
bodypart.mData.mPart == ESM::BodyPart::MP_Forearm ||
|
||||||
|
bodypart.mData.mPart == ESM::BodyPart::MP_Upperarm))
|
||||||
|
{
|
||||||
|
/* Allow 3rd person skins as a fallback for the arms if 1st person is missing. */
|
||||||
|
BodyPartMapType::const_iterator bIt = sBodyPartMap.lower_bound(BodyPartMapType::key_type(bodypart.mData.mPart));
|
||||||
|
while(bIt != sBodyPartMap.end() && bIt->first == bodypart.mData.mPart)
|
||||||
|
{
|
||||||
|
if(!parts[bIt->second])
|
||||||
|
parts[bIt->second] = &*it;
|
||||||
|
bIt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
for (std::map<int, int>::iterator bIt = bodypartMap.begin(); bIt != bodypartMap.end(); ++bIt )
|
}
|
||||||
if (bIt->second == bodypart.mData.mPart)
|
BodyPartMapType::const_iterator bIt = sBodyPartMap.lower_bound(BodyPartMapType::key_type(bodypart.mData.mPart));
|
||||||
sRaceMapping[thisCombination][bIt->first] = &*it;
|
while(bIt != sBodyPartMap.end() && bIt->first == bodypart.mData.mPart)
|
||||||
|
{
|
||||||
|
parts[bIt->second] = &*it;
|
||||||
|
bIt++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int part = ESM::PRT_Neck; part < ESM::PRT_Count; ++part)
|
const std::vector<const ESM::BodyPart*> &parts = sRaceMapping[thisCombination];
|
||||||
|
for(int part = ESM::PRT_Neck; part < ESM::PRT_Count; ++part)
|
||||||
{
|
{
|
||||||
const ESM::BodyPart* bodypart = sRaceMapping[thisCombination][part];
|
if(mPartPriorities[part] < 1)
|
||||||
if (mPartPriorities[part] < 1 && bodypart)
|
{
|
||||||
|
const ESM::BodyPart* bodypart = parts[part];
|
||||||
|
if(bodypart)
|
||||||
addOrReplaceIndividualPart(part, -1,1, "meshes\\"+bodypart->mModel);
|
addOrReplaceIndividualPart(part, -1,1, "meshes\\"+bodypart->mModel);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NifOgre::ObjectList NpcAnimation::insertBoundedPart(const std::string &model, int group, const std::string &bonename)
|
NifOgre::ObjectList NpcAnimation::insertBoundedPart(const std::string &model, int group, const std::string &bonename)
|
||||||
{
|
{
|
||||||
NifOgre::ObjectList objects = NifOgre::Loader::createObjects(mSkelBase, bonename, mInsert, model);
|
NifOgre::ObjectList objects = NifOgre::Loader::createObjects(mSkelBase, bonename, mInsert, model);
|
||||||
setRenderProperties(objects, mVisibilityFlags, RQG_Main, RQG_Alpha);
|
setRenderProperties(objects, (mViewMode == VM_FirstPerson) ? RV_FirstPerson : mVisibilityFlags, RQG_Main, RQG_Alpha);
|
||||||
|
|
||||||
for(size_t i = 0;i < objects.mEntities.size();i++)
|
for(size_t i = 0;i < objects.mEntities.size();i++)
|
||||||
objects.mEntities[i]->getUserObjectBindings().setUserAny(Ogre::Any(group));
|
{
|
||||||
|
Ogre::Entity *ent = objects.mEntities[i];
|
||||||
|
ent->getUserObjectBindings().setUserAny(Ogre::Any(group));
|
||||||
|
}
|
||||||
for(size_t i = 0;i < objects.mParticles.size();i++)
|
for(size_t i = 0;i < objects.mParticles.size();i++)
|
||||||
objects.mParticles[i]->getUserObjectBindings().setUserAny(Ogre::Any(group));
|
objects.mParticles[i]->getUserObjectBindings().setUserAny(Ogre::Any(group));
|
||||||
|
|
||||||
|
@ -382,6 +415,13 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed)
|
||||||
Ogre::Vector3 ret = Animation::runAnimation(timepassed);
|
Ogre::Vector3 ret = Animation::runAnimation(timepassed);
|
||||||
|
|
||||||
Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton();
|
Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton();
|
||||||
|
if(mViewMode == VM_FirstPerson && mCamera)
|
||||||
|
{
|
||||||
|
float pitch = mCamera->getPitch();
|
||||||
|
Ogre::Node *node = baseinst->getBone("Bip01 Neck");
|
||||||
|
node->pitch(Ogre::Radian(pitch*0.75f), Ogre::Node::TS_WORLD);
|
||||||
|
}
|
||||||
|
|
||||||
for(size_t i = 0;i < sPartListSize;i++)
|
for(size_t i = 0;i < sPartListSize;i++)
|
||||||
{
|
{
|
||||||
Ogre::Entity *ent = mObjectParts[i].mSkelBase;
|
Ogre::Entity *ent = mObjectParts[i].mSkelBase;
|
||||||
|
@ -458,9 +498,31 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vector<ESM::
|
||||||
{
|
{
|
||||||
const ESM::BodyPart *bodypart = 0;
|
const ESM::BodyPart *bodypart = 0;
|
||||||
if(!mNpc->isMale() && !part->mFemale.empty())
|
if(!mNpc->isMale() && !part->mFemale.empty())
|
||||||
|
{
|
||||||
bodypart = partStore.search(part->mFemale+ext);
|
bodypart = partStore.search(part->mFemale+ext);
|
||||||
|
if(!bodypart && mViewMode == VM_FirstPerson)
|
||||||
|
{
|
||||||
|
bodypart = partStore.search(part->mFemale);
|
||||||
|
if(bodypart && !(bodypart->mData.mPart == ESM::BodyPart::MP_Hand ||
|
||||||
|
bodypart->mData.mPart == ESM::BodyPart::MP_Wrist ||
|
||||||
|
bodypart->mData.mPart == ESM::BodyPart::MP_Forearm ||
|
||||||
|
bodypart->mData.mPart == ESM::BodyPart::MP_Upperarm))
|
||||||
|
bodypart = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
if(!bodypart && !part->mMale.empty())
|
if(!bodypart && !part->mMale.empty())
|
||||||
|
{
|
||||||
bodypart = partStore.search(part->mMale+ext);
|
bodypart = partStore.search(part->mMale+ext);
|
||||||
|
if(!bodypart && mViewMode == VM_FirstPerson)
|
||||||
|
{
|
||||||
|
bodypart = partStore.search(part->mMale);
|
||||||
|
if(bodypart && !(bodypart->mData.mPart == ESM::BodyPart::MP_Hand ||
|
||||||
|
bodypart->mData.mPart == ESM::BodyPart::MP_Wrist ||
|
||||||
|
bodypart->mData.mPart == ESM::BodyPart::MP_Forearm ||
|
||||||
|
bodypart->mData.mPart == ESM::BodyPart::MP_Upperarm))
|
||||||
|
bodypart = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(bodypart)
|
if(bodypart)
|
||||||
addOrReplaceIndividualPart(part->mPart, group, priority, "meshes\\"+bodypart->mModel);
|
addOrReplaceIndividualPart(part->mPart, group, priority, "meshes\\"+bodypart->mModel);
|
||||||
|
@ -472,8 +534,7 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vector<ESM::
|
||||||
void NpcAnimation::showWeapons(bool showWeapon)
|
void NpcAnimation::showWeapons(bool showWeapon)
|
||||||
{
|
{
|
||||||
mShowWeapons = showWeapon;
|
mShowWeapons = showWeapon;
|
||||||
if(showWeapon &&
|
if(showWeapon)
|
||||||
mViewMode != VM_FirstPerson/* FIXME: Remove this once first-person bodies work */)
|
|
||||||
{
|
{
|
||||||
MWWorld::InventoryStore &inv = MWWorld::Class::get(mPtr).getInventoryStore(mPtr);
|
MWWorld::InventoryStore &inv = MWWorld::Class::get(mPtr).getInventoryStore(mPtr);
|
||||||
mWeapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
mWeapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||||
|
|
|
@ -59,6 +59,9 @@ enum VisibilityFlags
|
||||||
// overlays, we only want these on the main render target
|
// overlays, we only want these on the main render target
|
||||||
RV_Overlay = 1024,
|
RV_Overlay = 1024,
|
||||||
|
|
||||||
|
// First person meshes do not cast shadows
|
||||||
|
RV_FirstPerson = 2048,
|
||||||
|
|
||||||
RV_Map = RV_Terrain + RV_Statics + RV_StaticsSmall + RV_Misc + RV_Water
|
RV_Map = RV_Terrain + RV_Statics + RV_StaticsSmall + RV_Misc + RV_Water
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -884,13 +884,6 @@ void RenderingManager::renderPlayer(const MWWorld::Ptr &ptr)
|
||||||
MWBase::Environment::get().getWorld()->scaleObject(ptr, 1.f);
|
MWBase::Environment::get().getWorld()->scaleObject(ptr, 1.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderingManager::getCameraData(Ogre::Vector3 &eyepos, float &pitch, float &yaw)
|
|
||||||
{
|
|
||||||
eyepos = mCamera->getPosition();
|
|
||||||
eyepos.z += mCamera->getHeight();
|
|
||||||
mCamera->getSightAngles(pitch, yaw);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RenderingManager::vanityRotateCamera(const float *rot)
|
bool RenderingManager::vanityRotateCamera(const float *rot)
|
||||||
{
|
{
|
||||||
if(!mCamera->isVanityOrPreviewModeEnabled())
|
if(!mCamera->isVanityOrPreviewModeEnabled())
|
||||||
|
|
|
@ -87,8 +87,6 @@ public:
|
||||||
|
|
||||||
bool vanityRotateCamera(const float *rot);
|
bool vanityRotateCamera(const float *rot);
|
||||||
|
|
||||||
void getCameraData(Ogre::Vector3 &eyepos, float &pitch, float &yaw);
|
|
||||||
|
|
||||||
void setupPlayer(const MWWorld::Ptr &ptr);
|
void setupPlayer(const MWWorld::Ptr &ptr);
|
||||||
void renderPlayer(const MWWorld::Ptr &ptr);
|
void renderPlayer(const MWWorld::Ptr &ptr);
|
||||||
|
|
||||||
|
|
|
@ -254,15 +254,12 @@ namespace MWWorld
|
||||||
|
|
||||||
std::pair<float, std::string> PhysicsSystem::getFacedHandle (MWWorld::World& world, float queryDistance)
|
std::pair<float, std::string> PhysicsSystem::getFacedHandle (MWWorld::World& world, float queryDistance)
|
||||||
{
|
{
|
||||||
btVector3 dir(0, 1, 0);
|
Ray ray = mRender.getCamera()->getCameraToViewportRay(0.5, 0.5);
|
||||||
dir = dir.rotate(btVector3(1, 0, 0), mCameraData.pitch);
|
|
||||||
dir = dir.rotate(btVector3(0, 0, 1), mCameraData.yaw);
|
|
||||||
dir.setX(-dir.x());
|
|
||||||
|
|
||||||
btVector3 origin(mCameraData.eyepos.x,
|
Ogre::Vector3 origin_ = ray.getOrigin();
|
||||||
mCameraData.eyepos.y,
|
btVector3 origin(origin_.x, origin_.y, origin_.z);
|
||||||
mCameraData.eyepos.z);
|
Ogre::Vector3 dir_ = ray.getDirection().normalisedCopy();
|
||||||
origin += dir * 5;
|
btVector3 dir(dir_.x, dir_.y, dir_.z);
|
||||||
|
|
||||||
btVector3 dest = origin + dir * queryDistance;
|
btVector3 dest = origin + dir * queryDistance;
|
||||||
std::pair <std::string, float> result;
|
std::pair <std::string, float> result;
|
||||||
|
@ -273,15 +270,12 @@ namespace MWWorld
|
||||||
|
|
||||||
std::vector < std::pair <float, std::string> > PhysicsSystem::getFacedHandles (float queryDistance)
|
std::vector < std::pair <float, std::string> > PhysicsSystem::getFacedHandles (float queryDistance)
|
||||||
{
|
{
|
||||||
btVector3 dir(0, 1, 0);
|
Ray ray = mRender.getCamera()->getCameraToViewportRay(0.5, 0.5);
|
||||||
dir = dir.rotate(btVector3(1, 0, 0), mCameraData.pitch);
|
|
||||||
dir = dir.rotate(btVector3(0, 0, 1), mCameraData.yaw);
|
|
||||||
dir.setX(-dir.x());
|
|
||||||
|
|
||||||
btVector3 origin(mCameraData.eyepos.x,
|
Ogre::Vector3 origin_ = ray.getOrigin();
|
||||||
mCameraData.eyepos.y,
|
btVector3 origin(origin_.x, origin_.y, origin_.z);
|
||||||
mCameraData.eyepos.z);
|
Ogre::Vector3 dir_ = ray.getDirection().normalisedCopy();
|
||||||
origin += dir * 5;
|
btVector3 dir(dir_.x, dir_.y, dir_.z);
|
||||||
|
|
||||||
btVector3 dest = origin + dir * queryDistance;
|
btVector3 dest = origin + dir * queryDistance;
|
||||||
std::vector < std::pair <float, std::string> > results;
|
std::vector < std::pair <float, std::string> > results;
|
||||||
|
@ -543,11 +537,4 @@ namespace MWWorld
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsSystem::updateCameraData(const Ogre::Vector3 &eyepos, float pitch, float yaw)
|
|
||||||
{
|
|
||||||
mCameraData.eyepos = eyepos;
|
|
||||||
mCameraData.pitch = pitch;
|
|
||||||
mCameraData.yaw = yaw;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,13 +77,7 @@ namespace MWWorld
|
||||||
|
|
||||||
bool getObjectAABB(const MWWorld::Ptr &ptr, Ogre::Vector3 &min, Ogre::Vector3 &max);
|
bool getObjectAABB(const MWWorld::Ptr &ptr, Ogre::Vector3 &min, Ogre::Vector3 &max);
|
||||||
|
|
||||||
void updateCameraData(const Ogre::Vector3 &eyepos, float pitch, float yaw);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct {
|
|
||||||
Ogre::Vector3 eyepos;
|
|
||||||
float pitch, yaw;
|
|
||||||
} mCameraData;
|
|
||||||
|
|
||||||
OEngine::Render::OgreRenderer &mRender;
|
OEngine::Render::OgreRenderer &mRender;
|
||||||
OEngine::Physic::PhysicEngine* mEngine;
|
OEngine::Physic::PhysicEngine* mEngine;
|
||||||
|
|
|
@ -163,13 +163,13 @@ namespace MWWorld
|
||||||
{
|
{
|
||||||
if (!target.isEmpty())
|
if (!target.isEmpty())
|
||||||
MWMechanics::Security(getPlayer()).pickLock(target, item, resultMessage, resultSound);
|
MWMechanics::Security(getPlayer()).pickLock(target, item, resultMessage, resultSound);
|
||||||
anim->play("pickprobe", MWMechanics::Priority_Weapon, MWRender::Animation::Group_UpperBody, true, "start", "stop", 0.0, 0);
|
anim->play("pickprobe", MWMechanics::Priority_Weapon, MWRender::Animation::Group_UpperBody, true, 1.0f, "start", "stop", 0.0, 0);
|
||||||
}
|
}
|
||||||
else if (item.getTypeName() == typeid(ESM::Probe).name())
|
else if (item.getTypeName() == typeid(ESM::Probe).name())
|
||||||
{
|
{
|
||||||
if (!target.isEmpty())
|
if (!target.isEmpty())
|
||||||
MWMechanics::Security(getPlayer()).probeTrap(target, item, resultMessage, resultSound);
|
MWMechanics::Security(getPlayer()).probeTrap(target, item, resultMessage, resultSound);
|
||||||
anim->play("pickprobe", MWMechanics::Priority_Weapon, MWRender::Animation::Group_UpperBody, true, "start", "stop", 0.0, 0);
|
anim->play("pickprobe", MWMechanics::Priority_Weapon, MWRender::Animation::Group_UpperBody, true, 1.0f, "start", "stop", 0.0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!resultMessage.empty())
|
if (!resultMessage.empty())
|
||||||
|
|
|
@ -1234,11 +1234,6 @@ namespace MWWorld
|
||||||
|
|
||||||
mWorldScene->update (duration, paused);
|
mWorldScene->update (duration, paused);
|
||||||
|
|
||||||
float pitch, yaw;
|
|
||||||
Ogre::Vector3 eyepos;
|
|
||||||
mRendering->getCameraData(eyepos, pitch, yaw);
|
|
||||||
mPhysics->updateCameraData(eyepos, pitch, yaw);
|
|
||||||
|
|
||||||
performUpdateSceneQueries ();
|
performUpdateSceneQueries ();
|
||||||
|
|
||||||
updateWindowManager ();
|
updateWindowManager ();
|
||||||
|
|
|
@ -122,7 +122,7 @@ void Cell::save(ESMWriter &esm)
|
||||||
|
|
||||||
void Cell::restore(ESMReader &esm, int iCtx) const
|
void Cell::restore(ESMReader &esm, int iCtx) const
|
||||||
{
|
{
|
||||||
esm.restoreContext(mContextList[iCtx]);
|
esm.restoreContext(mContextList.at (iCtx));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Cell::getDescription() const
|
std::string Cell::getDescription() const
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
|
|
||||||
<Widget type="Window" skin="" layer="Windows" align="Left|Top" position="0 0 565 390" name="_Main">
|
<Widget type="Window" skin="" layer="Windows" align="Left|Top" position="0 0 565 390" name="_Main">
|
||||||
|
|
||||||
<Widget type="ImageBox" skin="ImageBox" position="0 0 565 390" align="Top|Right" name="JImage">
|
<Widget type="ImageBox" skin="ImageBox" position="-70 0 705 390" align="Top|Right" name="JImage">
|
||||||
<Property key="ImageTexture" value="textures\tx_menubook.dds"/>
|
<Property key="ImageTexture" value="textures\tx_menubook.dds"/>
|
||||||
<Property key="ImageCoord" value="50 0 412 256"/>
|
<Widget type="Widget" position="70 0 565 390" align="Top|Right">
|
||||||
|
|
||||||
<Widget type="Widget" position="0 0 282 390">
|
<Widget type="Widget" position="0 0 282 390">
|
||||||
<Widget type="ImageButton" skin="ImageBox" position="205 350 48 32" name="PrevPageBTN">
|
<Widget type="ImageButton" skin="ImageBox" position="205 350 48 32" name="PrevPageBTN">
|
||||||
|
@ -44,6 +44,7 @@
|
||||||
<Widget type="Widget" skin="" position="30 22 240 300" name = "LeftPage"/>
|
<Widget type="Widget" skin="" position="30 22 240 300" name = "LeftPage"/>
|
||||||
<Widget type="Widget" skin="" position="300 22 240 300" name = "RightPage"/>
|
<Widget type="Widget" skin="" position="300 22 240 300" name = "RightPage"/>
|
||||||
</Widget>
|
</Widget>
|
||||||
|
</Widget>
|
||||||
</Widget>
|
</Widget>
|
||||||
|
|
||||||
</MyGUI>
|
</MyGUI>
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
<Property key="Caption" value="#{sConsoleTitle}"/>
|
<Property key="Caption" value="#{sConsoleTitle}"/>
|
||||||
<Property key="MinSize" value="200 100"/>
|
<Property key="MinSize" value="200 100"/>
|
||||||
<Property key="MaxSize" value="2000 2000"/>
|
<Property key="MaxSize" value="2000 2000"/>
|
||||||
|
<Property key="Visible" value="false"/>
|
||||||
|
|
||||||
<!-- Log window -->
|
<!-- Log window -->
|
||||||
<Widget type="EditBox" skin="MW_ConsoleLog" position="5 5 380 330" align="Stretch" name="list_History">
|
<Widget type="EditBox" skin="MW_ConsoleLog" position="5 5 380 330" align="Stretch" name="list_History">
|
||||||
|
|
|
@ -4,9 +4,10 @@
|
||||||
|
|
||||||
<Widget type="Window" skin="" layer="Windows" align="Left|Top" position="0 0 565 390" name="_Main">
|
<Widget type="Window" skin="" layer="Windows" align="Left|Top" position="0 0 565 390" name="_Main">
|
||||||
<!-- pages -->
|
<!-- pages -->
|
||||||
<Widget type="ImageBox" skin="ImageBox" position="0 0 565 390" align="Top|Right" name="JImage">
|
<Widget type="ImageBox" skin="ImageBox" position="-70 0 705 390" align="Top|Right" name="JImage">
|
||||||
<Property key="ImageTexture" value="textures\tx_menubook.dds"/>
|
<Property key="ImageTexture" value="textures\tx_menubook.dds"/>
|
||||||
<Property key="ImageCoord" value="50 0 412 256"/>
|
<Widget type="Widget" position="70 0 565 390" align="Top|Right">
|
||||||
|
|
||||||
|
|
||||||
<Widget type="Widget" position="0 0 282 390">
|
<Widget type="Widget" position="0 0 282 390">
|
||||||
<Widget type="ImageButton" skin="ImageBox" position="205 350 48 32" name="PrevPageBTN">
|
<Widget type="ImageButton" skin="ImageBox" position="205 350 48 32" name="PrevPageBTN">
|
||||||
|
@ -53,7 +54,7 @@
|
||||||
<Widget type="BookPage" skin="MW_BookPage" position="300 22 240 300" name="RightBookPage"/>
|
<Widget type="BookPage" skin="MW_BookPage" position="300 22 240 300" name="RightBookPage"/>
|
||||||
|
|
||||||
<!-- options overlay -->
|
<!-- options overlay -->
|
||||||
|
</Widget>
|
||||||
</Widget>
|
</Widget>
|
||||||
|
|
||||||
<!-- "options" -->
|
<!-- "options" -->
|
||||||
|
@ -103,7 +104,6 @@
|
||||||
<Property key="ImageNormal" value="textures\tx_menubook_cancel_idle.dds"/>
|
<Property key="ImageNormal" value="textures\tx_menubook_cancel_idle.dds"/>
|
||||||
<Property key="ImagePushed" value="textures\tx_menubook_cancel_pressed.dds"/>
|
<Property key="ImagePushed" value="textures\tx_menubook_cancel_pressed.dds"/>
|
||||||
</Widget>
|
</Widget>
|
||||||
|
|
||||||
</Widget>
|
</Widget>
|
||||||
</Widget>
|
</Widget>
|
||||||
</MyGUI>
|
</MyGUI>
|
||||||
|
|
Loading…
Reference in a new issue