mirror of
https://github.com/OpenMW/openmw.git
synced 2025-02-23 00:09:42 +00:00
merged with master
This commit is contained in:
commit
3a5da7e6e8
47 changed files with 810 additions and 159 deletions
|
@ -98,6 +98,10 @@ namespace CSMWorld
|
||||||
UniversalId::Type type = UniversalId::Type_None);
|
UniversalId::Type type = UniversalId::Type_None);
|
||||||
///< \param type Will be ignored, unless the collection supports multiple record types
|
///< \param type Will be ignored, unless the collection supports multiple record types
|
||||||
|
|
||||||
|
virtual void cloneRecord(const std::string& origin,
|
||||||
|
const std::string& destination,
|
||||||
|
const UniversalId::Type type);
|
||||||
|
|
||||||
virtual int searchId (const std::string& id) const;
|
virtual int searchId (const std::string& id) const;
|
||||||
////< Search record with \a id.
|
////< Search record with \a id.
|
||||||
/// \return index of record (if found) or -1 (not found)
|
/// \return index of record (if found) or -1 (not found)
|
||||||
|
@ -193,6 +197,19 @@ namespace CSMWorld
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename ESXRecordT, typename IdAccessorT>
|
||||||
|
void Collection<ESXRecordT, IdAccessorT>::cloneRecord(const std::string& origin,
|
||||||
|
const std::string& destination,
|
||||||
|
const UniversalId::Type type)
|
||||||
|
{
|
||||||
|
Record<ESXRecordT> copy;
|
||||||
|
copy.mModified = getRecord(origin).get();
|
||||||
|
copy.mState = RecordBase::State_ModifiedOnly;
|
||||||
|
copy.get().mId = destination;
|
||||||
|
|
||||||
|
insertRecord(copy, getAppendIndex(destination, type));
|
||||||
|
}
|
||||||
|
|
||||||
template<typename ESXRecordT, typename IdAccessorT>
|
template<typename ESXRecordT, typename IdAccessorT>
|
||||||
Collection<ESXRecordT, IdAccessorT>::Collection()
|
Collection<ESXRecordT, IdAccessorT>::Collection()
|
||||||
{}
|
{}
|
||||||
|
|
|
@ -74,6 +74,10 @@ namespace CSMWorld
|
||||||
UniversalId::Type type = UniversalId::Type_None) = 0;
|
UniversalId::Type type = UniversalId::Type_None) = 0;
|
||||||
///< If the record type does not match, an exception is thrown.
|
///< If the record type does not match, an exception is thrown.
|
||||||
|
|
||||||
|
virtual void cloneRecord(const std::string& origin,
|
||||||
|
const std::string& destination,
|
||||||
|
const UniversalId::Type type) = 0;
|
||||||
|
|
||||||
virtual const RecordBase& getRecord (const std::string& id) const = 0;
|
virtual const RecordBase& getRecord (const std::string& id) const = 0;
|
||||||
|
|
||||||
virtual const RecordBase& getRecord (int index) const = 0;
|
virtual const RecordBase& getRecord (int index) const = 0;
|
||||||
|
|
|
@ -4,10 +4,10 @@
|
||||||
#include <QAbstractItemModel>
|
#include <QAbstractItemModel>
|
||||||
|
|
||||||
#include "idtable.hpp"
|
#include "idtable.hpp"
|
||||||
#include "idtable.hpp"
|
#include <components/misc/stringops.hpp>
|
||||||
|
|
||||||
CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelIndex& index,
|
CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelIndex& index,
|
||||||
const QVariant& new_, QUndoCommand *parent)
|
const QVariant& new_, QUndoCommand* parent)
|
||||||
: QUndoCommand (parent), mModel (model), mIndex (index), mNew (new_)
|
: QUndoCommand (parent), mModel (model), mIndex (index), mNew (new_)
|
||||||
{
|
{
|
||||||
mOld = mModel.data (mIndex, Qt::EditRole);
|
mOld = mModel.data (mIndex, Qt::EditRole);
|
||||||
|
@ -25,7 +25,7 @@ void CSMWorld::ModifyCommand::undo()
|
||||||
mModel.setData (mIndex, mOld);
|
mModel.setData (mIndex, mOld);
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMWorld::CreateCommand::CreateCommand (IdTable& model, const std::string& id, QUndoCommand *parent)
|
CSMWorld::CreateCommand::CreateCommand (IdTable& model, const std::string& id, QUndoCommand* parent)
|
||||||
: QUndoCommand (parent), mModel (model), mId (id), mType (UniversalId::Type_None)
|
: QUndoCommand (parent), mModel (model), mId (id), mType (UniversalId::Type_None)
|
||||||
{
|
{
|
||||||
setText (("Create record " + id).c_str());
|
setText (("Create record " + id).c_str());
|
||||||
|
@ -54,7 +54,7 @@ void CSMWorld::CreateCommand::undo()
|
||||||
mModel.removeRow (mModel.getModelIndex (mId, 0).row());
|
mModel.removeRow (mModel.getModelIndex (mId, 0).row());
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMWorld::RevertCommand::RevertCommand (IdTable& model, const std::string& id, QUndoCommand *parent)
|
CSMWorld::RevertCommand::RevertCommand (IdTable& model, const std::string& id, QUndoCommand* parent)
|
||||||
: QUndoCommand (parent), mModel (model), mId (id), mOld (0)
|
: QUndoCommand (parent), mModel (model), mId (id), mOld (0)
|
||||||
{
|
{
|
||||||
setText (("Revert record " + id).c_str());
|
setText (("Revert record " + id).c_str());
|
||||||
|
@ -89,7 +89,7 @@ void CSMWorld::RevertCommand::undo()
|
||||||
mModel.setRecord (mId, *mOld);
|
mModel.setRecord (mId, *mOld);
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMWorld::DeleteCommand::DeleteCommand (IdTable& model, const std::string& id, QUndoCommand *parent)
|
CSMWorld::DeleteCommand::DeleteCommand (IdTable& model, const std::string& id, QUndoCommand* parent)
|
||||||
: QUndoCommand (parent), mModel (model), mId (id), mOld (0)
|
: QUndoCommand (parent), mModel (model), mId (id), mOld (0)
|
||||||
{
|
{
|
||||||
setText (("Delete record " + id).c_str());
|
setText (("Delete record " + id).c_str());
|
||||||
|
@ -126,7 +126,7 @@ void CSMWorld::DeleteCommand::undo()
|
||||||
|
|
||||||
|
|
||||||
CSMWorld::ReorderRowsCommand::ReorderRowsCommand (IdTable& model, int baseIndex,
|
CSMWorld::ReorderRowsCommand::ReorderRowsCommand (IdTable& model, int baseIndex,
|
||||||
const std::vector<int>& newOrder)
|
const std::vector<int>& newOrder)
|
||||||
: mModel (model), mBaseIndex (baseIndex), mNewOrder (newOrder)
|
: mModel (model), mBaseIndex (baseIndex), mNewOrder (newOrder)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
@ -140,8 +140,35 @@ void CSMWorld::ReorderRowsCommand::undo()
|
||||||
int size = static_cast<int> (mNewOrder.size());
|
int size = static_cast<int> (mNewOrder.size());
|
||||||
std::vector<int> reverse (size);
|
std::vector<int> reverse (size);
|
||||||
|
|
||||||
for (int i=0; i<size; ++i)
|
for (int i=0; i< size; ++i)
|
||||||
reverse.at (mNewOrder[i]) = i;
|
reverse.at (mNewOrder[i]) = i;
|
||||||
|
|
||||||
mModel.reorderRows (mBaseIndex, reverse);
|
mModel.reorderRows (mBaseIndex, reverse);
|
||||||
|
}
|
||||||
|
|
||||||
|
CSMWorld::CloneCommand::CloneCommand (CSMWorld::IdTable& model,
|
||||||
|
const std::string& idOrigin,
|
||||||
|
const std::string& IdDestination,
|
||||||
|
const CSMWorld::UniversalId::Type type,
|
||||||
|
QUndoCommand* parent) :
|
||||||
|
QUndoCommand (parent),
|
||||||
|
mModel (model),
|
||||||
|
mIdOrigin (idOrigin),
|
||||||
|
mIdDestination (Misc::StringUtils::lowerCase (IdDestination)),
|
||||||
|
mType (type)
|
||||||
|
{
|
||||||
|
setText ( ("Clone record " + idOrigin + " to the " + IdDestination).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::CloneCommand::redo()
|
||||||
|
{
|
||||||
|
mModel.cloneRecord (mIdOrigin, mIdDestination, mType);
|
||||||
|
|
||||||
|
for (std::map<int, QVariant>::const_iterator iter (mValues.begin()); iter != mValues.end(); ++iter)
|
||||||
|
mModel.setData (mModel.getModelIndex (mIdDestination, iter->first), iter->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::CloneCommand::undo()
|
||||||
|
{
|
||||||
|
mModel.removeRow (mModel.getModelIndex (mIdDestination, 0).row());
|
||||||
}
|
}
|
|
@ -39,6 +39,26 @@ namespace CSMWorld
|
||||||
virtual void undo();
|
virtual void undo();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CloneCommand : public QUndoCommand
|
||||||
|
{
|
||||||
|
IdTable& mModel;
|
||||||
|
std::string mIdOrigin;
|
||||||
|
std::string mIdDestination;
|
||||||
|
UniversalId::Type mType;
|
||||||
|
std::map<int, QVariant> mValues;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
CloneCommand (IdTable& model, const std::string& idOrigin,
|
||||||
|
const std::string& IdDestination,
|
||||||
|
const UniversalId::Type type,
|
||||||
|
QUndoCommand* parent = 0);
|
||||||
|
|
||||||
|
virtual void redo();
|
||||||
|
|
||||||
|
virtual void undo();
|
||||||
|
};
|
||||||
|
|
||||||
class CreateCommand : public QUndoCommand
|
class CreateCommand : public QUndoCommand
|
||||||
{
|
{
|
||||||
IdTable& mModel;
|
IdTable& mModel;
|
||||||
|
|
|
@ -154,14 +154,17 @@ CSMWorld::Data::Data() : mRefs (mCells)
|
||||||
|
|
||||||
mTopics.addColumn (new StringIdColumn<ESM::Dialogue>);
|
mTopics.addColumn (new StringIdColumn<ESM::Dialogue>);
|
||||||
mTopics.addColumn (new RecordStateColumn<ESM::Dialogue>);
|
mTopics.addColumn (new RecordStateColumn<ESM::Dialogue>);
|
||||||
|
mTopics.addColumn (new FixedRecordTypeColumn<ESM::Dialogue> (UniversalId::Type_Topic));
|
||||||
mTopics.addColumn (new DialogueTypeColumn<ESM::Dialogue>);
|
mTopics.addColumn (new DialogueTypeColumn<ESM::Dialogue>);
|
||||||
|
|
||||||
mJournals.addColumn (new StringIdColumn<ESM::Dialogue>);
|
mJournals.addColumn (new StringIdColumn<ESM::Dialogue>);
|
||||||
mJournals.addColumn (new RecordStateColumn<ESM::Dialogue>);
|
mJournals.addColumn (new RecordStateColumn<ESM::Dialogue>);
|
||||||
|
mJournals.addColumn (new FixedRecordTypeColumn<ESM::Dialogue> (UniversalId::Type_Journal));
|
||||||
mJournals.addColumn (new DialogueTypeColumn<ESM::Dialogue> (true));
|
mJournals.addColumn (new DialogueTypeColumn<ESM::Dialogue> (true));
|
||||||
|
|
||||||
mTopicInfos.addColumn (new StringIdColumn<Info> (true));
|
mTopicInfos.addColumn (new StringIdColumn<Info> (true));
|
||||||
mTopicInfos.addColumn (new RecordStateColumn<Info>);
|
mTopicInfos.addColumn (new RecordStateColumn<Info>);
|
||||||
|
mTopicInfos.addColumn (new FixedRecordTypeColumn<Info> (UniversalId::Type_TopicInfo));
|
||||||
mTopicInfos.addColumn (new TopicColumn<Info> (false));
|
mTopicInfos.addColumn (new TopicColumn<Info> (false));
|
||||||
mTopicInfos.addColumn (new ActorColumn<Info>);
|
mTopicInfos.addColumn (new ActorColumn<Info>);
|
||||||
mTopicInfos.addColumn (new RaceColumn<Info>);
|
mTopicInfos.addColumn (new RaceColumn<Info>);
|
||||||
|
@ -178,6 +181,7 @@ CSMWorld::Data::Data() : mRefs (mCells)
|
||||||
|
|
||||||
mJournalInfos.addColumn (new StringIdColumn<Info> (true));
|
mJournalInfos.addColumn (new StringIdColumn<Info> (true));
|
||||||
mJournalInfos.addColumn (new RecordStateColumn<Info>);
|
mJournalInfos.addColumn (new RecordStateColumn<Info>);
|
||||||
|
mJournalInfos.addColumn (new FixedRecordTypeColumn<Info> (UniversalId::Type_Journal));
|
||||||
mJournalInfos.addColumn (new TopicColumn<Info> (true));
|
mJournalInfos.addColumn (new TopicColumn<Info> (true));
|
||||||
mJournalInfos.addColumn (new QuestStatusTypeColumn<Info>);
|
mJournalInfos.addColumn (new QuestStatusTypeColumn<Info>);
|
||||||
mJournalInfos.addColumn (new QuestIndexColumn<Info>);
|
mJournalInfos.addColumn (new QuestIndexColumn<Info>);
|
||||||
|
@ -194,6 +198,7 @@ CSMWorld::Data::Data() : mRefs (mCells)
|
||||||
|
|
||||||
mRefs.addColumn (new StringIdColumn<CellRef> (true));
|
mRefs.addColumn (new StringIdColumn<CellRef> (true));
|
||||||
mRefs.addColumn (new RecordStateColumn<CellRef>);
|
mRefs.addColumn (new RecordStateColumn<CellRef>);
|
||||||
|
mRefs.addColumn (new FixedRecordTypeColumn<CellRef> (UniversalId::Type_Reference));
|
||||||
mRefs.addColumn (new CellColumn<CellRef>);
|
mRefs.addColumn (new CellColumn<CellRef>);
|
||||||
mRefs.addColumn (new IdColumn<CellRef>);
|
mRefs.addColumn (new IdColumn<CellRef>);
|
||||||
mRefs.addColumn (new PosColumn<CellRef> (&CellRef::mPos, 0, false));
|
mRefs.addColumn (new PosColumn<CellRef> (&CellRef::mPos, 0, false));
|
||||||
|
@ -224,6 +229,7 @@ CSMWorld::Data::Data() : mRefs (mCells)
|
||||||
|
|
||||||
mFilters.addColumn (new StringIdColumn<CSMFilter::Filter>);
|
mFilters.addColumn (new StringIdColumn<CSMFilter::Filter>);
|
||||||
mFilters.addColumn (new RecordStateColumn<CSMFilter::Filter>);
|
mFilters.addColumn (new RecordStateColumn<CSMFilter::Filter>);
|
||||||
|
mFilters.addColumn (new FixedRecordTypeColumn<CSMFilter::Filter> (UniversalId::Type_Filter));
|
||||||
mFilters.addColumn (new FilterColumn<CSMFilter::Filter>);
|
mFilters.addColumn (new FilterColumn<CSMFilter::Filter>);
|
||||||
mFilters.addColumn (new DescriptionColumn<CSMFilter::Filter>);
|
mFilters.addColumn (new DescriptionColumn<CSMFilter::Filter>);
|
||||||
mFilters.addColumn (new ScopeColumn<CSMFilter::Filter>);
|
mFilters.addColumn (new ScopeColumn<CSMFilter::Filter>);
|
||||||
|
|
|
@ -124,6 +124,17 @@ void CSMWorld::IdTable::addRecord (const std::string& id, UniversalId::Type type
|
||||||
endInsertRows();
|
endInsertRows();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSMWorld::IdTable::cloneRecord(const std::string& origin,
|
||||||
|
const std::string& destination,
|
||||||
|
CSMWorld::UniversalId::Type type)
|
||||||
|
{
|
||||||
|
int index = mIdCollection->getAppendIndex (destination);
|
||||||
|
beginInsertRows (QModelIndex(), index, index);
|
||||||
|
mIdCollection->cloneRecord(origin, destination, type);
|
||||||
|
endInsertRows();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
QModelIndex CSMWorld::IdTable::getModelIndex (const std::string& id, int column) const
|
QModelIndex CSMWorld::IdTable::getModelIndex (const std::string& id, int column) const
|
||||||
{
|
{
|
||||||
return index (mIdCollection->getIndex (id), column);
|
return index (mIdCollection->getIndex (id), column);
|
||||||
|
|
|
@ -63,6 +63,10 @@ namespace CSMWorld
|
||||||
void addRecord (const std::string& id, UniversalId::Type type = UniversalId::Type_None);
|
void addRecord (const std::string& id, UniversalId::Type type = UniversalId::Type_None);
|
||||||
///< \param type Will be ignored, unless the collection supports multiple record types
|
///< \param type Will be ignored, unless the collection supports multiple record types
|
||||||
|
|
||||||
|
void cloneRecord(const std::string& origin,
|
||||||
|
const std::string& destination,
|
||||||
|
UniversalId::Type type = UniversalId::Type_None);
|
||||||
|
|
||||||
QModelIndex getModelIndex (const std::string& id, int column) const;
|
QModelIndex getModelIndex (const std::string& id, int column) const;
|
||||||
|
|
||||||
void setRecord (const std::string& id, const RecordBase& record);
|
void setRecord (const std::string& id, const RecordBase& record);
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
|
|
||||||
#include "ref.hpp"
|
#include "ref.hpp"
|
||||||
#include "cell.hpp"
|
#include "cell.hpp"
|
||||||
|
#include "universalid.hpp"
|
||||||
|
#include "record.hpp"
|
||||||
|
|
||||||
void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool base)
|
void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool base)
|
||||||
{
|
{
|
||||||
|
@ -34,4 +36,15 @@ std::string CSMWorld::RefCollection::getNewId()
|
||||||
std::ostringstream stream;
|
std::ostringstream stream;
|
||||||
stream << "ref#" << mNextId++;
|
stream << "ref#" << mNextId++;
|
||||||
return stream.str();
|
return stream.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMWorld::RefCollection::cloneRecord(const std::string& origin,
|
||||||
|
const std::string& destination,
|
||||||
|
const CSMWorld::UniversalId::Type type,
|
||||||
|
const CSMWorld::UniversalId::ArgumentType argumentType)
|
||||||
|
{
|
||||||
|
Record<CSMWorld::CellRef> clone(getRecord(origin));
|
||||||
|
clone.mState = CSMWorld::RecordBase::State_ModifiedOnly;
|
||||||
|
clone.get().mId = destination;
|
||||||
|
insertRecord(clone, getAppendIndex(destination, type), type);
|
||||||
}
|
}
|
|
@ -8,6 +8,7 @@
|
||||||
namespace CSMWorld
|
namespace CSMWorld
|
||||||
{
|
{
|
||||||
struct Cell;
|
struct Cell;
|
||||||
|
struct UniversalId;
|
||||||
|
|
||||||
/// \brief References in cells
|
/// \brief References in cells
|
||||||
class RefCollection : public Collection<CellRef>
|
class RefCollection : public Collection<CellRef>
|
||||||
|
@ -25,6 +26,11 @@ namespace CSMWorld
|
||||||
///< Load a sequence of references.
|
///< Load a sequence of references.
|
||||||
|
|
||||||
std::string getNewId();
|
std::string getNewId();
|
||||||
|
|
||||||
|
void cloneRecord(const std::string& origin,
|
||||||
|
const std::string& destination,
|
||||||
|
const CSMWorld::UniversalId::Type type,
|
||||||
|
const CSMWorld::UniversalId::ArgumentType argumentType);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ namespace CSMWorld
|
||||||
///< If the data type does not match an exception is thrown.
|
///< If the data type does not match an exception is thrown.
|
||||||
|
|
||||||
virtual std::string getId (const RecordBase& record) const = 0;
|
virtual std::string getId (const RecordBase& record) const = 0;
|
||||||
|
virtual void setId(RecordBase& record, const std::string& id) = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,8 @@ namespace CSMWorld
|
||||||
BaseRefIdAdapter (UniversalId::Type type, const BaseColumns& base);
|
BaseRefIdAdapter (UniversalId::Type type, const BaseColumns& base);
|
||||||
|
|
||||||
virtual std::string getId (const RecordBase& record) const;
|
virtual std::string getId (const RecordBase& record) const;
|
||||||
|
|
||||||
|
virtual void setId (RecordBase& record, const std::string& id);
|
||||||
|
|
||||||
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
|
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
|
||||||
const;
|
const;
|
||||||
|
@ -50,6 +52,12 @@ namespace CSMWorld
|
||||||
: mType (type), mBase (base)
|
: mType (type), mBase (base)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
template<typename RecordT>
|
||||||
|
void BaseRefIdAdapter<RecordT>::setId (RecordBase& record, const std::string& id)
|
||||||
|
{
|
||||||
|
(dynamic_cast<Record<RecordT>&> (record).get().mId) = id;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename RecordT>
|
template<typename RecordT>
|
||||||
std::string BaseRefIdAdapter<RecordT>::getId (const RecordBase& record) const
|
std::string BaseRefIdAdapter<RecordT>::getId (const RecordBase& record) const
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include "refidcollection.hpp"
|
#include "refidcollection.hpp"
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <components/esm/esmreader.hpp>
|
#include <components/esm/esmreader.hpp>
|
||||||
|
|
||||||
|
@ -449,6 +450,16 @@ void CSMWorld::RefIdCollection::replace (int index, const RecordBase& record)
|
||||||
mData.getRecord (mData.globalToLocalIndex (index)).assign (record);
|
mData.getRecord (mData.globalToLocalIndex (index)).assign (record);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSMWorld::RefIdCollection::cloneRecord(const std::string& origin,
|
||||||
|
const std::string& destination,
|
||||||
|
const CSMWorld::UniversalId::Type type)
|
||||||
|
{
|
||||||
|
std::auto_ptr<RecordBase> newRecord(mData.getRecord(mData.searchId(origin)).clone());
|
||||||
|
newRecord->mState = RecordBase::State_ModifiedOnly;
|
||||||
|
mAdapters.find(type)->second->setId(*newRecord, destination);
|
||||||
|
mData.insertRecord(*newRecord, type, destination);
|
||||||
|
}
|
||||||
|
|
||||||
void CSMWorld::RefIdCollection::appendRecord (const RecordBase& record,
|
void CSMWorld::RefIdCollection::appendRecord (const RecordBase& record,
|
||||||
UniversalId::Type type)
|
UniversalId::Type type)
|
||||||
{
|
{
|
||||||
|
|
|
@ -69,6 +69,10 @@ namespace CSMWorld
|
||||||
|
|
||||||
virtual void removeRows (int index, int count);
|
virtual void removeRows (int index, int count);
|
||||||
|
|
||||||
|
virtual void cloneRecord(const std::string& origin,
|
||||||
|
const std::string& destination,
|
||||||
|
const UniversalId::Type type);
|
||||||
|
|
||||||
virtual void appendBlankRecord (const std::string& id, UniversalId::Type type);
|
virtual void appendBlankRecord (const std::string& id, UniversalId::Type type);
|
||||||
///< \param type Will be ignored, unless the collection supports multiple record types
|
///< \param type Will be ignored, unless the collection supports multiple record types
|
||||||
|
|
||||||
|
|
|
@ -330,4 +330,18 @@ const CSMWorld::RefIdDataContainer< ESM::Repair >& CSMWorld::RefIdData::getRepai
|
||||||
const CSMWorld::RefIdDataContainer< ESM::Static >& CSMWorld::RefIdData::getStatics() const
|
const CSMWorld::RefIdDataContainer< ESM::Static >& CSMWorld::RefIdData::getStatics() const
|
||||||
{
|
{
|
||||||
return mStatics;
|
return mStatics;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSMWorld::RefIdData::insertRecord(CSMWorld::RecordBase& record, CSMWorld::UniversalId::Type type, const std::string& id)
|
||||||
|
{
|
||||||
|
std::map<UniversalId::Type, RefIdDataContainerBase *>::iterator iter =
|
||||||
|
mRecordContainers.find (type);
|
||||||
|
|
||||||
|
if (iter==mRecordContainers.end())
|
||||||
|
throw std::logic_error ("invalid local index type");
|
||||||
|
|
||||||
|
iter->second->insertRecord(record);
|
||||||
|
|
||||||
|
mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (id),
|
||||||
|
LocalIndex (iter->second->getSize()-1, type)));
|
||||||
|
}
|
||||||
|
|
|
@ -46,6 +46,8 @@ namespace CSMWorld
|
||||||
virtual RecordBase& getRecord (int index)= 0;
|
virtual RecordBase& getRecord (int index)= 0;
|
||||||
|
|
||||||
virtual void appendRecord (const std::string& id) = 0;
|
virtual void appendRecord (const std::string& id) = 0;
|
||||||
|
|
||||||
|
virtual void insertRecord (RecordBase& record) = 0;
|
||||||
|
|
||||||
virtual void load (int index, ESM::ESMReader& reader, bool base) = 0;
|
virtual void load (int index, ESM::ESMReader& reader, bool base) = 0;
|
||||||
|
|
||||||
|
@ -68,6 +70,8 @@ namespace CSMWorld
|
||||||
virtual RecordBase& getRecord (int index);
|
virtual RecordBase& getRecord (int index);
|
||||||
|
|
||||||
virtual void appendRecord (const std::string& id);
|
virtual void appendRecord (const std::string& id);
|
||||||
|
|
||||||
|
virtual void insertRecord (RecordBase& record);
|
||||||
|
|
||||||
virtual void load (int index, ESM::ESMReader& reader, bool base);
|
virtual void load (int index, ESM::ESMReader& reader, bool base);
|
||||||
|
|
||||||
|
@ -78,6 +82,13 @@ namespace CSMWorld
|
||||||
virtual void save (int index, ESM::ESMWriter& writer) const;
|
virtual void save (int index, ESM::ESMWriter& writer) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename RecordT>
|
||||||
|
void RefIdDataContainer<RecordT>::insertRecord(RecordBase& record)
|
||||||
|
{
|
||||||
|
Record<RecordT>& newRecord = dynamic_cast<Record<RecordT>& >(record);
|
||||||
|
mContainer.push_back(newRecord);
|
||||||
|
}
|
||||||
|
|
||||||
template<typename RecordT>
|
template<typename RecordT>
|
||||||
int RefIdDataContainer<RecordT>::getSize() const
|
int RefIdDataContainer<RecordT>::getSize() const
|
||||||
{
|
{
|
||||||
|
@ -200,6 +211,8 @@ namespace CSMWorld
|
||||||
LocalIndex searchId (const std::string& id) const;
|
LocalIndex searchId (const std::string& id) const;
|
||||||
|
|
||||||
void erase (int index, int count);
|
void erase (int index, int count);
|
||||||
|
|
||||||
|
void insertRecord(CSMWorld::RecordBase& record, CSMWorld::UniversalId::Type type, const std::string& id);
|
||||||
|
|
||||||
const RecordBase& getRecord (const LocalIndex& index) const;
|
const RecordBase& getRecord (const LocalIndex& index) const;
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,7 @@ void CSVWorld::CellCreator::reset()
|
||||||
mX->setValue (0);
|
mX->setValue (0);
|
||||||
mY->setValue (0);
|
mY->setValue (0);
|
||||||
mType->setCurrentIndex (0);
|
mType->setCurrentIndex (0);
|
||||||
|
setType(0);
|
||||||
GenericCreator::reset();
|
GenericCreator::reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,4 +79,25 @@ void CSVWorld::CellCreator::setType (int index)
|
||||||
void CSVWorld::CellCreator::valueChanged (int index)
|
void CSVWorld::CellCreator::valueChanged (int index)
|
||||||
{
|
{
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVWorld::CellCreator::cloneMode(const std::string& originId,
|
||||||
|
const CSMWorld::UniversalId::Type type)
|
||||||
|
{
|
||||||
|
CSVWorld::GenericCreator::cloneMode(originId, type);
|
||||||
|
if (*(originId.begin()) == '#') //if originid points to the exterior cell
|
||||||
|
{
|
||||||
|
setType(1); //enable x and y controls
|
||||||
|
mType->setCurrentIndex(1);
|
||||||
|
} else {
|
||||||
|
setType(0);
|
||||||
|
mType->setCurrentIndex(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CSVWorld::CellCreator::toggleWidgets(bool active)
|
||||||
|
{
|
||||||
|
CSVWorld::GenericCreator::toggleWidgets(active);
|
||||||
|
mType->setEnabled(active);
|
||||||
|
}
|
||||||
|
|
|
@ -29,6 +29,11 @@ namespace CSVWorld
|
||||||
|
|
||||||
virtual void reset();
|
virtual void reset();
|
||||||
|
|
||||||
|
virtual void toggleWidgets(bool active = true);
|
||||||
|
|
||||||
|
virtual void cloneMode(const std::string& originId,
|
||||||
|
const CSMWorld::UniversalId::Type type);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
void setType (int index);
|
void setType (int index);
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define CSV_WORLD_CREATOR_H
|
#define CSV_WORLD_CREATOR_H
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
#include "../../model/world/universalid.hpp"
|
||||||
|
|
||||||
class QUndoStack;
|
class QUndoStack;
|
||||||
|
|
||||||
|
@ -24,8 +25,13 @@ namespace CSVWorld
|
||||||
|
|
||||||
virtual void reset() = 0;
|
virtual void reset() = 0;
|
||||||
|
|
||||||
|
virtual void cloneMode(const std::string& originId,
|
||||||
|
const CSMWorld::UniversalId::Type type) = 0;
|
||||||
|
|
||||||
virtual void setEditLock (bool locked) = 0;
|
virtual void setEditLock (bool locked) = 0;
|
||||||
|
|
||||||
|
virtual void toggleWidgets(bool active = true) = 0;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
void done();
|
void done();
|
||||||
|
|
|
@ -57,8 +57,15 @@ const CSMWorld::UniversalId& CSVWorld::GenericCreator::getCollectionId() const
|
||||||
}
|
}
|
||||||
|
|
||||||
CSVWorld::GenericCreator::GenericCreator (CSMWorld::Data& data, QUndoStack& undoStack,
|
CSVWorld::GenericCreator::GenericCreator (CSMWorld::Data& data, QUndoStack& undoStack,
|
||||||
const CSMWorld::UniversalId& id, bool relaxedIdRules)
|
const CSMWorld::UniversalId& id, bool relaxedIdRules):
|
||||||
: mData (data), mUndoStack (undoStack), mListId (id), mLocked (false)
|
|
||||||
|
mData (data),
|
||||||
|
mUndoStack (undoStack),
|
||||||
|
mListId (id),
|
||||||
|
mLocked (false),
|
||||||
|
mCloneMode(false),
|
||||||
|
mClonedType(CSMWorld::UniversalId::Type_None)
|
||||||
|
|
||||||
{
|
{
|
||||||
mLayout = new QHBoxLayout;
|
mLayout = new QHBoxLayout;
|
||||||
mLayout->setContentsMargins (0, 0, 0, 0);
|
mLayout->setContentsMargins (0, 0, 0, 0);
|
||||||
|
@ -89,6 +96,7 @@ void CSVWorld::GenericCreator::setEditLock (bool locked)
|
||||||
|
|
||||||
void CSVWorld::GenericCreator::reset()
|
void CSVWorld::GenericCreator::reset()
|
||||||
{
|
{
|
||||||
|
mCloneMode = false;
|
||||||
mId->setText ("");
|
mId->setText ("");
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
@ -120,16 +128,40 @@ void CSVWorld::GenericCreator::create()
|
||||||
{
|
{
|
||||||
if (!mLocked)
|
if (!mLocked)
|
||||||
{
|
{
|
||||||
std::string id = getId();
|
if (mCloneMode)
|
||||||
|
{
|
||||||
|
std::string id = getId();
|
||||||
|
std::auto_ptr<CSMWorld::CloneCommand> command (new CSMWorld::CloneCommand (
|
||||||
|
dynamic_cast<CSMWorld::IdTable&> (*mData.getTableModel(mListId)), mClonedId, id, mClonedType));
|
||||||
|
|
||||||
|
mUndoStack.push(command.release());
|
||||||
|
|
||||||
|
emit done();
|
||||||
|
emit requestFocus(id);
|
||||||
|
} else {
|
||||||
|
std::string id = getId();
|
||||||
|
|
||||||
std::auto_ptr<CSMWorld::CreateCommand> command (new CSMWorld::CreateCommand (
|
std::auto_ptr<CSMWorld::CreateCommand> command (new CSMWorld::CreateCommand (
|
||||||
dynamic_cast<CSMWorld::IdTable&> (*mData.getTableModel (mListId)), id));
|
dynamic_cast<CSMWorld::IdTable&> (*mData.getTableModel (mListId)), id));
|
||||||
|
|
||||||
configureCreateCommand (*command);
|
configureCreateCommand (*command);
|
||||||
|
|
||||||
mUndoStack.push (command.release());
|
mUndoStack.push (command.release());
|
||||||
|
|
||||||
emit done();
|
emit done();
|
||||||
emit requestFocus (id);
|
emit requestFocus (id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVWorld::GenericCreator::cloneMode(const std::string& originId,
|
||||||
|
const CSMWorld::UniversalId::Type type)
|
||||||
|
{
|
||||||
|
mCloneMode = true;
|
||||||
|
mClonedId = originId;
|
||||||
|
mClonedType = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVWorld::GenericCreator::toggleWidgets(bool active)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef CSV_WORLD_GENERICCREATOR_H
|
#ifndef CSV_WORLD_GENERICCREATOR_H
|
||||||
#define CSV_WORLD_GENERICCREATOR_H
|
#define CSV_WORLD_GENERICCREATOR_H
|
||||||
|
|
||||||
|
class QString;
|
||||||
class QPushButton;
|
class QPushButton;
|
||||||
class QLineEdit;
|
class QLineEdit;
|
||||||
class QHBoxLayout;
|
class QHBoxLayout;
|
||||||
|
@ -28,6 +29,11 @@ namespace CSVWorld
|
||||||
std::string mErrors;
|
std::string mErrors;
|
||||||
QHBoxLayout *mLayout;
|
QHBoxLayout *mLayout;
|
||||||
bool mLocked;
|
bool mLocked;
|
||||||
|
std::string mClonedId;
|
||||||
|
CSMWorld::UniversalId::Type mClonedType;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool mCloneMode;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
@ -57,11 +63,15 @@ namespace CSVWorld
|
||||||
|
|
||||||
virtual void reset();
|
virtual void reset();
|
||||||
|
|
||||||
|
virtual void toggleWidgets (bool active = true);
|
||||||
|
|
||||||
|
virtual void cloneMode(const std::string& originId,
|
||||||
|
const CSMWorld::UniversalId::Type type);
|
||||||
|
|
||||||
virtual std::string getErrors() const;
|
virtual std::string getErrors() const;
|
||||||
///< Return formatted error descriptions for the current state of the creator. if an empty
|
///< Return formatted error descriptions for the current state of the creator. if an empty
|
||||||
/// string is returned, there is no error.
|
/// string is returned, there is no error.
|
||||||
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
void textChanged (const QString& text);
|
void textChanged (const QString& text);
|
||||||
|
|
|
@ -40,4 +40,10 @@ void CSVWorld::ReferenceableCreator::reset()
|
||||||
{
|
{
|
||||||
mType->setCurrentIndex (0);
|
mType->setCurrentIndex (0);
|
||||||
GenericCreator::reset();
|
GenericCreator::reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVWorld::ReferenceableCreator::toggleWidgets(bool active)
|
||||||
|
{
|
||||||
|
CSVWorld::GenericCreator::toggleWidgets(active);
|
||||||
|
mType->setEnabled(active);
|
||||||
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ namespace CSVWorld
|
||||||
const CSMWorld::UniversalId& id);
|
const CSMWorld::UniversalId& id);
|
||||||
|
|
||||||
virtual void reset();
|
virtual void reset();
|
||||||
|
virtual void toggleWidgets(bool active = true);
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,15 +40,20 @@ CSVWorld::ReferenceCreator::ReferenceCreator (CSMWorld::Data& data, QUndoStack&
|
||||||
|
|
||||||
void CSVWorld::ReferenceCreator::reset()
|
void CSVWorld::ReferenceCreator::reset()
|
||||||
{
|
{
|
||||||
|
GenericCreator::reset();
|
||||||
mCell->setText ("");
|
mCell->setText ("");
|
||||||
mId = getData().getReferences().getNewId();
|
mId = getData().getReferences().getNewId();
|
||||||
GenericCreator::reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string CSVWorld::ReferenceCreator::getErrors() const
|
std::string CSVWorld::ReferenceCreator::getErrors() const
|
||||||
{
|
{
|
||||||
std::string errors = GenericCreator::getErrors();
|
std::string errors = GenericCreator::getErrors();
|
||||||
|
|
||||||
|
if (mCloneMode)
|
||||||
|
{
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
std::string cell = mCell->text().toUtf8().constData();
|
std::string cell = mCell->text().toUtf8().constData();
|
||||||
|
|
||||||
if (cell.empty())
|
if (cell.empty())
|
||||||
|
@ -72,4 +77,17 @@ std::string CSVWorld::ReferenceCreator::getErrors() const
|
||||||
void CSVWorld::ReferenceCreator::cellChanged()
|
void CSVWorld::ReferenceCreator::cellChanged()
|
||||||
{
|
{
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVWorld::ReferenceCreator::toggleWidgets(bool active)
|
||||||
|
{
|
||||||
|
CSVWorld::GenericCreator::toggleWidgets(active);
|
||||||
|
mCell->setEnabled(active);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVWorld::ReferenceCreator::cloneMode(const std::string& originId,
|
||||||
|
const CSMWorld::UniversalId::Type type)
|
||||||
|
{
|
||||||
|
CSVWorld::GenericCreator::cloneMode(originId, type);
|
||||||
|
cellChanged(); //otherwise ok button will remain disabled
|
||||||
|
}
|
||||||
|
|
|
@ -25,7 +25,11 @@ namespace CSVWorld
|
||||||
ReferenceCreator (CSMWorld::Data& data, QUndoStack& undoStack,
|
ReferenceCreator (CSMWorld::Data& data, QUndoStack& undoStack,
|
||||||
const CSMWorld::UniversalId& id);
|
const CSMWorld::UniversalId& id);
|
||||||
|
|
||||||
|
virtual void cloneMode(const std::string& originId,
|
||||||
|
const CSMWorld::UniversalId::Type type);
|
||||||
|
|
||||||
virtual void reset();
|
virtual void reset();
|
||||||
|
virtual void toggleWidgets(bool active = true);
|
||||||
|
|
||||||
virtual std::string getErrors() const;
|
virtual std::string getErrors() const;
|
||||||
///< Return formatted error descriptions for the current state of the creator. if an empty
|
///< Return formatted error descriptions for the current state of the creator. if an empty
|
||||||
|
|
|
@ -28,7 +28,11 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event)
|
||||||
if (!mEditLock)
|
if (!mEditLock)
|
||||||
{
|
{
|
||||||
if (selectedRows.size()==1)
|
if (selectedRows.size()==1)
|
||||||
|
{
|
||||||
menu.addAction (mEditAction);
|
menu.addAction (mEditAction);
|
||||||
|
if (mCreateAction)
|
||||||
|
menu.addAction(mCloneAction);
|
||||||
|
}
|
||||||
|
|
||||||
if (mCreateAction)
|
if (mCreateAction)
|
||||||
menu.addAction (mCreateAction);
|
menu.addAction (mCreateAction);
|
||||||
|
@ -155,7 +159,7 @@ std::vector<std::string> CSVWorld::Table::listDeletableSelectedIds() const
|
||||||
|
|
||||||
CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack,
|
CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack,
|
||||||
bool createAndDelete, bool sorting)
|
bool createAndDelete, bool sorting)
|
||||||
: mUndoStack (undoStack), mCreateAction (0), mEditLock (false), mRecordStatusDisplay (0)
|
: mUndoStack (undoStack), mCreateAction (0), mCloneAction(0), mEditLock (false), mRecordStatusDisplay (0)
|
||||||
{
|
{
|
||||||
mModel = &dynamic_cast<CSMWorld::IdTable&> (*data.getTableModel (id));
|
mModel = &dynamic_cast<CSMWorld::IdTable&> (*data.getTableModel (id));
|
||||||
|
|
||||||
|
@ -199,6 +203,10 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, Q
|
||||||
mCreateAction = new QAction (tr ("Add Record"), this);
|
mCreateAction = new QAction (tr ("Add Record"), this);
|
||||||
connect (mCreateAction, SIGNAL (triggered()), this, SIGNAL (createRequest()));
|
connect (mCreateAction, SIGNAL (triggered()), this, SIGNAL (createRequest()));
|
||||||
addAction (mCreateAction);
|
addAction (mCreateAction);
|
||||||
|
|
||||||
|
mCloneAction = new QAction (tr ("Clone Record"), this);
|
||||||
|
connect(mCloneAction, SIGNAL (triggered()), this, SLOT (cloneRecord()));
|
||||||
|
addAction(mCloneAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
mRevertAction = new QAction (tr ("Revert Record"), this);
|
mRevertAction = new QAction (tr ("Revert Record"), this);
|
||||||
|
@ -295,6 +303,19 @@ void CSVWorld::Table::editRecord()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVWorld::Table::cloneRecord()
|
||||||
|
{
|
||||||
|
if (!mEditLock)
|
||||||
|
{
|
||||||
|
QModelIndexList selectedRows = selectionModel()->selectedRows();
|
||||||
|
const CSMWorld::UniversalId& toClone = getUniversalId(selectedRows.begin()->row());
|
||||||
|
if (selectedRows.size()==1 && !mModel->getRecord(toClone.getId()).isDeleted())
|
||||||
|
{
|
||||||
|
emit cloneRequest (toClone);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CSVWorld::Table::moveUpRecord()
|
void CSVWorld::Table::moveUpRecord()
|
||||||
{
|
{
|
||||||
QModelIndexList selectedRows = selectionModel()->selectedRows();
|
QModelIndexList selectedRows = selectionModel()->selectedRows();
|
||||||
|
|
|
@ -32,6 +32,7 @@ namespace CSVWorld
|
||||||
QUndoStack& mUndoStack;
|
QUndoStack& mUndoStack;
|
||||||
QAction *mEditAction;
|
QAction *mEditAction;
|
||||||
QAction *mCreateAction;
|
QAction *mCreateAction;
|
||||||
|
QAction *mCloneAction;
|
||||||
QAction *mRevertAction;
|
QAction *mRevertAction;
|
||||||
QAction *mDeleteAction;
|
QAction *mDeleteAction;
|
||||||
QAction *mMoveUpAction;
|
QAction *mMoveUpAction;
|
||||||
|
@ -73,6 +74,7 @@ namespace CSVWorld
|
||||||
/// \param modified Number of added and modified records
|
/// \param modified Number of added and modified records
|
||||||
|
|
||||||
void createRequest();
|
void createRequest();
|
||||||
|
void cloneRequest(const CSMWorld::UniversalId&);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
|
@ -82,6 +84,8 @@ namespace CSVWorld
|
||||||
|
|
||||||
void editRecord();
|
void editRecord();
|
||||||
|
|
||||||
|
void cloneRecord();
|
||||||
|
|
||||||
void moveUpRecord();
|
void moveUpRecord();
|
||||||
|
|
||||||
void moveDownRecord();
|
void moveDownRecord();
|
||||||
|
|
|
@ -153,7 +153,19 @@ void CSVWorld::TableBottomBox::tableSizeChanged (int size, int deleted, int modi
|
||||||
void CSVWorld::TableBottomBox::createRequest()
|
void CSVWorld::TableBottomBox::createRequest()
|
||||||
{
|
{
|
||||||
mCreator->reset();
|
mCreator->reset();
|
||||||
|
mCreator->toggleWidgets(true);
|
||||||
mLayout->setCurrentWidget (mCreator);
|
mLayout->setCurrentWidget (mCreator);
|
||||||
setVisible (true);
|
setVisible (true);
|
||||||
mCreating = true;
|
mCreating = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVWorld::TableBottomBox::cloneRequest(const std::string& id,
|
||||||
|
const CSMWorld::UniversalId::Type type)
|
||||||
|
{
|
||||||
|
mCreator->reset();
|
||||||
|
mCreator->cloneMode(id, type);
|
||||||
|
mLayout->setCurrentWidget(mCreator);
|
||||||
|
mCreator->toggleWidgets(false);
|
||||||
|
setVisible (true);
|
||||||
|
mCreating = true;
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define CSV_WORLD_BOTTOMBOX_H
|
#define CSV_WORLD_BOTTOMBOX_H
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
#include <apps/opencs/model/world/universalid.hpp>
|
||||||
|
|
||||||
class QLabel;
|
class QLabel;
|
||||||
class QStackedLayout;
|
class QStackedLayout;
|
||||||
|
@ -76,6 +77,8 @@ namespace CSVWorld
|
||||||
/// \param modified Number of added and modified records
|
/// \param modified Number of added and modified records
|
||||||
|
|
||||||
void createRequest();
|
void createRequest();
|
||||||
|
void cloneRequest(const std::string& id,
|
||||||
|
const CSMWorld::UniversalId::Type type);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
#include "../../model/doc/document.hpp"
|
#include "../../model/doc/document.hpp"
|
||||||
|
|
||||||
#include "../filter/filterbox.hpp"
|
#include "../filter/filterbox.hpp"
|
||||||
|
|
||||||
#include "table.hpp"
|
#include "table.hpp"
|
||||||
#include "tablebottombox.hpp"
|
#include "tablebottombox.hpp"
|
||||||
#include "creator.hpp"
|
#include "creator.hpp"
|
||||||
|
@ -46,8 +45,15 @@ CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::D
|
||||||
mTable->selectionSizeUpdate();
|
mTable->selectionSizeUpdate();
|
||||||
|
|
||||||
if (mBottom->canCreateAndDelete())
|
if (mBottom->canCreateAndDelete())
|
||||||
|
{
|
||||||
connect (mTable, SIGNAL (createRequest()), mBottom, SLOT (createRequest()));
|
connect (mTable, SIGNAL (createRequest()), mBottom, SLOT (createRequest()));
|
||||||
|
|
||||||
|
connect (mTable, SIGNAL (cloneRequest(const CSMWorld::UniversalId&)), this,
|
||||||
|
SLOT(cloneRequest(const CSMWorld::UniversalId&)));
|
||||||
|
|
||||||
|
connect (this, SIGNAL(cloneRequest(const std::string&, const CSMWorld::UniversalId::Type)),
|
||||||
|
mBottom, SLOT(cloneRequest(const std::string&, const CSMWorld::UniversalId::Type)));
|
||||||
|
}
|
||||||
connect (mBottom, SIGNAL (requestFocus (const std::string&)),
|
connect (mBottom, SIGNAL (requestFocus (const std::string&)),
|
||||||
mTable, SLOT (requestFocus (const std::string&)));
|
mTable, SLOT (requestFocus (const std::string&)));
|
||||||
|
|
||||||
|
@ -75,4 +81,9 @@ void CSVWorld::TableSubView::updateEditorSetting(const QString &settingName, con
|
||||||
void CSVWorld::TableSubView::setStatusBar (bool show)
|
void CSVWorld::TableSubView::setStatusBar (bool show)
|
||||||
{
|
{
|
||||||
mBottom->setStatusBar (show);
|
mBottom->setStatusBar (show);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVWorld::TableSubView::cloneRequest(const CSMWorld::UniversalId& toClone)
|
||||||
|
{
|
||||||
|
emit cloneRequest(toClone.getId(), toClone.getType());
|
||||||
|
}
|
||||||
|
|
|
@ -5,6 +5,11 @@
|
||||||
|
|
||||||
class QModelIndex;
|
class QModelIndex;
|
||||||
|
|
||||||
|
namespace CSMWorld
|
||||||
|
{
|
||||||
|
class IdTable;
|
||||||
|
}
|
||||||
|
|
||||||
namespace CSMDoc
|
namespace CSMDoc
|
||||||
{
|
{
|
||||||
class Document;
|
class Document;
|
||||||
|
@ -34,9 +39,14 @@ namespace CSVWorld
|
||||||
|
|
||||||
virtual void setStatusBar (bool show);
|
virtual void setStatusBar (bool show);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void cloneRequest(const std::string&,
|
||||||
|
const CSMWorld::UniversalId::Type);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
void editRequest (int row);
|
void editRequest (int row);
|
||||||
|
void cloneRequest (const CSMWorld::UniversalId& toClone);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
namespace Ogre
|
namespace Ogre
|
||||||
{
|
{
|
||||||
|
@ -159,6 +160,9 @@ namespace MWBase
|
||||||
virtual bool isAIActive() = 0;
|
virtual bool isAIActive() = 0;
|
||||||
|
|
||||||
virtual void getObjectsInRange (const Ogre::Vector3& position, float radius, std::vector<MWWorld::Ptr>& objects) = 0;
|
virtual void getObjectsInRange (const Ogre::Vector3& position, float radius, std::vector<MWWorld::Ptr>& objects) = 0;
|
||||||
|
|
||||||
|
///return the list of actors which are following the given actor (ie AiFollow is active and the target is the actor)
|
||||||
|
virtual std::list<MWWorld::Ptr> getActorsFollowing(const MWWorld::Ptr& actor) = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include "../mwbase/mechanicsmanager.hpp"
|
#include "../mwbase/mechanicsmanager.hpp"
|
||||||
|
|
||||||
#include "aicombat.hpp"
|
#include "aicombat.hpp"
|
||||||
|
#include "aifollow.hpp"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
@ -795,7 +796,7 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
|
|
||||||
// If it's the player and God Mode is turned on, keep it alive
|
// If it's the player and God Mode is turned on, keep it alive
|
||||||
if(iter->first.getRefData().getHandle()=="player" &&
|
if(iter->first.getRefData().getHandle()=="player" &&
|
||||||
MWBase::Environment::get().getWorld()->getGodModeState())
|
MWBase::Environment::get().getWorld()->getGodModeState())
|
||||||
{
|
{
|
||||||
MWMechanics::DynamicStat<float> stat(stats.getHealth());
|
MWMechanics::DynamicStat<float> stat(stats.getHealth());
|
||||||
|
@ -928,4 +929,22 @@ namespace MWMechanics
|
||||||
out.push_back(iter->first);
|
out.push_back(iter->first);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::list<MWWorld::Ptr> Actors::getActorsFollowing(const MWWorld::Ptr& actor)
|
||||||
|
{
|
||||||
|
std::list<MWWorld::Ptr> list;
|
||||||
|
for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();iter++)
|
||||||
|
{
|
||||||
|
const MWWorld::Class &cls = MWWorld::Class::get(iter->first);
|
||||||
|
CreatureStats &stats = cls.getCreatureStats(iter->first);
|
||||||
|
|
||||||
|
if(stats.getAiSequence().getTypeId() == AiPackage::TypeIdFollow)
|
||||||
|
{
|
||||||
|
MWMechanics::AiFollow* package = static_cast<MWMechanics::AiFollow*>(stats.getAiSequence().getActivePackage());
|
||||||
|
if(package->getFollowedActor() == actor.getCellRef().mRefID)
|
||||||
|
list.push_front(iter->first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,7 +84,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
int getHoursToRest(const MWWorld::Ptr& ptr) const;
|
int getHoursToRest(const MWWorld::Ptr& ptr) const;
|
||||||
///< Calculate how many hours the given actor needs to rest in order to be fully healed
|
///< Calculate how many hours the given actor needs to rest in order to be fully healed
|
||||||
|
|
||||||
int countDeaths (const std::string& id) const;
|
int countDeaths (const std::string& id) const;
|
||||||
///< Return the number of deaths for actors with the given ID.
|
///< Return the number of deaths for actors with the given ID.
|
||||||
|
|
||||||
|
@ -94,7 +94,10 @@ namespace MWMechanics
|
||||||
void skipAnimation(const MWWorld::Ptr& ptr);
|
void skipAnimation(const MWWorld::Ptr& ptr);
|
||||||
bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName);
|
bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName);
|
||||||
|
|
||||||
void getObjectsInRange(const Ogre::Vector3& position, float radius, std::vector<MWWorld::Ptr>& out);
|
void getObjectsInRange(const Ogre::Vector3& position, float radius, std::vector<MWWorld::Ptr>& out);
|
||||||
|
|
||||||
|
std::list<MWWorld::Ptr> getActorsFollowing(const MWWorld::Ptr& actor);
|
||||||
|
///<return the list of actors which are following the given actor (ie AiFollow is active and the target is the actor)
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PtrControllerMap mActors;
|
PtrControllerMap mActors;
|
||||||
|
|
|
@ -208,7 +208,7 @@ namespace MWMechanics
|
||||||
mMovement.mPosition[1] = 0;
|
mMovement.mPosition[1] = 0;
|
||||||
chooseBestAttack(weapon, mMovement);
|
chooseBestAttack(weapon, mMovement);
|
||||||
|
|
||||||
if(mMovement.mPosition[0] != 0 || mMovement.mPosition[1])
|
if(mMovement.mPosition[0] || mMovement.mPosition[1])
|
||||||
{
|
{
|
||||||
mTimerCombatMove = 0.1f + 0.1f * static_cast<float>(rand())/RAND_MAX;
|
mTimerCombatMove = 0.1f + 0.1f * static_cast<float>(rand())/RAND_MAX;
|
||||||
mCombatMove = true;
|
mCombatMove = true;
|
||||||
|
@ -258,7 +258,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
// TODO: use movement settings instead of rotating directly
|
// TODO: use movement settings instead of rotating directly
|
||||||
MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false);
|
MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false);
|
||||||
//MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1;
|
//mMovement.mRotation[2] = 10*(Ogre::Degree(zAngle).valueRadians()-pos.rot[2]);
|
||||||
|
|
||||||
mMovement.mPosition[1] = 1;
|
mMovement.mPosition[1] = 1;
|
||||||
mReadyToAttack = false;
|
mReadyToAttack = false;
|
||||||
}
|
}
|
||||||
|
@ -280,7 +281,7 @@ namespace MWMechanics
|
||||||
float s1 = distBetween - weapRange;
|
float s1 = distBetween - weapRange;
|
||||||
float t = s1/speed1;
|
float t = s1/speed1;
|
||||||
float s2 = speed2 * t;
|
float s2 = speed2 * t;
|
||||||
float t_swing = 0.17f/weapSpeed;//0.17 should be the time of playing weapon anim from 'start' to 'hit' tags
|
float t_swing = 0.17f/weapSpeed;//instead of 0.17 should be the time of playing weapon anim from 'start' to 'hit' tags
|
||||||
if (t + s2/speed1 <= t_swing)
|
if (t + s2/speed1 <= t_swing)
|
||||||
{
|
{
|
||||||
mReadyToAttack = true;
|
mReadyToAttack = true;
|
||||||
|
@ -326,24 +327,12 @@ namespace MWMechanics
|
||||||
start.mY = pos.pos[1];
|
start.mY = pos.pos[1];
|
||||||
start.mZ = pos.pos[2];
|
start.mZ = pos.pos[2];
|
||||||
|
|
||||||
const ESM::Pathgrid *pathgrid =
|
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*actor.getCell()->mCell);
|
|
||||||
|
|
||||||
float xCell = 0;
|
|
||||||
float yCell = 0;
|
|
||||||
|
|
||||||
if (actor.getCell()->mCell->isExterior())
|
|
||||||
{
|
|
||||||
xCell = actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE;
|
|
||||||
yCell = actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!mPathFinder.isPathConstructed())
|
if(!mPathFinder.isPathConstructed())
|
||||||
mPathFinder.buildPath(start, dest, pathgrid, xCell, yCell, isOutside);
|
mPathFinder.buildPath(start, dest, actor.getCell(), isOutside);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PathFinder newPathFinder;
|
PathFinder newPathFinder;
|
||||||
newPathFinder.buildPath(start, dest, pathgrid, xCell, yCell, isOutside);
|
newPathFinder.buildPath(start, dest, actor.getCell(), isOutside);
|
||||||
|
|
||||||
//TO EXPLORE:
|
//TO EXPLORE:
|
||||||
//maybe here is a mistake (?): PathFinder::getPathSize() returns number of grid points in the path,
|
//maybe here is a mistake (?): PathFinder::getPathSize() returns number of grid points in the path,
|
||||||
|
@ -421,4 +410,4 @@ void chooseBestAttack(const ESM::Weapon* weapon, MWMechanics::Movement &movement
|
||||||
movement.mPosition[1] = movement.mPosition[0] = 0;
|
movement.mPosition[1] = movement.mPosition[0] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,8 +28,8 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
AiEscort::AiEscort(const std::string &actorId, int duration, float x, float y, float z)
|
AiEscort::AiEscort(const std::string &actorId, int duration, float x, float y, float z)
|
||||||
: mActorId(actorId), mX(x), mY(y), mZ(z), mDuration(duration)
|
: mActorId(actorId), mX(x), mY(y), mZ(z), mDuration(duration)
|
||||||
, cellX(std::numeric_limits<int>::max())
|
, mCellX(std::numeric_limits<int>::max())
|
||||||
, cellY(std::numeric_limits<int>::max())
|
, mCellY(std::numeric_limits<int>::max())
|
||||||
{
|
{
|
||||||
mMaxDist = 470;
|
mMaxDist = 470;
|
||||||
|
|
||||||
|
@ -47,8 +47,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
AiEscort::AiEscort(const std::string &actorId, const std::string &cellId,int duration, float x, float y, float z)
|
AiEscort::AiEscort(const std::string &actorId, const std::string &cellId,int duration, float x, float y, float z)
|
||||||
: mActorId(actorId), mCellId(cellId), mX(x), mY(y), mZ(z), mDuration(duration)
|
: mActorId(actorId), mCellId(cellId), mX(x), mY(y), mZ(z), mDuration(duration)
|
||||||
, cellX(std::numeric_limits<int>::max())
|
, mCellX(std::numeric_limits<int>::max())
|
||||||
, cellY(std::numeric_limits<int>::max())
|
, mCellY(std::numeric_limits<int>::max())
|
||||||
{
|
{
|
||||||
mMaxDist = 470;
|
mMaxDist = 470;
|
||||||
|
|
||||||
|
@ -84,9 +84,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||||
ESM::Position pos = actor.getRefData().getPosition();
|
ESM::Position pos = actor.getRefData().getPosition();
|
||||||
bool cellChange = actor.getCell()->mCell->mData.mX != cellX || actor.getCell()->mCell->mData.mY != cellY;
|
bool cellChange = actor.getCell()->mCell->mData.mX != mCellX || actor.getCell()->mCell->mData.mY != mCellY;
|
||||||
const ESM::Pathgrid *pathgrid =
|
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*actor.getCell()->mCell);
|
|
||||||
|
|
||||||
if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX)
|
if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX)
|
||||||
{
|
{
|
||||||
|
@ -116,15 +114,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
if(!mPathFinder.isPathConstructed() || cellChange)
|
if(!mPathFinder.isPathConstructed() || cellChange)
|
||||||
{
|
{
|
||||||
cellX = actor.getCell()->mCell->mData.mX;
|
mCellX = actor.getCell()->mCell->mData.mX;
|
||||||
cellY = actor.getCell()->mCell->mData.mY;
|
mCellY = actor.getCell()->mCell->mData.mY;
|
||||||
float xCell = 0;
|
|
||||||
float yCell = 0;
|
|
||||||
if (actor.getCell()->mCell->isExterior())
|
|
||||||
{
|
|
||||||
xCell = actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE;
|
|
||||||
yCell = actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
ESM::Pathgrid::Point dest;
|
ESM::Pathgrid::Point dest;
|
||||||
dest.mX = mX;
|
dest.mX = mX;
|
||||||
|
@ -136,7 +127,7 @@ namespace MWMechanics
|
||||||
start.mY = pos.pos[1];
|
start.mY = pos.pos[1];
|
||||||
start.mZ = pos.pos[2];
|
start.mZ = pos.pos[2];
|
||||||
|
|
||||||
mPathFinder.buildPath(start, dest, pathgrid, xCell, yCell, true);
|
mPathFinder.buildPath(start, dest, actor.getCell(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2]))
|
if(mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2]))
|
||||||
|
|
|
@ -34,8 +34,8 @@ namespace MWMechanics
|
||||||
unsigned int mDuration;
|
unsigned int mDuration;
|
||||||
|
|
||||||
PathFinder mPathFinder;
|
PathFinder mPathFinder;
|
||||||
int cellX;
|
int mCellX;
|
||||||
int cellY;
|
int mCellY;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,27 +1,120 @@
|
||||||
#include "aifollow.hpp"
|
#include "aifollow.hpp"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include "../mwbase/world.hpp"
|
||||||
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwworld/class.hpp"
|
||||||
|
#include "movement.hpp"
|
||||||
|
|
||||||
|
#include <OgreMath.h>
|
||||||
|
|
||||||
MWMechanics::AiFollow::AiFollow(const std::string &actorId,float duration, float x, float y, float z)
|
MWMechanics::AiFollow::AiFollow(const std::string &actorId,float duration, float x, float y, float z)
|
||||||
: mDuration(duration), mX(x), mY(y), mZ(z), mActorId(actorId)
|
: mDuration(duration), mX(x), mY(y), mZ(z), mActorId(actorId), mCellId(""), mTimer(0), mStuckTimer(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
MWMechanics::AiFollow::AiFollow(const std::string &actorId,const std::string &cellId,float duration, float x, float y, float z)
|
MWMechanics::AiFollow::AiFollow(const std::string &actorId,const std::string &cellId,float duration, float x, float y, float z)
|
||||||
: mDuration(duration), mX(x), mY(y), mZ(z), mActorId(actorId), mCellId(cellId)
|
: mDuration(duration), mX(x), mY(y), mZ(z), mActorId(actorId), mCellId(cellId), mTimer(0), mStuckTimer(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor,float duration)
|
||||||
|
{
|
||||||
|
const MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr(mActorId, false);
|
||||||
|
|
||||||
|
mTimer = mTimer + duration;
|
||||||
|
mStuckTimer = mStuckTimer + duration;
|
||||||
|
mTotalTime = mTotalTime + duration;
|
||||||
|
|
||||||
|
ESM::Position pos = actor.getRefData().getPosition();
|
||||||
|
|
||||||
|
if(mTotalTime > mDuration && mDuration != 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if((pos.pos[0]-mX)*(pos.pos[0]-mX) +
|
||||||
|
(pos.pos[1]-mY)*(pos.pos[1]-mY) +
|
||||||
|
(pos.pos[2]-mZ)*(pos.pos[2]-mZ) < 100*100)
|
||||||
|
{
|
||||||
|
if(actor.getCell()->isExterior())
|
||||||
|
{
|
||||||
|
if(mCellId == "")
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(mCellId == actor.getCell()->mCell->mName)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ESM::Pathgrid::Point dest;
|
||||||
|
dest.mX = target.getRefData().getPosition().pos[0];
|
||||||
|
dest.mY = target.getRefData().getPosition().pos[1];
|
||||||
|
dest.mZ = target.getRefData().getPosition().pos[2];
|
||||||
|
|
||||||
|
ESM::Pathgrid::Point start;
|
||||||
|
start.mX = pos.pos[0];
|
||||||
|
start.mY = pos.pos[1];
|
||||||
|
start.mZ = pos.pos[2];
|
||||||
|
|
||||||
|
if(mPathFinder.getPath().empty())
|
||||||
|
mPathFinder.buildPath(start, dest, actor.getCell(), true);
|
||||||
|
|
||||||
|
|
||||||
|
if(mTimer > 0.25)
|
||||||
|
{
|
||||||
|
if(!mPathFinder.getPath().empty())
|
||||||
|
{
|
||||||
|
ESM::Pathgrid::Point lastPos = mPathFinder.getPath().back();
|
||||||
|
|
||||||
|
if((dest.mX - lastPos.mX)*(dest.mX - lastPos.mX)
|
||||||
|
+(dest.mY - lastPos.mY)*(dest.mY - lastPos.mY)
|
||||||
|
+(dest.mZ - lastPos.mZ)*(dest.mZ - lastPos.mZ)
|
||||||
|
> 100*100)
|
||||||
|
mPathFinder.addPointToPath(dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
mTimer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mStuckTimer>0.5)
|
||||||
|
{
|
||||||
|
if((mStuckPos.pos[0] - pos.pos[0])*(mStuckPos.pos[0] - pos.pos[0])
|
||||||
|
+(mStuckPos.pos[1] - pos.pos[1])*(mStuckPos.pos[1] - pos.pos[1])
|
||||||
|
+(mStuckPos.pos[2] - pos.pos[2])*(mStuckPos.pos[2] - pos.pos[2]) < 100) //NPC is stuck
|
||||||
|
mPathFinder.buildPath(start, dest, actor.getCell(), true);
|
||||||
|
|
||||||
|
mStuckTimer = 0;
|
||||||
|
mStuckPos = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2]))
|
||||||
|
{
|
||||||
|
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
|
||||||
|
//MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false);
|
||||||
|
MWWorld::Class::get(actor).getMovementSettings(actor).mRotation[2] = 10*(Ogre::Degree(zAngle).valueRadians()-pos.rot[2]);
|
||||||
|
//std::cout << Ogre::Degree(zAngle).valueDegrees()-Ogre::Radian(actor.getRefData().getPosition().rot[2]).valueDegrees() << " "<< pos.rot[2] << " " << zAngle << "\n";
|
||||||
|
//MWWorld::Class::get(actor).get
|
||||||
|
}
|
||||||
|
|
||||||
|
if((dest.mX - pos.pos[0])*(dest.mX - pos.pos[0])+(dest.mY - pos.pos[1])*(dest.mY - pos.pos[1])+(dest.mZ - pos.pos[2])*(dest.mZ - pos.pos[2])
|
||||||
|
< 100*100)
|
||||||
|
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
||||||
|
else
|
||||||
|
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string MWMechanics::AiFollow::getFollowedActor()
|
||||||
|
{
|
||||||
|
return mActorId;
|
||||||
|
}
|
||||||
|
|
||||||
MWMechanics::AiFollow *MWMechanics::AiFollow::clone() const
|
MWMechanics::AiFollow *MWMechanics::AiFollow::clone() const
|
||||||
{
|
{
|
||||||
return new AiFollow(*this);
|
return new AiFollow(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor,float duration)
|
|
||||||
{
|
|
||||||
std::cout << "AiFollow completed.\n";
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int MWMechanics::AiFollow::getTypeId() const
|
int MWMechanics::AiFollow::getTypeId() const
|
||||||
{
|
{
|
||||||
return TypeIdFollow;
|
return TypeIdFollow;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include "aipackage.hpp"
|
#include "aipackage.hpp"
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include "pathfinding.hpp"
|
||||||
|
#include "../../../components/esm/defs.hpp"
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
@ -17,6 +19,8 @@ namespace MWMechanics
|
||||||
///< \return Package completed?
|
///< \return Package completed?
|
||||||
virtual int getTypeId() const;
|
virtual int getTypeId() const;
|
||||||
|
|
||||||
|
std::string getFollowedActor();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float mDuration;
|
float mDuration;
|
||||||
float mX;
|
float mX;
|
||||||
|
@ -24,6 +28,14 @@ namespace MWMechanics
|
||||||
float mZ;
|
float mZ;
|
||||||
std::string mActorId;
|
std::string mActorId;
|
||||||
std::string mCellId;
|
std::string mCellId;
|
||||||
|
|
||||||
|
float mTimer;
|
||||||
|
float mStuckTimer;
|
||||||
|
float mTotalTime;
|
||||||
|
|
||||||
|
ESM::Position mStuckPos;
|
||||||
|
|
||||||
|
PathFinder mPathFinder;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -124,6 +124,14 @@ void MWMechanics::AiSequence::queue (const AiPackage& package)
|
||||||
mPackages.push_back (package.clone());
|
mPackages.push_back (package.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MWMechanics::AiPackage* MWMechanics::AiSequence::getActivePackage()
|
||||||
|
{
|
||||||
|
if(mPackages.empty())
|
||||||
|
throw std::runtime_error(std::string("No AI Package!"));
|
||||||
|
else
|
||||||
|
return mPackages.front();
|
||||||
|
}
|
||||||
|
|
||||||
void MWMechanics::AiSequence::fill(const ESM::AIPackageList &list)
|
void MWMechanics::AiSequence::fill(const ESM::AIPackageList &list)
|
||||||
{
|
{
|
||||||
for (std::vector<ESM::AIPackage>::const_iterator it = list.mList.begin(); it != list.mList.end(); ++it)
|
for (std::vector<ESM::AIPackage>::const_iterator it = list.mList.begin(); it != list.mList.end(); ++it)
|
||||||
|
|
|
@ -59,6 +59,9 @@ namespace MWMechanics
|
||||||
///< Add \a package to the end of the sequence (executed after all other packages have been
|
///< Add \a package to the end of the sequence (executed after all other packages have been
|
||||||
/// completed)
|
/// completed)
|
||||||
|
|
||||||
|
AiPackage* getActivePackage();
|
||||||
|
///< return the current active package. If there is no active package, throw an exeption
|
||||||
|
|
||||||
void fill (const ESM::AIPackageList& list);
|
void fill (const ESM::AIPackageList& list);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,20 +61,11 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ESM::Pathgrid *pathgrid = world->getStore().get<ESM::Pathgrid>().search(*cell);
|
|
||||||
bool cellChange = cell->mData.mX != cellX || cell->mData.mY != cellY;
|
bool cellChange = cell->mData.mX != cellX || cell->mData.mY != cellY;
|
||||||
if(!mPathFinder.isPathConstructed() || cellChange)
|
if(!mPathFinder.isPathConstructed() || cellChange)
|
||||||
{
|
{
|
||||||
cellX = cell->mData.mX;
|
cellX = cell->mData.mX;
|
||||||
cellY = cell->mData.mY;
|
cellY = cell->mData.mY;
|
||||||
float xCell = 0;
|
|
||||||
float yCell = 0;
|
|
||||||
|
|
||||||
if(cell->isExterior())
|
|
||||||
{
|
|
||||||
xCell = cell->mData.mX * ESM::Land::REAL_SIZE;
|
|
||||||
yCell = cell->mData.mY * ESM::Land::REAL_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
ESM::Pathgrid::Point dest;
|
ESM::Pathgrid::Point dest;
|
||||||
dest.mX = mX;
|
dest.mX = mX;
|
||||||
|
@ -86,7 +77,7 @@ namespace MWMechanics
|
||||||
start.mY = pos.pos[1];
|
start.mY = pos.pos[1];
|
||||||
start.mZ = pos.pos[2];
|
start.mZ = pos.pos[2];
|
||||||
|
|
||||||
mPathFinder.buildPath(start, dest, pathgrid, xCell, yCell, true);
|
mPathFinder.buildPath(start, dest, actor.getCell(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2]))
|
if(mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2]))
|
||||||
|
|
|
@ -260,7 +260,7 @@ namespace MWMechanics
|
||||||
start.mY = pos.pos[1];
|
start.mY = pos.pos[1];
|
||||||
start.mZ = pos.pos[2];
|
start.mZ = pos.pos[2];
|
||||||
|
|
||||||
mPathFinder.buildPath(start, dest, mPathgrid, mXCell, mYCell, false);
|
mPathFinder.buildPath(start, dest, actor.getCell(), false);
|
||||||
|
|
||||||
if(mPathFinder.isPathConstructed())
|
if(mPathFinder.isPathConstructed())
|
||||||
{
|
{
|
||||||
|
|
|
@ -956,4 +956,9 @@ namespace MWMechanics
|
||||||
mActors.getObjectsInRange(position, radius, objects);
|
mActors.getObjectsInRange(position, radius, objects);
|
||||||
mObjects.getObjectsInRange(position, radius, objects);
|
mObjects.getObjectsInRange(position, radius, objects);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::list<MWWorld::Ptr> MechanicsManager::getActorsFollowing(const MWWorld::Ptr& actor)
|
||||||
|
{
|
||||||
|
return mActors.getActorsFollowing(actor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -136,7 +136,9 @@ namespace MWMechanics
|
||||||
virtual void toggleAI();
|
virtual void toggleAI();
|
||||||
virtual bool isAIActive();
|
virtual bool isAIActive();
|
||||||
|
|
||||||
virtual void getObjectsInRange (const Ogre::Vector3& position, float radius, std::vector<MWWorld::Ptr>& objects);
|
virtual void getObjectsInRange (const Ogre::Vector3& position, float radius, std::vector<MWWorld::Ptr>& objects);
|
||||||
|
|
||||||
|
virtual std::list<MWWorld::Ptr> getActorsFollowing(const MWWorld::Ptr& actor);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,30 +7,10 @@
|
||||||
#include "OgreVector3.h"
|
#include "OgreVector3.h"
|
||||||
|
|
||||||
|
|
||||||
#include <boost/graph/dijkstra_shortest_paths.hpp>
|
#include <map>
|
||||||
#include <boost/graph/adjacency_list.hpp>
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
struct found_path {};
|
|
||||||
|
|
||||||
typedef boost::adjacency_list< boost::vecS, boost::vecS, boost::undirectedS,
|
|
||||||
boost::property<boost::vertex_index_t, int, ESM::Pathgrid::Point>, boost::property<boost::edge_weight_t, float> >
|
|
||||||
PathGridGraph;
|
|
||||||
typedef boost::property_map<PathGridGraph, boost::edge_weight_t>::type WeightMap;
|
|
||||||
typedef PathGridGraph::vertex_descriptor PointID;
|
|
||||||
typedef PathGridGraph::edge_descriptor PointConnectionID;
|
|
||||||
|
|
||||||
class goalVisited : public boost::default_dijkstra_visitor
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
goalVisited(PointID goal) {mGoal = goal;};
|
|
||||||
void examine_vertex(PointID u, const PathGridGraph g) {if(u == mGoal) throw found_path();};
|
|
||||||
|
|
||||||
private:
|
|
||||||
PointID mGoal;
|
|
||||||
};
|
|
||||||
|
|
||||||
float distanceZCorrected(ESM::Pathgrid::Point point, float x, float y, float z)
|
float distanceZCorrected(ESM::Pathgrid::Point point, float x, float y, float z)
|
||||||
{
|
{
|
||||||
x -= point.mX;
|
x -= point.mX;
|
||||||
|
@ -82,64 +62,104 @@ namespace
|
||||||
return closestIndex;
|
return closestIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid, float xCell = 0, float yCell = 0)
|
/*std::list<ESM::Pathgrid::Point> reconstructPath(const std::vector<MWMechanics::PathFinder::Node>& graph,const ESM::Pathgrid* pathgrid, int lastNode,float xCell, float yCell)
|
||||||
{
|
{
|
||||||
PathGridGraph graph;
|
std::list<ESM::Pathgrid::Point> path;
|
||||||
|
while(graph[lastNode].parent != -1)
|
||||||
for(unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++)
|
|
||||||
{
|
{
|
||||||
PointID pID = boost::add_vertex(graph);
|
//std::cout << "not empty" << xCell;
|
||||||
graph[pID].mX = pathgrid->mPoints[counter].mX + xCell;
|
ESM::Pathgrid::Point pt = pathgrid->mPoints[lastNode];
|
||||||
graph[pID].mY = pathgrid->mPoints[counter].mY + yCell;
|
pt.mX += xCell;
|
||||||
graph[pID].mZ = pathgrid->mPoints[counter].mZ;
|
pt.mY += yCell;
|
||||||
|
path.push_front(pt);
|
||||||
|
lastNode = graph[lastNode].parent;
|
||||||
}
|
}
|
||||||
|
return path;
|
||||||
|
}*/
|
||||||
|
|
||||||
for(unsigned int counterTwo = 0; counterTwo < pathgrid->mEdges.size(); counterTwo++)
|
|
||||||
{
|
|
||||||
PointID u = pathgrid->mEdges[counterTwo].mV0;
|
|
||||||
PointID v = pathgrid->mEdges[counterTwo].mV1;
|
|
||||||
|
|
||||||
PointConnectionID edge;
|
|
||||||
bool done;
|
|
||||||
boost::tie(edge, done) = boost::add_edge(u, v, graph);
|
|
||||||
WeightMap weightmap = boost::get(boost::edge_weight, graph);
|
|
||||||
weightmap[edge] = distance(graph[u], graph[v]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return graph;
|
/*std::list<ESM::Pathgrid::Point> buildPath2(const ESM::Pathgrid* pathgrid,int start,int goal,float xCell = 0, float yCell = 0)
|
||||||
}
|
|
||||||
|
|
||||||
std::list<ESM::Pathgrid::Point> findPath(PointID start, PointID end, PathGridGraph graph)
|
|
||||||
{
|
{
|
||||||
std::vector<PointID> p(boost::num_vertices(graph));
|
std::vector<Node> graph;
|
||||||
std::vector<float> d(boost::num_vertices(graph));
|
for(unsigned int i = 0; i < pathgrid->mPoints.size(); i++)
|
||||||
std::list<ESM::Pathgrid::Point> shortest_path;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
boost::dijkstra_shortest_paths(graph, start,
|
Node node;
|
||||||
boost::predecessor_map(&p[0]).distance_map(&d[0]).visitor(goalVisited(end)));
|
node.label = i;
|
||||||
|
node.parent = -1;
|
||||||
|
graph.push_back(node);
|
||||||
|
}
|
||||||
|
for(unsigned int i = 0; i < pathgrid->mEdges.size(); i++)
|
||||||
|
{
|
||||||
|
Edge edge;
|
||||||
|
edge.destination = pathgrid->mEdges[i].mV1;
|
||||||
|
edge.cost = distance(pathgrid->mPoints[pathgrid->mEdges[i].mV0],pathgrid->mPoints[pathgrid->mEdges[i].mV1]);
|
||||||
|
graph[pathgrid->mEdges[i].mV0].edges.push_back(edge);
|
||||||
|
edge.destination = pathgrid->mEdges[i].mV0;
|
||||||
|
graph[pathgrid->mEdges[i].mV1].edges.push_back(edge);
|
||||||
}
|
}
|
||||||
|
|
||||||
catch(found_path& fg)
|
std::vector<float> g_score(pathgrid->mPoints.size(),-1.);
|
||||||
|
std::vector<float> f_score(pathgrid->mPoints.size(),-1.);
|
||||||
|
|
||||||
|
g_score[start] = 0;
|
||||||
|
f_score[start] = distance(pathgrid->mPoints[start],pathgrid->mPoints[goal]);
|
||||||
|
|
||||||
|
std::list<int> openset;
|
||||||
|
std::list<int> closedset;
|
||||||
|
openset.push_back(start);
|
||||||
|
|
||||||
|
int current = -1;
|
||||||
|
|
||||||
|
while(!openset.empty())
|
||||||
{
|
{
|
||||||
for(PointID v = end; ; v = p[v])
|
current = openset.front();
|
||||||
|
openset.pop_front();
|
||||||
|
|
||||||
|
if(current == goal) break;
|
||||||
|
|
||||||
|
closedset.push_back(current);
|
||||||
|
|
||||||
|
for(int j = 0;j<graph[current].edges.size();j++)
|
||||||
{
|
{
|
||||||
shortest_path.push_front(graph[v]);
|
//int next = graph[current].edges[j].destination
|
||||||
if(p[v] == v)
|
if(std::find(closedset.begin(),closedset.end(),graph[current].edges[j].destination) == closedset.end())
|
||||||
break;
|
{
|
||||||
|
int dest = graph[current].edges[j].destination;
|
||||||
|
float tentative_g = g_score[current] + graph[current].edges[j].cost;
|
||||||
|
bool isInOpenSet = std::find(openset.begin(),openset.end(),dest) != openset.end();
|
||||||
|
if(!isInOpenSet
|
||||||
|
|| tentative_g < g_score[dest] )
|
||||||
|
{
|
||||||
|
graph[dest].parent = current;
|
||||||
|
g_score[dest] = tentative_g;
|
||||||
|
f_score[dest] = tentative_g + distance(pathgrid->mPoints[dest],pathgrid->mPoints[goal]);
|
||||||
|
if(!isInOpenSet)
|
||||||
|
{
|
||||||
|
std::list<int>::iterator it = openset.begin();
|
||||||
|
for(it = openset.begin();it!= openset.end();it++)
|
||||||
|
{
|
||||||
|
if(g_score[*it]>g_score[dest])
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
openset.insert(it,dest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return shortest_path;
|
}
|
||||||
}
|
return reconstructPath(graph,pathgrid,current,xCell,yCell);
|
||||||
|
|
||||||
|
}*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
PathFinder::PathFinder()
|
PathFinder::PathFinder()
|
||||||
|
:mIsPathConstructed(false),mIsGraphConstructed(false)
|
||||||
{
|
{
|
||||||
mIsPathConstructed = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PathFinder::clearPath()
|
void PathFinder::clearPath()
|
||||||
|
@ -149,10 +169,124 @@ namespace MWMechanics
|
||||||
mIsPathConstructed = false;
|
mIsPathConstructed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PathFinder::buildPathgridGraph(const ESM::Pathgrid* pathGrid)
|
||||||
|
{
|
||||||
|
mGraph.clear();
|
||||||
|
mGScore.resize(pathGrid->mPoints.size(),-1);
|
||||||
|
mFScore.resize(pathGrid->mPoints.size(),-1);
|
||||||
|
Node defaultNode;
|
||||||
|
defaultNode.label = -1;
|
||||||
|
defaultNode.parent = -1;
|
||||||
|
mGraph.resize(pathGrid->mPoints.size(),defaultNode);
|
||||||
|
for(unsigned int i = 0; i < pathGrid->mPoints.size(); i++)
|
||||||
|
{
|
||||||
|
Node node;
|
||||||
|
node.label = i;
|
||||||
|
node.parent = -1;
|
||||||
|
mGraph[i] = node;
|
||||||
|
}
|
||||||
|
for(unsigned int i = 0; i < pathGrid->mEdges.size(); i++)
|
||||||
|
{
|
||||||
|
Edge edge;
|
||||||
|
edge.destination = pathGrid->mEdges[i].mV1;
|
||||||
|
edge.cost = distance(pathGrid->mPoints[pathGrid->mEdges[i].mV0],pathGrid->mPoints[pathGrid->mEdges[i].mV1]);
|
||||||
|
mGraph[pathGrid->mEdges[i].mV0].edges.push_back(edge);
|
||||||
|
edge.destination = pathGrid->mEdges[i].mV0;
|
||||||
|
mGraph[pathGrid->mEdges[i].mV1].edges.push_back(edge);
|
||||||
|
}
|
||||||
|
mIsGraphConstructed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PathFinder::cleanUpAStar()
|
||||||
|
{
|
||||||
|
for(int i=0;i<static_cast<int> (mGraph.size());i++)
|
||||||
|
{
|
||||||
|
mGraph[i].parent = -1;
|
||||||
|
mGScore[i] = -1;
|
||||||
|
mFScore[i] = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::list<ESM::Pathgrid::Point> PathFinder::aStarSearch(const ESM::Pathgrid* pathGrid,int start,int goal,float xCell, float yCell)
|
||||||
|
{
|
||||||
|
cleanUpAStar();
|
||||||
|
mGScore[start] = 0;
|
||||||
|
mFScore[start] = distance(pathGrid->mPoints[start],pathGrid->mPoints[goal]);
|
||||||
|
|
||||||
|
std::list<int> openset;
|
||||||
|
std::list<int> closedset;
|
||||||
|
openset.push_back(start);
|
||||||
|
|
||||||
|
int current = -1;
|
||||||
|
|
||||||
|
while(!openset.empty())
|
||||||
|
{
|
||||||
|
current = openset.front();
|
||||||
|
openset.pop_front();
|
||||||
|
|
||||||
|
if(current == goal) break;
|
||||||
|
|
||||||
|
closedset.push_back(current);
|
||||||
|
|
||||||
|
for(int j = 0;j<static_cast<int> (mGraph[current].edges.size());j++)
|
||||||
|
{
|
||||||
|
//int next = mGraph[current].edges[j].destination
|
||||||
|
if(std::find(closedset.begin(),closedset.end(),mGraph[current].edges[j].destination) == closedset.end())
|
||||||
|
{
|
||||||
|
int dest = mGraph[current].edges[j].destination;
|
||||||
|
float tentative_g = mGScore[current] + mGraph[current].edges[j].cost;
|
||||||
|
bool isInOpenSet = std::find(openset.begin(),openset.end(),dest) != openset.end();
|
||||||
|
if(!isInOpenSet
|
||||||
|
|| tentative_g < mGScore[dest] )
|
||||||
|
{
|
||||||
|
mGraph[dest].parent = current;
|
||||||
|
mGScore[dest] = tentative_g;
|
||||||
|
mFScore[dest] = tentative_g + distance(pathGrid->mPoints[dest],pathGrid->mPoints[goal]);
|
||||||
|
if(!isInOpenSet)
|
||||||
|
{
|
||||||
|
std::list<int>::iterator it = openset.begin();
|
||||||
|
for(it = openset.begin();it!= openset.end();it++)
|
||||||
|
{
|
||||||
|
if(mGScore[*it]>mGScore[dest])
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
openset.insert(it,dest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::list<ESM::Pathgrid::Point> path;
|
||||||
|
while(mGraph[current].parent != -1)
|
||||||
|
{
|
||||||
|
//std::cout << "not empty" << xCell;
|
||||||
|
ESM::Pathgrid::Point pt = pathGrid->mPoints[current];
|
||||||
|
pt.mX += xCell;
|
||||||
|
pt.mY += yCell;
|
||||||
|
path.push_front(pt);
|
||||||
|
current = mGraph[current].parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(path.empty())
|
||||||
|
{
|
||||||
|
ESM::Pathgrid::Point pt = pathGrid->mPoints[goal];
|
||||||
|
pt.mX += xCell;
|
||||||
|
pt.mY += yCell;
|
||||||
|
path.push_front(pt);
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
void PathFinder::buildPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint,
|
void PathFinder::buildPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint,
|
||||||
const ESM::Pathgrid *pathGrid, float xCell, float yCell, bool allowShortcuts)
|
const MWWorld::CellStore* cell, bool allowShortcuts)
|
||||||
{
|
{
|
||||||
mPath.clear();
|
mPath.clear();
|
||||||
|
if(mCell != cell) mIsGraphConstructed = false;
|
||||||
|
mCell = cell;
|
||||||
|
|
||||||
if(allowShortcuts)
|
if(allowShortcuts)
|
||||||
{
|
{
|
||||||
if(MWBase::Environment::get().getWorld()->castRay(startPoint.mX, startPoint.mY, startPoint.mZ,
|
if(MWBase::Environment::get().getWorld()->castRay(startPoint.mX, startPoint.mY, startPoint.mZ,
|
||||||
|
@ -162,13 +296,24 @@ namespace MWMechanics
|
||||||
|
|
||||||
if(!allowShortcuts)
|
if(!allowShortcuts)
|
||||||
{
|
{
|
||||||
|
const ESM::Pathgrid *pathGrid =
|
||||||
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*mCell->mCell);
|
||||||
|
float xCell = 0;
|
||||||
|
float yCell = 0;
|
||||||
|
|
||||||
|
if (mCell->isExterior())
|
||||||
|
{
|
||||||
|
xCell = mCell->mCell->mData.mX * ESM::Land::REAL_SIZE;
|
||||||
|
yCell = mCell->mCell->mData.mY * ESM::Land::REAL_SIZE;
|
||||||
|
}
|
||||||
int startNode = getClosestPoint(pathGrid, startPoint.mX - xCell, startPoint.mY - yCell,startPoint.mZ);
|
int startNode = getClosestPoint(pathGrid, startPoint.mX - xCell, startPoint.mY - yCell,startPoint.mZ);
|
||||||
int endNode = getClosestPoint(pathGrid, endPoint.mX - xCell, endPoint.mY - yCell, endPoint.mZ);
|
int endNode = getClosestPoint(pathGrid, endPoint.mX - xCell, endPoint.mY - yCell, endPoint.mZ);
|
||||||
|
|
||||||
if(startNode != -1 && endNode != -1)
|
if(startNode != -1 && endNode != -1)
|
||||||
{
|
{
|
||||||
PathGridGraph graph = buildGraph(pathGrid, xCell, yCell);
|
if(!mIsGraphConstructed) buildPathgridGraph(pathGrid);
|
||||||
mPath = findPath(startNode, endNode, graph);
|
|
||||||
|
mPath = aStarSearch(pathGrid,startNode,endNode,xCell,yCell);//findPath(startNode, endNode, mGraph);
|
||||||
|
|
||||||
if(!mPath.empty())
|
if(!mPath.empty())
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,6 +3,12 @@
|
||||||
|
|
||||||
#include <components/esm/loadpgrd.hpp>
|
#include <components/esm/loadpgrd.hpp>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
#include <boost/graph/adjacency_list.hpp>
|
||||||
|
|
||||||
|
namespace MWWorld
|
||||||
|
{
|
||||||
|
class CellStore;
|
||||||
|
}
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
@ -12,9 +18,11 @@ namespace MWMechanics
|
||||||
PathFinder();
|
PathFinder();
|
||||||
|
|
||||||
void clearPath();
|
void clearPath();
|
||||||
|
|
||||||
|
void buildPathgridGraph(const ESM::Pathgrid* pathGrid);
|
||||||
|
|
||||||
void buildPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint,
|
void buildPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint,
|
||||||
const ESM::Pathgrid* pathGrid, float xCell = 0, float yCell = 0,
|
const MWWorld::CellStore* cell, bool allowShortcuts = true);
|
||||||
bool allowShortcuts = true);
|
|
||||||
|
|
||||||
bool checkPathCompleted(float x, float y, float z);
|
bool checkPathCompleted(float x, float y, float z);
|
||||||
///< \Returns true if the last point of the path has been reached.
|
///< \Returns true if the last point of the path has been reached.
|
||||||
|
@ -44,9 +52,38 @@ namespace MWMechanics
|
||||||
//This functions deletes that point.
|
//This functions deletes that point.
|
||||||
void syncStart(const std::list<ESM::Pathgrid::Point> &path);
|
void syncStart(const std::list<ESM::Pathgrid::Point> &path);
|
||||||
|
|
||||||
|
void addPointToPath(ESM::Pathgrid::Point &point)
|
||||||
|
{
|
||||||
|
mPath.push_back(point);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::list<ESM::Pathgrid::Point> mPath;
|
|
||||||
|
struct Edge
|
||||||
|
{
|
||||||
|
int destination;
|
||||||
|
float cost;
|
||||||
|
};
|
||||||
|
struct Node
|
||||||
|
{
|
||||||
|
int label;
|
||||||
|
std::vector<Edge> edges;
|
||||||
|
int parent;//used in pathfinding
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<float> mGScore;
|
||||||
|
std::vector<float> mFScore;
|
||||||
|
|
||||||
|
std::list<ESM::Pathgrid::Point> aStarSearch(const ESM::Pathgrid* pathGrid,int start,int goal,float xCell = 0, float yCell = 0);
|
||||||
|
void cleanUpAStar();
|
||||||
|
|
||||||
|
std::vector<Node> mGraph;
|
||||||
bool mIsPathConstructed;
|
bool mIsPathConstructed;
|
||||||
|
|
||||||
|
|
||||||
|
std::list<ESM::Pathgrid::Point> mPath;
|
||||||
|
bool mIsGraphConstructed;
|
||||||
|
const MWWorld::CellStore* mCell;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
#include "../mwbase/mechanicsmanager.hpp"
|
||||||
#include "player.hpp"
|
#include "player.hpp"
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
|
@ -16,11 +17,35 @@ namespace MWWorld
|
||||||
void ActionTeleport::executeImp (const Ptr& actor)
|
void ActionTeleport::executeImp (const Ptr& actor)
|
||||||
{
|
{
|
||||||
MWBase::World* world = MWBase::Environment::get().getWorld();
|
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||||
world->getPlayer().setTeleported(true);
|
|
||||||
|
|
||||||
if (mCellName.empty())
|
//find any NPC that is following the actor and teleport him too
|
||||||
world->changeToExteriorCell (mPosition);
|
std::list<MWWorld::Ptr> followers = MWBase::Environment::get().getMechanicsManager()->getActorsFollowing(actor);
|
||||||
|
for(std::list<MWWorld::Ptr>::iterator it = followers.begin();it != followers.end();it++)
|
||||||
|
{
|
||||||
|
std::cout << "teleporting someone!" << (*it).getCellRef().mRefID;
|
||||||
|
executeImp(*it);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(actor == world->getPlayerPtr())
|
||||||
|
{
|
||||||
|
world->getPlayer().setTeleported(true);
|
||||||
|
if (mCellName.empty())
|
||||||
|
world->changeToExteriorCell (mPosition);
|
||||||
|
else
|
||||||
|
world->changeToInteriorCell (mCellName, mPosition);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
world->changeToInteriorCell (mCellName, mPosition);
|
{
|
||||||
|
if (mCellName.empty())
|
||||||
|
{
|
||||||
|
int cellX;
|
||||||
|
int cellY;
|
||||||
|
world->positionToIndex(mPosition.pos[0],mPosition.pos[1],cellX,cellY);
|
||||||
|
world->moveObject(actor,*world->getExterior(cellX,cellY),
|
||||||
|
mPosition.pos[0],mPosition.pos[1],mPosition.pos[2]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
world->moveObject(actor,*world->getInterior(mCellName),mPosition.pos[0],mPosition.pos[1],mPosition.pos[2]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue