mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-21 06:53:53 +00:00
Merge remote-tracking branch 'upstream/master' into versioninfo
This commit is contained in:
commit
f263acdac6
276 changed files with 8183 additions and 2355 deletions
|
@ -236,7 +236,9 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info)
|
|||
// Loop through all the references
|
||||
ESM::CellRef ref;
|
||||
if(!quiet) std::cout << " References:\n";
|
||||
while(cell.getNextRef(esm, ref))
|
||||
|
||||
bool deleted = false;
|
||||
while(cell.getNextRef(esm, ref, deleted))
|
||||
{
|
||||
if (save) {
|
||||
info.data.mCellRefs[&cell].push_back(ref);
|
||||
|
@ -244,13 +246,14 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info)
|
|||
|
||||
if(quiet) continue;
|
||||
|
||||
std::cout << " Refnum: " << ref.mRefnum << std::endl;
|
||||
std::cout << " Refnum: " << ref.mRefNum.mIndex << std::endl;
|
||||
std::cout << " ID: '" << ref.mRefID << "'\n";
|
||||
std::cout << " Owner: '" << ref.mOwner << "'\n";
|
||||
std::cout << " Enchantment charge: '" << ref.mEnchantmentCharge << "'\n";
|
||||
std::cout << " Uses/health: '" << ref.mCharge << "'\n";
|
||||
std::cout << " Gold value: '" << ref.mGoldValue << "'\n";
|
||||
std::cout << " Blocked: '" << static_cast<int>(ref.mReferenceBlocked) << "'" << std::endl;
|
||||
std::cout << " Deleted: " << deleted << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -133,16 +133,10 @@ void CSMDoc::WriteDialogueCollectionStage::perform (int stage, std::vector<std::
|
|||
state==CSMWorld::RecordBase::State_ModifiedOnly ||
|
||||
infoModified)
|
||||
{
|
||||
// always write the topic record
|
||||
std::string type;
|
||||
for (int i=0; i<4; ++i)
|
||||
/// \todo make endianess agnostic (change ESMWriter interface?)
|
||||
type += reinterpret_cast<const char *> (&topic.mModified.sRecordId)[i];
|
||||
|
||||
mState.getWriter().startRecord (type);
|
||||
mState.getWriter().startRecord (topic.mModified.sRecordId);
|
||||
mState.getWriter().writeHNCString ("NAME", topic.mModified.mId);
|
||||
topic.mModified.save (mState.getWriter());
|
||||
mState.getWriter().endRecord (type);
|
||||
mState.getWriter().endRecord (topic.mModified.sRecordId);
|
||||
|
||||
// write modified selected info records
|
||||
for (CSMWorld::InfoCollection::RecordConstIterator iter (range.first); iter!=range.second;
|
||||
|
@ -178,15 +172,10 @@ void CSMDoc::WriteDialogueCollectionStage::perform (int stage, std::vector<std::
|
|||
next->mModified.mId.substr (next->mModified.mId.find_last_of ('#')+1);
|
||||
}
|
||||
|
||||
std::string type;
|
||||
for (int i=0; i<4; ++i)
|
||||
/// \todo make endianess agnostic (change ESMWriter interface?)
|
||||
type += reinterpret_cast<const char *> (&info.sRecordId)[i];
|
||||
|
||||
mState.getWriter().startRecord (type);
|
||||
mState.getWriter().startRecord (info.sRecordId);
|
||||
mState.getWriter().writeHNCString ("INAM", info.mId);
|
||||
info.save (mState.getWriter());
|
||||
mState.getWriter().endRecord (type);
|
||||
mState.getWriter().endRecord (info.sRecordId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -104,10 +104,10 @@ namespace CSMDoc
|
|||
/// \todo make endianess agnostic (change ESMWriter interface?)
|
||||
type += reinterpret_cast<const char *> (&mCollection.getRecord (stage).mModified.sRecordId)[i];
|
||||
|
||||
mState.getWriter().startRecord (type);
|
||||
mState.getWriter().startRecord (mCollection.getRecord (stage).mModified.sRecordId);
|
||||
mState.getWriter().writeHNCString ("NAME", mCollection.getId (stage));
|
||||
mCollection.getRecord (stage).mModified.save (mState.getWriter());
|
||||
mState.getWriter().endRecord (type);
|
||||
mState.getWriter().endRecord (mCollection.getRecord (stage).mModified.sRecordId);
|
||||
}
|
||||
else if (state==CSMWorld::RecordBase::State_Deleted)
|
||||
{
|
||||
|
|
|
@ -98,6 +98,10 @@ namespace CSMWorld
|
|||
UniversalId::Type type = UniversalId::Type_None);
|
||||
///< \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;
|
||||
////< Search record with \a id.
|
||||
/// \return index of record (if found) or -1 (not found)
|
||||
|
@ -193,6 +197,19 @@ namespace CSMWorld
|
|||
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>
|
||||
Collection<ESXRecordT, IdAccessorT>::Collection()
|
||||
{}
|
||||
|
|
|
@ -74,6 +74,10 @@ namespace CSMWorld
|
|||
UniversalId::Type type = UniversalId::Type_None) = 0;
|
||||
///< 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 (int index) const = 0;
|
||||
|
|
|
@ -4,10 +4,10 @@
|
|||
#include <QAbstractItemModel>
|
||||
|
||||
#include "idtable.hpp"
|
||||
#include "idtable.hpp"
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
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_)
|
||||
{
|
||||
mOld = mModel.data (mIndex, Qt::EditRole);
|
||||
|
@ -25,7 +25,7 @@ void CSMWorld::ModifyCommand::undo()
|
|||
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)
|
||||
{
|
||||
setText (("Create record " + id).c_str());
|
||||
|
@ -54,7 +54,7 @@ void CSMWorld::CreateCommand::undo()
|
|||
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)
|
||||
{
|
||||
setText (("Revert record " + id).c_str());
|
||||
|
@ -89,7 +89,7 @@ void CSMWorld::RevertCommand::undo()
|
|||
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)
|
||||
{
|
||||
setText (("Delete record " + id).c_str());
|
||||
|
@ -126,7 +126,7 @@ void CSMWorld::DeleteCommand::undo()
|
|||
|
||||
|
||||
CSMWorld::ReorderRowsCommand::ReorderRowsCommand (IdTable& model, int baseIndex,
|
||||
const std::vector<int>& newOrder)
|
||||
const std::vector<int>& newOrder)
|
||||
: mModel (model), mBaseIndex (baseIndex), mNewOrder (newOrder)
|
||||
{}
|
||||
|
||||
|
@ -140,8 +140,35 @@ void CSMWorld::ReorderRowsCommand::undo()
|
|||
int size = static_cast<int> (mNewOrder.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;
|
||||
|
||||
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();
|
||||
};
|
||||
|
||||
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
|
||||
{
|
||||
IdTable& mModel;
|
||||
|
|
|
@ -154,14 +154,17 @@ CSMWorld::Data::Data() : mRefs (mCells)
|
|||
|
||||
mTopics.addColumn (new StringIdColumn<ESM::Dialogue>);
|
||||
mTopics.addColumn (new RecordStateColumn<ESM::Dialogue>);
|
||||
mTopics.addColumn (new FixedRecordTypeColumn<ESM::Dialogue> (UniversalId::Type_Topic));
|
||||
mTopics.addColumn (new DialogueTypeColumn<ESM::Dialogue>);
|
||||
|
||||
mJournals.addColumn (new StringIdColumn<ESM::Dialogue>);
|
||||
mJournals.addColumn (new RecordStateColumn<ESM::Dialogue>);
|
||||
mJournals.addColumn (new FixedRecordTypeColumn<ESM::Dialogue> (UniversalId::Type_Journal));
|
||||
mJournals.addColumn (new DialogueTypeColumn<ESM::Dialogue> (true));
|
||||
|
||||
mTopicInfos.addColumn (new StringIdColumn<Info> (true));
|
||||
mTopicInfos.addColumn (new RecordStateColumn<Info>);
|
||||
mTopicInfos.addColumn (new FixedRecordTypeColumn<Info> (UniversalId::Type_TopicInfo));
|
||||
mTopicInfos.addColumn (new TopicColumn<Info> (false));
|
||||
mTopicInfos.addColumn (new ActorColumn<Info>);
|
||||
mTopicInfos.addColumn (new RaceColumn<Info>);
|
||||
|
@ -178,6 +181,7 @@ CSMWorld::Data::Data() : mRefs (mCells)
|
|||
|
||||
mJournalInfos.addColumn (new StringIdColumn<Info> (true));
|
||||
mJournalInfos.addColumn (new RecordStateColumn<Info>);
|
||||
mJournalInfos.addColumn (new FixedRecordTypeColumn<Info> (UniversalId::Type_Journal));
|
||||
mJournalInfos.addColumn (new TopicColumn<Info> (true));
|
||||
mJournalInfos.addColumn (new QuestStatusTypeColumn<Info>);
|
||||
mJournalInfos.addColumn (new QuestIndexColumn<Info>);
|
||||
|
@ -194,6 +198,7 @@ CSMWorld::Data::Data() : mRefs (mCells)
|
|||
|
||||
mRefs.addColumn (new StringIdColumn<CellRef> (true));
|
||||
mRefs.addColumn (new RecordStateColumn<CellRef>);
|
||||
mRefs.addColumn (new FixedRecordTypeColumn<CellRef> (UniversalId::Type_Reference));
|
||||
mRefs.addColumn (new CellColumn<CellRef>);
|
||||
mRefs.addColumn (new IdColumn<CellRef>);
|
||||
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 RecordStateColumn<CSMFilter::Filter>);
|
||||
mFilters.addColumn (new FixedRecordTypeColumn<CSMFilter::Filter> (UniversalId::Type_Filter));
|
||||
mFilters.addColumn (new FilterColumn<CSMFilter::Filter>);
|
||||
mFilters.addColumn (new DescriptionColumn<CSMFilter::Filter>);
|
||||
mFilters.addColumn (new ScopeColumn<CSMFilter::Filter>);
|
||||
|
|
|
@ -124,6 +124,17 @@ void CSMWorld::IdTable::addRecord (const std::string& id, UniversalId::Type type
|
|||
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
|
||||
{
|
||||
return index (mIdCollection->getIndex (id), column);
|
||||
|
|
|
@ -63,6 +63,10 @@ namespace CSMWorld
|
|||
void addRecord (const std::string& id, UniversalId::Type type = UniversalId::Type_None);
|
||||
///< \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;
|
||||
|
||||
void setRecord (const std::string& id, const RecordBase& record);
|
||||
|
|
|
@ -8,6 +8,5 @@ void CSMWorld::CellRef::load (ESM::ESMReader &esm, Cell& cell, const std::string
|
|||
mId = id;
|
||||
mCell = cell.mId;
|
||||
|
||||
if (!mDeleted)
|
||||
cell.addRef (mId);
|
||||
cell.addRef (mId);
|
||||
}
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
#include "ref.hpp"
|
||||
#include "cell.hpp"
|
||||
#include "universalid.hpp"
|
||||
#include "record.hpp"
|
||||
|
||||
void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool base)
|
||||
{
|
||||
|
@ -14,7 +16,8 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool
|
|||
|
||||
CellRef ref;
|
||||
|
||||
while (cell2.getNextRef (reader, ref))
|
||||
bool deleted = false;
|
||||
while (cell2.getNextRef (reader, ref, deleted))
|
||||
{
|
||||
/// \todo handle deleted and moved references
|
||||
ref.load (reader, cell2, getNewId());
|
||||
|
@ -34,4 +37,15 @@ std::string CSMWorld::RefCollection::getNewId()
|
|||
std::ostringstream stream;
|
||||
stream << "ref#" << mNextId++;
|
||||
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
|
||||
{
|
||||
struct Cell;
|
||||
struct UniversalId;
|
||||
|
||||
/// \brief References in cells
|
||||
class RefCollection : public Collection<CellRef>
|
||||
|
@ -25,6 +26,11 @@ namespace CSMWorld
|
|||
///< Load a sequence of references.
|
||||
|
||||
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.
|
||||
|
||||
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);
|
||||
|
||||
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)
|
||||
const;
|
||||
|
@ -50,6 +52,12 @@ namespace CSMWorld
|
|||
: 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>
|
||||
std::string BaseRefIdAdapter<RecordT>::getId (const RecordBase& record) const
|
||||
{
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "refidcollection.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <memory>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
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,
|
||||
UniversalId::Type type)
|
||||
{
|
||||
|
|
|
@ -69,6 +69,10 @@ namespace CSMWorld
|
|||
|
||||
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);
|
||||
///< \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
|
||||
{
|
||||
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 void appendRecord (const std::string& id) = 0;
|
||||
|
||||
virtual void insertRecord (RecordBase& record) = 0;
|
||||
|
||||
virtual void load (int index, ESM::ESMReader& reader, bool base) = 0;
|
||||
|
||||
|
@ -68,6 +70,8 @@ namespace CSMWorld
|
|||
virtual RecordBase& getRecord (int index);
|
||||
|
||||
virtual void appendRecord (const std::string& id);
|
||||
|
||||
virtual void insertRecord (RecordBase& record);
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
template<typename RecordT>
|
||||
void RefIdDataContainer<RecordT>::insertRecord(RecordBase& record)
|
||||
{
|
||||
Record<RecordT>& newRecord = dynamic_cast<Record<RecordT>& >(record);
|
||||
mContainer.push_back(newRecord);
|
||||
}
|
||||
|
||||
template<typename RecordT>
|
||||
int RefIdDataContainer<RecordT>::getSize() const
|
||||
{
|
||||
|
@ -136,15 +147,10 @@ namespace CSMWorld
|
|||
if (state==CSMWorld::RecordBase::State_Modified ||
|
||||
state==CSMWorld::RecordBase::State_ModifiedOnly)
|
||||
{
|
||||
std::string type;
|
||||
for (int i=0; i<4; ++i)
|
||||
/// \todo make endianess agnostic (change ESMWriter interface?)
|
||||
type += reinterpret_cast<const char *> (&mContainer.at (index).mModified.sRecordId)[i];
|
||||
|
||||
writer.startRecord (type);
|
||||
writer.startRecord (mContainer.at (index).mModified.sRecordId);
|
||||
writer.writeHNCString ("NAME", getId (index));
|
||||
mContainer.at (index).mModified.save (writer);
|
||||
writer.endRecord (type);
|
||||
writer.endRecord (mContainer.at (index).mModified.sRecordId);
|
||||
}
|
||||
else if (state==CSMWorld::RecordBase::State_Deleted)
|
||||
{
|
||||
|
@ -200,6 +206,8 @@ namespace CSMWorld
|
|||
LocalIndex searchId (const std::string& id) const;
|
||||
|
||||
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;
|
||||
|
||||
|
|
|
@ -61,6 +61,7 @@ void CSVWorld::CellCreator::reset()
|
|||
mX->setValue (0);
|
||||
mY->setValue (0);
|
||||
mType->setCurrentIndex (0);
|
||||
setType(0);
|
||||
GenericCreator::reset();
|
||||
}
|
||||
|
||||
|
@ -78,4 +79,25 @@ void CSVWorld::CellCreator::setType (int index)
|
|||
void CSVWorld::CellCreator::valueChanged (int index)
|
||||
{
|
||||
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 toggleWidgets(bool active = true);
|
||||
|
||||
virtual void cloneMode(const std::string& originId,
|
||||
const CSMWorld::UniversalId::Type type);
|
||||
|
||||
private slots:
|
||||
|
||||
void setType (int index);
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define CSV_WORLD_CREATOR_H
|
||||
|
||||
#include <QWidget>
|
||||
#include "../../model/world/universalid.hpp"
|
||||
|
||||
class QUndoStack;
|
||||
|
||||
|
@ -24,8 +25,13 @@ namespace CSVWorld
|
|||
|
||||
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 toggleWidgets(bool active = true) = 0;
|
||||
|
||||
signals:
|
||||
|
||||
void done();
|
||||
|
|
|
@ -57,8 +57,15 @@ const CSMWorld::UniversalId& CSVWorld::GenericCreator::getCollectionId() const
|
|||
}
|
||||
|
||||
CSVWorld::GenericCreator::GenericCreator (CSMWorld::Data& data, QUndoStack& undoStack,
|
||||
const CSMWorld::UniversalId& id, bool relaxedIdRules)
|
||||
: mData (data), mUndoStack (undoStack), mListId (id), mLocked (false)
|
||||
const CSMWorld::UniversalId& id, bool relaxedIdRules):
|
||||
|
||||
mData (data),
|
||||
mUndoStack (undoStack),
|
||||
mListId (id),
|
||||
mLocked (false),
|
||||
mCloneMode(false),
|
||||
mClonedType(CSMWorld::UniversalId::Type_None)
|
||||
|
||||
{
|
||||
mLayout = new QHBoxLayout;
|
||||
mLayout->setContentsMargins (0, 0, 0, 0);
|
||||
|
@ -89,6 +96,7 @@ void CSVWorld::GenericCreator::setEditLock (bool locked)
|
|||
|
||||
void CSVWorld::GenericCreator::reset()
|
||||
{
|
||||
mCloneMode = false;
|
||||
mId->setText ("");
|
||||
update();
|
||||
}
|
||||
|
@ -120,16 +128,40 @@ void CSVWorld::GenericCreator::create()
|
|||
{
|
||||
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));
|
||||
|
||||
configureCreateCommand (*command);
|
||||
configureCreateCommand (*command);
|
||||
|
||||
mUndoStack.push (command.release());
|
||||
mUndoStack.push (command.release());
|
||||
|
||||
emit done();
|
||||
emit requestFocus (id);
|
||||
emit done();
|
||||
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
|
||||
#define CSV_WORLD_GENERICCREATOR_H
|
||||
|
||||
class QString;
|
||||
class QPushButton;
|
||||
class QLineEdit;
|
||||
class QHBoxLayout;
|
||||
|
@ -28,6 +29,11 @@ namespace CSVWorld
|
|||
std::string mErrors;
|
||||
QHBoxLayout *mLayout;
|
||||
bool mLocked;
|
||||
std::string mClonedId;
|
||||
CSMWorld::UniversalId::Type mClonedType;
|
||||
|
||||
protected:
|
||||
bool mCloneMode;
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -57,11 +63,15 @@ namespace CSVWorld
|
|||
|
||||
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;
|
||||
///< Return formatted error descriptions for the current state of the creator. if an empty
|
||||
/// string is returned, there is no error.
|
||||
|
||||
|
||||
private slots:
|
||||
|
||||
void textChanged (const QString& text);
|
||||
|
|
|
@ -40,4 +40,10 @@ void CSVWorld::ReferenceableCreator::reset()
|
|||
{
|
||||
mType->setCurrentIndex (0);
|
||||
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);
|
||||
|
||||
virtual void reset();
|
||||
virtual void toggleWidgets(bool active = true);
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
@ -40,15 +40,20 @@ CSVWorld::ReferenceCreator::ReferenceCreator (CSMWorld::Data& data, QUndoStack&
|
|||
|
||||
void CSVWorld::ReferenceCreator::reset()
|
||||
{
|
||||
GenericCreator::reset();
|
||||
mCell->setText ("");
|
||||
mId = getData().getReferences().getNewId();
|
||||
GenericCreator::reset();
|
||||
}
|
||||
|
||||
std::string CSVWorld::ReferenceCreator::getErrors() const
|
||||
{
|
||||
std::string errors = GenericCreator::getErrors();
|
||||
|
||||
if (mCloneMode)
|
||||
{
|
||||
return errors;
|
||||
}
|
||||
|
||||
std::string cell = mCell->text().toUtf8().constData();
|
||||
|
||||
if (cell.empty())
|
||||
|
@ -72,4 +77,17 @@ std::string CSVWorld::ReferenceCreator::getErrors() const
|
|||
void CSVWorld::ReferenceCreator::cellChanged()
|
||||
{
|
||||
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,
|
||||
const CSMWorld::UniversalId& id);
|
||||
|
||||
virtual void cloneMode(const std::string& originId,
|
||||
const CSMWorld::UniversalId::Type type);
|
||||
|
||||
virtual void reset();
|
||||
virtual void toggleWidgets(bool active = true);
|
||||
|
||||
virtual std::string getErrors() const;
|
||||
///< 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 (selectedRows.size()==1)
|
||||
{
|
||||
menu.addAction (mEditAction);
|
||||
if (mCreateAction)
|
||||
menu.addAction(mCloneAction);
|
||||
}
|
||||
|
||||
if (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,
|
||||
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));
|
||||
|
||||
|
@ -199,6 +203,10 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, Q
|
|||
mCreateAction = new QAction (tr ("Add Record"), this);
|
||||
connect (mCreateAction, SIGNAL (triggered()), this, SIGNAL (createRequest()));
|
||||
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);
|
||||
|
@ -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()
|
||||
{
|
||||
QModelIndexList selectedRows = selectionModel()->selectedRows();
|
||||
|
|
|
@ -32,6 +32,7 @@ namespace CSVWorld
|
|||
QUndoStack& mUndoStack;
|
||||
QAction *mEditAction;
|
||||
QAction *mCreateAction;
|
||||
QAction *mCloneAction;
|
||||
QAction *mRevertAction;
|
||||
QAction *mDeleteAction;
|
||||
QAction *mMoveUpAction;
|
||||
|
@ -73,6 +74,7 @@ namespace CSVWorld
|
|||
/// \param modified Number of added and modified records
|
||||
|
||||
void createRequest();
|
||||
void cloneRequest(const CSMWorld::UniversalId&);
|
||||
|
||||
private slots:
|
||||
|
||||
|
@ -82,6 +84,8 @@ namespace CSVWorld
|
|||
|
||||
void editRecord();
|
||||
|
||||
void cloneRecord();
|
||||
|
||||
void moveUpRecord();
|
||||
|
||||
void moveDownRecord();
|
||||
|
|
|
@ -153,7 +153,19 @@ void CSVWorld::TableBottomBox::tableSizeChanged (int size, int deleted, int modi
|
|||
void CSVWorld::TableBottomBox::createRequest()
|
||||
{
|
||||
mCreator->reset();
|
||||
mCreator->toggleWidgets(true);
|
||||
mLayout->setCurrentWidget (mCreator);
|
||||
setVisible (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
|
||||
|
||||
#include <QWidget>
|
||||
#include <apps/opencs/model/world/universalid.hpp>
|
||||
|
||||
class QLabel;
|
||||
class QStackedLayout;
|
||||
|
@ -76,6 +77,8 @@ namespace CSVWorld
|
|||
/// \param modified Number of added and modified records
|
||||
|
||||
void createRequest();
|
||||
void cloneRequest(const std::string& id,
|
||||
const CSMWorld::UniversalId::Type type);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
#include "../../model/doc/document.hpp"
|
||||
|
||||
#include "../filter/filterbox.hpp"
|
||||
|
||||
#include "table.hpp"
|
||||
#include "tablebottombox.hpp"
|
||||
#include "creator.hpp"
|
||||
|
@ -46,8 +45,15 @@ CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::D
|
|||
mTable->selectionSizeUpdate();
|
||||
|
||||
if (mBottom->canCreateAndDelete())
|
||||
{
|
||||
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&)),
|
||||
mTable, SLOT (requestFocus (const std::string&)));
|
||||
|
||||
|
@ -75,4 +81,9 @@ void CSVWorld::TableSubView::updateEditorSetting(const QString &settingName, con
|
|||
void CSVWorld::TableSubView::setStatusBar (bool show)
|
||||
{
|
||||
mBottom->setStatusBar (show);
|
||||
}
|
||||
}
|
||||
|
||||
void CSVWorld::TableSubView::cloneRequest(const CSMWorld::UniversalId& toClone)
|
||||
{
|
||||
emit cloneRequest(toClone.getId(), toClone.getType());
|
||||
}
|
||||
|
|
|
@ -5,6 +5,11 @@
|
|||
|
||||
class QModelIndex;
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
class IdTable;
|
||||
}
|
||||
|
||||
namespace CSMDoc
|
||||
{
|
||||
class Document;
|
||||
|
@ -34,9 +39,14 @@ namespace CSVWorld
|
|||
|
||||
virtual void setStatusBar (bool show);
|
||||
|
||||
signals:
|
||||
void cloneRequest(const std::string&,
|
||||
const CSMWorld::UniversalId::Type);
|
||||
|
||||
private slots:
|
||||
|
||||
void editRequest (int row);
|
||||
void cloneRequest (const CSMWorld::UniversalId& toClone);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -69,12 +69,16 @@ add_openmw_dir (mwmechanics
|
|||
mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects
|
||||
drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow
|
||||
aiescort aiactivate aicombat repair enchanting pathfinding security spellsuccess spellcasting
|
||||
disease pickpocket levelledlist
|
||||
disease pickpocket levelledlist combat steering
|
||||
)
|
||||
|
||||
add_openmw_dir (mwstate
|
||||
statemanagerimp charactermanager character
|
||||
)
|
||||
|
||||
add_openmw_dir (mwbase
|
||||
environment world scriptmanager dialoguemanager journal soundmanager mechanicsmanager
|
||||
inputmanager windowmanager
|
||||
inputmanager windowmanager statemanager
|
||||
)
|
||||
|
||||
# Main executable
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include <MyGUI_WidgetManager.h>
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include <components/compiler/extensions0.hpp>
|
||||
|
||||
#include <components/bsa/bsa_archive.hpp>
|
||||
|
@ -41,8 +43,7 @@
|
|||
|
||||
#include "mwmechanics/mechanicsmanagerimp.hpp"
|
||||
|
||||
|
||||
#include <SDL.h>
|
||||
#include "mwstate/statemanagerimp.hpp"
|
||||
|
||||
void OMW::Engine::executeLocalScripts()
|
||||
{
|
||||
|
@ -88,31 +89,47 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
|
|||
if (mUseSound)
|
||||
MWBase::Environment::get().getSoundManager()->update(frametime);
|
||||
|
||||
// global scripts
|
||||
MWBase::Environment::get().getScriptManager()->getGlobalScripts().run();
|
||||
bool paused = MWBase::Environment::get().getWindowManager()->isGuiMode();
|
||||
|
||||
bool changed = MWBase::Environment::get().getWorld()->hasCellChanged();
|
||||
// update game state
|
||||
MWBase::Environment::get().getStateManager()->update (frametime);
|
||||
|
||||
// local scripts
|
||||
executeLocalScripts(); // This does not handle the case where a global script causes a cell
|
||||
// change, followed by a cell change in a local script during the same
|
||||
// frame.
|
||||
if (MWBase::Environment::get().getStateManager()->getState()==
|
||||
MWBase::StateManager::State_Running)
|
||||
{
|
||||
// global scripts
|
||||
MWBase::Environment::get().getScriptManager()->getGlobalScripts().run();
|
||||
|
||||
// passing of time
|
||||
if (!MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||
MWBase::Environment::get().getWorld()->advanceTime(
|
||||
frametime*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/3600);
|
||||
bool changed = MWBase::Environment::get().getWorld()->hasCellChanged();
|
||||
|
||||
// local scripts
|
||||
executeLocalScripts(); // This does not handle the case where a global script causes a
|
||||
// cell change, followed by a cell change in a local script during
|
||||
// the same frame.
|
||||
|
||||
if (changed) // keep change flag for another frame, if cell changed happened in local script
|
||||
MWBase::Environment::get().getWorld()->markCellAsUnchanged();
|
||||
|
||||
if (!paused)
|
||||
MWBase::Environment::get().getWorld()->advanceTime(
|
||||
frametime*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/3600);
|
||||
}
|
||||
|
||||
if (changed) // keep change flag for another frame, if cell changed happend in local script
|
||||
MWBase::Environment::get().getWorld()->markCellAsUnchanged();
|
||||
|
||||
// update actors
|
||||
MWBase::Environment::get().getMechanicsManager()->update(frametime,
|
||||
MWBase::Environment::get().getWindowManager()->isGuiMode());
|
||||
paused);
|
||||
|
||||
if (MWBase::Environment::get().getStateManager()->getState()==
|
||||
MWBase::StateManager::State_Running)
|
||||
{
|
||||
MWWorld::Ptr player = mEnvironment.getWorld()->getPlayerPtr();
|
||||
if(!paused && player.getClass().getCreatureStats(player).isDead())
|
||||
MWBase::Environment::get().getStateManager()->endGame();
|
||||
}
|
||||
|
||||
// update world
|
||||
MWBase::Environment::get().getWorld()->update(frametime, MWBase::Environment::get().getWindowManager()->isGuiMode());
|
||||
MWBase::Environment::get().getWorld()->update(frametime, paused);
|
||||
|
||||
// update GUI
|
||||
Ogre::RenderWindow* window = mOgre->getWindow();
|
||||
|
@ -135,7 +152,7 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager)
|
|||
: mOgre (0)
|
||||
, mFpsLevel(0)
|
||||
, mVerboseScripts (false)
|
||||
, mNewGame (false)
|
||||
, mSkipMenu (false)
|
||||
, mUseSound (true)
|
||||
, mCompileAll (false)
|
||||
, mScriptContext (0)
|
||||
|
@ -265,12 +282,7 @@ void OMW::Engine::setCell (const std::string& cellName)
|
|||
|
||||
void OMW::Engine::addContentFile(const std::string& file)
|
||||
{
|
||||
if (file.find_last_of(".") == std::string::npos)
|
||||
{
|
||||
throw std::runtime_error("Missing extension in content file!");
|
||||
}
|
||||
|
||||
mContentFiles.push_back(file);
|
||||
mContentFiles.push_back(file);
|
||||
}
|
||||
|
||||
void OMW::Engine::setScriptsVerbosity(bool scriptsVerbosity)
|
||||
|
@ -278,9 +290,9 @@ void OMW::Engine::setScriptsVerbosity(bool scriptsVerbosity)
|
|||
mVerboseScripts = scriptsVerbosity;
|
||||
}
|
||||
|
||||
void OMW::Engine::setNewGame(bool newGame)
|
||||
void OMW::Engine::setSkipMenu (bool skipMenu)
|
||||
{
|
||||
mNewGame = newGame;
|
||||
mSkipMenu = skipMenu;
|
||||
}
|
||||
|
||||
std::string OMW::Engine::loadSettings (Settings::Manager & settings)
|
||||
|
@ -326,6 +338,9 @@ std::string OMW::Engine::loadSettings (Settings::Manager & settings)
|
|||
|
||||
void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
||||
{
|
||||
mEnvironment.setStateManager (
|
||||
new MWState::StateManager (mCfgMgr.getUserDataPath() / "saves", mContentFiles.at (0)));
|
||||
|
||||
Nif::NIFFile::CacheLock cachelock;
|
||||
|
||||
std::string renderSystem = settings.getString("render system", "Video");
|
||||
|
@ -392,10 +407,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
|||
input->setPlayer(&mEnvironment.getWorld()->getPlayer());
|
||||
|
||||
window->initUI();
|
||||
if (mNewGame)
|
||||
// still redundant work here: recreate CharacterCreation(),
|
||||
// double update visibility etc.
|
||||
window->setNewGame(true);
|
||||
window->renderWorldMap();
|
||||
|
||||
//Load translation data
|
||||
|
@ -403,7 +414,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
|||
for (size_t i = 0; i < mContentFiles.size(); i++)
|
||||
mTranslationDataStorage.loadTranslationData(mFileCollections, mContentFiles[i]);
|
||||
|
||||
Compiler::registerExtensions (mExtensions);
|
||||
Compiler::registerExtensions (mExtensions);
|
||||
|
||||
// Create sound system
|
||||
mEnvironment.setSoundManager (new MWSound::SoundManager(mUseSound));
|
||||
|
@ -427,12 +438,12 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
|||
mechanics->buildPlayer();
|
||||
window->updatePlayer();
|
||||
|
||||
if (!mNewGame)
|
||||
{
|
||||
// load cell
|
||||
ESM::Position pos;
|
||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
// load cell
|
||||
ESM::Position pos;
|
||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
|
||||
if (!mCellName.empty())
|
||||
{
|
||||
if (world->findExteriorPosition(mCellName, pos)) {
|
||||
world->changeToExteriorCell (pos);
|
||||
}
|
||||
|
@ -442,7 +453,11 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
|||
}
|
||||
}
|
||||
else
|
||||
mEnvironment.getWorld()->startNewGame();
|
||||
{
|
||||
pos.pos[0] = pos.pos[1] = pos.pos[2] = 0;
|
||||
pos.rot[0] = pos.rot[1] = pos.pos[2] = 0;
|
||||
world->changeToExteriorCell (pos);
|
||||
}
|
||||
|
||||
Ogre::FrameEvent event;
|
||||
event.timeSinceLastEvent = 0;
|
||||
|
@ -468,7 +483,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
|||
|
||||
void OMW::Engine::go()
|
||||
{
|
||||
assert (!mCellName.empty());
|
||||
assert (!mContentFiles.empty());
|
||||
assert (!mOgre);
|
||||
|
||||
|
@ -489,8 +503,14 @@ void OMW::Engine::go()
|
|||
if (!mStartupScript.empty())
|
||||
MWBase::Environment::get().getWindowManager()->executeInConsole (mStartupScript);
|
||||
|
||||
// start in main menu
|
||||
if (!mSkipMenu)
|
||||
MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu);
|
||||
else
|
||||
MWBase::Environment::get().getStateManager()->newGame (true);
|
||||
|
||||
// Start the main rendering loop
|
||||
while (!mEnvironment.getRequestExit())
|
||||
while (!mEnvironment.get().getStateManager()->hasQuitRequest())
|
||||
Ogre::Root::getSingleton().renderOneFrame();
|
||||
|
||||
// Save user settings
|
||||
|
@ -509,6 +529,9 @@ void OMW::Engine::activate()
|
|||
if (ptr.isEmpty())
|
||||
return;
|
||||
|
||||
if (ptr.getClass().getName(ptr) == "") // objects without name presented to user can never be activated
|
||||
return;
|
||||
|
||||
MWScript::InterpreterContext interpreterContext (&ptr.getRefData().getLocals(), ptr);
|
||||
|
||||
boost::shared_ptr<MWWorld::Action> action =
|
||||
|
|
|
@ -71,7 +71,7 @@ namespace OMW
|
|||
std::vector<std::string> mContentFiles;
|
||||
int mFpsLevel;
|
||||
bool mVerboseScripts;
|
||||
bool mNewGame;
|
||||
bool mSkipMenu;
|
||||
bool mUseSound;
|
||||
bool mCompileAll;
|
||||
std::string mFocusName;
|
||||
|
@ -151,8 +151,7 @@ namespace OMW
|
|||
/// Disable or enable all sounds
|
||||
void setSoundUsage(bool soundUsage);
|
||||
|
||||
/// Start as a new game.
|
||||
void setNewGame(bool newGame);
|
||||
void setSkipMenu (bool skipMenu);
|
||||
|
||||
void setGrabMouse(bool grab) { mGrab = grab; }
|
||||
|
||||
|
|
|
@ -115,7 +115,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
|||
("resources", bpo::value<std::string>()->default_value("resources"),
|
||||
"set resources directory")
|
||||
|
||||
("start", bpo::value<std::string>()->default_value("Beshara"),
|
||||
("start", bpo::value<std::string>()->default_value(""),
|
||||
"set initial cell")
|
||||
|
||||
("content", bpo::value<StringsVector>()->default_value(StringsVector(), "")
|
||||
|
@ -136,8 +136,8 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
|||
("script-run", bpo::value<std::string>()->default_value(""),
|
||||
"select a file containing a list of console commands that is executed on startup")
|
||||
|
||||
("new-game", bpo::value<bool>()->implicit_value(true)
|
||||
->default_value(false), "activate char gen/new game mechanics")
|
||||
("skip-menu", bpo::value<bool>()->implicit_value(true)
|
||||
->default_value(false), "skip main menu on game startup")
|
||||
|
||||
("fs-strict", bpo::value<bool>()->implicit_value(true)
|
||||
->default_value(false), "strict file system handling (no case folding)")
|
||||
|
@ -231,7 +231,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
|||
|
||||
// startup-settings
|
||||
engine.setCell(variables["start"].as<std::string>());
|
||||
engine.setNewGame(variables["new-game"].as<bool>());
|
||||
engine.setSkipMenu (variables["skip-menu"].as<bool>());
|
||||
|
||||
// other settings
|
||||
engine.setSoundUsage(!variables["no-sound"].as<bool>());
|
||||
|
|
|
@ -11,13 +11,14 @@
|
|||
#include "mechanicsmanager.hpp"
|
||||
#include "inputmanager.hpp"
|
||||
#include "windowmanager.hpp"
|
||||
#include "statemanager.hpp"
|
||||
|
||||
MWBase::Environment *MWBase::Environment::sThis = 0;
|
||||
bool MWBase::Environment::sExit = false;
|
||||
|
||||
MWBase::Environment::Environment()
|
||||
: mWorld (0), mSoundManager (0), mScriptManager (0), mWindowManager (0),
|
||||
mMechanicsManager (0), mDialogueManager (0), mJournal (0), mInputManager (0), mFrameDuration (0)
|
||||
mMechanicsManager (0), mDialogueManager (0), mJournal (0), mInputManager (0), mFrameDuration (0),
|
||||
mStateManager (0)
|
||||
{
|
||||
assert (!sThis);
|
||||
sThis = this;
|
||||
|
@ -69,6 +70,11 @@ void MWBase::Environment::setInputManager (InputManager *inputManager)
|
|||
mInputManager = inputManager;
|
||||
}
|
||||
|
||||
void MWBase::Environment::setStateManager (StateManager *stateManager)
|
||||
{
|
||||
mStateManager = stateManager;
|
||||
}
|
||||
|
||||
void MWBase::Environment::setFrameDuration (float duration)
|
||||
{
|
||||
mFrameDuration = duration;
|
||||
|
@ -122,6 +128,12 @@ MWBase::InputManager *MWBase::Environment::getInputManager() const
|
|||
return mInputManager;
|
||||
}
|
||||
|
||||
MWBase::StateManager *MWBase::Environment::getStateManager() const
|
||||
{
|
||||
assert (mStateManager);
|
||||
return mStateManager;
|
||||
}
|
||||
|
||||
float MWBase::Environment::getFrameDuration() const
|
||||
{
|
||||
return mFrameDuration;
|
||||
|
@ -152,6 +164,9 @@ void MWBase::Environment::cleanup()
|
|||
|
||||
delete mInputManager;
|
||||
mInputManager = 0;
|
||||
|
||||
delete mStateManager;
|
||||
mStateManager = 0;
|
||||
}
|
||||
|
||||
const MWBase::Environment& MWBase::Environment::get()
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace MWBase
|
|||
class MechanicsManager;
|
||||
class InputManager;
|
||||
class WindowManager;
|
||||
class StateManager;
|
||||
|
||||
/// \brief Central hub for mw-subsystems
|
||||
///
|
||||
|
@ -30,10 +31,9 @@ namespace MWBase
|
|||
DialogueManager *mDialogueManager;
|
||||
Journal *mJournal;
|
||||
InputManager *mInputManager;
|
||||
StateManager *mStateManager;
|
||||
float mFrameDuration;
|
||||
|
||||
static bool sExit;
|
||||
|
||||
Environment (const Environment&);
|
||||
///< not implemented
|
||||
|
||||
|
@ -46,9 +46,6 @@ namespace MWBase
|
|||
|
||||
~Environment();
|
||||
|
||||
static void setRequestExit () { sExit = true; }
|
||||
static bool getRequestExit () { return sExit; }
|
||||
|
||||
void setWorld (World *world);
|
||||
|
||||
void setSoundManager (SoundManager *soundManager);
|
||||
|
@ -65,6 +62,8 @@ namespace MWBase
|
|||
|
||||
void setInputManager (InputManager *inputManager);
|
||||
|
||||
void setStateManager (StateManager *stateManager);
|
||||
|
||||
void setFrameDuration (float duration);
|
||||
///< Set length of current frame in seconds.
|
||||
|
||||
|
@ -84,6 +83,8 @@ namespace MWBase
|
|||
|
||||
InputManager *getInputManager() const;
|
||||
|
||||
StateManager *getStateManager() const;
|
||||
|
||||
float getFrameDuration() const;
|
||||
|
||||
void cleanup();
|
||||
|
|
|
@ -5,10 +5,18 @@
|
|||
#include <deque>
|
||||
#include <map>
|
||||
|
||||
#include <libs/platform/stdint.h>
|
||||
|
||||
#include "../mwdialogue/journalentry.hpp"
|
||||
#include "../mwdialogue/topic.hpp"
|
||||
#include "../mwdialogue/quest.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
class ESMReader;
|
||||
class ESMWriter;
|
||||
}
|
||||
|
||||
namespace MWBase
|
||||
{
|
||||
/// \brief Interface for the player's journal (implemented in MWDialogue)
|
||||
|
@ -46,7 +54,7 @@ namespace MWBase
|
|||
virtual int getJournalIndex (const std::string& id) const = 0;
|
||||
///< Get the journal index.
|
||||
|
||||
virtual void addTopic (const std::string& topicId, const std::string& infoId) = 0;
|
||||
virtual void addTopic (const std::string& topicId, const std::string& infoId, const std::string& actorName) = 0;
|
||||
|
||||
virtual TEntryIter begin() const = 0;
|
||||
///< Iterator pointing to the begin of the main journal.
|
||||
|
@ -69,6 +77,12 @@ namespace MWBase
|
|||
|
||||
virtual TTopicIter topicEnd() const = 0;
|
||||
///< Iterator pointing past the last topic.
|
||||
|
||||
virtual int countSavedGameRecords() const = 0;
|
||||
|
||||
virtual void write (ESM::ESMWriter& writer) const = 0;
|
||||
|
||||
virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
|
||||
namespace Ogre
|
||||
{
|
||||
|
@ -135,28 +136,35 @@ namespace MWBase
|
|||
float currentTemporaryDispositionDelta, bool& success, float& tempChange, float& permChange) = 0;
|
||||
///< Perform a persuasion action on NPC
|
||||
|
||||
virtual void forceStateUpdate(const MWWorld::Ptr &ptr) = 0;
|
||||
///< Forces an object to refresh its animation state.
|
||||
virtual void forceStateUpdate(const MWWorld::Ptr &ptr) = 0;
|
||||
///< Forces an object to refresh its animation state.
|
||||
|
||||
virtual void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number=1) = 0;
|
||||
///< Run animation for a MW-reference. Calls to this function for references that are currently not
|
||||
/// in the scene should be ignored.
|
||||
///
|
||||
/// \param mode 0 normal, 1 immediate start, 2 immediate loop
|
||||
/// \param count How many times the animation should be run
|
||||
virtual void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number=1) = 0;
|
||||
///< Run animation for a MW-reference. Calls to this function for references that are currently not
|
||||
/// in the scene should be ignored.
|
||||
///
|
||||
/// \param mode 0 normal, 1 immediate start, 2 immediate loop
|
||||
/// \param count How many times the animation should be run
|
||||
|
||||
virtual void skipAnimation(const MWWorld::Ptr& ptr) = 0;
|
||||
///< Skip the animation for the given MW-reference for one frame. Calls to this function for
|
||||
/// references that are currently not in the scene should be ignored.
|
||||
virtual void skipAnimation(const MWWorld::Ptr& ptr) = 0;
|
||||
///< Skip the animation for the given MW-reference for one frame. Calls to this function for
|
||||
/// references that are currently not in the scene should be ignored.
|
||||
|
||||
virtual bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName) = 0;
|
||||
virtual bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName) = 0;
|
||||
|
||||
/// Update magic effects for an actor. Usually done automatically once per frame, but if we're currently
|
||||
/// paused we may want to do it manually (after equipping permanent enchantment)
|
||||
virtual void updateMagicEffects (const MWWorld::Ptr& ptr) = 0;
|
||||
/// Update magic effects for an actor. Usually done automatically once per frame, but if we're currently
|
||||
/// paused we may want to do it manually (after equipping permanent enchantment)
|
||||
virtual void updateMagicEffects (const MWWorld::Ptr& ptr) = 0;
|
||||
|
||||
virtual void toggleAI() = 0;
|
||||
virtual bool isAIActive() = 0;
|
||||
virtual void toggleAI() = 0;
|
||||
virtual bool isAIActive() = 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;
|
||||
|
||||
virtual void playerLoaded() = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -35,8 +35,6 @@ namespace MWBase
|
|||
|
||||
virtual ~ScriptManager() {}
|
||||
|
||||
virtual void resetGlobalScripts() = 0;
|
||||
|
||||
virtual void run (const std::string& name, Interpreter::Context& interpreterContext) = 0;
|
||||
///< Run the script with the given name (compile first, if not compiled yet)
|
||||
|
||||
|
|
|
@ -147,6 +147,10 @@ namespace MWBase
|
|||
virtual void update(float duration) = 0;
|
||||
|
||||
virtual void setListenerPosDir(const Ogre::Vector3 &pos, const Ogre::Vector3 &dir, const Ogre::Vector3 &up) = 0;
|
||||
|
||||
virtual void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated) = 0;
|
||||
|
||||
virtual void clear() = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
81
apps/openmw/mwbase/statemanager.hpp
Normal file
81
apps/openmw/mwbase/statemanager.hpp
Normal file
|
@ -0,0 +1,81 @@
|
|||
#ifndef GAME_MWSTATE_STATEMANAGER_H
|
||||
#define GAME_MWSTATE_STATEMANAGER_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace MWState
|
||||
{
|
||||
struct Slot;
|
||||
class Character;
|
||||
}
|
||||
|
||||
namespace MWBase
|
||||
{
|
||||
/// \brief Interface for game state manager (implemented in MWState)
|
||||
class StateManager
|
||||
{
|
||||
public:
|
||||
|
||||
enum State
|
||||
{
|
||||
State_NoGame,
|
||||
State_Ended,
|
||||
State_Running
|
||||
};
|
||||
|
||||
typedef std::vector<MWState::Character>::const_iterator CharacterIterator;
|
||||
|
||||
private:
|
||||
|
||||
StateManager (const StateManager&);
|
||||
///< not implemented
|
||||
|
||||
StateManager& operator= (const StateManager&);
|
||||
///< not implemented
|
||||
|
||||
public:
|
||||
|
||||
StateManager() {}
|
||||
|
||||
virtual ~StateManager() {}
|
||||
|
||||
virtual void requestQuit() = 0;
|
||||
|
||||
virtual bool hasQuitRequest() const = 0;
|
||||
|
||||
virtual void askLoadRecent() = 0;
|
||||
|
||||
virtual State getState() const = 0;
|
||||
|
||||
virtual void newGame (bool bypass = false) = 0;
|
||||
///< Start a new game.
|
||||
///
|
||||
/// \param bypass Skip new game mechanics.
|
||||
|
||||
virtual void endGame() = 0;
|
||||
|
||||
virtual void saveGame (const std::string& description, const MWState::Slot *slot = 0) = 0;
|
||||
///< Write a saved game to \a slot or create a new slot if \a slot == 0.
|
||||
///
|
||||
/// \note Slot must belong to the current character.
|
||||
|
||||
virtual void loadGame (const MWState::Character *character, const MWState::Slot *slot) = 0;
|
||||
///< Load a saved game file from \a slot.
|
||||
///
|
||||
/// \note \a slot must belong to \a character.
|
||||
|
||||
virtual MWState::Character *getCurrentCharacter (bool create = true) = 0;
|
||||
///< \param create Create a new character, if there is no current character.
|
||||
|
||||
virtual CharacterIterator characterBegin() = 0;
|
||||
///< Any call to SaveGame and getCurrentCharacter can invalidate the returned
|
||||
/// iterator.
|
||||
|
||||
virtual CharacterIterator characterEnd() = 0;
|
||||
|
||||
virtual void update (float duration) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -33,6 +33,8 @@ namespace OEngine
|
|||
namespace ESM
|
||||
{
|
||||
struct Class;
|
||||
class ESMReader;
|
||||
class ESMWriter;
|
||||
}
|
||||
|
||||
namespace MWWorld
|
||||
|
@ -279,12 +281,19 @@ namespace MWBase
|
|||
|
||||
virtual const Translation::Storage& getTranslationDataStorage() const = 0;
|
||||
|
||||
/// Warning: do not use MyGUI::InputManager::setKeyFocusWidget directly. Instead use this.
|
||||
virtual void setKeyFocusWidget (MyGUI::Widget* widget) = 0;
|
||||
|
||||
virtual Loading::Listener* getLoadingScreen() = 0;
|
||||
|
||||
/// Should the cursor be visible?
|
||||
virtual bool getCursorVisible() = 0;
|
||||
|
||||
/// Clear all savegame-specific data
|
||||
virtual void clear() = 0;
|
||||
|
||||
virtual void write (ESM::ESMWriter& writer) = 0;
|
||||
virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define GAME_MWBASE_WORLD_H
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include <components/settings/settings.hpp>
|
||||
|
||||
|
@ -30,12 +31,14 @@ namespace OEngine
|
|||
namespace ESM
|
||||
{
|
||||
class ESMReader;
|
||||
class ESMWriter;
|
||||
struct Position;
|
||||
struct Cell;
|
||||
struct Class;
|
||||
struct Potion;
|
||||
struct Spell;
|
||||
struct NPC;
|
||||
struct CellId;
|
||||
}
|
||||
|
||||
namespace MWRender
|
||||
|
@ -94,13 +97,26 @@ namespace MWBase
|
|||
|
||||
virtual void startNewGame() = 0;
|
||||
|
||||
virtual void clear() = 0;
|
||||
|
||||
virtual int countSavedGameRecords() const = 0;
|
||||
|
||||
virtual void write (ESM::ESMWriter& writer) const = 0;
|
||||
|
||||
virtual void readRecord (ESM::ESMReader& reader, int32_t type,
|
||||
const std::map<int, int>& contentFileMap) = 0;
|
||||
|
||||
virtual OEngine::Render::Fader* getFader() = 0;
|
||||
///< \ŧodo remove this function. Rendering details should not be exposed.
|
||||
///< \todo remove this function. Rendering details should not be exposed.
|
||||
|
||||
virtual MWWorld::CellStore *getExterior (int x, int y) = 0;
|
||||
|
||||
virtual MWWorld::CellStore *getInterior (const std::string& name) = 0;
|
||||
|
||||
virtual MWWorld::CellStore *getCell (const ESM::CellId& id) = 0;
|
||||
|
||||
virtual void useDeathCamera() = 0;
|
||||
|
||||
virtual void setWaterHeight(const float height) = 0;
|
||||
|
||||
virtual void toggleWater() = 0;
|
||||
|
@ -139,16 +155,26 @@ namespace MWBase
|
|||
virtual bool isPositionExplored (float nX, float nY, int x, int y, bool interior) = 0;
|
||||
///< see MWRender::LocalMap::isPositionExplored
|
||||
|
||||
virtual MWWorld::Globals::Data& getGlobalVariable (const std::string& name) = 0;
|
||||
virtual void setGlobalInt (const std::string& name, int value) = 0;
|
||||
///< Set value independently from real type.
|
||||
|
||||
virtual MWWorld::Globals::Data getGlobalVariable (const std::string& name) const = 0;
|
||||
virtual void setGlobalFloat (const std::string& name, float value) = 0;
|
||||
///< Set value independently from real type.
|
||||
|
||||
virtual int getGlobalInt (const std::string& name) const = 0;
|
||||
///< Get value independently from real type.
|
||||
|
||||
virtual float getGlobalFloat (const std::string& name) const = 0;
|
||||
///< Get value independently from real type.
|
||||
|
||||
virtual char getGlobalVariableType (const std::string& name) const = 0;
|
||||
///< Return ' ', if there is no global variable with this name.
|
||||
|
||||
virtual std::vector<std::string> getGlobals () const = 0;
|
||||
|
||||
virtual std::string getCurrentCellName() const = 0;
|
||||
virtual std::string getCellName (const MWWorld::CellStore *cell = 0) const = 0;
|
||||
///< Return name of the cell.
|
||||
///
|
||||
/// \note If cell==0, the cell the player is currently in will be used instead to
|
||||
/// generate a name.
|
||||
|
||||
virtual void removeRefScript (MWWorld::RefData *ref) = 0;
|
||||
//< Remove the script attached to ref from mLocalScripts
|
||||
|
@ -185,8 +211,12 @@ namespace MWBase
|
|||
virtual void setDay (int day) = 0;
|
||||
///< Set in-game time day.
|
||||
|
||||
virtual int getDay() = 0;
|
||||
virtual int getMonth() = 0;
|
||||
virtual int getDay() const = 0;
|
||||
virtual int getMonth() const = 0;
|
||||
virtual int getYear() const = 0;
|
||||
|
||||
virtual std::string getMonthName (int month = -1) const = 0;
|
||||
///< Return name of month (-1: current month)
|
||||
|
||||
virtual MWWorld::TimeStamp getTimeStamp() const = 0;
|
||||
///< Return current in-game time stamp.
|
||||
|
@ -215,6 +245,8 @@ namespace MWBase
|
|||
virtual void changeToExteriorCell (const ESM::Position& position) = 0;
|
||||
///< Move to exterior cell.
|
||||
|
||||
virtual void changeToCell (const ESM::CellId& cellId, const ESM::Position& position) = 0;
|
||||
|
||||
virtual const ESM::Cell *getExterior (const std::string& cellName) const = 0;
|
||||
///< Return a cell matching the given name or a 0-pointer, if there is no such cell.
|
||||
|
||||
|
@ -225,7 +257,7 @@ namespace MWBase
|
|||
|
||||
/// Returns a pointer to the object the provided object would hit (if within the
|
||||
/// specified distance), and the point where the hit occurs. This will attempt to
|
||||
/// use the "Head" node as a basis.
|
||||
/// use the "Head" node, or alternatively the "Bip01 Head" node as a basis.
|
||||
virtual std::pair<MWWorld::Ptr,Ogre::Vector3> getHitContact(const MWWorld::Ptr &ptr, float distance) = 0;
|
||||
|
||||
virtual void adjustPosition (const MWWorld::Ptr& ptr) = 0;
|
||||
|
@ -336,7 +368,7 @@ namespace MWBase
|
|||
virtual bool isSwimming(const MWWorld::Ptr &object) const = 0;
|
||||
///Is the head of the creature underwater?
|
||||
virtual bool isSubmerged(const MWWorld::Ptr &object) const = 0;
|
||||
virtual bool isUnderwater(const MWWorld::Ptr::CellStore* cell, const Ogre::Vector3 &pos) const = 0;
|
||||
virtual bool isUnderwater(const MWWorld::CellStore* cell, const Ogre::Vector3 &pos) const = 0;
|
||||
virtual bool isOnGround(const MWWorld::Ptr &ptr) const = 0;
|
||||
|
||||
virtual void togglePOV() = 0;
|
||||
|
@ -384,6 +416,7 @@ namespace MWBase
|
|||
virtual void playVideo(const std::string& name, bool allowSkipping) = 0;
|
||||
virtual void stopVideo() = 0;
|
||||
virtual void frameStarted (float dt, bool paused) = 0;
|
||||
virtual void screenshot (Ogre::Image& image, int w, int h) = 0;
|
||||
|
||||
/// Find default position inside exterior cell specified by name
|
||||
/// \return false if exterior with given name not exists, true otherwise
|
||||
|
@ -428,6 +461,8 @@ namespace MWBase
|
|||
virtual void launchProjectile (const std::string& id, bool stack, const ESM::EffectList& effects,
|
||||
const MWWorld::Ptr& actor, const std::string& sourceName) = 0;
|
||||
|
||||
virtual const std::vector<std::string>& getContentFiles() const = 0;
|
||||
|
||||
virtual void breakInvisibility (const MWWorld::Ptr& actor) = 0;
|
||||
|
||||
// Are we in an exterior or pseudo-exterior cell and it's night?
|
||||
|
@ -466,6 +501,9 @@ namespace MWBase
|
|||
|
||||
/// Spawn a blood effect for \a ptr at \a worldPosition
|
||||
virtual void spawnBloodEffect (const MWWorld::Ptr& ptr, const Ogre::Vector3& worldPosition) = 0;
|
||||
|
||||
virtual void explodeSpell (const Ogre::Vector3& origin, const MWWorld::Ptr& object, const ESM::EffectList& effects,
|
||||
const MWWorld::Ptr& caster, const std::string& id, const std::string& sourceName) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -289,7 +289,7 @@ namespace MWClass
|
|||
|
||||
std::pair<int, std::string> Armor::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const
|
||||
{
|
||||
MWWorld::InventoryStore& invStore = MWWorld::Class::get(npc).getInventoryStore(npc);
|
||||
MWWorld::InventoryStore& invStore = npc.getClass().getInventoryStore(npc);
|
||||
|
||||
if (ptr.getCellRef().mCharge == 0)
|
||||
return std::make_pair(0, "#{sInventoryMessage1}");
|
||||
|
@ -300,20 +300,23 @@ namespace MWClass
|
|||
if (slots_.first.empty())
|
||||
return std::make_pair(0, "");
|
||||
|
||||
std::string npcRace = npc.get<ESM::NPC>()->mBase->mRace;
|
||||
|
||||
// Beast races cannot equip shoes / boots, or full helms (head part vs hair part)
|
||||
const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(npcRace);
|
||||
if(race->mData.mFlags & ESM::Race::Beast)
|
||||
if (npc.getClass().isNpc())
|
||||
{
|
||||
std::vector<ESM::PartReference> parts = ptr.get<ESM::Armor>()->mBase->mParts.mParts;
|
||||
std::string npcRace = npc.get<ESM::NPC>()->mBase->mRace;
|
||||
|
||||
for(std::vector<ESM::PartReference>::iterator itr = parts.begin(); itr != parts.end(); ++itr)
|
||||
// Beast races cannot equip shoes / boots, or full helms (head part vs hair part)
|
||||
const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(npcRace);
|
||||
if(race->mData.mFlags & ESM::Race::Beast)
|
||||
{
|
||||
if((*itr).mPart == ESM::PRT_Head)
|
||||
return std::make_pair(0, "#{sNotifyMessage13}");
|
||||
if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot)
|
||||
return std::make_pair(0, "#{sNotifyMessage14}");
|
||||
std::vector<ESM::PartReference> parts = ptr.get<ESM::Armor>()->mBase->mParts.mParts;
|
||||
|
||||
for(std::vector<ESM::PartReference>::iterator itr = parts.begin(); itr != parts.end(); ++itr)
|
||||
{
|
||||
if((*itr).mPart == ESM::PRT_Head)
|
||||
return std::make_pair(0, "#{sNotifyMessage13}");
|
||||
if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot)
|
||||
return std::make_pair(0, "#{sNotifyMessage14}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -363,12 +366,12 @@ namespace MWClass
|
|||
return MWWorld::Ptr(&cell.mArmors.insert(*ref), &cell);
|
||||
}
|
||||
|
||||
float Armor::getEnchantmentPoints (const MWWorld::Ptr& ptr) const
|
||||
int Armor::getEnchantmentPoints (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::Armor> *ref =
|
||||
ptr.get<ESM::Armor>();
|
||||
|
||||
return ref->mBase->mData.mEnchant/10.f;
|
||||
return ref->mBase->mData.mEnchant;
|
||||
}
|
||||
|
||||
bool Armor::canSell (const MWWorld::Ptr& item, int npcServices) const
|
||||
|
|
|
@ -79,7 +79,7 @@ namespace MWClass
|
|||
|
||||
virtual std::string getModel(const MWWorld::Ptr &ptr) const;
|
||||
|
||||
virtual float getEnchantmentPoints (const MWWorld::Ptr& ptr) const;
|
||||
virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const;
|
||||
|
||||
virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const;
|
||||
};
|
||||
|
|
|
@ -189,12 +189,12 @@ namespace MWClass
|
|||
return MWWorld::Ptr(&cell.mBooks.insert(*ref), &cell);
|
||||
}
|
||||
|
||||
float Book::getEnchantmentPoints (const MWWorld::Ptr& ptr) const
|
||||
int Book::getEnchantmentPoints (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::Book> *ref =
|
||||
ptr.get<ESM::Book>();
|
||||
|
||||
return ref->mBase->mData.mEnchant/10.f;
|
||||
return ref->mBase->mData.mEnchant;
|
||||
}
|
||||
|
||||
bool Book::canSell (const MWWorld::Ptr& item, int npcServices) const
|
||||
|
|
|
@ -58,7 +58,7 @@ namespace MWClass
|
|||
|
||||
virtual std::string getModel(const MWWorld::Ptr &ptr) const;
|
||||
|
||||
virtual float getEnchantmentPoints (const MWWorld::Ptr& ptr) const;
|
||||
virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const;
|
||||
|
||||
virtual float getWeight (const MWWorld::Ptr& ptr) const;
|
||||
|
||||
|
|
|
@ -238,20 +238,23 @@ namespace MWClass
|
|||
if (slots_.first.empty())
|
||||
return std::make_pair(0, "");
|
||||
|
||||
std::string npcRace = npc.get<ESM::NPC>()->mBase->mRace;
|
||||
|
||||
// Beast races cannot equip shoes / boots, or full helms (head part vs hair part)
|
||||
const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(npcRace);
|
||||
if(race->mData.mFlags & ESM::Race::Beast)
|
||||
if (npc.getClass().isNpc())
|
||||
{
|
||||
std::vector<ESM::PartReference> parts = ptr.get<ESM::Clothing>()->mBase->mParts.mParts;
|
||||
std::string npcRace = npc.get<ESM::NPC>()->mBase->mRace;
|
||||
|
||||
for(std::vector<ESM::PartReference>::iterator itr = parts.begin(); itr != parts.end(); ++itr)
|
||||
// Beast races cannot equip shoes / boots, or full helms (head part vs hair part)
|
||||
const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(npcRace);
|
||||
if(race->mData.mFlags & ESM::Race::Beast)
|
||||
{
|
||||
if((*itr).mPart == ESM::PRT_Head)
|
||||
return std::make_pair(0, "#{sNotifyMessage13}");
|
||||
if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot)
|
||||
return std::make_pair(0, "#{sNotifyMessage15}");
|
||||
std::vector<ESM::PartReference> parts = ptr.get<ESM::Clothing>()->mBase->mParts.mParts;
|
||||
|
||||
for(std::vector<ESM::PartReference>::iterator itr = parts.begin(); itr != parts.end(); ++itr)
|
||||
{
|
||||
if((*itr).mPart == ESM::PRT_Head)
|
||||
return std::make_pair(0, "#{sNotifyMessage13}");
|
||||
if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot)
|
||||
return std::make_pair(0, "#{sNotifyMessage15}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -276,12 +279,12 @@ namespace MWClass
|
|||
return MWWorld::Ptr(&cell.mClothes.insert(*ref), &cell);
|
||||
}
|
||||
|
||||
float Clothing::getEnchantmentPoints (const MWWorld::Ptr& ptr) const
|
||||
int Clothing::getEnchantmentPoints (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::Clothing> *ref =
|
||||
ptr.get<ESM::Clothing>();
|
||||
|
||||
return ref->mBase->mData.mEnchant/10.f;
|
||||
return ref->mBase->mData.mEnchant;
|
||||
}
|
||||
|
||||
bool Clothing::canSell (const MWWorld::Ptr& item, int npcServices) const
|
||||
|
|
|
@ -71,7 +71,7 @@ namespace MWClass
|
|||
|
||||
virtual std::string getModel(const MWWorld::Ptr &ptr) const;
|
||||
|
||||
virtual float getEnchantmentPoints (const MWWorld::Ptr& ptr) const;
|
||||
virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const;
|
||||
|
||||
virtual float getWeight (const MWWorld::Ptr& ptr) const;
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "container.hpp"
|
||||
|
||||
#include <components/esm/loadcont.hpp>
|
||||
#include <components/esm/containerstate.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
@ -258,4 +259,26 @@ namespace MWClass
|
|||
|
||||
return MWWorld::Ptr(&cell.mContainers.insert(*ref), &cell);
|
||||
}
|
||||
|
||||
void Container::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
|
||||
const
|
||||
{
|
||||
const ESM::ContainerState& state2 = dynamic_cast<const ESM::ContainerState&> (state);
|
||||
|
||||
ensureCustomData (ptr);
|
||||
|
||||
dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mContainerStore.
|
||||
readState (state2.mInventory);
|
||||
}
|
||||
|
||||
void Container::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
|
||||
const
|
||||
{
|
||||
ESM::ContainerState& state2 = dynamic_cast<ESM::ContainerState&> (state);
|
||||
|
||||
ensureCustomData (ptr);
|
||||
|
||||
dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mContainerStore.
|
||||
writeState (state2.mInventory);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,6 +54,14 @@ namespace MWClass
|
|||
virtual void unlock (const MWWorld::Ptr& ptr) const;
|
||||
///< Unlock object
|
||||
|
||||
virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
|
||||
const;
|
||||
///< Read additional state from \a state into \a ptr.
|
||||
|
||||
virtual void writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
|
||||
const;
|
||||
///< Write additional state from \a ptr into \a state.
|
||||
|
||||
static void registerSelf();
|
||||
|
||||
virtual std::string getModel(const MWWorld::Ptr &ptr) const;
|
||||
|
|
|
@ -2,10 +2,12 @@
|
|||
#include "creature.hpp"
|
||||
|
||||
#include <components/esm/loadcrea.hpp>
|
||||
#include <components/esm/creaturestate.hpp>
|
||||
|
||||
#include "../mwmechanics/creaturestats.hpp"
|
||||
#include "../mwmechanics/magiceffects.hpp"
|
||||
#include "../mwmechanics/movement.hpp"
|
||||
#include "../mwmechanics/spellcasting.hpp"
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
|
@ -26,22 +28,30 @@
|
|||
|
||||
#include "../mwgui/tooltips.hpp"
|
||||
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
|
||||
#include "../mwmechanics/npcstats.hpp"
|
||||
#include "../mwmechanics/combat.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
struct CustomData : public MWWorld::CustomData
|
||||
{
|
||||
MWMechanics::CreatureStats mCreatureStats;
|
||||
MWWorld::ContainerStore mContainerStore;
|
||||
MWWorld::ContainerStore* mContainerStore; // may be InventoryStore for some creatures
|
||||
MWMechanics::Movement mMovement;
|
||||
|
||||
virtual MWWorld::CustomData *clone() const;
|
||||
|
||||
CustomData() : mContainerStore(0) {}
|
||||
virtual ~CustomData() { delete mContainerStore; }
|
||||
};
|
||||
|
||||
MWWorld::CustomData *CustomData::clone() const
|
||||
{
|
||||
return new CustomData (*this);
|
||||
CustomData* cloned = new CustomData (*this);
|
||||
cloned->mContainerStore = mContainerStore->clone();
|
||||
return cloned;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -106,15 +116,23 @@ namespace MWClass
|
|||
data->mCreatureStats.getSpells().add (*iter);
|
||||
|
||||
// inventory
|
||||
data->mContainerStore.fill(ref->mBase->mInventory, getId(ptr), "",
|
||||
if (ref->mBase->mFlags & ESM::Creature::Weapon)
|
||||
data->mContainerStore = new MWWorld::InventoryStore();
|
||||
else
|
||||
data->mContainerStore = new MWWorld::ContainerStore();
|
||||
|
||||
// store
|
||||
ptr.getRefData().setCustomData (data.release());
|
||||
|
||||
getContainerStore(ptr).fill(ref->mBase->mInventory, getId(ptr), "",
|
||||
MWBase::Environment::get().getWorld()->getStore());
|
||||
|
||||
// TODO: this is not quite correct, in vanilla the merchant's gold pool is not available in his inventory.
|
||||
// (except for gold you gave him)
|
||||
data->mContainerStore.add(MWWorld::ContainerStore::sGoldId, ref->mBase->mData.mGold, ptr);
|
||||
getContainerStore(ptr).add(MWWorld::ContainerStore::sGoldId, ref->mBase->mData.mGold, ptr);
|
||||
|
||||
// store
|
||||
ptr.getRefData().setCustomData (data.release());
|
||||
if (ref->mBase->mFlags & ESM::Creature::Weapon)
|
||||
getInventoryStore(ptr).autoEquip(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -133,8 +151,10 @@ namespace MWClass
|
|||
|
||||
void Creature::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
|
||||
|
||||
MWRender::Actors& actors = renderingInterface.getActors();
|
||||
actors.insertCreature(ptr);
|
||||
actors.insertCreature(ptr, ref->mBase->mFlags & ESM::Creature::Weapon);
|
||||
}
|
||||
|
||||
void Creature::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const
|
||||
|
@ -178,9 +198,40 @@ namespace MWClass
|
|||
{
|
||||
MWWorld::LiveCellRef<ESM::Creature> *ref =
|
||||
ptr.get<ESM::Creature>();
|
||||
const MWWorld::Store<ESM::GameSetting> &gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||
MWMechanics::CreatureStats &stats = getCreatureStats(ptr);
|
||||
|
||||
// Get the weapon used (if hand-to-hand, weapon = inv.end())
|
||||
MWWorld::Ptr weapon;
|
||||
if (ptr.getClass().hasInventoryStore(ptr))
|
||||
{
|
||||
MWWorld::InventoryStore &inv = getInventoryStore(ptr);
|
||||
MWWorld::ContainerStoreIterator weaponslot = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||
if (weaponslot != inv.end() && weaponslot->getTypeName() == typeid(ESM::Weapon).name())
|
||||
weapon = *weaponslot;
|
||||
}
|
||||
|
||||
// Reduce fatigue
|
||||
// somewhat of a guess, but using the weapon weight makes sense
|
||||
const float fFatigueAttackBase = gmst.find("fFatigueAttackBase")->getFloat();
|
||||
const float fFatigueAttackMult = gmst.find("fFatigueAttackMult")->getFloat();
|
||||
const float fWeaponFatigueMult = gmst.find("fWeaponFatigueMult")->getFloat();
|
||||
MWMechanics::DynamicStat<float> fatigue = stats.getFatigue();
|
||||
const float normalizedEncumbrance = getEncumbrance(ptr) / getCapacity(ptr);
|
||||
float fatigueLoss = fFatigueAttackBase + normalizedEncumbrance * fFatigueAttackMult;
|
||||
if (!weapon.isEmpty())
|
||||
fatigueLoss += weapon.getClass().getWeight(weapon) * stats.getAttackStrength() * fWeaponFatigueMult;
|
||||
fatigue.setCurrent(fatigue.getCurrent() - fatigueLoss);
|
||||
stats.setFatigue(fatigue);
|
||||
|
||||
// TODO: where is the distance defined?
|
||||
std::pair<MWWorld::Ptr, Ogre::Vector3> result = MWBase::Environment::get().getWorld()->getHitContact(ptr, 100);
|
||||
float dist = 200.f;
|
||||
if (!weapon.isEmpty())
|
||||
{
|
||||
const float fCombatDistance = gmst.find("fCombatDistance")->getFloat();
|
||||
dist = fCombatDistance * weapon.get<ESM::Weapon>()->mBase->mData.mReach;
|
||||
}
|
||||
std::pair<MWWorld::Ptr, Ogre::Vector3> result = MWBase::Environment::get().getWorld()->getHitContact(ptr, dist);
|
||||
if (result.first.isEmpty())
|
||||
return; // Didn't hit anything
|
||||
|
||||
|
@ -191,7 +242,6 @@ namespace MWClass
|
|||
|
||||
Ogre::Vector3 hitPosition = result.second;
|
||||
|
||||
MWMechanics::CreatureStats &stats = getCreatureStats(ptr);
|
||||
MWMechanics::CreatureStats &otherstats = victim.getClass().getCreatureStats(victim);
|
||||
const MWMechanics::MagicEffects &mageffects = stats.getMagicEffects();
|
||||
float hitchance = ref->mBase->mData.mCombat +
|
||||
|
@ -226,12 +276,64 @@ namespace MWClass
|
|||
break;
|
||||
}
|
||||
|
||||
// I think this should be random, since attack1-3 animations don't have an attack strength like NPCs do
|
||||
float damage = min + (max - min) * ::rand()/(RAND_MAX+1.0);
|
||||
|
||||
// TODO: do not do this if the attack is blocked
|
||||
MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, hitPosition);
|
||||
if (!weapon.isEmpty())
|
||||
{
|
||||
const bool weaphashealth = get(weapon).hasItemHealth(weapon);
|
||||
const unsigned char *attack = NULL;
|
||||
if(type == ESM::Weapon::AT_Chop)
|
||||
attack = weapon.get<ESM::Weapon>()->mBase->mData.mChop;
|
||||
else if(type == ESM::Weapon::AT_Slash)
|
||||
attack = weapon.get<ESM::Weapon>()->mBase->mData.mSlash;
|
||||
else if(type == ESM::Weapon::AT_Thrust)
|
||||
attack = weapon.get<ESM::Weapon>()->mBase->mData.mThrust;
|
||||
if(attack)
|
||||
{
|
||||
float weaponDamage = attack[0] + ((attack[1]-attack[0])*stats.getAttackStrength());
|
||||
weaponDamage *= 0.5f + (stats.getAttribute(ESM::Attribute::Luck).getModified() / 100.0f);
|
||||
if(weaphashealth)
|
||||
{
|
||||
int weapmaxhealth = weapon.get<ESM::Weapon>()->mBase->mData.mHealth;
|
||||
if(weapon.getCellRef().mCharge == -1)
|
||||
weapon.getCellRef().mCharge = weapmaxhealth;
|
||||
weaponDamage *= float(weapon.getCellRef().mCharge) / weapmaxhealth;
|
||||
}
|
||||
|
||||
victim.getClass().onHit(victim, damage, true, MWWorld::Ptr(), ptr, true);
|
||||
if (!MWBase::Environment::get().getWorld()->getGodModeState())
|
||||
weapon.getCellRef().mCharge -= std::min(std::max(1,
|
||||
(int)(damage * gmst.find("fWeaponDamageMult")->getFloat())), weapon.getCellRef().mCharge);
|
||||
|
||||
// Weapon broken? unequip it
|
||||
if (weapon.getCellRef().mCharge == 0)
|
||||
weapon = *getInventoryStore(ptr).unequipItem(weapon, ptr);
|
||||
|
||||
damage += weaponDamage;
|
||||
}
|
||||
|
||||
// Apply "On hit" enchanted weapons
|
||||
std::string enchantmentName = !weapon.isEmpty() ? weapon.getClass().getEnchantment(weapon) : "";
|
||||
if (!enchantmentName.empty())
|
||||
{
|
||||
const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().find(
|
||||
enchantmentName);
|
||||
if (enchantment->mData.mType == ESM::Enchantment::WhenStrikes)
|
||||
{
|
||||
MWMechanics::CastSpell cast(ptr, victim);
|
||||
cast.mHitPosition = hitPosition;
|
||||
cast.cast(weapon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!weapon.isEmpty() && MWMechanics::blockMeleeAttack(ptr, victim, weapon, damage))
|
||||
damage = 0;
|
||||
|
||||
if (damage > 0)
|
||||
MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, hitPosition);
|
||||
|
||||
victim.getClass().onHit(victim, damage, true, weapon, ptr, true);
|
||||
}
|
||||
|
||||
void Creature::onHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, bool successful) const
|
||||
|
@ -258,31 +360,60 @@ namespace MWClass
|
|||
ptr.getRefData().getLocals().setVarByInt(script, "onpchitme", 1);
|
||||
}
|
||||
|
||||
// Check for knockdown
|
||||
float agilityTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * fKnockDownMult->getFloat();
|
||||
float knockdownTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified()
|
||||
* iKnockDownOddsMult->getInt() * 0.01 + iKnockDownOddsBase->getInt();
|
||||
int roll = std::rand()/ (static_cast<double> (RAND_MAX) + 1) * 100; // [0, 99]
|
||||
if (ishealth && agilityTerm <= damage && knockdownTerm <= roll)
|
||||
{
|
||||
getCreatureStats(ptr).setKnockedDown(true);
|
||||
if (damage > 0.0f && !object.isEmpty())
|
||||
MWMechanics::resistNormalWeapon(ptr, attacker, object, damage);
|
||||
|
||||
}
|
||||
else
|
||||
getCreatureStats(ptr).setHitRecovery(true); // Is this supposed to always occur?
|
||||
|
||||
if(ishealth)
|
||||
if (damage > 0.f)
|
||||
{
|
||||
if(damage > 0.0f)
|
||||
// Check for knockdown
|
||||
float agilityTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * fKnockDownMult->getFloat();
|
||||
float knockdownTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified()
|
||||
* iKnockDownOddsMult->getInt() * 0.01 + iKnockDownOddsBase->getInt();
|
||||
int roll = std::rand()/ (static_cast<double> (RAND_MAX) + 1) * 100; // [0, 99]
|
||||
if (ishealth && agilityTerm <= damage && knockdownTerm <= roll)
|
||||
{
|
||||
getCreatureStats(ptr).setKnockedDown(true);
|
||||
|
||||
}
|
||||
else
|
||||
getCreatureStats(ptr).setHitRecovery(true); // Is this supposed to always occur?
|
||||
|
||||
if(ishealth)
|
||||
{
|
||||
MWBase::Environment::get().getSoundManager()->playSound3D(ptr, "Health Damage", 1.0f, 1.0f);
|
||||
float health = getCreatureStats(ptr).getHealth().getCurrent() - damage;
|
||||
setActorHealth(ptr, health, attacker);
|
||||
float health = getCreatureStats(ptr).getHealth().getCurrent() - damage;
|
||||
setActorHealth(ptr, health, attacker);
|
||||
}
|
||||
else
|
||||
{
|
||||
MWMechanics::DynamicStat<float> fatigue(getCreatureStats(ptr).getFatigue());
|
||||
fatigue.setCurrent(fatigue.getCurrent() - damage, true);
|
||||
getCreatureStats(ptr).setFatigue(fatigue);
|
||||
}
|
||||
}
|
||||
else
|
||||
}
|
||||
|
||||
void Creature::block(const MWWorld::Ptr &ptr) const
|
||||
{
|
||||
MWWorld::InventoryStore& inv = getInventoryStore(ptr);
|
||||
MWWorld::ContainerStoreIterator shield = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft);
|
||||
if (shield == inv.end())
|
||||
return;
|
||||
|
||||
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
||||
switch(shield->getClass().getEquipmentSkill(*shield))
|
||||
{
|
||||
MWMechanics::DynamicStat<float> fatigue(getCreatureStats(ptr).getFatigue());
|
||||
fatigue.setCurrent(fatigue.getCurrent() - damage, true);
|
||||
getCreatureStats(ptr).setFatigue(fatigue);
|
||||
case ESM::Skill::LightArmor:
|
||||
sndMgr->playSound3D(ptr, "Light Armor Hit", 1.0f, 1.0f);
|
||||
break;
|
||||
case ESM::Skill::MediumArmor:
|
||||
sndMgr->playSound3D(ptr, "Medium Armor Hit", 1.0f, 1.0f);
|
||||
break;
|
||||
case ESM::Skill::HeavyArmor:
|
||||
sndMgr->playSound3D(ptr, "Heavy Armor Hit", 1.0f, 1.0f);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -325,18 +456,33 @@ namespace MWClass
|
|||
return boost::shared_ptr<MWWorld::Action>(new MWWorld::ActionTalk(ptr));
|
||||
}
|
||||
|
||||
MWWorld::ContainerStore& Creature::getContainerStore (const MWWorld::Ptr& ptr)
|
||||
const
|
||||
MWWorld::ContainerStore& Creature::getContainerStore (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
ensureCustomData (ptr);
|
||||
|
||||
return dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mContainerStore;
|
||||
return *dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mContainerStore;
|
||||
}
|
||||
|
||||
MWWorld::InventoryStore& Creature::getInventoryStore(const MWWorld::Ptr &ptr) const
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
|
||||
|
||||
if (ref->mBase->mFlags & ESM::Creature::Weapon)
|
||||
return dynamic_cast<MWWorld::InventoryStore&>(getContainerStore(ptr));
|
||||
else
|
||||
throw std::runtime_error("this creature has no inventory store");
|
||||
}
|
||||
|
||||
bool Creature::hasInventoryStore(const MWWorld::Ptr &ptr) const
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
|
||||
|
||||
return (ref->mBase->mFlags & ESM::Creature::Weapon);
|
||||
}
|
||||
|
||||
std::string Creature::getScript (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::Creature> *ref =
|
||||
ptr.get<ESM::Creature>();
|
||||
MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
|
||||
|
||||
return ref->mBase->mScript;
|
||||
}
|
||||
|
@ -613,6 +759,28 @@ namespace MWClass
|
|||
return 0;
|
||||
}
|
||||
|
||||
void Creature::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
|
||||
const
|
||||
{
|
||||
const ESM::CreatureState& state2 = dynamic_cast<const ESM::CreatureState&> (state);
|
||||
|
||||
ensureCustomData (ptr);
|
||||
|
||||
dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mContainerStore->
|
||||
readState (state2.mInventory);
|
||||
}
|
||||
|
||||
void Creature::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
|
||||
const
|
||||
{
|
||||
ESM::CreatureState& state2 = dynamic_cast<ESM::CreatureState&> (state);
|
||||
|
||||
ensureCustomData (ptr);
|
||||
|
||||
dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mContainerStore->
|
||||
writeState (state2.mInventory);
|
||||
}
|
||||
|
||||
const ESM::GameSetting* Creature::fMinWalkSpeedCreature;
|
||||
const ESM::GameSetting* Creature::fMaxWalkSpeedCreature;
|
||||
const ESM::GameSetting *Creature::fEncumberedMoveEffect;
|
||||
|
|
|
@ -56,6 +56,8 @@ namespace MWClass
|
|||
|
||||
virtual void hit(const MWWorld::Ptr& ptr, int type) const;
|
||||
|
||||
virtual void block(const MWWorld::Ptr &ptr) const;
|
||||
|
||||
virtual void onHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, bool successful) const;
|
||||
|
||||
virtual void setActorHealth(const MWWorld::Ptr& ptr, float health, const MWWorld::Ptr& attacker) const;
|
||||
|
@ -68,6 +70,11 @@ namespace MWClass
|
|||
const MWWorld::Ptr& ptr) const;
|
||||
///< Return container store
|
||||
|
||||
virtual MWWorld::InventoryStore& getInventoryStore (const MWWorld::Ptr& ptr) const;
|
||||
///< Return inventory store
|
||||
|
||||
virtual bool hasInventoryStore (const MWWorld::Ptr &ptr) const;
|
||||
|
||||
virtual std::string getScript (const MWWorld::Ptr& ptr) const;
|
||||
///< Return name of the script attached to ptr
|
||||
|
||||
|
@ -84,7 +91,7 @@ namespace MWClass
|
|||
|
||||
virtual bool isEssential (const MWWorld::Ptr& ptr) const;
|
||||
///< Is \a ptr essential? (i.e. may losing \a ptr make the game unwinnable)
|
||||
|
||||
|
||||
virtual int getServices (const MWWorld::Ptr& actor) const;
|
||||
|
||||
virtual bool isPersistent (const MWWorld::Ptr& ptr) const;
|
||||
|
@ -118,6 +125,14 @@ namespace MWClass
|
|||
|
||||
/// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini)
|
||||
virtual int getBloodTexture (const MWWorld::Ptr& ptr) const;
|
||||
|
||||
virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
|
||||
const;
|
||||
///< Read additional state from \a state into \a ptr.
|
||||
|
||||
virtual void writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
|
||||
const;
|
||||
///< Write additional state from \a ptr into \a state.
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,24 @@
|
|||
|
||||
#include <components/esm/loadlevlist.hpp>
|
||||
|
||||
#include "../mwmechanics/levelledlist.hpp"
|
||||
|
||||
#include "../mwworld/customdata.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
struct CustomData : public MWWorld::CustomData
|
||||
{
|
||||
// TODO: save the creature we spawned here
|
||||
virtual MWWorld::CustomData *clone() const;
|
||||
};
|
||||
|
||||
MWWorld::CustomData *CustomData::clone() const
|
||||
{
|
||||
return new CustomData (*this);
|
||||
}
|
||||
}
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
std::string CreatureLevList::getName (const MWWorld::Ptr& ptr) const
|
||||
|
@ -16,4 +34,33 @@ namespace MWClass
|
|||
|
||||
registerClass (typeid (ESM::CreatureLevList).name(), instance);
|
||||
}
|
||||
|
||||
void CreatureLevList::insertObjectRendering(const MWWorld::Ptr &ptr, MWRender::RenderingInterface &renderingInterface) const
|
||||
{
|
||||
ensureCustomData(ptr);
|
||||
}
|
||||
|
||||
void CreatureLevList::ensureCustomData(const MWWorld::Ptr &ptr) const
|
||||
{
|
||||
if (!ptr.getRefData().getCustomData())
|
||||
{
|
||||
std::auto_ptr<CustomData> data (new CustomData);
|
||||
|
||||
MWWorld::LiveCellRef<ESM::CreatureLevList> *ref =
|
||||
ptr.get<ESM::CreatureLevList>();
|
||||
|
||||
std::string id = MWMechanics::getLevelledItem(ref->mBase, true);
|
||||
|
||||
if (!id.empty())
|
||||
{
|
||||
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
|
||||
MWWorld::ManualRef ref(store, id);
|
||||
ref.getPtr().getCellRef().mPos = ptr.getCellRef().mPos;
|
||||
// TODO: hold on to this for respawn purposes later
|
||||
MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(), *ptr.getCell() , ptr.getCellRef().mPos);
|
||||
}
|
||||
|
||||
ptr.getRefData().setCustomData(data.release());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@ namespace MWClass
|
|||
{
|
||||
class CreatureLevList : public MWWorld::Class
|
||||
{
|
||||
void ensureCustomData (const MWWorld::Ptr& ptr) const;
|
||||
|
||||
public:
|
||||
|
||||
virtual std::string getName (const MWWorld::Ptr& ptr) const;
|
||||
|
@ -14,6 +16,9 @@ namespace MWClass
|
|||
/// can return an empty string.
|
||||
|
||||
static void registerSelf();
|
||||
|
||||
virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const;
|
||||
///< Add reference into a cell for rendering
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "light.hpp"
|
||||
|
||||
#include <components/esm/loadligh.hpp>
|
||||
#include <components/esm/lightstate.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
@ -269,4 +270,24 @@ namespace MWClass
|
|||
}
|
||||
return std::make_pair(1,"");
|
||||
}
|
||||
|
||||
void Light::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
|
||||
const
|
||||
{
|
||||
const ESM::LightState& state2 = dynamic_cast<const ESM::LightState&> (state);
|
||||
|
||||
ensureCustomData (ptr);
|
||||
|
||||
dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mTime = state2.mTime;
|
||||
}
|
||||
|
||||
void Light::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
|
||||
const
|
||||
{
|
||||
ESM::LightState& state2 = dynamic_cast<ESM::LightState&> (state);
|
||||
|
||||
ensureCustomData (ptr);
|
||||
|
||||
state2.mTime = dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mTime;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,6 +71,14 @@ namespace MWClass
|
|||
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;
|
||||
|
||||
virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
|
||||
const;
|
||||
///< Read additional state from \a state into \a ptr.
|
||||
|
||||
virtual void writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
|
||||
const;
|
||||
///< Write additional state from \a ptr into \a state.
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -155,11 +155,8 @@ namespace MWClass
|
|||
int count = ptr.getRefData().getCount();
|
||||
|
||||
bool gold = isGold(ptr);
|
||||
|
||||
if (gold && ptr.getCellRef().mGoldValue != 1)
|
||||
count = ptr.getCellRef().mGoldValue;
|
||||
else if (gold)
|
||||
count *= ref->mBase->mData.mValue;
|
||||
if (gold)
|
||||
count *= getValue(ptr);
|
||||
|
||||
std::string countString;
|
||||
if (!gold)
|
||||
|
@ -204,7 +201,7 @@ namespace MWClass
|
|||
MWBase::Environment::get().getWorld()->getStore();
|
||||
|
||||
if (isGold(ptr)) {
|
||||
int goldAmount = ptr.getRefData().getCount();
|
||||
int goldAmount = getValue(ptr) * ptr.getRefData().getCount();
|
||||
|
||||
std::string base = "Gold_001";
|
||||
if (goldAmount >= 100)
|
||||
|
@ -223,6 +220,7 @@ namespace MWClass
|
|||
newRef.getPtr().get<ESM::Miscellaneous>();
|
||||
newPtr = MWWorld::Ptr(&cell.mMiscItems.insert(*ref), &cell);
|
||||
newPtr.getCellRef().mGoldValue = goldAmount;
|
||||
newPtr.getRefData().setCount(1);
|
||||
} else {
|
||||
MWWorld::LiveCellRef<ESM::Miscellaneous> *ref =
|
||||
ptr.get<ESM::Miscellaneous>();
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include <components/esm/loadmgef.hpp>
|
||||
#include <components/esm/loadnpc.hpp>
|
||||
#include <components/esm/npcstate.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
@ -20,6 +21,7 @@
|
|||
#include "../mwmechanics/movement.hpp"
|
||||
#include "../mwmechanics/spellcasting.hpp"
|
||||
#include "../mwmechanics/disease.hpp"
|
||||
#include "../mwmechanics/combat.hpp"
|
||||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "../mwworld/actiontalk.hpp"
|
||||
|
@ -36,9 +38,6 @@
|
|||
|
||||
namespace
|
||||
{
|
||||
const Ogre::Radian kOgrePi (Ogre::Math::PI);
|
||||
const Ogre::Radian kOgrePiOverTwo (Ogre::Math::PI / Ogre::Real(2.0));
|
||||
|
||||
struct CustomData : public MWWorld::CustomData
|
||||
{
|
||||
MWMechanics::NpcStats mNpcStats;
|
||||
|
@ -144,7 +143,7 @@ namespace
|
|||
*
|
||||
* and by adding class, race, specialization bonus.
|
||||
*/
|
||||
void autoCalculateSkills(const ESM::NPC* npc, MWMechanics::NpcStats& npcStats)
|
||||
void autoCalculateSkills(const ESM::NPC* npc, MWMechanics::NpcStats& npcStats, const MWWorld::Ptr& ptr)
|
||||
{
|
||||
const ESM::Class *class_ =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Class>().find(npc->mClass);
|
||||
|
@ -193,6 +192,18 @@ namespace
|
|||
majorMultiplier = 1.0f;
|
||||
break;
|
||||
}
|
||||
if (class_->mData.mSkills[k][1] == skillIndex)
|
||||
{
|
||||
// Major skill -> add starting spells for this skill if existing
|
||||
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
|
||||
MWWorld::Store<ESM::Spell>::iterator it = store.get<ESM::Spell>().begin();
|
||||
for (; it != store.get<ESM::Spell>().end(); ++it)
|
||||
{
|
||||
if (it->mData.mFlags & ESM::Spell::F_Autocalc
|
||||
&& MWMechanics::spellSchoolToSkill(MWMechanics::getSpellSchool(&*it, ptr)) == skillIndex)
|
||||
npcStats.getSpells().add(it->mId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// is this skill in the same Specialization as the class?
|
||||
|
@ -243,6 +254,8 @@ namespace MWClass
|
|||
fKnockDownMult = gmst.find("fKnockDownMult");
|
||||
iKnockDownOddsMult = gmst.find("iKnockDownOddsMult");
|
||||
iKnockDownOddsBase = gmst.find("iKnockDownOddsBase");
|
||||
fDamageStrengthBase = gmst.find("fDamageStrengthBase");
|
||||
fDamageStrengthMult = gmst.find("fDamageStrengthMult");
|
||||
|
||||
inited = true;
|
||||
}
|
||||
|
@ -305,7 +318,15 @@ namespace MWClass
|
|||
data->mNpcStats.setReputation(ref->mBase->mNpdt12.mReputation);
|
||||
|
||||
autoCalculateAttributes(ref->mBase, data->mNpcStats);
|
||||
autoCalculateSkills(ref->mBase, data->mNpcStats);
|
||||
autoCalculateSkills(ref->mBase, data->mNpcStats, ptr);
|
||||
}
|
||||
|
||||
// race powers
|
||||
const ESM::Race *race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(ref->mBase->mRace);
|
||||
for (std::vector<std::string>::const_iterator iter (race->mPowers.mList.begin());
|
||||
iter!=race->mPowers.mList.end(); ++iter)
|
||||
{
|
||||
data->mNpcStats.getSpells().add (*iter);
|
||||
}
|
||||
|
||||
if (data->mNpcStats.getFactionRanks().size())
|
||||
|
@ -450,10 +471,11 @@ namespace MWClass
|
|||
fatigue.setCurrent(fatigue.getCurrent() - fatigueLoss);
|
||||
getCreatureStats(ptr).setFatigue(fatigue);
|
||||
|
||||
|
||||
float dist = 100.0f * (!weapon.isEmpty() ?
|
||||
const float fCombatDistance = gmst.find("fCombatDistance")->getFloat();
|
||||
float dist = fCombatDistance * (!weapon.isEmpty() ?
|
||||
weapon.get<ESM::Weapon>()->mBase->mData.mReach :
|
||||
gmst.find("fHandToHandReach")->getFloat());
|
||||
|
||||
// TODO: Use second to work out the hit angle
|
||||
std::pair<MWWorld::Ptr, Ogre::Vector3> result = world->getHitContact(ptr, dist);
|
||||
MWWorld::Ptr victim = result.first;
|
||||
|
@ -497,16 +519,17 @@ namespace MWClass
|
|||
{
|
||||
const bool weaphashealth = get(weapon).hasItemHealth(weapon);
|
||||
const unsigned char *attack = NULL;
|
||||
if(type == MWMechanics::CreatureStats::AT_Chop)
|
||||
if(type == ESM::Weapon::AT_Chop)
|
||||
attack = weapon.get<ESM::Weapon>()->mBase->mData.mChop;
|
||||
else if(type == MWMechanics::CreatureStats::AT_Slash)
|
||||
else if(type == ESM::Weapon::AT_Slash)
|
||||
attack = weapon.get<ESM::Weapon>()->mBase->mData.mSlash;
|
||||
else if(type == MWMechanics::CreatureStats::AT_Thrust)
|
||||
else if(type == ESM::Weapon::AT_Thrust)
|
||||
attack = weapon.get<ESM::Weapon>()->mBase->mData.mThrust;
|
||||
if(attack)
|
||||
{
|
||||
damage = attack[0] + ((attack[1]-attack[0])*stats.getAttackStrength());
|
||||
damage *= 0.5f + (stats.getAttribute(ESM::Attribute::Luck).getModified() / 100.0f);
|
||||
damage *= fDamageStrengthBase->getFloat() +
|
||||
(stats.getAttribute(ESM::Attribute::Strength).getModified() * fDamageStrengthMult->getFloat() * 0.1);
|
||||
if(weaphashealth)
|
||||
{
|
||||
int weapmaxhealth = weapon.get<ESM::Weapon>()->mBase->mData.mHealth;
|
||||
|
@ -514,7 +537,7 @@ namespace MWClass
|
|||
weapon.getCellRef().mCharge = weapmaxhealth;
|
||||
damage *= float(weapon.getCellRef().mCharge) / weapmaxhealth;
|
||||
}
|
||||
|
||||
|
||||
if (!MWBase::Environment::get().getWorld()->getGodModeState())
|
||||
weapon.getCellRef().mCharge -= std::min(std::max(1,
|
||||
(int)(damage * gmst.find("fWeaponDamageMult")->getFloat())), weapon.getCellRef().mCharge);
|
||||
|
@ -579,33 +602,16 @@ namespace MWClass
|
|||
enchantmentName);
|
||||
if (enchantment->mData.mType == ESM::Enchantment::WhenStrikes)
|
||||
{
|
||||
// Check if we have enough charges
|
||||
const float enchantCost = enchantment->mData.mCost;
|
||||
int eSkill = stats.getSkill(ESM::Skill::Enchant).getModified();
|
||||
const int castCost = std::max(1.f, enchantCost - (enchantCost / 100) * (eSkill - 10));
|
||||
|
||||
if (weapon.getCellRef().mEnchantmentCharge == -1)
|
||||
weapon.getCellRef().mEnchantmentCharge = enchantment->mData.mCharge;
|
||||
if (weapon.getCellRef().mEnchantmentCharge < castCost)
|
||||
{
|
||||
if (ptr.getRefData().getHandle() == "player")
|
||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicInsufficientCharge}");
|
||||
}
|
||||
else
|
||||
{
|
||||
weapon.getCellRef().mEnchantmentCharge -= castCost;
|
||||
|
||||
MWMechanics::CastSpell cast(ptr, victim);
|
||||
cast.cast(weapon);
|
||||
|
||||
if (ptr.getRefData().getHandle() == "player")
|
||||
skillUsageSucceeded (ptr, ESM::Skill::Enchant, 3);
|
||||
}
|
||||
MWMechanics::CastSpell cast(ptr, victim);
|
||||
cast.mHitPosition = hitPosition;
|
||||
cast.cast(weapon);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: do not do this if the attack is blocked
|
||||
if (healthdmg)
|
||||
if (!weapon.isEmpty() && MWMechanics::blockMeleeAttack(ptr, victim, weapon, damage))
|
||||
damage = 0;
|
||||
|
||||
if (healthdmg && damage > 0)
|
||||
MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, hitPosition);
|
||||
|
||||
othercls.onHit(victim, damage, healthdmg, weapon, ptr, true);
|
||||
|
@ -644,6 +650,9 @@ namespace MWClass
|
|||
if (!attacker.isEmpty())
|
||||
MWMechanics::diseaseContact(ptr, attacker);
|
||||
|
||||
if (damage > 0.0f && !object.isEmpty())
|
||||
MWMechanics::resistNormalWeapon(ptr, attacker, object, damage);
|
||||
|
||||
if(damage > 0.0f)
|
||||
{
|
||||
// 'ptr' is losing health. Play a 'hit' voiced dialog entry if not already saying
|
||||
|
@ -715,6 +724,9 @@ namespace MWClass
|
|||
if (armorref.mCharge == 0)
|
||||
inv.unequipItem(armor, ptr);
|
||||
|
||||
if (ptr.getRefData().getHandle() == "player")
|
||||
skillUsageSucceeded(ptr, get(armor).getEquipmentSkill(armor), 0);
|
||||
|
||||
switch(get(armor).getEquipmentSkill(armor))
|
||||
{
|
||||
case ESM::Skill::LightArmor:
|
||||
|
@ -728,6 +740,8 @@ namespace MWClass
|
|||
break;
|
||||
}
|
||||
}
|
||||
else if(ptr.getRefData().getHandle() == "player")
|
||||
skillUsageSucceeded(ptr, ESM::Skill::Unarmored, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -746,6 +760,30 @@ namespace MWClass
|
|||
}
|
||||
}
|
||||
|
||||
void Npc::block(const MWWorld::Ptr &ptr) const
|
||||
{
|
||||
MWWorld::InventoryStore& inv = getInventoryStore(ptr);
|
||||
MWWorld::ContainerStoreIterator shield = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft);
|
||||
if (shield == inv.end())
|
||||
return;
|
||||
|
||||
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
||||
switch(shield->getClass().getEquipmentSkill(*shield))
|
||||
{
|
||||
case ESM::Skill::LightArmor:
|
||||
sndMgr->playSound3D(ptr, "Light Armor Hit", 1.0f, 1.0f);
|
||||
break;
|
||||
case ESM::Skill::MediumArmor:
|
||||
sndMgr->playSound3D(ptr, "Medium Armor Hit", 1.0f, 1.0f);
|
||||
break;
|
||||
case ESM::Skill::HeavyArmor:
|
||||
sndMgr->playSound3D(ptr, "Heavy Armor Hit", 1.0f, 1.0f);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Npc::setActorHealth(const MWWorld::Ptr& ptr, float health, const MWWorld::Ptr& attacker) const
|
||||
{
|
||||
MWMechanics::CreatureStats &crstats = getCreatureStats(ptr);
|
||||
|
@ -964,7 +1002,7 @@ namespace MWClass
|
|||
|
||||
return ref->mBase->mFlags & ESM::NPC::Essential;
|
||||
}
|
||||
|
||||
|
||||
void Npc::registerSelf()
|
||||
{
|
||||
boost::shared_ptr<Class> instance (new Npc);
|
||||
|
@ -1233,6 +1271,28 @@ namespace MWClass
|
|||
return 0;
|
||||
}
|
||||
|
||||
void Npc::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
|
||||
const
|
||||
{
|
||||
const ESM::NpcState& state2 = dynamic_cast<const ESM::NpcState&> (state);
|
||||
|
||||
ensureCustomData (ptr);
|
||||
|
||||
dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mInventoryStore.
|
||||
readState (state2.mInventory);
|
||||
}
|
||||
|
||||
void Npc::writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
|
||||
const
|
||||
{
|
||||
ESM::NpcState& state2 = dynamic_cast<ESM::NpcState&> (state);
|
||||
|
||||
ensureCustomData (ptr);
|
||||
|
||||
dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mInventoryStore.
|
||||
writeState (state2.mInventory);
|
||||
}
|
||||
|
||||
const ESM::GameSetting *Npc::fMinWalkSpeed;
|
||||
const ESM::GameSetting *Npc::fMaxWalkSpeed;
|
||||
const ESM::GameSetting *Npc::fEncumberedMoveEffect;
|
||||
|
@ -1252,4 +1312,7 @@ namespace MWClass
|
|||
const ESM::GameSetting *Npc::fKnockDownMult;
|
||||
const ESM::GameSetting *Npc::iKnockDownOddsMult;
|
||||
const ESM::GameSetting *Npc::iKnockDownOddsBase;
|
||||
const ESM::GameSetting *Npc::fDamageStrengthBase;
|
||||
const ESM::GameSetting *Npc::fDamageStrengthMult;
|
||||
|
||||
}
|
||||
|
|
|
@ -36,6 +36,8 @@ namespace MWClass
|
|||
static const ESM::GameSetting *fKnockDownMult;
|
||||
static const ESM::GameSetting *iKnockDownOddsMult;
|
||||
static const ESM::GameSetting *iKnockDownOddsBase;
|
||||
static const ESM::GameSetting *fDamageStrengthBase;
|
||||
static const ESM::GameSetting *fDamageStrengthMult;
|
||||
|
||||
public:
|
||||
|
||||
|
@ -71,10 +73,14 @@ namespace MWClass
|
|||
virtual MWWorld::InventoryStore& getInventoryStore (const MWWorld::Ptr& ptr) const;
|
||||
///< Return inventory store
|
||||
|
||||
virtual bool hasInventoryStore(const MWWorld::Ptr &ptr) const { return true; }
|
||||
|
||||
virtual void hit(const MWWorld::Ptr& ptr, int type) const;
|
||||
|
||||
virtual void onHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, bool successful) const;
|
||||
|
||||
virtual void block(const MWWorld::Ptr &ptr) const;
|
||||
|
||||
virtual void setActorHealth(const MWWorld::Ptr& ptr, float health, const MWWorld::Ptr& attacker) const;
|
||||
|
||||
virtual boost::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr,
|
||||
|
@ -131,7 +137,7 @@ namespace MWClass
|
|||
///< Is \a ptr essential? (i.e. may losing \a ptr make the game unwinnable)
|
||||
|
||||
virtual int getServices (const MWWorld::Ptr& actor) const;
|
||||
|
||||
|
||||
virtual bool isPersistent (const MWWorld::Ptr& ptr) const;
|
||||
|
||||
virtual std::string getSoundIdFromSndGen(const MWWorld::Ptr &ptr, const std::string &name) const;
|
||||
|
@ -152,6 +158,14 @@ namespace MWClass
|
|||
virtual bool isNpc() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
|
||||
const;
|
||||
///< Read additional state from \a state into \a ptr.
|
||||
|
||||
virtual void writeAdditionalState (const MWWorld::Ptr& ptr, ESM::ObjectState& state)
|
||||
const;
|
||||
///< Write additional state from \a ptr into \a state.
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -429,12 +429,12 @@ namespace MWClass
|
|||
return MWWorld::Ptr(&cell.mWeapons.insert(*ref), &cell);
|
||||
}
|
||||
|
||||
float Weapon::getEnchantmentPoints (const MWWorld::Ptr& ptr) const
|
||||
int Weapon::getEnchantmentPoints (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::Weapon> *ref =
|
||||
ptr.get<ESM::Weapon>();
|
||||
|
||||
return ref->mBase->mData.mEnchant/10.f;
|
||||
return ref->mBase->mData.mEnchant;
|
||||
}
|
||||
|
||||
bool Weapon::canSell (const MWWorld::Ptr& item, int npcServices) const
|
||||
|
|
|
@ -84,7 +84,7 @@ namespace MWClass
|
|||
|
||||
virtual float getWeight (const MWWorld::Ptr& ptr) const;
|
||||
|
||||
virtual float getEnchantmentPoints (const MWWorld::Ptr& ptr) const;
|
||||
virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -286,7 +286,7 @@ namespace MWDialogue
|
|||
|
||||
MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor);
|
||||
win->addResponse (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext), title);
|
||||
MWBase::Environment::get().getJournal()->addTopic (topic, info->mId);
|
||||
MWBase::Environment::get().getJournal()->addTopic (topic, info->mId, mActor.getClass().getName(mActor));
|
||||
|
||||
executeScript (info->mResultScript);
|
||||
|
||||
|
@ -420,7 +420,7 @@ namespace MWDialogue
|
|||
MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Dialogue);
|
||||
|
||||
// Apply disposition change to NPC's base disposition
|
||||
if (mActor.getTypeName() == typeid(ESM::NPC).name())
|
||||
if (mActor.getClass().isNpc())
|
||||
{
|
||||
MWMechanics::NpcStats& npcStats = MWWorld::Class::get(mActor).getNpcStats(mActor);
|
||||
npcStats.setBaseDisposition(npcStats.getBaseDisposition() + mPermanentDispositionChange);
|
||||
|
@ -451,7 +451,7 @@ namespace MWDialogue
|
|||
|
||||
MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor);
|
||||
MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addResponse (Interpreter::fixDefinesDialog(text, interpreterContext));
|
||||
MWBase::Environment::get().getJournal()->addTopic (mLastTopic, info->mId);
|
||||
MWBase::Environment::get().getJournal()->addTopic (mLastTopic, info->mId, mActor.getClass().getName(mActor));
|
||||
executeScript (info->mResultScript);
|
||||
}
|
||||
}
|
||||
|
@ -586,7 +586,8 @@ namespace MWDialogue
|
|||
MWBase::WindowManager *winMgr = MWBase::Environment::get().getWindowManager();
|
||||
if(winMgr->getSubtitlesEnabled())
|
||||
winMgr->messageBox(info->mResponse);
|
||||
sndMgr->say(actor, info->mSound);
|
||||
if (!info->mSound.empty())
|
||||
sndMgr->say(actor, info->mSound);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -171,7 +171,7 @@ bool MWDialogue::Filter::testSelectStructNumeric (const SelectWrapper& select) c
|
|||
|
||||
// internally all globals are float :(
|
||||
return select.selectCompare (
|
||||
MWBase::Environment::get().getWorld()->getGlobalVariable (select.getName()).mFloat);
|
||||
MWBase::Environment::get().getWorld()->getGlobalFloat (select.getName()));
|
||||
|
||||
case SelectWrapper::Function_Local:
|
||||
{
|
||||
|
@ -216,7 +216,7 @@ bool MWDialogue::Filter::testSelectStructNumeric (const SelectWrapper& select) c
|
|||
float ratio = MWWorld::Class::get (player).getCreatureStats (player).getHealth().getCurrent() /
|
||||
MWWorld::Class::get (player).getCreatureStats (player).getHealth().getModified();
|
||||
|
||||
return select.selectCompare (ratio);
|
||||
return select.selectCompare (static_cast<int>(ratio*100));
|
||||
}
|
||||
|
||||
case SelectWrapper::Function_PcDynamicStat:
|
||||
|
@ -536,7 +536,7 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co
|
|||
|
||||
case SelectWrapper::Function_CreatureTargetted:
|
||||
|
||||
return MWWorld::Class::get (mActor).getCreatureStats (mActor).getCreatureTargetted();
|
||||
return mActor.getClass().getCreatureStats (mActor).getCreatureTargetted();
|
||||
|
||||
case SelectWrapper::Function_Werewolf:
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <components/esm/journalentry.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
||||
|
@ -10,23 +12,55 @@
|
|||
|
||||
namespace MWDialogue
|
||||
{
|
||||
JournalEntry::JournalEntry() {}
|
||||
Entry::Entry() {}
|
||||
|
||||
JournalEntry::JournalEntry (const std::string& topic, const std::string& infoId)
|
||||
: mTopic (topic), mInfoId (infoId)
|
||||
{}
|
||||
|
||||
std::string JournalEntry::getText (const MWWorld::ESMStore& store) const
|
||||
Entry::Entry (const std::string& topic, const std::string& infoId)
|
||||
: mInfoId (infoId)
|
||||
{
|
||||
const ESM::Dialogue *dialogue =
|
||||
store.get<ESM::Dialogue>().find (mTopic);
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>().find (topic);
|
||||
|
||||
for (std::vector<ESM::DialInfo>::const_iterator iter (dialogue->mInfo.begin());
|
||||
iter!=dialogue->mInfo.end(); ++iter)
|
||||
if (iter->mId == mInfoId)
|
||||
return iter->mResponse;
|
||||
{
|
||||
/// \todo text replacement
|
||||
mText = iter->mResponse;
|
||||
return;
|
||||
}
|
||||
|
||||
throw std::runtime_error ("unknown info ID " + mInfoId + " for topic " + mTopic);
|
||||
throw std::runtime_error ("unknown info ID " + mInfoId + " for topic " + topic);
|
||||
}
|
||||
|
||||
Entry::Entry (const ESM::JournalEntry& record) : mInfoId (record.mInfo), mText (record.mText), mActorName(record.mActorName) {}
|
||||
|
||||
std::string Entry::getText() const
|
||||
{
|
||||
return mText;
|
||||
}
|
||||
|
||||
void Entry::write (ESM::JournalEntry& entry) const
|
||||
{
|
||||
entry.mInfo = mInfoId;
|
||||
entry.mText = mText;
|
||||
entry.mActorName = mActorName;
|
||||
}
|
||||
|
||||
|
||||
JournalEntry::JournalEntry() {}
|
||||
|
||||
JournalEntry::JournalEntry (const std::string& topic, const std::string& infoId)
|
||||
: Entry (topic, infoId), mTopic (topic)
|
||||
{}
|
||||
|
||||
JournalEntry::JournalEntry (const ESM::JournalEntry& record)
|
||||
: Entry (record), mTopic (record.mTopic)
|
||||
{}
|
||||
|
||||
void JournalEntry::write (ESM::JournalEntry& entry) const
|
||||
{
|
||||
Entry::write (entry);
|
||||
entry.mTopic = mTopic;
|
||||
}
|
||||
|
||||
JournalEntry JournalEntry::makeFromQuest (const std::string& topic, int index)
|
||||
|
@ -49,6 +83,7 @@ namespace MWDialogue
|
|||
throw std::runtime_error ("unknown journal index for topic " + topic);
|
||||
}
|
||||
|
||||
|
||||
StampedJournalEntry::StampedJournalEntry()
|
||||
: mDay (0), mMonth (0), mDayOfMonth (0)
|
||||
{}
|
||||
|
@ -58,11 +93,24 @@ namespace MWDialogue
|
|||
: JournalEntry (topic, infoId), mDay (day), mMonth (month), mDayOfMonth (dayOfMonth)
|
||||
{}
|
||||
|
||||
StampedJournalEntry::StampedJournalEntry (const ESM::JournalEntry& record)
|
||||
: JournalEntry (record), mDay (record.mDay), mMonth (record.mMonth),
|
||||
mDayOfMonth (record.mDayOfMonth)
|
||||
{}
|
||||
|
||||
void StampedJournalEntry::write (ESM::JournalEntry& entry) const
|
||||
{
|
||||
JournalEntry::write (entry);
|
||||
entry.mDay = mDay;
|
||||
entry.mMonth = mMonth;
|
||||
entry.mDayOfMonth = mDayOfMonth;
|
||||
}
|
||||
|
||||
StampedJournalEntry StampedJournalEntry::makeFromQuest (const std::string& topic, int index)
|
||||
{
|
||||
int day = MWBase::Environment::get().getWorld()->getGlobalVariable ("dayspassed").mLong;
|
||||
int month = MWBase::Environment::get().getWorld()->getGlobalVariable ("month").mLong;
|
||||
int dayOfMonth = MWBase::Environment::get().getWorld()->getGlobalVariable ("day").mLong;
|
||||
int day = MWBase::Environment::get().getWorld()->getGlobalInt ("dayspassed");
|
||||
int month = MWBase::Environment::get().getWorld()->getGlobalInt ("month");
|
||||
int dayOfMonth = MWBase::Environment::get().getWorld()->getGlobalInt ("day");
|
||||
|
||||
return StampedJournalEntry (topic, idFromIndex (topic, index), day, month, dayOfMonth);
|
||||
}
|
||||
|
|
|
@ -3,24 +3,45 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
namespace MWWorld
|
||||
namespace ESM
|
||||
{
|
||||
struct ESMStore;
|
||||
struct JournalEntry;
|
||||
}
|
||||
|
||||
namespace MWDialogue
|
||||
{
|
||||
/// \brief A quest or dialogue entry
|
||||
struct JournalEntry
|
||||
/// \brief Basic quest/dialogue/topic entry
|
||||
struct Entry
|
||||
{
|
||||
std::string mInfoId;
|
||||
std::string mText;
|
||||
std::string mActorName; // optional
|
||||
|
||||
Entry();
|
||||
|
||||
Entry (const std::string& topic, const std::string& infoId);
|
||||
|
||||
Entry (const ESM::JournalEntry& record);
|
||||
|
||||
std::string getText() const;
|
||||
|
||||
void write (ESM::JournalEntry& entry) const;
|
||||
};
|
||||
|
||||
/// \brief A dialogue entry
|
||||
///
|
||||
/// Same as entry, but store TopicID
|
||||
struct JournalEntry : public Entry
|
||||
{
|
||||
std::string mTopic;
|
||||
std::string mInfoId;
|
||||
|
||||
JournalEntry();
|
||||
|
||||
JournalEntry (const std::string& topic, const std::string& infoId);
|
||||
|
||||
std::string getText (const MWWorld::ESMStore& store) const;
|
||||
JournalEntry (const ESM::JournalEntry& record);
|
||||
|
||||
void write (ESM::JournalEntry& entry) const;
|
||||
|
||||
static JournalEntry makeFromQuest (const std::string& topic, int index);
|
||||
|
||||
|
@ -39,6 +60,10 @@ namespace MWDialogue
|
|||
StampedJournalEntry (const std::string& topic, const std::string& infoId,
|
||||
int day, int month, int dayOfMonth);
|
||||
|
||||
StampedJournalEntry (const ESM::JournalEntry& record);
|
||||
|
||||
void write (ESM::JournalEntry& entry) const;
|
||||
|
||||
static StampedJournalEntry makeFromQuest (const std::string& topic, int index);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
|
||||
#include "journalimp.hpp"
|
||||
|
||||
#include <iterator>
|
||||
|
||||
#include <components/esm/esmwriter.hpp>
|
||||
#include <components/esm/esmreader.hpp>
|
||||
#include <components/esm/queststate.hpp>
|
||||
#include <components/esm/journalentry.hpp>
|
||||
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
|
@ -26,6 +33,38 @@ namespace MWDialogue
|
|||
return iter->second;
|
||||
}
|
||||
|
||||
Topic& Journal::getTopic (const std::string& id)
|
||||
{
|
||||
TTopicContainer::iterator iter = mTopics.find (id);
|
||||
|
||||
if (iter==mTopics.end())
|
||||
{
|
||||
std::pair<TTopicContainer::iterator, bool> result
|
||||
= mTopics.insert (std::make_pair (id, Topic (id)));
|
||||
|
||||
iter = result.first;
|
||||
}
|
||||
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
bool Journal::isThere (const std::string& topicId, const std::string& infoId) const
|
||||
{
|
||||
if (const ESM::Dialogue *dialogue =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>().search (topicId))
|
||||
{
|
||||
if (infoId.empty())
|
||||
return true;
|
||||
|
||||
for (std::vector<ESM::DialInfo>::const_iterator iter (dialogue->mInfo.begin());
|
||||
iter!=dialogue->mInfo.end(); ++iter)
|
||||
if (iter->mId == infoId)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Journal::Journal()
|
||||
{}
|
||||
|
||||
|
@ -64,19 +103,13 @@ namespace MWDialogue
|
|||
quest.setIndex (index);
|
||||
}
|
||||
|
||||
void Journal::addTopic (const std::string& topicId, const std::string& infoId)
|
||||
void Journal::addTopic (const std::string& topicId, const std::string& infoId, const std::string& actorName)
|
||||
{
|
||||
TTopicContainer::iterator iter = mTopics.find (topicId);
|
||||
Topic& topic = getTopic (topicId);
|
||||
|
||||
if (iter==mTopics.end())
|
||||
{
|
||||
std::pair<TTopicContainer::iterator, bool> result
|
||||
= mTopics.insert (std::make_pair (topicId, Topic (topicId)));
|
||||
|
||||
iter = result.first;
|
||||
}
|
||||
|
||||
iter->second.addEntry (JournalEntry (topicId, infoId));
|
||||
JournalEntry entry(topicId, infoId);
|
||||
entry.mActorName = actorName;
|
||||
topic.addEntry (entry);
|
||||
}
|
||||
|
||||
int Journal::getJournalIndex (const std::string& id) const
|
||||
|
@ -118,4 +151,106 @@ namespace MWDialogue
|
|||
{
|
||||
return mTopics.end();
|
||||
}
|
||||
|
||||
int Journal::countSavedGameRecords() const
|
||||
{
|
||||
int count = static_cast<int> (mQuests.size());
|
||||
|
||||
for (TQuestIter iter (mQuests.begin()); iter!=mQuests.end(); ++iter)
|
||||
count += std::distance (iter->second.begin(), iter->second.end());
|
||||
|
||||
count += std::distance (mJournal.begin(), mJournal.end());
|
||||
|
||||
for (TTopicIter iter (mTopics.begin()); iter!=mTopics.end(); ++iter)
|
||||
count += std::distance (iter->second.begin(), iter->second.end());
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void Journal::write (ESM::ESMWriter& writer) const
|
||||
{
|
||||
for (TQuestIter iter (mQuests.begin()); iter!=mQuests.end(); ++iter)
|
||||
{
|
||||
const Quest& quest = iter->second;
|
||||
|
||||
ESM::QuestState state;
|
||||
quest.write (state);
|
||||
writer.startRecord (ESM::REC_QUES);
|
||||
state.save (writer);
|
||||
writer.endRecord (ESM::REC_QUES);
|
||||
|
||||
for (Topic::TEntryIter iter (quest.begin()); iter!=quest.end(); ++iter)
|
||||
{
|
||||
ESM::JournalEntry entry;
|
||||
entry.mType = ESM::JournalEntry::Type_Quest;
|
||||
entry.mTopic = quest.getTopic();
|
||||
iter->write (entry);
|
||||
writer.startRecord (ESM::REC_JOUR);
|
||||
entry.save (writer);
|
||||
writer.endRecord (ESM::REC_JOUR);
|
||||
}
|
||||
}
|
||||
|
||||
for (TEntryIter iter (mJournal.begin()); iter!=mJournal.end(); ++iter)
|
||||
{
|
||||
ESM::JournalEntry entry;
|
||||
entry.mType = ESM::JournalEntry::Type_Journal;
|
||||
iter->write (entry);
|
||||
writer.startRecord (ESM::REC_JOUR);
|
||||
entry.save (writer);
|
||||
writer.endRecord (ESM::REC_JOUR);
|
||||
}
|
||||
|
||||
for (TTopicIter iter (mTopics.begin()); iter!=mTopics.end(); ++iter)
|
||||
{
|
||||
const Topic& topic = iter->second;
|
||||
|
||||
for (Topic::TEntryIter iter (topic.begin()); iter!=topic.end(); ++iter)
|
||||
{
|
||||
ESM::JournalEntry entry;
|
||||
entry.mType = ESM::JournalEntry::Type_Topic;
|
||||
entry.mTopic = topic.getTopic();
|
||||
iter->write (entry);
|
||||
writer.startRecord (ESM::REC_JOUR);
|
||||
entry.save (writer);
|
||||
writer.endRecord (ESM::REC_JOUR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Journal::readRecord (ESM::ESMReader& reader, int32_t type)
|
||||
{
|
||||
if (type==ESM::REC_JOUR)
|
||||
{
|
||||
ESM::JournalEntry record;
|
||||
record.load (reader);
|
||||
|
||||
if (isThere (record.mTopic, record.mInfo))
|
||||
switch (record.mType)
|
||||
{
|
||||
case ESM::JournalEntry::Type_Quest:
|
||||
|
||||
getQuest (record.mTopic).insertEntry (record);
|
||||
break;
|
||||
|
||||
case ESM::JournalEntry::Type_Journal:
|
||||
|
||||
mJournal.push_back (record);
|
||||
break;
|
||||
|
||||
case ESM::JournalEntry::Type_Topic:
|
||||
|
||||
getTopic (record.mTopic).insertEntry (record);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (type==ESM::REC_QUES)
|
||||
{
|
||||
ESM::QuestState record;
|
||||
record.load (reader);
|
||||
|
||||
if (isThere (record.mTopic))
|
||||
mQuests.insert (std::make_pair (record.mTopic, record));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,8 +15,14 @@ namespace MWDialogue
|
|||
TQuestContainer mQuests;
|
||||
TTopicContainer mTopics;
|
||||
|
||||
private:
|
||||
|
||||
Quest& getQuest (const std::string& id);
|
||||
|
||||
Topic& getTopic (const std::string& id);
|
||||
|
||||
bool isThere (const std::string& topicId, const std::string& infoId = "") const;
|
||||
|
||||
public:
|
||||
|
||||
Journal();
|
||||
|
@ -32,7 +38,7 @@ namespace MWDialogue
|
|||
virtual int getJournalIndex (const std::string& id) const;
|
||||
///< Get the journal index.
|
||||
|
||||
virtual void addTopic (const std::string& topicId, const std::string& infoId);
|
||||
virtual void addTopic (const std::string& topicId, const std::string& infoId, const std::string& actorName);
|
||||
|
||||
virtual TEntryIter begin() const;
|
||||
///< Iterator pointing to the begin of the main journal.
|
||||
|
@ -55,6 +61,12 @@ namespace MWDialogue
|
|||
|
||||
virtual TTopicIter topicEnd() const;
|
||||
///< Iterator pointing past the last topic.
|
||||
|
||||
virtual int countSavedGameRecords() const;
|
||||
|
||||
virtual void write (ESM::ESMWriter& writer) const;
|
||||
|
||||
virtual void readRecord (ESM::ESMReader& reader, int32_t type);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
|
||||
#include "quest.hpp"
|
||||
|
||||
#include <components/esm/queststate.hpp>
|
||||
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
|
@ -16,7 +18,11 @@ namespace MWDialogue
|
|||
: Topic (topic), mIndex (0), mFinished (false)
|
||||
{}
|
||||
|
||||
const std::string Quest::getName() const
|
||||
Quest::Quest (const ESM::QuestState& state)
|
||||
: Topic (state.mTopic), mIndex (state.mState), mFinished (state.mFinished!=0)
|
||||
{}
|
||||
|
||||
std::string Quest::getName() const
|
||||
{
|
||||
const ESM::Dialogue *dialogue =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>().find (mTopic);
|
||||
|
@ -39,21 +45,24 @@ namespace MWDialogue
|
|||
const ESM::Dialogue *dialogue =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>().find (mTopic);
|
||||
|
||||
bool found=false;
|
||||
for (std::vector<ESM::DialInfo>::const_iterator iter (dialogue->mInfo.begin());
|
||||
iter!=dialogue->mInfo.end(); ++iter)
|
||||
if (iter->mData.mDisposition==index && iter->mQuestStatus!=ESM::DialInfo::QS_Name)
|
||||
{
|
||||
mIndex = index;
|
||||
|
||||
if (iter->mQuestStatus==ESM::DialInfo::QS_Finished)
|
||||
mFinished = true;
|
||||
else if (iter->mQuestStatus==ESM::DialInfo::QS_Restart)
|
||||
mFinished = false;
|
||||
|
||||
return;
|
||||
found = true;
|
||||
// Don't return here. Quest status may actually be in a different info record, since we don't merge these (yet?)
|
||||
}
|
||||
|
||||
throw std::runtime_error ("unknown journal index for topic " + mTopic);
|
||||
if (found)
|
||||
mIndex = index;
|
||||
else
|
||||
throw std::runtime_error ("unknown journal index for topic " + mTopic);
|
||||
}
|
||||
|
||||
bool Quest::isFinished() const
|
||||
|
@ -79,12 +88,20 @@ namespace MWDialogue
|
|||
if (index==-1)
|
||||
throw std::runtime_error ("unknown journal entry for topic " + mTopic);
|
||||
|
||||
setIndex (index);
|
||||
if (index > mIndex)
|
||||
setIndex (index);
|
||||
|
||||
for (TEntryIter iter (mEntries.begin()); iter!=mEntries.end(); ++iter)
|
||||
if (*iter==entry.mInfoId)
|
||||
if (iter->mInfoId==entry.mInfoId)
|
||||
return;
|
||||
|
||||
mEntries.push_back (entry.mInfoId);
|
||||
mEntries.push_back (entry); // we want slicing here
|
||||
}
|
||||
|
||||
void Quest::write (ESM::QuestState& state) const
|
||||
{
|
||||
state.mTopic = getTopic();
|
||||
state.mState = mIndex;
|
||||
state.mFinished = mFinished;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,9 +3,14 @@
|
|||
|
||||
#include "topic.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
struct QuestState;
|
||||
}
|
||||
|
||||
namespace MWDialogue
|
||||
{
|
||||
/// \brief A quest in progress or a compelted quest
|
||||
/// \brief A quest in progress or a completed quest
|
||||
class Quest : public Topic
|
||||
{
|
||||
int mIndex;
|
||||
|
@ -17,13 +22,15 @@ namespace MWDialogue
|
|||
|
||||
Quest (const std::string& topic);
|
||||
|
||||
const std::string getName() const;
|
||||
Quest (const ESM::QuestState& state);
|
||||
|
||||
virtual std::string getName() const;
|
||||
///< May be an empty string
|
||||
|
||||
int getIndex() const;
|
||||
|
||||
void setIndex (int index);
|
||||
///< Calling this function with a non-existant index while throw an exception.
|
||||
///< Calling this function with a non-existent index will throw an exception.
|
||||
|
||||
bool isFinished() const;
|
||||
|
||||
|
@ -31,6 +38,8 @@ namespace MWDialogue
|
|||
///< Add entry and adjust index accordingly.
|
||||
///
|
||||
/// \note Redundant entries are ignored, but the index is still adjusted.
|
||||
|
||||
void write (ESM::QuestState& state) const;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
|
||||
#include "topic.hpp"
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
namespace MWDialogue
|
||||
|
@ -9,7 +12,8 @@ namespace MWDialogue
|
|||
{}
|
||||
|
||||
Topic::Topic (const std::string& topic)
|
||||
: mTopic (topic)
|
||||
: mTopic (topic), mName (
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>().find (topic)->mId)
|
||||
{}
|
||||
|
||||
Topic::~Topic()
|
||||
|
@ -20,11 +24,29 @@ namespace MWDialogue
|
|||
if (entry.mTopic!=mTopic)
|
||||
throw std::runtime_error ("topic does not match: " + mTopic);
|
||||
|
||||
for (TEntryIter iter = begin(); iter!=end(); ++iter)
|
||||
if (*iter==entry.mInfoId)
|
||||
// bail out if we already have heard this
|
||||
for (Topic::TEntryIter it = mEntries.begin(); it != mEntries.end(); ++it)
|
||||
{
|
||||
if (it->mInfoId == entry.mInfoId)
|
||||
return;
|
||||
}
|
||||
|
||||
mEntries.push_back (entry.mInfoId);
|
||||
mEntries.push_back (entry); // we want slicing here
|
||||
}
|
||||
|
||||
void Topic::insertEntry (const ESM::JournalEntry& entry)
|
||||
{
|
||||
mEntries.push_back (entry);
|
||||
}
|
||||
|
||||
std::string Topic::getTopic() const
|
||||
{
|
||||
return mTopic;
|
||||
}
|
||||
|
||||
std::string Topic::getName() const
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
|
||||
Topic::TEntryIter Topic::begin() const
|
||||
|
|
|
@ -6,6 +6,11 @@
|
|||
|
||||
#include "journalentry.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
struct JournalEntry;
|
||||
}
|
||||
|
||||
namespace MWDialogue
|
||||
{
|
||||
/// \brief Collection of seen responses for a topic
|
||||
|
@ -13,13 +18,14 @@ namespace MWDialogue
|
|||
{
|
||||
public:
|
||||
|
||||
typedef std::vector<std::string> TEntryContainer;
|
||||
typedef std::vector<Entry> TEntryContainer;
|
||||
typedef TEntryContainer::const_iterator TEntryIter;
|
||||
|
||||
protected:
|
||||
|
||||
std::string mTopic;
|
||||
TEntryContainer mEntries; // info-IDs
|
||||
std::string mName;
|
||||
TEntryContainer mEntries;
|
||||
|
||||
public:
|
||||
|
||||
|
@ -34,7 +40,13 @@ namespace MWDialogue
|
|||
///
|
||||
/// \note Redundant entries are ignored.
|
||||
|
||||
std::string const & getName () const { return mTopic; }
|
||||
void insertEntry (const ESM::JournalEntry& entry);
|
||||
///< Add entry without checking for redundant entries or modifying the state of the
|
||||
/// topic otherwise
|
||||
|
||||
std::string getTopic() const;
|
||||
|
||||
virtual std::string getName() const;
|
||||
|
||||
TEntryIter begin() const;
|
||||
///< Iterator pointing to the begin of the journal for this topic.
|
||||
|
|
|
@ -33,8 +33,7 @@ namespace MWGui
|
|||
|
||||
getWidget(mBirthList, "BirthsignList");
|
||||
mBirthList->setScrollVisible(true);
|
||||
mBirthList->eventListSelectAccept += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth);
|
||||
mBirthList->eventListMouseItemActivate += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth);
|
||||
mBirthList->eventListSelectAccept += MyGUI::newDelegate(this, &BirthDialog::onAccept);
|
||||
mBirthList->eventListChangePosition += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth);
|
||||
|
||||
MyGUI::Button* backButton;
|
||||
|
@ -97,6 +96,14 @@ namespace MWGui
|
|||
eventDone(this);
|
||||
}
|
||||
|
||||
void BirthDialog::onAccept(MyGUI::ListBox *_sender, size_t _index)
|
||||
{
|
||||
onSelectBirth(_sender, _index);
|
||||
if(mBirthList->getIndexSelected() == MyGUI::ITEM_NONE)
|
||||
return;
|
||||
eventDone(this);
|
||||
}
|
||||
|
||||
void BirthDialog::onBackClicked(MyGUI::Widget* _sender)
|
||||
{
|
||||
eventBack();
|
||||
|
|
|
@ -38,6 +38,7 @@ namespace MWGui
|
|||
protected:
|
||||
void onSelectBirth(MyGUI::ListBox* _sender, size_t _index);
|
||||
|
||||
void onAccept(MyGUI::ListBox* _sender, size_t index);
|
||||
void onOkClicked(MyGUI::Widget* _sender);
|
||||
void onBackClicked(MyGUI::Widget* _sender);
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/soundmanager.hpp"
|
||||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
#include "../mwmechanics/creaturestats.hpp"
|
||||
#include "../mwmechanics/npcstats.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/fallback.hpp"
|
||||
|
||||
|
@ -47,9 +47,8 @@ namespace
|
|||
void updatePlayerHealth()
|
||||
{
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
MWMechanics::CreatureStats& creatureStats = MWWorld::Class::get(player).getCreatureStats(player);
|
||||
|
||||
creatureStats.updateHealth();
|
||||
MWMechanics::NpcStats& npcStats = MWWorld::Class::get(player).getNpcStats(player);
|
||||
npcStats.updateHealth();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -82,8 +82,7 @@ namespace MWGui
|
|||
|
||||
getWidget(mClassList, "ClassList");
|
||||
mClassList->setScrollVisible(true);
|
||||
mClassList->eventListSelectAccept += MyGUI::newDelegate(this, &PickClassDialog::onSelectClass);
|
||||
mClassList->eventListMouseItemActivate += MyGUI::newDelegate(this, &PickClassDialog::onSelectClass);
|
||||
mClassList->eventListSelectAccept += MyGUI::newDelegate(this, &PickClassDialog::onAccept);
|
||||
mClassList->eventListChangePosition += MyGUI::newDelegate(this, &PickClassDialog::onSelectClass);
|
||||
|
||||
getWidget(mClassImage, "ClassImage");
|
||||
|
@ -152,6 +151,14 @@ namespace MWGui
|
|||
eventBack();
|
||||
}
|
||||
|
||||
void PickClassDialog::onAccept(MyGUI::ListBox* _sender, size_t _index)
|
||||
{
|
||||
onSelectClass(_sender, _index);
|
||||
if(mClassList->getIndexSelected() == MyGUI::ITEM_NONE)
|
||||
return;
|
||||
eventDone(this);
|
||||
}
|
||||
|
||||
void PickClassDialog::onSelectClass(MyGUI::ListBox* _sender, size_t _index)
|
||||
{
|
||||
if (_index == MyGUI::ITEM_NONE)
|
||||
|
|
|
@ -111,6 +111,7 @@ namespace MWGui
|
|||
|
||||
protected:
|
||||
void onSelectClass(MyGUI::ListBox* _sender, size_t _index);
|
||||
void onAccept(MyGUI::ListBox* _sender, size_t _index);
|
||||
|
||||
void onOkClicked(MyGUI::Widget* _sender);
|
||||
void onBackClicked(MyGUI::Widget* _sender);
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace MWGui
|
|||
|
||||
void CompanionItemModel::copyItem (const ItemStack& item, size_t count)
|
||||
{
|
||||
if (mActor.getTypeName() == typeid(ESM::NPC).name())
|
||||
if (mActor.getClass().isNpc())
|
||||
{
|
||||
MWMechanics::NpcStats& stats = MWWorld::Class::get(mActor).getNpcStats(mActor);
|
||||
stats.modifyProfit(MWWorld::Class::get(item.mBase).getValue(item.mBase) * count);
|
||||
|
@ -23,7 +23,7 @@ namespace MWGui
|
|||
|
||||
void CompanionItemModel::removeItem (const ItemStack& item, size_t count)
|
||||
{
|
||||
if (mActor.getTypeName() == typeid(ESM::NPC).name())
|
||||
if (mActor.getClass().isNpc())
|
||||
{
|
||||
MWMechanics::NpcStats& stats = MWWorld::Class::get(mActor).getNpcStats(mActor);
|
||||
stats.modifyProfit(-MWWorld::Class::get(item.mBase).getValue(item.mBase) * count);
|
||||
|
|
|
@ -235,7 +235,7 @@ namespace MWGui
|
|||
|
||||
mItemView->setModel (mSortModel);
|
||||
|
||||
MyGUI::InputManager::getInstance().setKeyFocusWidget(mCloseButton);
|
||||
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCloseButton);
|
||||
|
||||
// Careful here. setTitle may cause size updates, causing itemview redraw, so make sure to do it last
|
||||
// or we end up using a possibly invalid model.
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/soundmanager.hpp"
|
||||
#include "../mwbase/dialoguemanager.hpp"
|
||||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/containerstore.hpp"
|
||||
|
||||
|
@ -296,6 +298,28 @@ namespace MWGui
|
|||
return;
|
||||
}
|
||||
|
||||
// check if the player is attempting to use a soulstone or item that was stolen from this actor
|
||||
if (mPtr != player)
|
||||
{
|
||||
for (int i=0; i<2; ++i)
|
||||
{
|
||||
MWWorld::Ptr item = (i == 0) ? mEnchanting.getOldItem() : mEnchanting.getGem();
|
||||
if (Misc::StringUtils::ciEqual(item.getCellRef().mOwner, mPtr.getCellRef().mRefID))
|
||||
{
|
||||
std::string msg = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("sNotifyMessage49")->getString();
|
||||
if (msg.find("%s") != std::string::npos)
|
||||
msg.replace(msg.find("%s"), 2, item.getClass().getName(item));
|
||||
MWBase::Environment::get().getWindowManager()->messageBox(msg);
|
||||
MWBase::Environment::get().getDialogueManager()->say(mPtr, "Thief");
|
||||
MWBase::Environment::get().getMechanicsManager()->reportCrime(player, mPtr, MWBase::MechanicsManager::OT_Theft,
|
||||
item.getClass().getValue(item));
|
||||
MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Enchanting);
|
||||
MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Dialogue);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int result = mEnchanting.create();
|
||||
|
||||
if(result==1)
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#include <boost/range/algorithm/copy.hpp>
|
||||
#include <OgreUTFString.h>
|
||||
|
||||
#include <OgreResourceGroupManager.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
int convertFromHex(std::string hex)
|
||||
|
@ -288,6 +290,16 @@ namespace MWGui
|
|||
MyGUI::ImageBox* box = mParent->createWidget<MyGUI::ImageBox> ("ImageBox",
|
||||
MyGUI::IntCoord(0, mHeight, width, height), MyGUI::Align::Left | MyGUI::Align::Top,
|
||||
mParent->getName() + boost::lexical_cast<std::string>(mParent->getChildCount()));
|
||||
|
||||
// Apparently a bug with some morrowind versions, they reference the image without the size suffix.
|
||||
// So if the image isn't found, try appending the size.
|
||||
if (!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup("bookart\\"+image))
|
||||
{
|
||||
std::stringstream str;
|
||||
str << image.substr(0, image.rfind(".")) << "_" << width << "_" << height << image.substr(image.rfind("."));
|
||||
image = str.str();
|
||||
}
|
||||
|
||||
box->setImageTexture("bookart\\" + image);
|
||||
box->setProperty("NeedMouse", "false");
|
||||
}
|
||||
|
|
|
@ -74,9 +74,9 @@ void InventoryItemModel::update()
|
|||
|
||||
ItemStack newItem (item, this, item.getRefData().getCount());
|
||||
|
||||
if (mActor.getTypeName() == typeid(ESM::NPC).name())
|
||||
if (mActor.getClass().hasInventoryStore(mActor))
|
||||
{
|
||||
MWWorld::InventoryStore& store = MWWorld::Class::get(mActor).getInventoryStore(mActor);
|
||||
MWWorld::InventoryStore& store = mActor.getClass().getInventoryStore(mActor);
|
||||
for (int slot=0; slot<MWWorld::InventoryStore::Slots; ++slot)
|
||||
{
|
||||
MWWorld::ContainerStoreIterator equipped = store.getSlot(slot);
|
||||
|
|
|
@ -196,34 +196,6 @@ book JournalBooks::createEmptyJournalBook ()
|
|||
typesetter->lineBreak ();
|
||||
typesetter->write (body, to_utf8_span ("You should have gone though the starting quest and got an initial quest."));
|
||||
|
||||
BookTypesetter::Style* big = typesetter->createStyle ("", MyGUI::Colour::Black);
|
||||
BookTypesetter::Style* test = typesetter->createStyle ("MonoFont", MyGUI::Colour::Blue);
|
||||
|
||||
typesetter->sectionBreak (20);
|
||||
typesetter->write (body, to_utf8_span (
|
||||
"The layout engine doesn't currently support aligning fonts to "
|
||||
"their baseline within a single line so the following text looks "
|
||||
"funny. In order to properly implement it, a stupidly simple "
|
||||
"change is needed in MyGUI to report the where the baseline is for "
|
||||
"a particular font"
|
||||
));
|
||||
|
||||
typesetter->sectionBreak (20);
|
||||
typesetter->write (big, to_utf8_span ("big text g"));
|
||||
typesetter->write (body, to_utf8_span (" проверяем только в дебаге"));
|
||||
typesetter->write (body, to_utf8_span (" normal g"));
|
||||
typesetter->write (big, to_utf8_span (" done g"));
|
||||
|
||||
typesetter->sectionBreak (20);
|
||||
typesetter->write (test, to_utf8_span (
|
||||
"int main (int argc,\n"
|
||||
" char ** argv)\n"
|
||||
"{\n"
|
||||
" print (\"hello world!\\n\");\n"
|
||||
" return 0;\n"
|
||||
"}\n"
|
||||
));
|
||||
|
||||
return typesetter->complete ();
|
||||
}
|
||||
|
||||
|
|
|
@ -20,8 +20,6 @@ namespace MWGui {
|
|||
|
||||
struct JournalViewModelImpl;
|
||||
|
||||
static void injectMonthName (std::ostream & os, int month);
|
||||
|
||||
struct JournalViewModelImpl : JournalViewModel
|
||||
{
|
||||
typedef KeywordSearch <std::string, intptr_t> KeywordSearchT;
|
||||
|
@ -206,10 +204,12 @@ struct JournalViewModelImpl : JournalViewModel
|
|||
if (active_only && i->second.isFinished ())
|
||||
continue;
|
||||
|
||||
/// \todo quest.getName() is broken? returns empty string
|
||||
//const MWDialogue::Quest& quest = i->second;
|
||||
|
||||
visitor (reinterpret_cast <QuestId> (&i->second), toUtf8Span (i->first));
|
||||
const MWDialogue::Quest& quest = i->second;
|
||||
// Unfortunately Morrowind.esm has no quest names, since the quest book was added with tribunal.
|
||||
if (quest.getName().empty())
|
||||
visitor (reinterpret_cast <QuestId> (&i->second), toUtf8Span (i->first));
|
||||
else
|
||||
visitor (reinterpret_cast <QuestId> (&i->second), toUtf8Span (quest.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -235,21 +235,21 @@ struct JournalViewModelImpl : JournalViewModel
|
|||
|
||||
std::string getText () const
|
||||
{
|
||||
return itr->getText(MWBase::Environment::get().getWorld()->getStore());
|
||||
return itr->getText();
|
||||
}
|
||||
|
||||
Utf8Span timestamp () const
|
||||
{
|
||||
if (timestamp_buffer.empty ())
|
||||
{
|
||||
std::string dayStr = MyGUI::LanguageManager::getInstance().replaceTags("#{sDay}");
|
||||
|
||||
std::ostringstream os;
|
||||
|
||||
os << itr->mDayOfMonth << ' ';
|
||||
|
||||
injectMonthName (os, itr->mMonth);
|
||||
|
||||
const std::string& dayStr = MyGUI::LanguageManager::getInstance().replaceTags("#{sDay}");
|
||||
os << " (" << dayStr << " " << (itr->mDay + 1) << ')';
|
||||
os
|
||||
<< itr->mDayOfMonth << ' '
|
||||
<< MWBase::Environment::get().getWorld()->getMonthName (itr->mMonth)
|
||||
<< " (" << dayStr << " " << (itr->mDay + 1) << ')';
|
||||
|
||||
timestamp_buffer = os.str ();
|
||||
}
|
||||
|
@ -270,7 +270,7 @@ struct JournalViewModelImpl : JournalViewModel
|
|||
{
|
||||
for (MWDialogue::Topic::TEntryIter j = quest->begin (); j != quest->end (); ++j)
|
||||
{
|
||||
if (i->mInfoId == *j)
|
||||
if (i->mInfoId == j->mInfoId)
|
||||
visitor (JournalEntryImpl <MWBase::Journal::TEntryIter> (this, i));
|
||||
}
|
||||
}
|
||||
|
@ -290,9 +290,7 @@ struct JournalViewModelImpl : JournalViewModel
|
|||
void visitTopicName (TopicId topicId, boost::function <void (Utf8Span)> visitor) const
|
||||
{
|
||||
MWDialogue::Topic const & topic = * reinterpret_cast <MWDialogue::Topic const *> (topicId);
|
||||
// This is to get the correct case for the topic
|
||||
const std::string& name = MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>().find(topic.getName())->mId;
|
||||
visitor (toUtf8Span (name));
|
||||
visitor (toUtf8Span (topic.getName()));
|
||||
}
|
||||
|
||||
void visitTopicNamesStartingWith (char character, boost::function < void (TopicId , Utf8Span) > visitor) const
|
||||
|
@ -304,10 +302,7 @@ struct JournalViewModelImpl : JournalViewModel
|
|||
if (i->first [0] != std::tolower (character, mLocale))
|
||||
continue;
|
||||
|
||||
// This is to get the correct case for the topic
|
||||
const std::string& name = MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>().find(i->first)->mId;
|
||||
|
||||
visitor (TopicId (&i->second), toUtf8Span (name));
|
||||
visitor (TopicId (&i->second), toUtf8Span (i->second.getName()));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -316,24 +311,18 @@ struct JournalViewModelImpl : JournalViewModel
|
|||
{
|
||||
MWDialogue::Topic const & mTopic;
|
||||
|
||||
mutable std::string source_buffer;
|
||||
|
||||
TopicEntryImpl (JournalViewModelImpl const * model, MWDialogue::Topic const & topic, iterator_t itr) :
|
||||
BaseEntry (model, itr), mTopic (topic)
|
||||
{}
|
||||
|
||||
std::string getText () const
|
||||
{
|
||||
/// \todo defines are not replaced (%PCName etc). should probably be done elsewhere though since we need the actor
|
||||
return mTopic.getEntry (*itr).getText(MWBase::Environment::get().getWorld()->getStore());
|
||||
|
||||
return itr->getText();
|
||||
}
|
||||
|
||||
Utf8Span source () const
|
||||
{
|
||||
if (source_buffer.empty ())
|
||||
source_buffer = "someone";
|
||||
return toUtf8Span (source_buffer);
|
||||
return toUtf8Span (itr->mActorName);
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -349,38 +338,6 @@ struct JournalViewModelImpl : JournalViewModel
|
|||
}
|
||||
};
|
||||
|
||||
static void injectMonthName (std::ostream & os, int month)
|
||||
{
|
||||
MyGUI::LanguageManager& lm = MyGUI::LanguageManager::getInstance();
|
||||
|
||||
if (month == 0)
|
||||
os << lm.replaceTags ("#{sMonthMorningstar}");
|
||||
else if (month == 1)
|
||||
os << lm.replaceTags ("#{sMonthSunsdawn}");
|
||||
else if (month == 2)
|
||||
os << lm.replaceTags ("#{sMonthFirstseed}");
|
||||
else if (month == 3)
|
||||
os << lm.replaceTags ("#{sMonthRainshand}");
|
||||
else if (month == 4)
|
||||
os << lm.replaceTags ("#{sMonthSecondseed}");
|
||||
else if (month == 5)
|
||||
os << lm.replaceTags ("#{sMonthMidyear}");
|
||||
else if (month == 6)
|
||||
os << lm.replaceTags ("#{sMonthSunsheight}");
|
||||
else if (month == 7)
|
||||
os << lm.replaceTags ("#{sMonthLastseed}");
|
||||
else if (month == 8)
|
||||
os << lm.replaceTags ("#{sMonthHeartfire}");
|
||||
else if (month == 9)
|
||||
os << lm.replaceTags ("#{sMonthFrostfall}");
|
||||
else if (month == 10)
|
||||
os << lm.replaceTags ("#{sMonthSunsdusk}");
|
||||
else if (month == 11)
|
||||
os << lm.replaceTags ("#{sMonthEveningstar}");
|
||||
else
|
||||
os << month;
|
||||
}
|
||||
|
||||
JournalViewModel::Ptr JournalViewModel::create ()
|
||||
{
|
||||
return boost::make_shared <JournalViewModelImpl> ();
|
||||
|
|
|
@ -155,7 +155,6 @@ namespace MWGui
|
|||
void LevelupDialog::onOkButtonClicked (MyGUI::Widget* sender)
|
||||
{
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr();
|
||||
MWMechanics::CreatureStats& creatureStats = MWWorld::Class::get(player).getCreatureStats (player);
|
||||
MWMechanics::NpcStats& pcStats = MWWorld::Class::get(player).getNpcStats (player);
|
||||
|
||||
if (mSpentAttributes.size() < 3)
|
||||
|
@ -165,15 +164,14 @@ namespace MWGui
|
|||
// increase attributes
|
||||
for (int i=0; i<3; ++i)
|
||||
{
|
||||
MWMechanics::AttributeValue attribute = creatureStats.getAttribute(mSpentAttributes[i]);
|
||||
MWMechanics::AttributeValue attribute = pcStats.getAttribute(mSpentAttributes[i]);
|
||||
attribute.setBase (attribute.getBase () + pcStats.getLevelupAttributeMultiplier (mSpentAttributes[i]));
|
||||
|
||||
if (attribute.getBase() >= 100)
|
||||
attribute.setBase(100);
|
||||
creatureStats.setAttribute(mSpentAttributes[i], attribute);
|
||||
pcStats.setAttribute(mSpentAttributes[i], attribute);
|
||||
}
|
||||
|
||||
creatureStats.levelUp();
|
||||
pcStats.levelUp ();
|
||||
|
||||
MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Levelup);
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
#include "mainmenu.hpp"
|
||||
|
||||
#include <OgreRoot.h>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/soundmanager.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/journal.hpp"
|
||||
#include "../mwbase/dialoguemanager.hpp"
|
||||
#include "../mwbase/statemanager.hpp"
|
||||
|
||||
#include "../mwstate/character.hpp"
|
||||
|
||||
#include "savegamedialog.hpp"
|
||||
|
||||
|
@ -16,90 +17,132 @@ namespace MWGui
|
|||
|
||||
MainMenu::MainMenu(int w, int h)
|
||||
: OEngine::GUI::Layout("openmw_mainmenu.layout")
|
||||
, mButtonBox(0)
|
||||
, mButtonBox(0), mWidth (w), mHeight (h)
|
||||
, mSaveGameDialog(NULL)
|
||||
{
|
||||
onResChange(w,h);
|
||||
updateMenu();
|
||||
}
|
||||
|
||||
MainMenu::~MainMenu()
|
||||
{
|
||||
delete mSaveGameDialog;
|
||||
}
|
||||
|
||||
void MainMenu::onResChange(int w, int h)
|
||||
{
|
||||
setCoord(0,0,w,h);
|
||||
mWidth = w;
|
||||
mHeight = h;
|
||||
|
||||
updateMenu();
|
||||
}
|
||||
|
||||
if (mButtonBox)
|
||||
MyGUI::Gui::getInstance ().destroyWidget(mButtonBox);
|
||||
void MainMenu::setVisible (bool visible)
|
||||
{
|
||||
if (visible)
|
||||
updateMenu();
|
||||
|
||||
mButtonBox = mMainWidget->createWidget<MyGUI::Widget>("", MyGUI::IntCoord(0, 0, 0, 0), MyGUI::Align::Default);
|
||||
int curH = 0;
|
||||
|
||||
std::vector<std::string> buttons;
|
||||
buttons.push_back("return");
|
||||
buttons.push_back("newgame");
|
||||
//buttons.push_back("loadgame");
|
||||
//buttons.push_back("savegame");
|
||||
buttons.push_back("options");
|
||||
//buttons.push_back("credits");
|
||||
buttons.push_back("exitgame");
|
||||
|
||||
int maxwidth = 0;
|
||||
|
||||
mButtons.clear();
|
||||
for (std::vector<std::string>::iterator it = buttons.begin(); it != buttons.end(); ++it)
|
||||
{
|
||||
MWGui::ImageButton* button = mButtonBox->createWidget<MWGui::ImageButton>
|
||||
("ImageBox", MyGUI::IntCoord(0, curH, 0, 0), MyGUI::Align::Default);
|
||||
button->setProperty("ImageHighlighted", "textures\\menu_" + *it + "_over.dds");
|
||||
button->setProperty("ImageNormal", "textures\\menu_" + *it + ".dds");
|
||||
button->setProperty("ImagePushed", "textures\\menu_" + *it + "_pressed.dds");
|
||||
MyGUI::IntSize requested = button->getRequestedSize();
|
||||
button->eventMouseButtonClick += MyGUI::newDelegate(this, &MainMenu::onButtonClicked);
|
||||
mButtons[*it] = button;
|
||||
curH += requested.height;
|
||||
|
||||
if (requested.width > maxwidth)
|
||||
maxwidth = requested.width;
|
||||
}
|
||||
for (std::map<std::string, MWGui::ImageButton*>::iterator it = mButtons.begin(); it != mButtons.end(); ++it)
|
||||
{
|
||||
MyGUI::IntSize requested = it->second->getRequestedSize();
|
||||
it->second->setCoord((maxwidth-requested.width) / 2, it->second->getTop(), requested.width, requested.height);
|
||||
}
|
||||
|
||||
mButtonBox->setCoord (w/2 - maxwidth/2, h/2 - curH/2, maxwidth, curH);
|
||||
OEngine::GUI::Layout::setVisible (visible);
|
||||
}
|
||||
|
||||
void MainMenu::onButtonClicked(MyGUI::Widget *sender)
|
||||
{
|
||||
std::string name = *sender->getUserData<std::string>();
|
||||
MWBase::Environment::get().getSoundManager()->playSound("Menu Click", 1.f, 1.f);
|
||||
if (sender == mButtons["return"])
|
||||
if (name == "return")
|
||||
{
|
||||
MWBase::Environment::get().getSoundManager ()->resumeSounds (MWBase::SoundManager::Play_TypeSfx);
|
||||
MWBase::Environment::get().getWindowManager ()->removeGuiMode (GM_MainMenu);
|
||||
}
|
||||
else if (sender == mButtons["options"])
|
||||
else if (name == "options")
|
||||
MWBase::Environment::get().getWindowManager ()->pushGuiMode (GM_Settings);
|
||||
else if (sender == mButtons["exitgame"])
|
||||
MWBase::Environment::get().setRequestExit();
|
||||
else if (sender == mButtons["newgame"])
|
||||
else if (name == "exitgame")
|
||||
MWBase::Environment::get().getStateManager()->requestQuit();
|
||||
else if (name == "newgame")
|
||||
{
|
||||
MWBase::Environment::get().getWorld()->startNewGame();
|
||||
MWBase::Environment::get().getWindowManager()->setNewGame(true);
|
||||
MWBase::Environment::get().getDialogueManager()->clear();
|
||||
MWBase::Environment::get().getJournal()->clear();
|
||||
MWBase::Environment::get().getStateManager()->newGame();
|
||||
}
|
||||
|
||||
else if (sender == mButtons["loadgame"])
|
||||
else
|
||||
{
|
||||
MWGui::SaveGameDialog* dialog = new MWGui::SaveGameDialog();
|
||||
dialog->setLoadOrSave(true);
|
||||
dialog->setVisible(true);
|
||||
}
|
||||
else if (sender == mButtons["savegame"])
|
||||
{
|
||||
MWGui::SaveGameDialog* dialog = new MWGui::SaveGameDialog();
|
||||
dialog->setLoadOrSave(false);
|
||||
dialog->setVisible(true);
|
||||
if (!mSaveGameDialog)
|
||||
mSaveGameDialog = new SaveGameDialog();
|
||||
if (name == "loadgame")
|
||||
mSaveGameDialog->setLoadOrSave(true);
|
||||
else if (name == "savegame")
|
||||
mSaveGameDialog->setLoadOrSave(false);
|
||||
mSaveGameDialog->setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
void MainMenu::updateMenu()
|
||||
{
|
||||
setCoord(0,0, mWidth, mHeight);
|
||||
|
||||
|
||||
if (!mButtonBox)
|
||||
mButtonBox = mMainWidget->createWidget<MyGUI::Widget>("", MyGUI::IntCoord(0, 0, 0, 0), MyGUI::Align::Default);
|
||||
|
||||
int curH = 0;
|
||||
|
||||
MWBase::StateManager::State state = MWBase::Environment::get().getStateManager()->getState();
|
||||
|
||||
std::vector<std::string> buttons;
|
||||
|
||||
if (state==MWBase::StateManager::State_Running)
|
||||
buttons.push_back("return");
|
||||
|
||||
buttons.push_back("newgame");
|
||||
|
||||
if (MWBase::Environment::get().getStateManager()->characterBegin()!=
|
||||
MWBase::Environment::get().getStateManager()->characterEnd())
|
||||
buttons.push_back("loadgame");
|
||||
|
||||
if (state==MWBase::StateManager::State_Running &&
|
||||
MWBase::Environment::get().getWorld()->getGlobalInt ("chargenstate")==-1)
|
||||
buttons.push_back("savegame");
|
||||
|
||||
buttons.push_back("options");
|
||||
//buttons.push_back("credits");
|
||||
buttons.push_back("exitgame");
|
||||
|
||||
// Create new buttons if needed
|
||||
for (std::vector<std::string>::iterator it = buttons.begin(); it != buttons.end(); ++it)
|
||||
{
|
||||
if (mButtons.find(*it) == mButtons.end())
|
||||
{
|
||||
MWGui::ImageButton* button = mButtonBox->createWidget<MWGui::ImageButton>
|
||||
("ImageBox", MyGUI::IntCoord(0, curH, 0, 0), MyGUI::Align::Default);
|
||||
button->setProperty("ImageHighlighted", "textures\\menu_" + *it + "_over.dds");
|
||||
button->setProperty("ImageNormal", "textures\\menu_" + *it + ".dds");
|
||||
button->setProperty("ImagePushed", "textures\\menu_" + *it + "_pressed.dds");
|
||||
button->eventMouseButtonClick += MyGUI::newDelegate(this, &MainMenu::onButtonClicked);
|
||||
button->setUserData(std::string(*it));
|
||||
mButtons[*it] = button;
|
||||
}
|
||||
}
|
||||
|
||||
// Start by hiding all buttons
|
||||
int maxwidth = 0;
|
||||
for (std::map<std::string, MWGui::ImageButton*>::iterator it = mButtons.begin(); it != mButtons.end(); ++it)
|
||||
{
|
||||
it->second->setVisible(false);
|
||||
MyGUI::IntSize requested = it->second->getRequestedSize();
|
||||
if (requested.width > maxwidth)
|
||||
maxwidth = requested.width;
|
||||
}
|
||||
|
||||
// Now show and position the ones we want
|
||||
for (std::vector<std::string>::iterator it = buttons.begin(); it != buttons.end(); ++it)
|
||||
{
|
||||
assert(mButtons.find(*it) != mButtons.end());
|
||||
MWGui::ImageButton* button = mButtons[*it];
|
||||
button->setVisible(true);
|
||||
MyGUI::IntSize requested = button->getRequestedSize();
|
||||
button->setCoord((maxwidth-requested.width) / 2, curH, requested.width, requested.height);
|
||||
curH += requested.height;
|
||||
}
|
||||
|
||||
mButtonBox->setCoord (mWidth/2 - maxwidth/2, mHeight/2 - curH/2, maxwidth, curH);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,19 +5,33 @@
|
|||
namespace MWGui
|
||||
{
|
||||
|
||||
class SaveGameDialog;
|
||||
|
||||
class MainMenu : public OEngine::GUI::Layout
|
||||
{
|
||||
public:
|
||||
MainMenu(int w, int h);
|
||||
int mWidth;
|
||||
int mHeight;
|
||||
|
||||
void onResChange(int w, int h);
|
||||
public:
|
||||
|
||||
private:
|
||||
MyGUI::Widget* mButtonBox;
|
||||
MainMenu(int w, int h);
|
||||
~MainMenu();
|
||||
|
||||
std::map<std::string, MWGui::ImageButton*> mButtons;
|
||||
void onResChange(int w, int h);
|
||||
|
||||
void onButtonClicked (MyGUI::Widget* sender);
|
||||
virtual void setVisible (bool visible);
|
||||
|
||||
private:
|
||||
|
||||
MyGUI::Widget* mButtonBox;
|
||||
|
||||
std::map<std::string, MWGui::ImageButton*> mButtons;
|
||||
|
||||
void onButtonClicked (MyGUI::Widget* sender);
|
||||
|
||||
void updateMenu();
|
||||
|
||||
SaveGameDialog* mSaveGameDialog;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -373,8 +373,9 @@ namespace MWGui
|
|||
|
||||
// ------------------------------------------------------------------------------------------
|
||||
|
||||
MapWindow::MapWindow(const std::string& cacheDir)
|
||||
: MWGui::WindowPinnableBase("openmw_map_window.layout")
|
||||
MapWindow::MapWindow(DragAndDrop* drag, const std::string& cacheDir)
|
||||
: WindowPinnableBase("openmw_map_window.layout")
|
||||
, NoDrop(drag, mMainWidget)
|
||||
, mGlobal(false)
|
||||
, mGlobalMap(0)
|
||||
, mGlobalMapRender(0)
|
||||
|
@ -434,7 +435,7 @@ namespace MWGui
|
|||
|
||||
|
||||
static int _counter=0;
|
||||
MyGUI::Button* markerWidget = mGlobalMapImage->createWidget<MyGUI::Button>("ButtonImage",
|
||||
MyGUI::Button* markerWidget = mGlobalMapOverlay->createWidget<MyGUI::Button>("ButtonImage",
|
||||
widgetCoord, MyGUI::Align::Default, "Door" + boost::lexical_cast<std::string>(_counter));
|
||||
markerWidget->setImageResource("DoorMarker");
|
||||
markerWidget->setUserString("ToolTipType", "Layout");
|
||||
|
@ -499,10 +500,11 @@ namespace MWGui
|
|||
mGlobalMap->setCanvasSize (mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight());
|
||||
mGlobalMapImage->setSize(mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight());
|
||||
|
||||
for (unsigned int i=0; i<mGlobalMapImage->getChildCount (); ++i)
|
||||
// force markers to foreground
|
||||
for (unsigned int i=0; i<mGlobalMapOverlay->getChildCount (); ++i)
|
||||
{
|
||||
if (mGlobalMapImage->getChildAt (i)->getName().substr(0,4) == "Door")
|
||||
mGlobalMapImage->getChildAt (i)->castType<MyGUI::Button>()->setImageResource("DoorMarker");
|
||||
if (mGlobalMapOverlay->getChildAt (i)->getName().substr(0,4) == "Door")
|
||||
mGlobalMapOverlay->getChildAt (i)->castType<MyGUI::Button>()->setImageResource("DoorMarker");
|
||||
}
|
||||
|
||||
globalMapUpdatePlayer();
|
||||
|
@ -573,4 +575,31 @@ namespace MWGui
|
|||
mGlobalMap->setViewOffset(viewoffs);
|
||||
}
|
||||
|
||||
void MapWindow::clear()
|
||||
{
|
||||
mGlobalMapRender->clear();
|
||||
|
||||
while (mEventBoxGlobal->getChildCount())
|
||||
MyGUI::Gui::getInstance().destroyWidget(mEventBoxGlobal->getChildAt(0));
|
||||
while (mGlobalMapOverlay->getChildCount())
|
||||
MyGUI::Gui::getInstance().destroyWidget(mGlobalMapOverlay->getChildAt(0));
|
||||
}
|
||||
|
||||
void MapWindow::write(ESM::ESMWriter &writer)
|
||||
{
|
||||
mGlobalMapRender->write(writer);
|
||||
}
|
||||
|
||||
void MapWindow::readRecord(ESM::ESMReader &reader, int32_t type)
|
||||
{
|
||||
std::vector<std::pair<int, int> > exploredCells;
|
||||
mGlobalMapRender->readRecord(reader, type, exploredCells);
|
||||
|
||||
for (std::vector<std::pair<int, int> >::iterator it = exploredCells.begin(); it != exploredCells.end(); ++it)
|
||||
{
|
||||
const ESM::Cell* cell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Cell>().search(it->first, it->second);
|
||||
if (cell && !cell->mName.empty())
|
||||
addVisitedLocation(cell->mName, it->first, it->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,12 @@ namespace MWRender
|
|||
class GlobalMap;
|
||||
}
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
class ESMReader;
|
||||
class ESMWriter;
|
||||
}
|
||||
|
||||
namespace Loading
|
||||
{
|
||||
class Listener;
|
||||
|
@ -75,10 +81,10 @@ namespace MWGui
|
|||
float mLastDirectionY;
|
||||
};
|
||||
|
||||
class MapWindow : public MWGui::WindowPinnableBase, public LocalMapBase
|
||||
class MapWindow : public MWGui::WindowPinnableBase, public LocalMapBase, public NoDrop
|
||||
{
|
||||
public:
|
||||
MapWindow(const std::string& cacheDir);
|
||||
MapWindow(DragAndDrop* drag, const std::string& cacheDir);
|
||||
virtual ~MapWindow();
|
||||
|
||||
void setCellName(const std::string& cellName);
|
||||
|
@ -92,6 +98,14 @@ namespace MWGui
|
|||
|
||||
virtual void open();
|
||||
|
||||
void onFrame(float dt) { NoDrop::onFrame(dt); }
|
||||
|
||||
/// Clear all savegame-specific data
|
||||
void clear();
|
||||
|
||||
void write (ESM::ESMWriter& writer);
|
||||
void readRecord (ESM::ESMReader& reader, int32_t type);
|
||||
|
||||
private:
|
||||
void onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id);
|
||||
void onMouseDrag(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id);
|
||||
|
|
|
@ -287,24 +287,6 @@ namespace MWGui
|
|||
else {
|
||||
mainWidgetSize.width = textSize.width + 3*textPadding;
|
||||
}
|
||||
mainWidgetSize.height = textSize.height + 2*textPadding + textButtonPadding + buttonHeight * buttons.size() + buttonMainPadding;
|
||||
|
||||
mMainWidget->setSize(mainWidgetSize);
|
||||
|
||||
MyGUI::IntCoord absCoord;
|
||||
absCoord.left = (gameWindowSize.width - mainWidgetSize.width)/2;
|
||||
absCoord.top = (gameWindowSize.height - mainWidgetSize.height)/2;
|
||||
|
||||
mMainWidget->setCoord(absCoord);
|
||||
mMainWidget->setSize(mainWidgetSize);
|
||||
|
||||
|
||||
MyGUI::IntCoord messageWidgetCoord;
|
||||
messageWidgetCoord.left = (mainWidgetSize.width - textSize.width)/2;
|
||||
messageWidgetCoord.top = textPadding;
|
||||
mMessageWidget->setCoord(messageWidgetCoord);
|
||||
|
||||
mMessageWidget->setSize(textSize);
|
||||
|
||||
MyGUI::IntCoord buttonCord;
|
||||
MyGUI::IntSize buttonSize(0, buttonHeight);
|
||||
|
@ -326,6 +308,21 @@ namespace MWGui
|
|||
top += buttonSize.height + 2*buttonTopPadding;
|
||||
}
|
||||
|
||||
mainWidgetSize.height = top + buttonMainPadding;
|
||||
mMainWidget->setSize(mainWidgetSize);
|
||||
|
||||
MyGUI::IntPoint absPos;
|
||||
absPos.left = (gameWindowSize.width - mainWidgetSize.width)/2;
|
||||
absPos.top = (gameWindowSize.height - mainWidgetSize.height)/2;
|
||||
|
||||
mMainWidget->setPosition(absPos);
|
||||
|
||||
MyGUI::IntCoord messageWidgetCoord;
|
||||
messageWidgetCoord.left = (mainWidgetSize.width - textSize.width)/2;
|
||||
messageWidgetCoord.top = textPadding;
|
||||
messageWidgetCoord.width = textSize.width;
|
||||
messageWidgetCoord.height = textSize.height;
|
||||
mMessageWidget->setCoord(messageWidgetCoord);
|
||||
}
|
||||
|
||||
// Set key focus to "Ok" button
|
||||
|
@ -335,7 +332,7 @@ namespace MWGui
|
|||
{
|
||||
if(Misc::StringUtils::ciEqual((*button)->getCaption(), ok))
|
||||
{
|
||||
MyGUI::InputManager::getInstance().setKeyFocusWidget(*button);
|
||||
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(*button);
|
||||
(*button)->eventKeyButtonPressed += MyGUI::newDelegate(this, &InteractiveMessageBox::onKeyPressed);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -3,8 +3,15 @@
|
|||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
#include "../mwworld/actionequip.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
||||
#include "../mwmechanics/spellcasting.hpp"
|
||||
#include "../mwmechanics/spells.hpp"
|
||||
#include "../mwmechanics/creaturestats.hpp"
|
||||
|
||||
#include "../mwgui/inventorywindow.hpp"
|
||||
#include "../mwgui/bookwindow.hpp"
|
||||
#include "../mwgui/scrollwindow.hpp"
|
||||
|
@ -17,8 +24,8 @@ namespace
|
|||
{
|
||||
bool sortItems(const MWWorld::Ptr& left, const MWWorld::Ptr& right)
|
||||
{
|
||||
int cmp = MWWorld::Class::get(left).getName(left).compare(
|
||||
MWWorld::Class::get(right).getName(right));
|
||||
int cmp = left.getClass().getName(left).compare(
|
||||
right.getClass().getName(right));
|
||||
return cmp < 0;
|
||||
}
|
||||
|
||||
|
@ -334,10 +341,7 @@ namespace MWGui
|
|||
// equip, if it can be equipped
|
||||
if (!MWWorld::Class::get(item).getEquipmentSlots(item).first.empty())
|
||||
{
|
||||
// Note: can't use Class::use here because enchanted scrolls for example would then open the scroll window instead of equipping
|
||||
|
||||
MWWorld::ActionEquip action(item);
|
||||
action.execute (MWBase::Environment::get().getWorld ()->getPlayerPtr());
|
||||
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->useItem(item);
|
||||
}
|
||||
|
||||
store.setSelectedEnchantItem(it);
|
||||
|
|
|
@ -70,8 +70,7 @@ namespace MWGui
|
|||
setText("RaceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu5", "Race"));
|
||||
getWidget(mRaceList, "RaceList");
|
||||
mRaceList->setScrollVisible(true);
|
||||
mRaceList->eventListSelectAccept += MyGUI::newDelegate(this, &RaceDialog::onSelectRace);
|
||||
mRaceList->eventListMouseItemActivate += MyGUI::newDelegate(this, &RaceDialog::onSelectRace);
|
||||
mRaceList->eventListSelectAccept += MyGUI::newDelegate(this, &RaceDialog::onAccept);
|
||||
mRaceList->eventListChangePosition += MyGUI::newDelegate(this, &RaceDialog::onSelectRace);
|
||||
|
||||
setText("SkillsT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sBonusSkillTitle", "Skill Bonus"));
|
||||
|
@ -241,6 +240,14 @@ namespace MWGui
|
|||
updateSpellPowers();
|
||||
}
|
||||
|
||||
void RaceDialog::onAccept(MyGUI::ListBox *_sender, size_t _index)
|
||||
{
|
||||
onSelectRace(_sender, _index);
|
||||
if(mRaceList->getIndexSelected() == MyGUI::ITEM_NONE)
|
||||
return;
|
||||
eventDone(this);
|
||||
}
|
||||
|
||||
void RaceDialog::getBodyParts (int part, std::vector<std::string>& out)
|
||||
{
|
||||
out.clear();
|
||||
|
|
|
@ -67,6 +67,7 @@ namespace MWGui
|
|||
void onSelectNextHair(MyGUI::Widget* _sender);
|
||||
|
||||
void onSelectRace(MyGUI::ListBox* _sender, size_t _index);
|
||||
void onAccept(MyGUI::ListBox* _sender, size_t _index);
|
||||
|
||||
void onOkClicked(MyGUI::Widget* _sender);
|
||||
void onBackClicked(MyGUI::Widget* _sender);
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace MWGui
|
|||
|
||||
void ReferenceInterface::checkReferenceAvailable()
|
||||
{
|
||||
MWWorld::Ptr::CellStore* playerCell = MWBase::Environment::get().getWorld()->getPlayerPtr().getCell();
|
||||
MWWorld::CellStore* playerCell = MWBase::Environment::get().getWorld()->getPlayerPtr().getCell();
|
||||
|
||||
// check if player has changed cell, or count of the reference has become 0
|
||||
if ((playerCell != mCurrentPlayerCell && mCurrentPlayerCell != NULL)
|
||||
|
|
|
@ -1,12 +1,28 @@
|
|||
#include "savegamedialog.hpp"
|
||||
#include "widgets.hpp"
|
||||
|
||||
#include <OgreImage.h>
|
||||
#include <OgreTextureManager.h>
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
#include <components/settings/settings.hpp>
|
||||
|
||||
#include "../mwbase/statemanager.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
|
||||
#include "../mwstate/character.hpp"
|
||||
|
||||
#include "confirmationdialog.hpp"
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
|
||||
SaveGameDialog::SaveGameDialog()
|
||||
: WindowModal("openmw_savegame_dialog.layout")
|
||||
, mSaving(true)
|
||||
, mCurrentCharacter(NULL)
|
||||
{
|
||||
getWidget(mScreenshot, "Screenshot");
|
||||
getWidget(mCharacterSelection, "SelectCharacter");
|
||||
|
@ -18,21 +34,89 @@ namespace MWGui
|
|||
getWidget(mSpacer, "Spacer");
|
||||
mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SaveGameDialog::onOkButtonClicked);
|
||||
mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SaveGameDialog::onCancelButtonClicked);
|
||||
mCharacterSelection->eventComboChangePosition += MyGUI::newDelegate(this, &SaveGameDialog::onCharacterSelected);
|
||||
mSaveList->eventListChangePosition += MyGUI::newDelegate(this, &SaveGameDialog::onSlotSelected);
|
||||
mSaveList->eventListSelectAccept += MyGUI::newDelegate(this, &SaveGameDialog::onSlotActivated);
|
||||
mSaveNameEdit->eventEditSelectAccept += MyGUI::newDelegate(this, &SaveGameDialog::onEditSelectAccept);
|
||||
mSaveNameEdit->eventEditTextChange += MyGUI::newDelegate(this, &SaveGameDialog::onSaveNameChanged);
|
||||
}
|
||||
|
||||
void SaveGameDialog::onSlotActivated(MyGUI::ListBox *sender, size_t pos)
|
||||
{
|
||||
onSlotSelected(sender, pos);
|
||||
accept();
|
||||
}
|
||||
|
||||
void SaveGameDialog::onSaveNameChanged(MyGUI::EditBox *sender)
|
||||
{
|
||||
// This might have previously been a save slot from the list. If so, that is no longer the case
|
||||
mSaveList->setIndexSelected(MyGUI::ITEM_NONE);
|
||||
onSlotSelected(mSaveList, MyGUI::ITEM_NONE);
|
||||
}
|
||||
|
||||
void SaveGameDialog::onEditSelectAccept(MyGUI::EditBox *sender)
|
||||
{
|
||||
accept();
|
||||
}
|
||||
|
||||
void SaveGameDialog::open()
|
||||
{
|
||||
WindowModal::open();
|
||||
|
||||
mSaveNameEdit->setCaption ("");
|
||||
if (mSaving)
|
||||
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveNameEdit);
|
||||
|
||||
center();
|
||||
|
||||
MWBase::StateManager* mgr = MWBase::Environment::get().getStateManager();
|
||||
if (mgr->characterBegin() == mgr->characterEnd())
|
||||
return;
|
||||
|
||||
mCurrentCharacter = mgr->getCurrentCharacter (false);
|
||||
|
||||
std::string directory =
|
||||
Misc::StringUtils::lowerCase (Settings::Manager::getString ("character", "Saves"));
|
||||
|
||||
mCharacterSelection->removeAllItems();
|
||||
|
||||
for (MWBase::StateManager::CharacterIterator it = mgr->characterBegin(); it != mgr->characterEnd(); ++it)
|
||||
{
|
||||
if (it->begin()!=it->end())
|
||||
{
|
||||
std::stringstream title;
|
||||
title << it->getSignature().mPlayerName;
|
||||
title << " (Level " << it->getSignature().mPlayerLevel << " " << it->getSignature().mPlayerClass << ")";
|
||||
|
||||
mCharacterSelection->addItem (title.str());
|
||||
|
||||
if (mCurrentCharacter == &*it ||
|
||||
(!mCurrentCharacter && !mSaving && directory==Misc::StringUtils::lowerCase (
|
||||
it->begin()->mPath.parent_path().filename().string())))
|
||||
{
|
||||
mCurrentCharacter = &*it;
|
||||
mCharacterSelection->setIndexSelected(mCharacterSelection->getItemCount()-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fillSaveList();
|
||||
|
||||
}
|
||||
|
||||
void SaveGameDialog::setLoadOrSave(bool load)
|
||||
{
|
||||
mSaving = !load;
|
||||
mSaveNameEdit->setVisible(!load);
|
||||
mCharacterSelection->setUserString("Hidden", load ? "false" : "true");
|
||||
mCharacterSelection->setVisible(load);
|
||||
mSpacer->setUserString("Hidden", load ? "false" : "true");
|
||||
|
||||
if (!load)
|
||||
{
|
||||
mCurrentCharacter = MWBase::Environment::get().getStateManager()->getCurrentCharacter (false);
|
||||
}
|
||||
|
||||
center();
|
||||
}
|
||||
|
||||
|
@ -41,9 +125,161 @@ namespace MWGui
|
|||
setVisible(false);
|
||||
}
|
||||
|
||||
void SaveGameDialog::onOkButtonClicked(MyGUI::Widget *sender)
|
||||
void SaveGameDialog::onConfirmationGiven()
|
||||
{
|
||||
setVisible(false);
|
||||
accept(true);
|
||||
}
|
||||
|
||||
void SaveGameDialog::accept(bool reallySure)
|
||||
{
|
||||
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(NULL);
|
||||
|
||||
// Get the selected slot, if any
|
||||
unsigned int i=0;
|
||||
const MWState::Slot* slot = NULL;
|
||||
|
||||
if (mCurrentCharacter)
|
||||
{
|
||||
for (MWState::Character::SlotIterator it = mCurrentCharacter->begin(); it != mCurrentCharacter->end(); ++it,++i)
|
||||
{
|
||||
if (i == mSaveList->getIndexSelected())
|
||||
slot = &*it;
|
||||
}
|
||||
}
|
||||
|
||||
if (mSaving)
|
||||
{
|
||||
// If overwriting an existing slot, ask for confirmation first
|
||||
if (slot != NULL && !reallySure)
|
||||
{
|
||||
ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog();
|
||||
dialog->open("#{sMessage4}");
|
||||
dialog->eventOkClicked.clear();
|
||||
dialog->eventOkClicked += MyGUI::newDelegate(this, &SaveGameDialog::onConfirmationGiven);
|
||||
dialog->eventCancelClicked.clear();
|
||||
return;
|
||||
}
|
||||
if (mSaveNameEdit->getCaption().empty())
|
||||
{
|
||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage65}");
|
||||
return;
|
||||
}
|
||||
MWBase::Environment::get().getStateManager()->saveGame (mSaveNameEdit->getCaption(), slot);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mCurrentCharacter && slot)
|
||||
MWBase::Environment::get().getStateManager()->loadGame (mCurrentCharacter, slot);
|
||||
}
|
||||
|
||||
setVisible(false);
|
||||
|
||||
if (MWBase::Environment::get().getStateManager()->getState()==
|
||||
MWBase::StateManager::State_NoGame)
|
||||
{
|
||||
MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu);
|
||||
}
|
||||
}
|
||||
|
||||
void SaveGameDialog::onOkButtonClicked(MyGUI::Widget *sender)
|
||||
{
|
||||
accept();
|
||||
}
|
||||
|
||||
void SaveGameDialog::onCharacterSelected(MyGUI::ComboBox *sender, size_t pos)
|
||||
{
|
||||
MWBase::StateManager* mgr = MWBase::Environment::get().getStateManager();
|
||||
|
||||
unsigned int i=0;
|
||||
const MWState::Character* character = NULL;
|
||||
for (MWBase::StateManager::CharacterIterator it = mgr->characterBegin(); it != mgr->characterEnd(); ++it, ++i)
|
||||
{
|
||||
if (i == pos)
|
||||
character = &*it;
|
||||
}
|
||||
assert(character && "Can't find selected character");
|
||||
|
||||
mCurrentCharacter = character;
|
||||
fillSaveList();
|
||||
}
|
||||
|
||||
void SaveGameDialog::fillSaveList()
|
||||
{
|
||||
mSaveList->removeAllItems();
|
||||
if (!mCurrentCharacter)
|
||||
return;
|
||||
for (MWState::Character::SlotIterator it = mCurrentCharacter->begin(); it != mCurrentCharacter->end(); ++it)
|
||||
{
|
||||
mSaveList->addItem(it->mProfile.mDescription);
|
||||
}
|
||||
onSlotSelected(mSaveList, MyGUI::ITEM_NONE);
|
||||
}
|
||||
|
||||
void SaveGameDialog::onSlotSelected(MyGUI::ListBox *sender, size_t pos)
|
||||
{
|
||||
if (pos == MyGUI::ITEM_NONE)
|
||||
{
|
||||
mInfoText->setCaption("");
|
||||
mScreenshot->setImageTexture("");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mSaving)
|
||||
mSaveNameEdit->setCaption(sender->getItemNameAt(pos));
|
||||
|
||||
const MWState::Slot* slot = NULL;
|
||||
unsigned int i=0;
|
||||
for (MWState::Character::SlotIterator it = mCurrentCharacter->begin(); it != mCurrentCharacter->end(); ++it, ++i)
|
||||
{
|
||||
if (i == pos)
|
||||
slot = &*it;
|
||||
}
|
||||
assert(slot && "Can't find selected slot");
|
||||
|
||||
std::stringstream text;
|
||||
time_t time = slot->mTimeStamp;
|
||||
struct tm* timeinfo;
|
||||
timeinfo = localtime(&time);
|
||||
|
||||
text << asctime(timeinfo) << "\n";
|
||||
text << "Level " << slot->mProfile.mPlayerLevel << "\n";
|
||||
text << slot->mProfile.mPlayerCell << "\n";
|
||||
// text << "Time played: " << slot->mProfile.mTimePlayed << "\n";
|
||||
|
||||
int hour = int(slot->mProfile.mInGameTime.mGameHour);
|
||||
bool pm = hour >= 12;
|
||||
if (hour >= 13) hour -= 12;
|
||||
if (hour == 0) hour = 12;
|
||||
|
||||
text
|
||||
<< slot->mProfile.mInGameTime.mDay << " "
|
||||
<< MWBase::Environment::get().getWorld()->getMonthName(slot->mProfile.mInGameTime.mMonth)
|
||||
<< " " << hour << " " << (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}");
|
||||
|
||||
mInfoText->setCaptionWithReplacing(text.str());
|
||||
|
||||
// Decode screenshot
|
||||
std::vector<char> data = slot->mProfile.mScreenshot; // MemoryDataStream doesn't work with const data :(
|
||||
Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(&data[0], data.size()));
|
||||
Ogre::Image image;
|
||||
image.load(stream, "jpg");
|
||||
|
||||
const std::string textureName = "@savegame_screenshot";
|
||||
Ogre::TexturePtr texture;
|
||||
texture = Ogre::TextureManager::getSingleton().getByName(textureName);
|
||||
mScreenshot->setImageTexture("");
|
||||
if (texture.isNull())
|
||||
{
|
||||
texture = Ogre::TextureManager::getSingleton().createManual(textureName,
|
||||
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
|
||||
Ogre::TEX_TYPE_2D,
|
||||
image.getWidth(), image.getHeight(), 0, Ogre::PF_BYTE_RGBA, Ogre::TU_DYNAMIC_WRITE_ONLY);
|
||||
}
|
||||
texture->unload();
|
||||
texture->setWidth(image.getWidth());
|
||||
texture->setHeight(image.getHeight());
|
||||
texture->loadImage(image);
|
||||
|
||||
mScreenshot->setImageTexture(textureName);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,11 @@
|
|||
|
||||
#include "windowbase.hpp"
|
||||
|
||||
namespace MWState
|
||||
{
|
||||
class Character;
|
||||
}
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
|
||||
|
@ -15,12 +20,22 @@ namespace MWGui
|
|||
|
||||
void setLoadOrSave(bool load);
|
||||
|
||||
private:
|
||||
void onCancelButtonClicked (MyGUI::Widget* sender);
|
||||
void onOkButtonClicked (MyGUI::Widget* sender);
|
||||
void onCharacterSelected (MyGUI::ComboBox* sender, size_t pos);
|
||||
void onSlotSelected (MyGUI::ListBox* sender, size_t pos);
|
||||
void onSlotActivated (MyGUI::ListBox* sender, size_t pos);
|
||||
void onEditSelectAccept (MyGUI::EditBox* sender);
|
||||
void onSaveNameChanged (MyGUI::EditBox* sender);
|
||||
void onConfirmationGiven();
|
||||
|
||||
void accept(bool reallySure=false);
|
||||
|
||||
void fillSaveList();
|
||||
|
||||
private:
|
||||
MyGUI::ImageBox* mScreenshot;
|
||||
bool mSaving;
|
||||
|
||||
MyGUI::ComboBox* mCharacterSelection;
|
||||
MyGUI::EditBox* mInfoText;
|
||||
|
@ -30,6 +45,8 @@ namespace MWGui
|
|||
MyGUI::EditBox* mSaveNameEdit;
|
||||
MyGUI::Widget* mSpacer;
|
||||
|
||||
const MWState::Character* mCurrentCharacter;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue