1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-29 07:15:32 +00:00

Merge pull request #10 from cc9cii/master-cherry-pick-3

Merge master (cherry pick 3)
This commit is contained in:
cc9cii 2015-11-05 20:35:10 +11:00
commit 9f4ecc2f8e
119 changed files with 2641 additions and 588 deletions

View file

@ -40,8 +40,8 @@ script:
- cd ./build
- if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then ${ANALYZE}make -j2; fi
- if [ "$COVERITY_SCAN_BRANCH" != 1 ] && [ "${TRAVIS_OS_NAME}" = "osx" ]; then make package; fi
after_script:
- if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi
- if [ "${TRAVIS_OS_NAME}" = "linux" ]; then cd .. && ./CI/check_tabs.sh; fi
notifications:
recipients:
- corrmage+travis-ci@gmail.com

View file

@ -19,6 +19,7 @@ Programmers
Alexander Nadeau (wareya)
Alexander Olofsson (Ace)
Artem Kotsynyak (greye)
artemutin
Arthur Moore (EmperorArthur)
athile
Bret Curtis (psi29a)
@ -110,6 +111,7 @@ Programmers
viadanna
Vincent Heuken
vocollapse
zelurker
Manual
------

9
CI/check_tabs.sh Executable file
View file

@ -0,0 +1,9 @@
#!/bin/bash
OUTPUT=$(grep -nRP '\t' --include=\*.{cpp,hpp,c,h} apps components)
if [[ $OUTPUT ]] ; then
echo "Error: Tab characters found!"
echo $OUTPUT
exit 1
fi

16
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,16 @@
Description
===========
Your pull request description should include (if applicable):
* A link back to the bug report or forum discussion that prompted the change
* Summary of the changes made
* Reasoning / motivation behind the change
* What testing you have carried out to verify the change
Other notes
===========
* Separate your work into multiple pull requests whenever possible. As a rule of thumb, each feature and each bugfix should go into a separate PR, unless they are closely related or dependent upon each other. Small pull requests are easier to review, and are less likely to require further changes before we can merge them. A "mega" pull request with lots of unrelated commits in it is likely to get held up in review for a long time.
* Feel free to submit incomplete pull requests. Even if the work can not be merged yet, pull requests are a great place to collect early feedback. Just make sure to mark it as *[Incomplete]* or *[Do not merge yet]* in the title.
* If you plan on contributing often, please read the [Developer Reference](https://wiki.openmw.org/index.php?title=Developer_Reference) on our wiki, especially the [Policies and Standards](https://wiki.openmw.org/index.php?title=Policies_and_Standards).

View file

@ -493,14 +493,14 @@ void Record<ESM::Book>::print()
std::cout << " Enchantment Points: " << mData.mData.mEnchant << std::endl;
if (mPrintPlain)
{
std::cout << " Text:" << std::endl;
std::cout << "START--------------------------------------" << std::endl;
std::cout << mData.mText << std::endl;
std::cout << "END----------------------------------------" << std::endl;
std::cout << " Text:" << std::endl;
std::cout << "START--------------------------------------" << std::endl;
std::cout << mData.mText << std::endl;
std::cout << "END----------------------------------------" << std::endl;
}
else
{
std::cout << " Text: [skipped]" << std::endl;
std::cout << " Text: [skipped]" << std::endl;
}
}
@ -799,14 +799,14 @@ void Record<ESM::DialInfo>::print()
{
if (mPrintPlain)
{
std::cout << " Result Script:" << std::endl;
std::cout << "START--------------------------------------" << std::endl;
std::cout << mData.mResultScript << std::endl;
std::cout << "END----------------------------------------" << std::endl;
std::cout << " Result Script:" << std::endl;
std::cout << "START--------------------------------------" << std::endl;
std::cout << mData.mResultScript << std::endl;
std::cout << "END----------------------------------------" << std::endl;
}
else
{
std::cout << " Result Script: [skipped]" << std::endl;
std::cout << " Result Script: [skipped]" << std::endl;
}
}
}
@ -841,19 +841,13 @@ void Record<ESM::Land>::print()
std::cout << " Flags: " << landFlags(mData.mFlags) << std::endl;
std::cout << " DataTypes: " << mData.mDataTypes << std::endl;
// Seems like this should done with reference counting in the
// loader to me. But I'm not really knowledgable about this
// record type yet. --Cory
bool wasLoaded = (mData.mDataLoaded != 0);
if (mData.mDataTypes) mData.loadData(mData.mDataTypes);
if (mData.mDataLoaded)
if (const ESM::Land::LandData *data = mData.getLandData (mData.mDataTypes))
{
std::cout << " Height Offset: " << mData.mLandData->mHeightOffset << std::endl;
std::cout << " Height Offset: " << data->mHeightOffset << std::endl;
// Lots of missing members.
std::cout << " Unknown1: " << mData.mLandData->mUnk1 << std::endl;
std::cout << " Unknown2: " << mData.mLandData->mUnk2 << std::endl;
std::cout << " Unknown1: " << data->mUnk1 << std::endl;
std::cout << " Unknown2: " << data->mUnk2 << std::endl;
}
if (!wasLoaded) mData.unloadData();
}
template<>
@ -1207,14 +1201,14 @@ void Record<ESM::Script>::print()
if (mPrintPlain)
{
std::cout << " Script:" << std::endl;
std::cout << "START--------------------------------------" << std::endl;
std::cout << mData.mScriptText << std::endl;
std::cout << "END----------------------------------------" << std::endl;
std::cout << " Script:" << std::endl;
std::cout << "START--------------------------------------" << std::endl;
std::cout << mData.mScriptText << std::endl;
std::cout << "END----------------------------------------" << std::endl;
}
else
{
std::cout << " Script: [skipped]" << std::endl;
std::cout << " Script: [skipped]" << std::endl;
}
}

View file

@ -53,7 +53,7 @@ namespace EsmTool
}
void setPrintPlain(bool plain) {
mPrintPlain = plain;
mPrintPlain = plain;
}
virtual void load(ESM::ESMReader &esm) = 0;

View file

@ -296,7 +296,7 @@ namespace ESSImport
ESM::ESMWriter writer;
writer.setFormat (ESM::Header::CurrentFormat);
writer.setFormat (ESM::SavedGame::sCurrentFormat);
std::ofstream stream(mOutFile.c_str(), std::ios::binary);
// all unused

View file

@ -35,13 +35,18 @@ opencs_hdrs_noqt (model/world
opencs_units (model/tools
tools reportmodel
tools reportmodel mergeoperation
)
opencs_units_noqt (model/tools
mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck
birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck
startscriptcheck search searchoperation searchstage pathgridcheck soundgencheck magiceffectcheck
mergestages
)
opencs_hdrs_noqt (model/tools
mergestate
)
@ -62,7 +67,7 @@ opencs_hdrs_noqt (view/doc
opencs_units (view/world
table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator
cellcreator referenceablecreator referencecreator scenesubview
cellcreator referenceablecreator startscriptcreator referencecreator scenesubview
infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable
dialoguespinbox recordbuttonbar tableeditidaction scripterrortable extendedcommandconfigurator
)
@ -94,7 +99,7 @@ opencs_hdrs_noqt (view/render
opencs_units (view/tools
reportsubview reporttable searchsubview searchbox
reportsubview reporttable searchsubview searchbox merge
)
opencs_units_noqt (view/tools

View file

@ -26,7 +26,8 @@
CS::Editor::Editor (OgreInit::OgreInit& ogreInit)
: mUserSettings (mCfgMgr), mOverlaySystem (0), mDocumentManager (mCfgMgr),
mViewManager (mDocumentManager), mPid(""),
mLock(), mIpcServerName ("org.openmw.OpenCS"), mServer(NULL), mClientSocket(NULL)
mLock(), mMerge (mDocumentManager),
mIpcServerName ("org.openmw.OpenCS"), mServer(NULL), mClientSocket(NULL)
{
std::pair<Files::PathContainer, std::vector<std::string> > config = readConfig();
@ -48,9 +49,12 @@ CS::Editor::Editor (OgreInit::OgreInit& ogreInit)
mNewGame.setLocalData (mLocal);
mFileDialog.setLocalData (mLocal);
mMerge.setLocalData (mLocal);
connect (&mDocumentManager, SIGNAL (documentAdded (CSMDoc::Document *)),
this, SLOT (documentAdded (CSMDoc::Document *)));
connect (&mDocumentManager, SIGNAL (documentAboutToBeRemoved (CSMDoc::Document *)),
this, SLOT (documentAboutToBeRemoved (CSMDoc::Document *)));
connect (&mDocumentManager, SIGNAL (lastDocumentDeleted()),
this, SLOT (lastDocumentDeleted()));
@ -58,6 +62,7 @@ CS::Editor::Editor (OgreInit::OgreInit& ogreInit)
connect (&mViewManager, SIGNAL (newAddonRequest ()), this, SLOT (createAddon ()));
connect (&mViewManager, SIGNAL (loadDocumentRequest ()), this, SLOT (loadDocument ()));
connect (&mViewManager, SIGNAL (editSettingsRequest()), this, SLOT (showSettings ()));
connect (&mViewManager, SIGNAL (mergeDocument (CSMDoc::Document *)), this, SLOT (mergeDocument (CSMDoc::Document *)));
connect (&mStartup, SIGNAL (createGame()), this, SLOT (createGame ()));
connect (&mStartup, SIGNAL (createAddon()), this, SLOT (createAddon ()));
@ -490,6 +495,12 @@ void CS::Editor::documentAdded (CSMDoc::Document *document)
showSplashMessage();
}
void CS::Editor::documentAboutToBeRemoved (CSMDoc::Document *document)
{
if (mMerge.getDocument()==document)
mMerge.cancel();
}
void CS::Editor::lastDocumentDeleted()
{
QApplication::quit();
@ -535,3 +546,11 @@ void CS::Editor::showSplashMessage()
splash->raise(); // for X windows
}
}
void CS::Editor::mergeDocument (CSMDoc::Document *document)
{
mMerge.configure (document);
mMerge.show();
mMerge.raise();
mMerge.activateWindow();
}

View file

@ -32,11 +32,18 @@
#include "view/settings/dialog.hpp"
#include "view/render/overlaysystem.hpp"
#include "view/tools/merge.hpp"
namespace OgreInit
{
class OgreInit;
}
namespace CSMDoc
{
class Document;
}
namespace CS
{
class Editor : public QObject
@ -59,6 +66,7 @@ namespace CS
boost::interprocess::file_lock mLock;
boost::filesystem::ofstream mPidFile;
bool mFsStrict;
CSVTools::Merge mMerge;
void showSplashMessage();
@ -103,8 +111,12 @@ namespace CS
void documentAdded (CSMDoc::Document *document);
void documentAboutToBeRemoved (CSMDoc::Document *document);
void lastDocumentDeleted();
void mergeDocument (CSMDoc::Document *document);
private:
QString mIpcServerName;

View file

@ -2251,14 +2251,14 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration,
ToUTF8::FromType encoding, const CSMWorld::ResourcesManager& resourcesManager,
const std::vector<std::string>& blacklistedScripts)
: mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding, resourcesManager),
mTools (*this),
mTools (*this, encoding),
mProjectPath ((configuration.getUserDataPath() / "projects") /
(savePath.filename().string() + ".project")),
mSavingOperation (*this, mProjectPath, encoding),
mSaving (&mSavingOperation),
mResDir(resDir),
mRunner (mProjectPath), mPhysics(boost::shared_ptr<CSVWorld::PhysicsSystem>()),
mIdCompletionManager(mData)
mDirty (false), mIdCompletionManager(mData)
{
if (mContentFiles.empty())
throw std::runtime_error ("Empty content file sequence");
@ -2296,6 +2296,8 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration,
connect (&mTools, SIGNAL (progress (int, int, int)), this, SLOT (progress (int, int, int)));
connect (&mTools, SIGNAL (done (int, bool)), this, SLOT (operationDone (int, bool)));
connect (&mTools, SIGNAL (mergeDone (CSMDoc::Document*)),
this, SIGNAL (mergeDone (CSMDoc::Document*)));
connect (&mSaving, SIGNAL (progress (int, int, int)), this, SLOT (progress (int, int, int)));
connect (&mSaving, SIGNAL (done (int, bool)), this, SLOT (operationDone (int, bool)));
@ -2320,7 +2322,7 @@ int CSMDoc::Document::getState() const
{
int state = 0;
if (!mUndoStack.isClean())
if (!mUndoStack.isClean() || mDirty)
state |= State_Modified;
if (mSaving.isRunning())
@ -2385,6 +2387,12 @@ void CSMDoc::Document::runSearch (const CSMWorld::UniversalId& searchId, const C
emit stateChanged (getState(), this);
}
void CSMDoc::Document::runMerge (std::auto_ptr<CSMDoc::Document> target)
{
mTools.runMerge (target);
emit stateChanged (getState(), this);
}
void CSMDoc::Document::abortOperation (int type)
{
if (type==State_Saving)
@ -2406,6 +2414,9 @@ void CSMDoc::Document::reportMessage (const CSMDoc::Message& message, int type)
void CSMDoc::Document::operationDone (int type, bool failed)
{
if (type==CSMDoc::State_Saving && !failed)
mDirty = false;
emit stateChanged (getState(), this);
}
@ -2490,3 +2501,8 @@ CSMWorld::IdCompletionManager &CSMDoc::Document::getIdCompletionManager()
{
return mIdCompletionManager;
}
void CSMDoc::Document::flagAsDirty()
{
mDirty = true;
}

View file

@ -67,6 +67,8 @@ namespace CSMDoc
Blacklist mBlacklist;
Runner mRunner;
boost::shared_ptr<CSVWorld::PhysicsSystem> mPhysics;
bool mDirty;
CSMWorld::IdCompletionManager mIdCompletionManager;
// It is important that the undo stack is declared last, because on desctruction it fires a signal, that is connected to a slot, that is
@ -125,7 +127,9 @@ namespace CSMDoc
CSMWorld::UniversalId newSearch();
void runSearch (const CSMWorld::UniversalId& searchId, const CSMTools::Search& search);
void runMerge (std::auto_ptr<CSMDoc::Document> target);
void abortOperation (int type);
const CSMWorld::Data& getData() const;
@ -148,12 +152,18 @@ namespace CSMDoc
CSMWorld::IdCompletionManager &getIdCompletionManager();
void flagAsDirty();
signals:
void stateChanged (int state, CSMDoc::Document *document);
void progress (int current, int max, int type, int threads, CSMDoc::Document *document);
/// \attention When this signal is emitted, *this hands over the ownership of the
/// document. This signal must be handled to avoid a leak.
void mergeDone (CSMDoc::Document *document);
private slots:
void modificationStateChanged (bool clean);
@ -171,4 +181,3 @@ namespace CSMDoc
}
#endif

View file

@ -56,10 +56,24 @@ bool CSMDoc::DocumentManager::isEmpty()
void CSMDoc::DocumentManager::addDocument (const std::vector<boost::filesystem::path>& files, const boost::filesystem::path& savePath,
bool new_)
{
Document *document = new Document (mConfiguration, files, new_, savePath, mResDir, mEncoding, mResourcesManager, mBlacklistedScripts);
Document *document = makeDocument (files, savePath, new_);
insertDocument (document);
}
CSMDoc::Document *CSMDoc::DocumentManager::makeDocument (
const std::vector< boost::filesystem::path >& files,
const boost::filesystem::path& savePath, bool new_)
{
return new Document (mConfiguration, files, new_, savePath, mResDir, mEncoding, mResourcesManager, mBlacklistedScripts);
}
void CSMDoc::DocumentManager::insertDocument (CSMDoc::Document *document)
{
mDocuments.push_back (document);
connect (document, SIGNAL (mergeDone (CSMDoc::Document*)),
this, SLOT (insertDocument (CSMDoc::Document*)));
emit loadRequest (document);
mLoader.hasThingsToDo().wakeAll();
@ -72,6 +86,8 @@ void CSMDoc::DocumentManager::removeDocument (CSMDoc::Document *document)
if (iter==mDocuments.end())
throw std::runtime_error ("removing invalid document");
emit documentAboutToBeRemoved (document);
mDocuments.erase (iter);
document->deleteLater();

View file

@ -50,6 +50,15 @@ namespace CSMDoc
///< \param new_ Do not load the last content file in \a files and instead create in an
/// appropriate way.
/// Create a new document. The ownership of the created document is transferred to
/// the calling function. The DocumentManager does not manage it. Loading has not
/// taken place at the point when the document is returned.
///
/// \param new_ Do not load the last content file in \a files and instead create in an
/// appropriate way.
Document *makeDocument (const std::vector< boost::filesystem::path >& files,
const boost::filesystem::path& savePath, bool new_);
void setResourceDir (const boost::filesystem::path& parResDir);
void setEncoding (ToUTF8::FromType encoding);
@ -79,10 +88,16 @@ namespace CSMDoc
void removeDocument (CSMDoc::Document *document);
///< Emits the lastDocumentDeleted signal, if applicable.
/// Hand over document to *this. The ownership is transferred. The DocumentManager
/// will initiate the load procedure, if necessary
void insertDocument (CSMDoc::Document *document);
signals:
void documentAdded (CSMDoc::Document *document);
void documentAboutToBeRemoved (CSMDoc::Document *document);
void loadRequest (CSMDoc::Document *document);
void lastDocumentDeleted();

View file

@ -83,7 +83,9 @@ namespace CSMDoc
void executeStage();
void operationDone();
protected slots:
virtual void operationDone();
};
}

View file

@ -134,23 +134,34 @@ void CSMDoc::WriteDialogueCollectionStage::perform (int stage, Messages& message
state==CSMWorld::RecordBase::State_ModifiedOnly ||
infoModified)
{
mState.getWriter().startRecord (topic.mModified.sRecordId);
mState.getWriter().writeHNCString ("NAME", topic.mModified.mId);
topic.mModified.save (mState.getWriter());
mState.getWriter().endRecord (topic.mModified.sRecordId);
if (infoModified && state != CSMWorld::RecordBase::State_Modified
&& state != CSMWorld::RecordBase::State_ModifiedOnly)
{
mState.getWriter().startRecord (topic.mBase.sRecordId);
mState.getWriter().writeHNCString ("NAME", topic.mBase.mId);
topic.mBase.save (mState.getWriter());
mState.getWriter().endRecord (topic.mBase.sRecordId);
}
else
{
mState.getWriter().startRecord (topic.mModified.sRecordId);
mState.getWriter().writeHNCString ("NAME", topic.mModified.mId);
topic.mModified.save (mState.getWriter());
mState.getWriter().endRecord (topic.mModified.sRecordId);
}
// write modified selected info records
for (CSMWorld::InfoCollection::RecordConstIterator iter (range.first); iter!=range.second;
++iter)
{
CSMWorld::RecordBase::State state = iter->mState;
CSMWorld::RecordBase::State infoState = iter->mState;
if (state==CSMWorld::RecordBase::State_Deleted)
if (infoState==CSMWorld::RecordBase::State_Deleted)
{
/// \todo wrote record with delete flag
}
else if (state==CSMWorld::RecordBase::State_Modified ||
state==CSMWorld::RecordBase::State_ModifiedOnly)
else if (infoState==CSMWorld::RecordBase::State_Modified ||
infoState==CSMWorld::RecordBase::State_ModifiedOnly)
{
ESM::DialInfo info = iter->get();
info.mId = info.mId.substr (info.mId.find_last_of ('#')+1);
@ -415,15 +426,16 @@ void CSMDoc::WriteLandCollectionStage::perform (int stage, Messages& messages)
if (land.mState==CSMWorld::RecordBase::State_Modified ||
land.mState==CSMWorld::RecordBase::State_ModifiedOnly)
{
CSMWorld::Land record = land.get();
const CSMWorld::Land& record = land.get();
mState.getWriter().startRecord (record.mLand->sRecordId);
mState.getWriter().startRecord (record.sRecordId);
record.mLand->save (mState.getWriter());
if(record.mLand->mLandData)
record.mLand->mLandData->save (mState.getWriter());
record.save (mState.getWriter());
mState.getWriter().endRecord (record.mLand->sRecordId);
if (const ESM::Land::LandData *data = record.getLandData (record.mDataTypes))
data->save (mState.getWriter());
mState.getWriter().endRecord (record.sRecordId);
}
else if (land.mState==CSMWorld::RecordBase::State_Deleted)
{

View file

@ -12,7 +12,7 @@ namespace CSMDoc
State_Saving = 16,
State_Verifying = 32,
State_Compiling = 64, // not implemented yet
State_Merging = 64,
State_Searching = 128,
State_Loading = 256 // pseudo-state; can not be encountered in a loaded document
};

View file

@ -0,0 +1,59 @@
#include "mergeoperation.hpp"
#include "../doc/state.hpp"
#include "../doc/document.hpp"
#include "mergestages.hpp"
CSMTools::MergeOperation::MergeOperation (CSMDoc::Document& document, ToUTF8::FromType encoding)
: CSMDoc::Operation (CSMDoc::State_Merging, true), mState (document)
{
appendStage (new StartMergeStage (mState));
appendStage (new MergeIdCollectionStage<ESM::Global> (mState, &CSMWorld::Data::getGlobals));
appendStage (new MergeIdCollectionStage<ESM::GameSetting> (mState, &CSMWorld::Data::getGmsts));
appendStage (new MergeIdCollectionStage<ESM::Skill> (mState, &CSMWorld::Data::getSkills));
appendStage (new MergeIdCollectionStage<ESM::Class> (mState, &CSMWorld::Data::getClasses));
appendStage (new MergeIdCollectionStage<ESM::Faction> (mState, &CSMWorld::Data::getFactions));
appendStage (new MergeIdCollectionStage<ESM::Race> (mState, &CSMWorld::Data::getRaces));
appendStage (new MergeIdCollectionStage<ESM::Sound> (mState, &CSMWorld::Data::getSounds));
appendStage (new MergeIdCollectionStage<ESM::Script> (mState, &CSMWorld::Data::getScripts));
appendStage (new MergeIdCollectionStage<ESM::Region> (mState, &CSMWorld::Data::getRegions));
appendStage (new MergeIdCollectionStage<ESM::BirthSign> (mState, &CSMWorld::Data::getBirthsigns));
appendStage (new MergeIdCollectionStage<ESM::Spell> (mState, &CSMWorld::Data::getSpells));
appendStage (new MergeIdCollectionStage<ESM::Dialogue> (mState, &CSMWorld::Data::getTopics));
appendStage (new MergeIdCollectionStage<ESM::Dialogue> (mState, &CSMWorld::Data::getJournals));
appendStage (new MergeIdCollectionStage<CSMWorld::Cell> (mState, &CSMWorld::Data::getCells));
appendStage (new MergeIdCollectionStage<ESM::Filter> (mState, &CSMWorld::Data::getFilters));
appendStage (new MergeIdCollectionStage<ESM::Enchantment> (mState, &CSMWorld::Data::getEnchantments));
appendStage (new MergeIdCollectionStage<ESM::BodyPart> (mState, &CSMWorld::Data::getBodyParts));
appendStage (new MergeIdCollectionStage<ESM::DebugProfile> (mState, &CSMWorld::Data::getDebugProfiles));
appendStage (new MergeIdCollectionStage<ESM::SoundGenerator> (mState, &CSMWorld::Data::getSoundGens));
appendStage (new MergeIdCollectionStage<ESM::MagicEffect> (mState, &CSMWorld::Data::getMagicEffects));
appendStage (new MergeIdCollectionStage<ESM::StartScript> (mState, &CSMWorld::Data::getStartScripts));
appendStage (new MergeIdCollectionStage<CSMWorld::Pathgrid, CSMWorld::SubCellCollection<CSMWorld::Pathgrid> > (mState, &CSMWorld::Data::getPathgrids));
appendStage (new MergeIdCollectionStage<CSMWorld::Info, CSMWorld::InfoCollection> (mState, &CSMWorld::Data::getTopicInfos));
appendStage (new MergeIdCollectionStage<CSMWorld::Info, CSMWorld::InfoCollection> (mState, &CSMWorld::Data::getJournalInfos));
appendStage (new MergeRefIdsStage (mState));
appendStage (new MergeReferencesStage (mState));
appendStage (new MergeReferencesStage (mState));
appendStage (new ListLandTexturesMergeStage (mState));
appendStage (new MergeLandTexturesStage (mState));
appendStage (new MergeLandStage (mState));
appendStage (new FinishMergedDocumentStage (mState, encoding));
}
void CSMTools::MergeOperation::setTarget (std::auto_ptr<CSMDoc::Document> document)
{
mState.mTarget = document;
}
void CSMTools::MergeOperation::operationDone()
{
CSMDoc::Operation::operationDone();
if (mState.mCompleted)
emit mergeDone (mState.mTarget.release());
}

View file

@ -0,0 +1,45 @@
#ifndef CSM_TOOLS_MERGEOPERATION_H
#define CSM_TOOLS_MERGEOPERATION_H
#include <memory>
#include <components/to_utf8/to_utf8.hpp>
#include "../doc/operation.hpp"
#include "mergestate.hpp"
namespace CSMDoc
{
class Document;
}
namespace CSMTools
{
class MergeOperation : public CSMDoc::Operation
{
Q_OBJECT
MergeState mState;
public:
MergeOperation (CSMDoc::Document& document, ToUTF8::FromType encoding);
/// \attention Do not call this function while a merge is running.
void setTarget (std::auto_ptr<CSMDoc::Document> document);
protected slots:
virtual void operationDone();
signals:
/// \attention When this signal is emitted, *this hands over the ownership of the
/// document. This signal must be handled to avoid a leak.
void mergeDone (CSMDoc::Document *document);
};
}
#endif

View file

@ -0,0 +1,258 @@
#include "mergestages.hpp"
#include <sstream>
#include <components/misc/stringops.hpp>
#include "mergestate.hpp"
#include "../doc/document.hpp"
#include "../world/data.hpp"
CSMTools::StartMergeStage::StartMergeStage (MergeState& state)
: mState (state)
{}
int CSMTools::StartMergeStage::setup()
{
return 1;
}
void CSMTools::StartMergeStage::perform (int stage, CSMDoc::Messages& messages)
{
mState.mCompleted = false;
mState.mTextureIndices.clear();
}
CSMTools::FinishMergedDocumentStage::FinishMergedDocumentStage (MergeState& state, ToUTF8::FromType encoding)
: mState (state), mEncoder (encoding)
{}
int CSMTools::FinishMergedDocumentStage::setup()
{
return 1;
}
void CSMTools::FinishMergedDocumentStage::perform (int stage, CSMDoc::Messages& messages)
{
// We know that the content file list contains at least two entries and that the first one
// does exist on disc (otherwise it would have been impossible to initiate a merge on that
// document).
boost::filesystem::path path = mState.mSource.getContentFiles()[0];
ESM::ESMReader reader;
reader.setEncoder (&mEncoder);
reader.open (path.string());
CSMWorld::MetaData source;
source.mId = "sys::meta";
source.load (reader);
CSMWorld::MetaData target = mState.mTarget->getData().getMetaData();
target.mAuthor = source.mAuthor;
target.mDescription = source.mDescription;
mState.mTarget->getData().setMetaData (target);
mState.mCompleted = true;
}
CSMTools::MergeRefIdsStage::MergeRefIdsStage (MergeState& state) : mState (state) {}
int CSMTools::MergeRefIdsStage::setup()
{
return mState.mSource.getData().getReferenceables().getSize();
}
void CSMTools::MergeRefIdsStage::perform (int stage, CSMDoc::Messages& messages)
{
mState.mSource.getData().getReferenceables().copyTo (
stage, mState.mTarget->getData().getReferenceables());
}
CSMTools::MergeReferencesStage::MergeReferencesStage (MergeState& state)
: mState (state)
{}
int CSMTools::MergeReferencesStage::setup()
{
mIndex.clear();
return mState.mSource.getData().getReferences().getSize();
}
void CSMTools::MergeReferencesStage::perform (int stage, CSMDoc::Messages& messages)
{
const CSMWorld::Record<CSMWorld::CellRef>& record =
mState.mSource.getData().getReferences().getRecord (stage);
if (!record.isDeleted())
{
CSMWorld::CellRef ref = record.get();
ref.mOriginalCell = ref.mCell;
ref.mRefNum.mIndex = mIndex[Misc::StringUtils::lowerCase (ref.mCell)]++;
ref.mRefNum.mContentFile = 0;
CSMWorld::Record<CSMWorld::CellRef> newRecord (
CSMWorld::RecordBase::State_ModifiedOnly, 0, &ref);
mState.mTarget->getData().getReferences().appendRecord (newRecord);
}
}
CSMTools::ListLandTexturesMergeStage::ListLandTexturesMergeStage (MergeState& state)
: mState (state)
{}
int CSMTools::ListLandTexturesMergeStage::setup()
{
return mState.mSource.getData().getLand().getSize();
}
void CSMTools::ListLandTexturesMergeStage::perform (int stage, CSMDoc::Messages& messages)
{
const CSMWorld::Record<CSMWorld::Land>& record =
mState.mSource.getData().getLand().getRecord (stage);
if (!record.isDeleted())
{
const CSMWorld::Land& land = record.get();
// make sure record is loaded
land.loadData (ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML |
ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX | ESM::Land::DATA_WNAM);
if (const ESM::Land::LandData *data = land.getLandData (ESM::Land::DATA_VTEX))
{
// list texture indices
std::pair<uint16_t, int> key;
key.second = land.mPlugin;
for (int i=0; i<ESM::Land::LAND_NUM_TEXTURES; ++i)
{
key.first = data->mTextures[i];
mState.mTextureIndices[key] = -1;
}
}
}
}
CSMTools::MergeLandTexturesStage::MergeLandTexturesStage (MergeState& state)
: mState (state), mNext (mState.mTextureIndices.end())
{}
int CSMTools::MergeLandTexturesStage::setup()
{
// Should use the size of mState.mTextureIndices instead, but that is not available at this
// point. Unless there are any errors in the land and land texture records this will not
// make a difference.
return mState.mSource.getData().getLandTextures().getSize();
}
void CSMTools::MergeLandTexturesStage::perform (int stage, CSMDoc::Messages& messages)
{
if (stage==0)
mNext = mState.mTextureIndices.begin();
bool found = false;
do
{
if (mNext==mState.mTextureIndices.end())
return;
mNext->second = stage+1;
std::ostringstream stream;
stream << mNext->first.first-1 << "_" << mNext->first.second;
int index = mState.mSource.getData().getLandTextures().searchId (stream.str());
if (index!=-1)
{
CSMWorld::LandTexture texture =
mState.mSource.getData().getLandTextures().getRecord (index).get();
std::ostringstream stream;
stream << mNext->second-1 << "_0";
texture.mIndex = mNext->second-1;
texture.mId = stream.str();
CSMWorld::Record<CSMWorld::LandTexture> newRecord (
CSMWorld::RecordBase::State_ModifiedOnly, 0, &texture);
mState.mTarget->getData().getLandTextures().appendRecord (newRecord);
found = true;
}
++mNext;
}
while (!found);
}
CSMTools::MergeLandStage::MergeLandStage (MergeState& state) : mState (state) {}
int CSMTools::MergeLandStage::setup()
{
return mState.mSource.getData().getLand().getSize();
}
void CSMTools::MergeLandStage::perform (int stage, CSMDoc::Messages& messages)
{
const CSMWorld::Record<CSMWorld::Land>& record =
mState.mSource.getData().getLand().getRecord (stage);
if (!record.isDeleted())
{
const CSMWorld::Land& land = record.get();
land.loadData (ESM::Land::DATA_VCLR | ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML |
ESM::Land::DATA_VTEX | ESM::Land::DATA_WNAM);
CSMWorld::Land newLand (land);
newLand.mEsm = 0; // avoid potential dangling pointer (ESMReader isn't needed anyway,
// because record is already fully loaded)
newLand.mPlugin = 0;
if (land.mDataTypes & ESM::Land::DATA_VTEX)
{
// adjust land texture references
if (ESM::Land::LandData *data = newLand.getLandData())
{
std::pair<uint16_t, int> key;
key.second = land.mPlugin;
for (int i=0; i<ESM::Land::LAND_NUM_TEXTURES; ++i)
{
key.first = data->mTextures[i];
std::map<std::pair<uint16_t, int>, int>::const_iterator iter =
mState.mTextureIndices.find (key);
if (iter!=mState.mTextureIndices.end())
data->mTextures[i] = iter->second;
else
data->mTextures[i] = 0;
}
}
}
CSMWorld::Record<CSMWorld::Land> newRecord (
CSMWorld::RecordBase::State_ModifiedOnly, 0, &newLand);
mState.mTarget->getData().getLand().appendRecord (newRecord);
}
}

View file

@ -0,0 +1,166 @@
#ifndef CSM_TOOLS_MERGESTAGES_H
#define CSM_TOOLS_MERGESTAGES_H
#include <algorithm>
#include <map>
#include <components/to_utf8/to_utf8.hpp>
#include "../doc/stage.hpp"
#include "../world/data.hpp"
#include "mergestate.hpp"
namespace CSMTools
{
class StartMergeStage : public CSMDoc::Stage
{
MergeState& mState;
public:
StartMergeStage (MergeState& state);
virtual int setup();
///< \return number of steps
virtual void perform (int stage, CSMDoc::Messages& messages);
///< Messages resulting from this stage will be appended to \a messages.
};
class FinishMergedDocumentStage : public CSMDoc::Stage
{
MergeState& mState;
ToUTF8::Utf8Encoder mEncoder;
public:
FinishMergedDocumentStage (MergeState& state, ToUTF8::FromType encoding);
virtual int setup();
///< \return number of steps
virtual void perform (int stage, CSMDoc::Messages& messages);
///< Messages resulting from this stage will be appended to \a messages.
};
template<typename RecordType, typename Collection = CSMWorld::IdCollection<RecordType> >
class MergeIdCollectionStage : public CSMDoc::Stage
{
MergeState& mState;
Collection& (CSMWorld::Data::*mAccessor)();
public:
MergeIdCollectionStage (MergeState& state, Collection& (CSMWorld::Data::*accessor)());
virtual int setup();
///< \return number of steps
virtual void perform (int stage, CSMDoc::Messages& messages);
///< Messages resulting from this stage will be appended to \a messages.
};
template<typename RecordType, typename Collection>
MergeIdCollectionStage<RecordType, Collection>::MergeIdCollectionStage (MergeState& state, Collection& (CSMWorld::Data::*accessor)())
: mState (state), mAccessor (accessor)
{}
template<typename RecordType, typename Collection>
int MergeIdCollectionStage<RecordType, Collection>::setup()
{
return (mState.mSource.getData().*mAccessor)().getSize();
}
template<typename RecordType, typename Collection>
void MergeIdCollectionStage<RecordType, Collection>::perform (int stage, CSMDoc::Messages& messages)
{
const Collection& source = (mState.mSource.getData().*mAccessor)();
Collection& target = (mState.mTarget->getData().*mAccessor)();
const CSMWorld::Record<RecordType>& record = source.getRecord (stage);
if (!record.isDeleted())
target.appendRecord (CSMWorld::Record<RecordType> (CSMWorld::RecordBase::State_ModifiedOnly, 0, &record.get()));
}
class MergeRefIdsStage : public CSMDoc::Stage
{
MergeState& mState;
public:
MergeRefIdsStage (MergeState& state);
virtual int setup();
///< \return number of steps
virtual void perform (int stage, CSMDoc::Messages& messages);
///< Messages resulting from this stage will be appended to \a messages.
};
class MergeReferencesStage : public CSMDoc::Stage
{
MergeState& mState;
std::map<std::string, int> mIndex;
public:
MergeReferencesStage (MergeState& state);
virtual int setup();
///< \return number of steps
virtual void perform (int stage, CSMDoc::Messages& messages);
///< Messages resulting from this stage will be appended to \a messages.
};
class ListLandTexturesMergeStage : public CSMDoc::Stage
{
MergeState& mState;
public:
ListLandTexturesMergeStage (MergeState& state);
virtual int setup();
///< \return number of steps
virtual void perform (int stage, CSMDoc::Messages& messages);
///< Messages resulting from this stage will be appended to \a messages.
};
class MergeLandTexturesStage : public CSMDoc::Stage
{
MergeState& mState;
std::map<std::pair<uint16_t, int>, int>::iterator mNext;
public:
MergeLandTexturesStage (MergeState& state);
virtual int setup();
///< \return number of steps
virtual void perform (int stage, CSMDoc::Messages& messages);
///< Messages resulting from this stage will be appended to \a messages.
};
class MergeLandStage : public CSMDoc::Stage
{
MergeState& mState;
public:
MergeLandStage (MergeState& state);
virtual int setup();
///< \return number of steps
virtual void perform (int stage, CSMDoc::Messages& messages);
///< Messages resulting from this stage will be appended to \a messages.
};
}
#endif

View file

@ -0,0 +1,24 @@
#ifndef CSM_TOOLS_MERGESTATE_H
#define CSM_TOOLS_MERGESTATE_H
#include <stdint.h>
#include <memory>
#include <map>
#include "../doc/document.hpp"
namespace CSMTools
{
struct MergeState
{
std::auto_ptr<CSMDoc::Document> mTarget;
CSMDoc::Document& mSource;
bool mCompleted;
std::map<std::pair<uint16_t, int>, int> mTextureIndices; // (texture, content file) -> new texture
MergeState (CSMDoc::Document& source) : mSource (source), mCompleted (false) {}
};
}
#endif

View file

@ -468,6 +468,9 @@ void CSMTools::ReferenceableCheckStage::creatureCheck (
if (creature.mData.mGold < 0) //It seems that this is for gold in merchant creatures
messages.push_back (std::make_pair (id, creature.mId + " has negative gold "));
if (creature.mScale == 0)
messages.push_back (std::make_pair (id, creature.mId + " has zero scale value"));
// Check that mentioned scripts exist
scriptCheck<ESM::Creature>(creature, messages, id.toString());
}

View file

@ -28,6 +28,7 @@
#include "pathgridcheck.hpp"
#include "soundgencheck.hpp"
#include "magiceffectcheck.hpp"
#include "mergeoperation.hpp"
CSMDoc::OperationHolder *CSMTools::Tools::get (int type)
{
@ -35,6 +36,7 @@ CSMDoc::OperationHolder *CSMTools::Tools::get (int type)
{
case CSMDoc::State_Verifying: return &mVerifier;
case CSMDoc::State_Searching: return &mSearch;
case CSMDoc::State_Merging: return &mMerge;
}
return 0;
@ -53,7 +55,7 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier()
std::vector<QString> settings;
settings.push_back ("script-editor/warnings");
mVerifierOperation->configureSettings (settings);
connect (&mVerifier, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int)));
@ -120,9 +122,9 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier()
return &mVerifier;
}
CSMTools::Tools::Tools (CSMDoc::Document& document)
CSMTools::Tools::Tools (CSMDoc::Document& document, ToUTF8::FromType encoding)
: mDocument (document), mData (document.getData()), mVerifierOperation (0),
mSearchOperation (0), mNextReportNumber (0)
mSearchOperation (0), mMergeOperation (0), mNextReportNumber (0), mEncoding (encoding)
{
// index 0: load error log
mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel));
@ -132,6 +134,10 @@ CSMTools::Tools::Tools (CSMDoc::Document& document)
connect (&mSearch, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool)));
connect (&mSearch, SIGNAL (reportMessage (const CSMDoc::Message&, int)),
this, SLOT (verifierMessage (const CSMDoc::Message&, int)));
connect (&mMerge, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int)));
connect (&mMerge, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool)));
// don't need to connect report message, since there are no messages for merge
}
CSMTools::Tools::~Tools()
@ -148,6 +154,12 @@ CSMTools::Tools::~Tools()
delete mSearchOperation;
}
if (mMergeOperation)
{
mMerge.abortAndWait();
delete mMergeOperation;
}
for (std::map<int, ReportModel *>::iterator iter (mReports.begin()); iter!=mReports.end(); ++iter)
delete iter->second;
}
@ -159,7 +171,7 @@ CSMWorld::UniversalId CSMTools::Tools::runVerifier (const CSMWorld::UniversalId&
if (mReports.find (reportNumber)==mReports.end())
mReports.insert (std::make_pair (reportNumber, new ReportModel));
mActiveReports[CSMDoc::State_Verifying] = reportNumber;
getVerifier()->start();
@ -189,6 +201,25 @@ void CSMTools::Tools::runSearch (const CSMWorld::UniversalId& searchId, const Se
mSearch.start();
}
void CSMTools::Tools::runMerge (std::auto_ptr<CSMDoc::Document> target)
{
// not setting an active report, because merge does not produce messages
if (!mMergeOperation)
{
mMergeOperation = new MergeOperation (mDocument, mEncoding);
mMerge.setOperation (mMergeOperation);
connect (mMergeOperation, SIGNAL (mergeDone (CSMDoc::Document*)),
this, SIGNAL (mergeDone (CSMDoc::Document*)));
}
target->flagAsDirty();
mMergeOperation->setTarget (target);
mMerge.start();
}
void CSMTools::Tools::abortOperation (int type)
{
if (CSMDoc::OperationHolder *operation = get (type))
@ -201,6 +232,7 @@ int CSMTools::Tools::getRunningOperations() const
{
CSMDoc::State_Verifying,
CSMDoc::State_Searching,
CSMDoc::State_Merging,
-1
};
@ -231,4 +263,3 @@ void CSMTools::Tools::verifierMessage (const CSMDoc::Message& message, int type)
if (iter!=mActiveReports.end())
mReports[iter->second]->add (message);
}

View file

@ -1,9 +1,14 @@
#ifndef CSM_TOOLS_TOOLS_H
#define CSM_TOOLS_TOOLS_H
#include <memory>
#include <map>
#include <components/to_utf8/to_utf8.hpp>
#include <QObject>
#include <map>
#include <boost/filesystem/path.hpp>
#include "../doc/operationholder.hpp"
@ -24,6 +29,7 @@ namespace CSMTools
class ReportModel;
class Search;
class SearchOperation;
class MergeOperation;
class Tools : public QObject
{
@ -35,9 +41,12 @@ namespace CSMTools
CSMDoc::OperationHolder mVerifier;
SearchOperation *mSearchOperation;
CSMDoc::OperationHolder mSearch;
MergeOperation *mMergeOperation;
CSMDoc::OperationHolder mMerge;
std::map<int, ReportModel *> mReports;
int mNextReportNumber;
std::map<int, int> mActiveReports; // type, report number
ToUTF8::FromType mEncoding;
// not implemented
Tools (const Tools&);
@ -53,7 +62,7 @@ namespace CSMTools
public:
Tools (CSMDoc::Document& document);
Tools (CSMDoc::Document& document, ToUTF8::FromType encoding);
virtual ~Tools();
@ -67,7 +76,9 @@ namespace CSMTools
CSMWorld::UniversalId newSearch();
void runSearch (const CSMWorld::UniversalId& searchId, const Search& search);
void runMerge (std::auto_ptr<CSMDoc::Document> target);
void abortOperation (int type);
///< \attention The operation is not aborted immediately.
@ -85,6 +96,10 @@ namespace CSMTools
void progress (int current, int max, int type);
void done (int type, bool failed);
/// \attention When this signal is emitted, *this hands over the ownership of the
/// document. This signal must be handled to avoid a leak.
void mergeDone (CSMDoc::Document *document);
};
}

View file

@ -77,7 +77,7 @@ bool CSMWorld::ColumnBase::isId (Display display)
Display_Video,
Display_Id,
Display_SkillImpact,
Display_SkillId,
Display_EffectRange,
Display_EffectId,
Display_PartRefType,
@ -85,7 +85,10 @@ bool CSMWorld::ColumnBase::isId (Display display)
Display_InfoCondFunc,
Display_InfoCondVar,
Display_InfoCondComp,
Display_RaceSkill,
Display_EffectSkill,
Display_EffectAttribute,
Display_IngredEffectId,
Display_None
};

View file

@ -14,6 +14,13 @@ namespace CSMWorld
{
struct ColumnBase
{
enum TableEditModes
{
TableEdit_None, // no editing
TableEdit_Full, // edit cells and add/remove rows
TableEdit_FixedRows // edit cells only
};
enum Roles
{
Role_Flags = Qt::UserRole,
@ -113,7 +120,7 @@ namespace CSMWorld
Display_SoundGeneratorType,
Display_School,
Display_Id,
Display_SkillImpact,
Display_SkillId,
Display_EffectRange,
Display_EffectId,
Display_PartRefType,
@ -121,10 +128,13 @@ namespace CSMWorld
Display_InfoCondFunc,
Display_InfoCondVar,
Display_InfoCondComp,
Display_RaceSkill,
Display_String32,
Display_LongString256,
Display_EffectSkill, // must display at least one, unlike Display_Skill
Display_EffectAttribute, // must display at least one, unlike Display_Attribute
Display_IngredEffectId, // display none allowed, unlike Display_EffectId
//top level columns that nest other columns
Display_NestedHeader
};
@ -187,8 +197,8 @@ namespace CSMWorld
template<typename ESXRecordT>
struct NestedParentColumn : public Column<ESXRecordT>
{
NestedParentColumn (int id, int flags = ColumnBase::Flag_Dialogue) : Column<ESXRecordT> (id,
ColumnBase::Display_NestedHeader, flags)
NestedParentColumn (int id, int flags = ColumnBase::Flag_Dialogue, bool fixedRows = false)
: Column<ESXRecordT> (id, ColumnBase::Display_NestedHeader, flags), mFixedRows(fixedRows)
{}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
@ -199,13 +209,20 @@ namespace CSMWorld
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return true; // required by IdTree::hasChildren()
// by default editable; also see IdTree::hasChildren()
if (mFixedRows)
return QVariant::fromValue(ColumnBase::TableEdit_FixedRows);
else
return QVariant::fromValue(ColumnBase::TableEdit_Full);
}
virtual bool isEditable() const
{
return true;
}
private:
bool mFixedRows;
};
struct NestedChildColumn : public NestableColumn
@ -220,4 +237,6 @@ namespace CSMWorld
};
}
Q_DECLARE_METATYPE(CSMWorld::ColumnBase::TableEditModes)
#endif

View file

@ -71,7 +71,6 @@ namespace CSMWorld
{ ColumnId_Weight, "Weight" },
{ ColumnId_EnchantmentPoints, "Enchantment Points" },
{ ColumnId_Quality, "Quality" },
{ ColumnId_Ai, "AI" },
{ ColumnId_AiHello, "AI Hello" },
{ ColumnId_AiFlee, "AI Flee" },
{ ColumnId_AiFight, "AI Fight" },
@ -199,8 +198,6 @@ namespace CSMWorld
{ ColumnId_RotY, "Rotation Y"},
{ ColumnId_RotZ, "Rotation Z"},
{ ColumnId_Skill, "Skill" },
{ ColumnId_OwnerGlobal, "Owner Global" },
{ ColumnId_DefaultProfile, "Default Profile" },
{ ColumnId_BypassNewGame, "Bypass New Game" },
@ -252,7 +249,7 @@ namespace CSMWorld
{ ColumnId_AiWanderDist, "Wander Dist" },
{ ColumnId_AiDuration, "Ai Duration" },
{ ColumnId_AiWanderToD, "Wander ToD" },
{ ColumnId_AiWanderIdle, "Wander Idle" },
//{ ColumnId_AiWanderIdle, "Wander Idle" },
{ ColumnId_AiWanderRepeat, "Wander Repeat" },
{ ColumnId_AiActivateName, "Activate" },
{ ColumnId_AiTargetId, "Target ID" },
@ -265,13 +262,13 @@ namespace CSMWorld
{ ColumnId_LevelledList,"Levelled List" },
{ ColumnId_LevelledItemId,"Levelled Item" },
{ ColumnId_LevelledItemLevel,"Level" },
{ ColumnId_LevelledItemLevel,"Item Level" },
{ ColumnId_LevelledItemType, "Calculate all levels <= player" },
{ ColumnId_LevelledItemTypeEach, "Select a new item each instance" },
{ ColumnId_LevelledItemChanceNone, "Chance None" },
{ ColumnId_PowerList, "Powers" },
{ ColumnId_SkillImpact, "Skills" },
{ ColumnId_Skill, "Skill" },
{ ColumnId_InfoList, "Info List" },
{ ColumnId_InfoCondition, "Info Conditions" },
@ -281,26 +278,24 @@ namespace CSMWorld
{ ColumnId_InfoCondValue, "Values" },
{ ColumnId_OriginalCell, "Original Cell" },
{ ColumnId_NpcAttributes, "Attributes" },
{ ColumnId_NpcSkills, "Skills" },
{ ColumnId_NpcAttributes, "NPC Attributes" },
{ ColumnId_NpcSkills, "NPC Skill" },
{ ColumnId_UChar, "Value [0..255]" },
{ ColumnId_NpcMisc, "Misc" },
{ ColumnId_NpcLevel, "Level" },
{ ColumnId_NpcMisc, "NPC Misc" },
{ ColumnId_Level, "Level" },
{ ColumnId_NpcFactionID, "Faction ID" },
{ ColumnId_NpcHealth, "Health" },
{ ColumnId_NpcMana, "Mana" },
{ ColumnId_NpcFatigue, "Fatigue" },
{ ColumnId_NpcDisposition, "Disposition" },
{ ColumnId_Mana, "Mana" },
{ ColumnId_Fatigue, "Fatigue" },
{ ColumnId_NpcDisposition, "NPC Disposition" },
{ ColumnId_NpcReputation, "Reputation" },
{ ColumnId_NpcRank, "Rank" },
{ ColumnId_NpcGold, "Gold" },
{ ColumnId_NpcRank, "NPC Rank" },
{ ColumnId_Gold, "Gold" },
{ ColumnId_NpcPersistence, "Persistent" },
{ ColumnId_RaceAttributes, "Attributes" },
{ ColumnId_RaceMaleValue, "Male" },
{ ColumnId_RaceFemaleValue, "Female" },
{ ColumnId_RaceAttributes, "Race Attributes" },
{ ColumnId_Male, "Male" },
{ ColumnId_RaceSkillBonus, "Skill Bonus" },
{ ColumnId_RaceSkill, "Skills" },
{ ColumnId_RaceBonus, "Bonus" },
{ ColumnId_Interior, "Interior" },
@ -315,6 +310,22 @@ namespace CSMWorld
{ ColumnId_FileDescription, "File Description" },
{ ColumnId_Author, "Author" },
{ ColumnId_CreatureAttributes, "Creature Attributes" },
{ ColumnId_AttributeValue, "Attrib Value" },
{ ColumnId_CreatureAttack, "Creature Attack" },
{ ColumnId_MinAttack, "Min Attack" },
{ ColumnId_MaxAttack, "Max Attack" },
{ ColumnId_CreatureMisc, "Creature Misc" },
{ ColumnId_Idle1, "Idle 1" },
{ ColumnId_Idle2, "Idle 2" },
{ ColumnId_Idle3, "Idle 3" },
{ ColumnId_Idle4, "Idle 4" },
{ ColumnId_Idle5, "Idle 5" },
{ ColumnId_Idle6, "Idle 6" },
{ ColumnId_Idle7, "Idle 7" },
{ ColumnId_Idle8, "Idle 8" },
{ ColumnId_SpellSrc, "From Race" },
{ ColumnId_SpellCost, "Cast Cost" },
{ ColumnId_SpellChance, "Cast Chance" },
@ -574,7 +585,7 @@ namespace
case CSMWorld::Columns::ColumnId_MeshType: return sMeshTypes;
case CSMWorld::Columns::ColumnId_SoundGeneratorType: return sSoundGeneratorType;
case CSMWorld::Columns::ColumnId_School: return sSchools;
case CSMWorld::Columns::ColumnId_SkillImpact: return sSkills;
case CSMWorld::Columns::ColumnId_Skill: return sSkills;
case CSMWorld::Columns::ColumnId_EffectRange: return sEffectRange;
case CSMWorld::Columns::ColumnId_EffectId: return sEffectId;
case CSMWorld::Columns::ColumnId_PartRefType: return sPartRefType;
@ -583,7 +594,6 @@ namespace
// FIXME: don't have dynamic value enum delegate, use Display_String for now
//case CSMWorld::Columns::ColumnId_InfoCond: return sInfoCond;
case CSMWorld::Columns::ColumnId_InfoCondComp: return sInfoCondComp;
case CSMWorld::Columns::ColumnId_RaceSkill: return sSkills;
default: return 0;
}

View file

@ -65,7 +65,7 @@ namespace CSMWorld
ColumnId_Weight = 50,
ColumnId_EnchantmentPoints = 51,
ColumnId_Quality = 52,
ColumnId_Ai = 53,
// unused
ColumnId_AiHello = 54,
ColumnId_AiFlee = 55,
ColumnId_AiFight = 56,
@ -102,7 +102,7 @@ namespace CSMWorld
ColumnId_OriginalCreature = 87,
ColumnId_Biped = 88,
ColumnId_HasWeapon = 89,
// unused
// used for SpellSrc
ColumnId_Swims = 91,
ColumnId_Flies = 92,
ColumnId_Walks = 93,
@ -189,7 +189,7 @@ namespace CSMWorld
ColumnId_RotX = 174,
ColumnId_RotY = 175,
ColumnId_RotZ = 176,
ColumnId_Skill = 177,
// used for SpellCost
ColumnId_OwnerGlobal = 178,
ColumnId_DefaultProfile = 179,
ColumnId_BypassNewGame = 180,
@ -241,7 +241,7 @@ namespace CSMWorld
ColumnId_AiWanderDist = 221,
ColumnId_AiDuration = 222,
ColumnId_AiWanderToD = 223,
ColumnId_AiWanderIdle = 224,
// unused
ColumnId_AiWanderRepeat = 225,
ColumnId_AiActivateName = 226,
// use ColumnId_PosX, etc for AI destinations
@ -261,7 +261,7 @@ namespace CSMWorld
ColumnId_LevelledItemChanceNone = 238,
ColumnId_PowerList = 239,
ColumnId_SkillImpact = 240, // impact from magic effects
ColumnId_Skill = 240,
ColumnId_InfoList = 241,
ColumnId_InfoCondition = 242,
@ -276,22 +276,22 @@ namespace CSMWorld
ColumnId_NpcSkills = 249,
ColumnId_UChar = 250,
ColumnId_NpcMisc = 251,
ColumnId_NpcLevel = 252,
ColumnId_Level = 252,
ColumnId_NpcFactionID = 253,
ColumnId_NpcHealth = 254,
ColumnId_NpcMana = 255,
ColumnId_NpcFatigue = 256,
// used for SpellChance
ColumnId_Mana = 255,
ColumnId_Fatigue = 256,
ColumnId_NpcDisposition = 257,
ColumnId_NpcReputation = 258,
ColumnId_NpcRank = 259,
ColumnId_NpcGold = 260,
ColumnId_Gold = 260,
ColumnId_NpcPersistence = 261,
ColumnId_RaceAttributes = 262,
ColumnId_RaceMaleValue = 263,
ColumnId_RaceFemaleValue = 264,
ColumnId_Male = 263,
// unused
ColumnId_RaceSkillBonus = 265,
ColumnId_RaceSkill = 266,
// unused
ColumnId_RaceBonus = 267,
ColumnId_Interior = 268,
@ -309,9 +309,25 @@ namespace CSMWorld
ColumnId_MinMagnitude = 278,
ColumnId_MaxMagnitude = 279,
ColumnId_SpellSrc = 280,
ColumnId_SpellCost = 281,
ColumnId_SpellChance = 282,
ColumnId_CreatureAttributes = 280,
ColumnId_AttributeValue = 281,
ColumnId_CreatureAttack = 282,
ColumnId_MinAttack = 283,
ColumnId_MaxAttack = 284,
ColumnId_CreatureMisc = 285,
ColumnId_Idle1 = 286,
ColumnId_Idle2 = 287,
ColumnId_Idle3 = 288,
ColumnId_Idle4 = 289,
ColumnId_Idle5 = 290,
ColumnId_Idle6 = 291,
ColumnId_Idle7 = 292,
ColumnId_Idle8 = 293,
ColumnId_SpellSrc = 90,
ColumnId_SpellCost = 177,
ColumnId_SpellChance = 254,
// Allocated to a separate value range, so we don't get a collision should we ever need
// to extend the number of use values.

View file

@ -205,22 +205,24 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
mRaces.getNestableColumn(index)->addColumn(
new NestedChildColumn (Columns::ColumnId_SpellId, ColumnBase::Display_Spell));
// Race attributes
mRaces.addColumn (new NestedParentColumn<ESM::Race> (Columns::ColumnId_RaceAttributes));
mRaces.addColumn (new NestedParentColumn<ESM::Race> (Columns::ColumnId_RaceAttributes,
ColumnBase::Flag_Dialogue, true)); // fixed rows table
index = mRaces.getColumns()-1;
mRaces.addAdapter (std::make_pair(&mRaces.getColumn(index), new RaceAttributeAdapter()));
mRaces.getNestableColumn(index)->addColumn(
new NestedChildColumn (Columns::ColumnId_RaceAttributes, ColumnBase::Display_String,
new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute,
ColumnBase::Flag_Dialogue, false));
mRaces.getNestableColumn(index)->addColumn(
new NestedChildColumn (Columns::ColumnId_RaceMaleValue, ColumnBase::Display_Integer));
new NestedChildColumn (Columns::ColumnId_Male, ColumnBase::Display_Integer));
mRaces.getNestableColumn(index)->addColumn(
new NestedChildColumn (Columns::ColumnId_RaceFemaleValue, ColumnBase::Display_Integer));
new NestedChildColumn (Columns::ColumnId_Female, ColumnBase::Display_Integer));
// Race skill bonus
mRaces.addColumn (new NestedParentColumn<ESM::Race> (Columns::ColumnId_RaceSkillBonus));
mRaces.addColumn (new NestedParentColumn<ESM::Race> (Columns::ColumnId_RaceSkillBonus,
ColumnBase::Flag_Dialogue, true)); // fixed rows table
index = mRaces.getColumns()-1;
mRaces.addAdapter (std::make_pair(&mRaces.getColumn(index), new RaceSkillsBonusAdapter()));
mRaces.getNestableColumn(index)->addColumn(
new NestedChildColumn (Columns::ColumnId_RaceSkill, ColumnBase::Display_RaceSkill));
new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_SkillId));
mRaces.getNestableColumn(index)->addColumn(
new NestedChildColumn (Columns::ColumnId_RaceBonus, ColumnBase::Display_Integer));
@ -282,9 +284,9 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
mSpells.getNestableColumn(index)->addColumn(
new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_EffectId));
mSpells.getNestableColumn(index)->addColumn(
new NestedChildColumn (Columns::ColumnId_SkillImpact, ColumnBase::Display_SkillImpact));
new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_EffectSkill));
mSpells.getNestableColumn(index)->addColumn(
new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute));
new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_EffectAttribute));
mSpells.getNestableColumn(index)->addColumn(
new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_EffectRange));
mSpells.getNestableColumn(index)->addColumn(
@ -398,9 +400,9 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
mEnchantments.getNestableColumn(index)->addColumn(
new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_EffectId));
mEnchantments.getNestableColumn(index)->addColumn(
new NestedChildColumn (Columns::ColumnId_SkillImpact, ColumnBase::Display_SkillImpact));
new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_EffectSkill));
mEnchantments.getNestableColumn(index)->addColumn(
new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute));
new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_EffectAttribute));
mEnchantments.getNestableColumn(index)->addColumn(
new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_EffectRange));
mEnchantments.getNestableColumn(index)->addColumn(
@ -873,11 +875,21 @@ const CSMWorld::IdCollection<CSMWorld::Land>& CSMWorld::Data::getLand() const
return mLand;
}
CSMWorld::IdCollection<CSMWorld::Land>& CSMWorld::Data::getLand()
{
return mLand;
}
const CSMWorld::IdCollection<CSMWorld::LandTexture>& CSMWorld::Data::getLandTextures() const
{
return mLandTextures;
}
CSMWorld::IdCollection<CSMWorld::LandTexture>& CSMWorld::Data::getLandTextures()
{
return mLandTextures;
}
const CSMWorld::IdCollection<ESM::SoundGenerator>& CSMWorld::Data::getSoundGens() const
{
return mSoundGens;
@ -928,6 +940,12 @@ const CSMWorld::MetaData& CSMWorld::Data::getMetaData() const
return mMetaData.getRecord (0).get();
}
void CSMWorld::Data::setMetaData (const MetaData& metaData)
{
Record<MetaData> record (RecordBase::State_ModifiedOnly, 0, &metaData);
mMetaData.setRecord (0, record);
}
QAbstractItemModel *CSMWorld::Data::getTableModel (const CSMWorld::UniversalId& id)
{
std::map<UniversalId::Type, QAbstractItemModel *>::iterator iter = mModelIndex.find (id.getType());
@ -1039,8 +1057,10 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages)
{
int index = mLand.load(*mReader, mBase);
if (index!=-1 && !mBase)
mLand.getRecord (index).mModified.mLand->loadData (
// Load all land data for now. A future optimisation may only load non-base data
// if a suitable mechanism for avoiding race conditions can be established.
if (index!=-1/* && !mBase*/)
mLand.getRecord (index).get().loadData (
ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | ESM::Land::DATA_VCLR |
ESM::Land::DATA_VTEX | ESM::Land::DATA_WNAM);

View file

@ -224,8 +224,12 @@ namespace CSMWorld
const IdCollection<CSMWorld::Land>& getLand() const;
IdCollection<CSMWorld::Land>& getLand();
const IdCollection<CSMWorld::LandTexture>& getLandTextures() const;
IdCollection<CSMWorld::LandTexture>& getLandTextures();
const IdCollection<ESM::SoundGenerator>& getSoundGens() const;
IdCollection<ESM::SoundGenerator>& getSoundGens();
@ -247,6 +251,8 @@ namespace CSMWorld
const MetaData& getMetaData() const;
void setMetaData (const MetaData& metaData);
QAbstractItemModel *getTableModel (const UniversalId& id);
///< If no table model is available for \a id, an exception is thrown.
///

View file

@ -16,7 +16,7 @@ namespace
CSMWorld::InfoTableProxyModel::InfoTableProxyModel(CSMWorld::UniversalId::Type type, QObject *parent)
: IdTableProxyModel(parent),
mType(type),
mInfoColumnId(type == UniversalId::Type_TopicInfos ? Columns::ColumnId_Topic :
mInfoColumnId(type == UniversalId::Type_TopicInfos ? Columns::ColumnId_Topic :
Columns::ColumnId_Journal),
mInfoColumnIndex(-1),
mLastAddedSourceRow(-1)

View file

@ -4,25 +4,13 @@
namespace CSMWorld
{
Land::Land()
{
mLand.reset(new ESM::Land());
}
void Land::load(ESM::ESMReader &esm)
{
mLand->load(esm);
ESM::Land::load(esm);
std::ostringstream stream;
stream << "#" << mLand->mX << " " << mLand->mY;
stream << "#" << mX << " " << mY;
mId = stream.str();
}
void Land::blank()
{
/// \todo
}
}

View file

@ -2,7 +2,7 @@
#define CSM_WORLD_LAND_H
#include <string>
#include <boost/shared_ptr.hpp>
#include <components/esm/loadland.hpp>
namespace CSMWorld
@ -11,18 +11,12 @@ namespace CSMWorld
///
/// \todo Add worldspace support to the Land record.
/// \todo Add a proper copy constructor (currently worked around using shared_ptr)
struct Land
struct Land : public ESM::Land
{
Land();
boost::shared_ptr<ESM::Land> mLand;
std::string mId;
/// Loads the metadata and ID
void load (ESM::ESMReader &esm);
void blank();
};
}

View file

@ -923,7 +923,7 @@ namespace CSMWorld
switch (subColIndex)
{
case 0: return QString(ESM::Attribute::sAttributeNames[subRowIndex].c_str());
case 0: return subRowIndex;
case 1: return race.mData.mAttributeValues[subRowIndex].mMale;
case 2: return race.mData.mAttributeValues[subRowIndex].mFemale;
default: throw std::runtime_error("Race Attribute subcolumn index out of range");

View file

@ -317,8 +317,34 @@ namespace CSMWorld
else
throw std::runtime_error("Magic effects ID unexpected value");
}
case 1: return effect.mSkill;
case 2: return effect.mAttribute;
case 1:
{
switch (effect.mEffectID)
{
case ESM::MagicEffect::DrainSkill:
case ESM::MagicEffect::DamageSkill:
case ESM::MagicEffect::RestoreSkill:
case ESM::MagicEffect::FortifySkill:
case ESM::MagicEffect::AbsorbSkill:
return effect.mSkill;
default:
return QVariant();
}
}
case 2:
{
switch (effect.mEffectID)
{
case ESM::MagicEffect::DrainAttribute:
case ESM::MagicEffect::DamageAttribute:
case ESM::MagicEffect::RestoreAttribute:
case ESM::MagicEffect::FortifyAttribute:
case ESM::MagicEffect::AbsorbAttribute:
return effect.mAttribute;
default:
return QVariant();
}
}
case 3:
{
if (effect.mRange >=0 && effect.mRange <=2)

View file

@ -6,6 +6,7 @@
#include <components/esm/loadcont.hpp>
#include <components/esm/attr.hpp>
#include <components/esm/loadmgef.hpp>
#include "nestedtablewrapper.hpp"
#include "usertype.hpp"
@ -30,8 +31,9 @@ QVariant CSMWorld::PotionRefIdAdapter::getData (const RefIdColumn *column, const
if (column==mAutoCalc)
return record.get().mData.mAutoCalc!=0;
// to show nested tables in dialogue subview, see IdTree::hasChildren()
if (column==mColumns.mEffects)
return true; // to show nested tables in dialogue subview, see IdTree::hasChildren()
return QVariant::fromValue(ColumnBase::TableEdit_Full);
return InventoryRefIdAdapter<ESM::Potion>::getData (column, data, index);
}
@ -57,6 +59,156 @@ void CSMWorld::PotionRefIdAdapter::setData (const RefIdColumn *column, RefIdData
}
CSMWorld::IngredientColumns::IngredientColumns (const InventoryColumns& columns)
: InventoryColumns (columns) {}
CSMWorld::IngredientRefIdAdapter::IngredientRefIdAdapter (const IngredientColumns& columns)
: InventoryRefIdAdapter<ESM::Ingredient> (UniversalId::Type_Ingredient, columns),
mColumns(columns)
{}
QVariant CSMWorld::IngredientRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data,
int index) const
{
if (column==mColumns.mEffects)
return QVariant::fromValue(ColumnBase::TableEdit_FixedRows);
return InventoryRefIdAdapter<ESM::Ingredient>::getData (column, data, index);
}
void CSMWorld::IngredientRefIdAdapter::setData (const RefIdColumn *column, RefIdData& data, int index,
const QVariant& value) const
{
InventoryRefIdAdapter<ESM::Ingredient>::setData (column, data, index, value);
return;
}
CSMWorld::IngredEffectRefIdAdapter::IngredEffectRefIdAdapter()
: mType(UniversalId::Type_Ingredient)
{}
CSMWorld::IngredEffectRefIdAdapter::~IngredEffectRefIdAdapter()
{}
void CSMWorld::IngredEffectRefIdAdapter::addNestedRow (const RefIdColumn *column,
RefIdData& data, int index, int position) const
{
// Do nothing, this table cannot be changed by the user
}
void CSMWorld::IngredEffectRefIdAdapter::removeNestedRow (const RefIdColumn *column,
RefIdData& data, int index, int rowToRemove) const
{
// Do nothing, this table cannot be changed by the user
}
void CSMWorld::IngredEffectRefIdAdapter::setNestedTable (const RefIdColumn* column,
RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const
{
Record<ESM::Ingredient>& record =
static_cast<Record<ESM::Ingredient>&> (data.getRecord (RefIdData::LocalIndex (index, mType)));
ESM::Ingredient ingredient = record.get();
ingredient.mData =
static_cast<const NestedTableWrapper<std::vector<typename ESM::Ingredient::IRDTstruct> >&>(nestedTable).mNestedTable.at(0);
record.setModified (ingredient);
}
CSMWorld::NestedTableWrapperBase* CSMWorld::IngredEffectRefIdAdapter::nestedTable (const RefIdColumn* column,
const RefIdData& data, int index) const
{
const Record<ESM::Ingredient>& record =
static_cast<const Record<ESM::Ingredient>&> (data.getRecord (RefIdData::LocalIndex (index, mType)));
// return the whole struct
std::vector<typename ESM::Ingredient::IRDTstruct> wrap;
wrap.push_back(record.get().mData);
// deleted by dtor of NestedTableStoring
return new NestedTableWrapper<std::vector<typename ESM::Ingredient::IRDTstruct> >(wrap);
}
QVariant CSMWorld::IngredEffectRefIdAdapter::getNestedData (const RefIdColumn *column,
const RefIdData& data, int index, int subRowIndex, int subColIndex) const
{
const Record<ESM::Ingredient>& record =
static_cast<const Record<ESM::Ingredient>&> (data.getRecord (RefIdData::LocalIndex (index, mType)));
if (subRowIndex < 0 || subRowIndex >= 4)
throw std::runtime_error ("index out of range");
switch (subColIndex)
{
case 0: return record.get().mData.mEffectID[subRowIndex];
case 1:
{
switch (record.get().mData.mEffectID[subRowIndex])
{
case ESM::MagicEffect::DrainSkill:
case ESM::MagicEffect::DamageSkill:
case ESM::MagicEffect::RestoreSkill:
case ESM::MagicEffect::FortifySkill:
case ESM::MagicEffect::AbsorbSkill:
return record.get().mData.mSkills[subRowIndex];
default:
return QVariant();
}
}
case 2:
{
switch (record.get().mData.mEffectID[subRowIndex])
{
case ESM::MagicEffect::DrainAttribute:
case ESM::MagicEffect::DamageAttribute:
case ESM::MagicEffect::RestoreAttribute:
case ESM::MagicEffect::FortifyAttribute:
case ESM::MagicEffect::AbsorbAttribute:
return record.get().mData.mAttributes[subRowIndex];
default:
return QVariant();
}
}
default:
throw std::runtime_error("Trying to access non-existing column in the nested table!");
}
}
void CSMWorld::IngredEffectRefIdAdapter::setNestedData (const RefIdColumn *column,
RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const
{
Record<ESM::Ingredient>& record =
static_cast<Record<ESM::Ingredient>&> (data.getRecord (RefIdData::LocalIndex (row, mType)));
ESM::Ingredient ingredient = record.get();
if (subRowIndex < 0 || subRowIndex >= 4)
throw std::runtime_error ("index out of range");
switch(subColIndex)
{
case 0: ingredient.mData.mEffectID[subRowIndex] = value.toInt(); break;
case 1: ingredient.mData.mSkills[subRowIndex] = value.toInt(); break;
case 2: ingredient.mData.mAttributes[subRowIndex] = value.toInt(); break;
default:
throw std::runtime_error("Trying to access non-existing column in the nested table!");
}
record.setModified (ingredient);
}
int CSMWorld::IngredEffectRefIdAdapter::getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const
{
return 3; // effect, skill, attribute
}
int CSMWorld::IngredEffectRefIdAdapter::getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const
{
return 4; // up to 4 effects
}
CSMWorld::ApparatusRefIdAdapter::ApparatusRefIdAdapter (const InventoryColumns& columns,
const RefIdColumn *type, const RefIdColumn *quality)
: InventoryRefIdAdapter<ESM::Apparatus> (UniversalId::Type_Apparatus, columns),
@ -123,7 +275,7 @@ QVariant CSMWorld::ArmorRefIdAdapter::getData (const RefIdColumn *column,
return record.get().mData.mArmor;
if (column==mPartRef)
return true; // to show nested tables in dialogue subview, see IdTree::hasChildren()
return QVariant::fromValue(ColumnBase::TableEdit_Full);
return EnchantableRefIdAdapter<ESM::Armor>::getData (column, data, index);
}
@ -211,7 +363,7 @@ QVariant CSMWorld::ClothingRefIdAdapter::getData (const RefIdColumn *column,
return record.get().mData.mType;
if (column==mPartRef)
return true; // to show nested tables in dialogue subview, see IdTree::hasChildren()
return QVariant::fromValue(ColumnBase::TableEdit_Full);
return EnchantableRefIdAdapter<ESM::Clothing>::getData (column, data, index);
}
@ -259,7 +411,7 @@ QVariant CSMWorld::ContainerRefIdAdapter::getData (const RefIdColumn *column,
return (record.get().mFlags & ESM::Container::Respawn)!=0;
if (column==mContent)
return true; // Required to show nested tables in dialogue subview
return QVariant::fromValue(ColumnBase::TableEdit_Full);
return NameRefIdAdapter<ESM::Container>::getData (column, data, index);
}
@ -301,12 +453,11 @@ void CSMWorld::ContainerRefIdAdapter::setData (const RefIdColumn *column, RefIdD
CSMWorld::CreatureColumns::CreatureColumns (const ActorColumns& actorColumns)
: ActorColumns (actorColumns),
mType(NULL),
mSoul(NULL),
mScale(NULL),
mOriginal(NULL),
mCombat(NULL),
mMagic(NULL),
mStealth(NULL)
mAttributes(NULL),
mAttacks(NULL),
mMisc(NULL)
{}
CSMWorld::CreatureRefIdAdapter::CreatureRefIdAdapter (const CreatureColumns& columns)
@ -322,23 +473,20 @@ QVariant CSMWorld::CreatureRefIdAdapter::getData (const RefIdColumn *column, con
if (column==mColumns.mType)
return record.get().mData.mType;
if (column==mColumns.mSoul)
return record.get().mData.mSoul;
if (column==mColumns.mScale)
return record.get().mScale;
if (column==mColumns.mOriginal)
return QString::fromUtf8 (record.get().mOriginal.c_str());
if (column==mColumns.mCombat)
return static_cast<int> (record.get().mData.mCombat);
if (column==mColumns.mAttributes)
return QVariant::fromValue(ColumnBase::TableEdit_FixedRows);
if (column==mColumns.mMagic)
return static_cast<int> (record.get().mData.mMagic);
if (column==mColumns.mAttacks)
return QVariant::fromValue(ColumnBase::TableEdit_FixedRows);
if (column==mColumns.mStealth)
return static_cast<int> (record.get().mData.mStealth);
if (column==mColumns.mMisc)
return QVariant::fromValue(ColumnBase::TableEdit_Full);
std::map<const RefIdColumn *, unsigned int>::const_iterator iter =
mColumns.mFlags.find (column);
@ -359,18 +507,10 @@ void CSMWorld::CreatureRefIdAdapter::setData (const RefIdColumn *column, RefIdDa
if (column==mColumns.mType)
creature.mData.mType = value.toInt();
else if (column==mColumns.mSoul)
creature.mData.mSoul = value.toInt();
else if (column==mColumns.mScale)
creature.mScale = value.toFloat();
else if (column==mColumns.mOriginal)
creature.mOriginal = value.toString().toUtf8().constData();
else if (column==mColumns.mCombat)
creature.mData.mCombat = value.toInt();
else if (column==mColumns.mMagic)
creature.mData.mMagic = value.toInt();
else if (column==mColumns.mStealth)
creature.mData.mStealth = value.toInt();
else
{
std::map<const RefIdColumn *, unsigned int>::const_iterator iter =
@ -586,13 +726,13 @@ QVariant CSMWorld::NpcRefIdAdapter::getData (const RefIdColumn *column, const Re
if (column==mColumns.mAttributes || column==mColumns.mSkills)
{
if ((record.get().mFlags & ESM::NPC::Autocalc) != 0)
return QVariant(QVariant::UserType);
return QVariant::fromValue(ColumnBase::TableEdit_None);
else
return true;
return QVariant::fromValue(ColumnBase::TableEdit_FixedRows);
}
if (column==mColumns.mMisc)
return true;
return QVariant::fromValue(ColumnBase::TableEdit_Full);
std::map<const RefIdColumn *, unsigned int>::const_iterator iter =
mColumns.mFlags.find (column);
@ -744,18 +884,7 @@ QVariant CSMWorld::NpcAttributesRefIdAdapter::getNestedData (const RefIdColumn *
const ESM::NPC::NPDTstruct52& npcStruct = npc.mNpdt52;
if (subColIndex == 0)
switch (subRowIndex)
{
case 0: return QString("Strength");
case 1: return QString("Intelligence");
case 2: return QString("Willpower");
case 3: return QString("Agility");
case 4: return QString("Speed");
case 5: return QString("Endurance");
case 6: return QString("Personality");
case 7: return QString("Luck");
default: return QVariant(); // throw an exception here?
}
return subRowIndex;
else if (subColIndex == 1)
if (npc.mNpdtType == ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS)
{
@ -886,7 +1015,7 @@ QVariant CSMWorld::NpcSkillsRefIdAdapter::getNestedData (const RefIdColumn *colu
throw std::runtime_error ("index out of range");
if (subColIndex == 0)
return QString(ESM::Skill::sSkillNames[subRowIndex].c_str());
return subRowIndex;
else if (subColIndex == 1)
{
if (npc.mNpdtType == ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS)
@ -1088,6 +1217,289 @@ int CSMWorld::NpcMiscRefIdAdapter::getNestedRowsCount(const RefIdColumn *column,
return 1; // fixed at size 1
}
CSMWorld::CreatureAttributesRefIdAdapter::CreatureAttributesRefIdAdapter()
{}
void CSMWorld::CreatureAttributesRefIdAdapter::addNestedRow (const RefIdColumn *column,
RefIdData& data, int index, int position) const
{
// Do nothing, this table cannot be changed by the user
}
void CSMWorld::CreatureAttributesRefIdAdapter::removeNestedRow (const RefIdColumn *column,
RefIdData& data, int index, int rowToRemove) const
{
// Do nothing, this table cannot be changed by the user
}
void CSMWorld::CreatureAttributesRefIdAdapter::setNestedTable (const RefIdColumn* column,
RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const
{
Record<ESM::Creature>& record =
static_cast<Record<ESM::Creature>&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Creature)));
ESM::Creature creature = record.get();
// store the whole struct
creature.mData =
static_cast<const NestedTableWrapper<std::vector<typename ESM::Creature::NPDTstruct> > &>(nestedTable).mNestedTable.at(0);
record.setModified (creature);
}
CSMWorld::NestedTableWrapperBase* CSMWorld::CreatureAttributesRefIdAdapter::nestedTable (const RefIdColumn* column,
const RefIdData& data, int index) const
{
const Record<ESM::Creature>& record =
static_cast<const Record<ESM::Creature>&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Creature)));
// return the whole struct
std::vector<typename ESM::Creature::NPDTstruct> wrap;
wrap.push_back(record.get().mData);
// deleted by dtor of NestedTableStoring
return new NestedTableWrapper<std::vector<typename ESM::Creature::NPDTstruct> >(wrap);
}
QVariant CSMWorld::CreatureAttributesRefIdAdapter::getNestedData (const RefIdColumn *column,
const RefIdData& data, int index, int subRowIndex, int subColIndex) const
{
const Record<ESM::Creature>& record =
static_cast<const Record<ESM::Creature>&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Creature)));
const ESM::Creature creature = record.get();
if (subColIndex == 0)
return subRowIndex;
else if (subColIndex == 1)
switch (subRowIndex)
{
case 0: return creature.mData.mStrength;
case 1: return creature.mData.mIntelligence;
case 2: return creature.mData.mWillpower;
case 3: return creature.mData.mAgility;
case 4: return creature.mData.mSpeed;
case 5: return creature.mData.mEndurance;
case 6: return creature.mData.mPersonality;
case 7: return creature.mData.mLuck;
default: return QVariant(); // throw an exception here?
}
else
return QVariant(); // throw an exception here?
}
void CSMWorld::CreatureAttributesRefIdAdapter::setNestedData (const RefIdColumn *column,
RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const
{
Record<ESM::Creature>& record =
static_cast<Record<ESM::Creature>&> (data.getRecord (RefIdData::LocalIndex (row, UniversalId::Type_Creature)));
ESM::Creature creature = record.get();
if (subColIndex == 1)
switch(subRowIndex)
{
case 0: creature.mData.mStrength = value.toInt(); break;
case 1: creature.mData.mIntelligence = value.toInt(); break;
case 2: creature.mData.mWillpower = value.toInt(); break;
case 3: creature.mData.mAgility = value.toInt(); break;
case 4: creature.mData.mSpeed = value.toInt(); break;
case 5: creature.mData.mEndurance = value.toInt(); break;
case 6: creature.mData.mPersonality = value.toInt(); break;
case 7: creature.mData.mLuck = value.toInt(); break;
default: return; // throw an exception here?
}
else
return; // throw an exception here?
record.setModified (creature);
}
int CSMWorld::CreatureAttributesRefIdAdapter::getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const
{
return 2;
}
int CSMWorld::CreatureAttributesRefIdAdapter::getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const
{
// There are 8 attributes
return 8;
}
CSMWorld::CreatureAttackRefIdAdapter::CreatureAttackRefIdAdapter()
{}
void CSMWorld::CreatureAttackRefIdAdapter::addNestedRow (const RefIdColumn *column,
RefIdData& data, int index, int position) const
{
// Do nothing, this table cannot be changed by the user
}
void CSMWorld::CreatureAttackRefIdAdapter::removeNestedRow (const RefIdColumn *column,
RefIdData& data, int index, int rowToRemove) const
{
// Do nothing, this table cannot be changed by the user
}
void CSMWorld::CreatureAttackRefIdAdapter::setNestedTable (const RefIdColumn* column,
RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const
{
Record<ESM::Creature>& record =
static_cast<Record<ESM::Creature>&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Creature)));
ESM::Creature creature = record.get();
// store the whole struct
creature.mData =
static_cast<const NestedTableWrapper<std::vector<typename ESM::Creature::NPDTstruct> > &>(nestedTable).mNestedTable.at(0);
record.setModified (creature);
}
CSMWorld::NestedTableWrapperBase* CSMWorld::CreatureAttackRefIdAdapter::nestedTable (const RefIdColumn* column,
const RefIdData& data, int index) const
{
const Record<ESM::Creature>& record =
static_cast<const Record<ESM::Creature>&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Creature)));
// return the whole struct
std::vector<typename ESM::Creature::NPDTstruct> wrap;
wrap.push_back(record.get().mData);
// deleted by dtor of NestedTableStoring
return new NestedTableWrapper<std::vector<typename ESM::Creature::NPDTstruct> >(wrap);
}
QVariant CSMWorld::CreatureAttackRefIdAdapter::getNestedData (const RefIdColumn *column,
const RefIdData& data, int index, int subRowIndex, int subColIndex) const
{
const Record<ESM::Creature>& record =
static_cast<const Record<ESM::Creature>&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Creature)));
const ESM::Creature creature = record.get();
if (subRowIndex < 0 || subRowIndex > 2 || subColIndex < 0 || subColIndex > 2)
throw std::runtime_error ("index out of range");
if (subColIndex == 0)
return subRowIndex + 1;
else if (subColIndex < 3) // 1 or 2
return creature.mData.mAttack[(subRowIndex * 2) + (subColIndex - 1)];
else
return QVariant(); // throw an exception here?
}
void CSMWorld::CreatureAttackRefIdAdapter::setNestedData (const RefIdColumn *column,
RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const
{
Record<ESM::Creature>& record =
static_cast<Record<ESM::Creature>&> (data.getRecord (RefIdData::LocalIndex (row, UniversalId::Type_Creature)));
ESM::Creature creature = record.get();
if (subRowIndex < 0 || subRowIndex > 2)
throw std::runtime_error ("index out of range");
if (subColIndex == 1 || subColIndex == 2)
creature.mData.mAttack[(subRowIndex * 2) + (subColIndex - 1)] = value.toInt();
else
return; // throw an exception here?
record.setModified (creature);
}
int CSMWorld::CreatureAttackRefIdAdapter::getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const
{
return 3;
}
int CSMWorld::CreatureAttackRefIdAdapter::getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const
{
// There are 3 attacks
return 3;
}
CSMWorld::CreatureMiscRefIdAdapter::CreatureMiscRefIdAdapter()
{}
CSMWorld::CreatureMiscRefIdAdapter::~CreatureMiscRefIdAdapter()
{}
void CSMWorld::CreatureMiscRefIdAdapter::addNestedRow (const RefIdColumn *column,
RefIdData& data, int index, int position) const
{
throw std::logic_error ("cannot add a row to a fixed table");
}
void CSMWorld::CreatureMiscRefIdAdapter::removeNestedRow (const RefIdColumn *column,
RefIdData& data, int index, int rowToRemove) const
{
throw std::logic_error ("cannot remove a row to a fixed table");
}
void CSMWorld::CreatureMiscRefIdAdapter::setNestedTable (const RefIdColumn* column,
RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const
{
throw std::logic_error ("table operation not supported");
}
CSMWorld::NestedTableWrapperBase* CSMWorld::CreatureMiscRefIdAdapter::nestedTable (const RefIdColumn* column,
const RefIdData& data, int index) const
{
throw std::logic_error ("table operation not supported");
}
QVariant CSMWorld::CreatureMiscRefIdAdapter::getNestedData (const RefIdColumn *column,
const RefIdData& data, int index, int subRowIndex, int subColIndex) const
{
const Record<ESM::Creature>& record =
static_cast<const Record<ESM::Creature>&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Creature)));
const ESM::Creature creature = record.get();
switch (subColIndex)
{
case 0: return creature.mData.mLevel;
case 1: return creature.mData.mHealth;
case 2: return creature.mData.mMana;
case 3: return creature.mData.mFatigue;
case 4: return creature.mData.mSoul;
case 5: return creature.mData.mCombat;
case 6: return creature.mData.mMagic;
case 7: return creature.mData.mStealth;
case 8: return creature.mData.mGold;
default: return QVariant(); // throw an exception here?
}
}
void CSMWorld::CreatureMiscRefIdAdapter::setNestedData (const RefIdColumn *column,
RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const
{
Record<ESM::Creature>& record =
static_cast<Record<ESM::Creature>&> (data.getRecord (RefIdData::LocalIndex (row, UniversalId::Type_Creature)));
ESM::Creature creature = record.get();
switch(subColIndex)
{
case 0: creature.mData.mLevel = value.toInt(); break;
case 1: creature.mData.mHealth = value.toInt(); break;
case 2: creature.mData.mMana = value.toInt(); break;
case 3: creature.mData.mFatigue = value.toInt(); break;
case 4: creature.mData.mSoul = value.toInt(); break;
case 5: creature.mData.mCombat = value.toInt(); break;
case 6: creature.mData.mMagic = value.toInt(); break;
case 7: creature.mData.mStealth = value.toInt(); break;
case 8: creature.mData.mGold = value.toInt(); break;
default: return; // throw an exception here?
}
record.setModified (creature);
}
int CSMWorld::CreatureMiscRefIdAdapter::getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const
{
return 9; // Level, Health, Mana, Fatigue, Soul, Combat, Magic, Steath, Gold
}
int CSMWorld::CreatureMiscRefIdAdapter::getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const
{
return 1; // fixed at size 1
}
CSMWorld::WeaponColumns::WeaponColumns (const EnchantableColumns& columns)
: EnchantableColumns (columns) {}
@ -1187,9 +1599,6 @@ QVariant ActorRefIdAdapter<ESM::NPC>::getData (const RefIdColumn *column, const
const Record<ESM::NPC>& record = static_cast<const Record<ESM::NPC>&> (
data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<ESM::NPC>::getType())));
if (column==mActors.mHasAi)
return record.get().mHasAI!=0;
if (column==mActors.mHello)
return record.get().mAiData.mHello;
@ -1203,21 +1612,21 @@ QVariant ActorRefIdAdapter<ESM::NPC>::getData (const RefIdColumn *column, const
return record.get().mAiData.mAlarm;
if (column==mActors.mInventory)
return true; // to show nested tables in dialogue subview, see IdTree::hasChildren()
return QVariant::fromValue(ColumnBase::TableEdit_Full);
if (column==mActors.mSpells)
{
if ((record.get().mFlags & ESM::NPC::Autocalc) != 0)
return QVariant(QVariant::UserType);
return QVariant::fromValue(ColumnBase::TableEdit_None);
else
return true;
return QVariant::fromValue(ColumnBase::TableEdit_Full);
}
if (column==mActors.mDestinations)
return true; // to show nested tables in dialogue subview, see IdTree::hasChildren()
return QVariant::fromValue(ColumnBase::TableEdit_Full);
if (column==mActors.mAiPackages)
return true; // to show nested tables in dialogue subview, see IdTree::hasChildren()
return QVariant::fromValue(ColumnBase::TableEdit_Full);
std::map<const RefIdColumn *, unsigned int>::const_iterator iter =
mActors.mServices.find (column);
@ -1371,9 +1780,6 @@ QVariant ActorRefIdAdapter<ESM::Creature>::getData (const RefIdColumn *column, c
const Record<ESM::Creature>& record = static_cast<const Record<ESM::Creature>&> (
data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<ESM::Creature>::getType())));
if (column==mActors.mHasAi)
return record.get().mHasAI!=0;
if (column==mActors.mHello)
return record.get().mAiData.mHello;
@ -1387,16 +1793,16 @@ QVariant ActorRefIdAdapter<ESM::Creature>::getData (const RefIdColumn *column, c
return record.get().mAiData.mAlarm;
if (column==mActors.mInventory)
return true; // to show nested tables in dialogue subview, see IdTree::hasChildren()
return QVariant::fromValue(ColumnBase::TableEdit_Full);
if (column==mActors.mSpells)
return true; // to show nested tables in dialogue subview, see IdTree::hasChildren()
return QVariant::fromValue(ColumnBase::TableEdit_Full);
if (column==mActors.mDestinations)
return true; // to show nested tables in dialogue subview, see IdTree::hasChildren()
return QVariant::fromValue(ColumnBase::TableEdit_Full);
if (column==mActors.mAiPackages)
return true; // to show nested tables in dialogue subview, see IdTree::hasChildren()
return QVariant::fromValue(ColumnBase::TableEdit_Full);
std::map<const RefIdColumn *, unsigned int>::const_iterator iter =
mActors.mServices.find (column);

View file

@ -15,6 +15,7 @@
#include <components/esm/loadclas.hpp>
#include <components/esm/loadrace.hpp>
#include "columnbase.hpp"
#include "record.hpp"
#include "refiddata.hpp"
#include "universalid.hpp"
@ -346,6 +347,66 @@ namespace CSMWorld
///< If the data type does not match an exception is thrown.
};
struct IngredientColumns : public InventoryColumns
{
const RefIdColumn *mEffects;
IngredientColumns (const InventoryColumns& columns);
};
class IngredientRefIdAdapter : public InventoryRefIdAdapter<ESM::Ingredient>
{
IngredientColumns mColumns;
public:
IngredientRefIdAdapter (const IngredientColumns& columns);
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
const;
virtual void setData (const RefIdColumn *column, RefIdData& data, int index,
const QVariant& value) const;
///< If the data type does not match an exception is thrown.
};
class IngredEffectRefIdAdapter : public NestedRefIdAdapterBase
{
UniversalId::Type mType;
// not implemented
IngredEffectRefIdAdapter (const IngredEffectRefIdAdapter&);
IngredEffectRefIdAdapter& operator= (const IngredEffectRefIdAdapter&);
public:
IngredEffectRefIdAdapter();
virtual ~IngredEffectRefIdAdapter();
virtual void addNestedRow (const RefIdColumn *column,
RefIdData& data, int index, int position) const;
virtual void removeNestedRow (const RefIdColumn *column,
RefIdData& data, int index, int rowToRemove) const;
virtual void setNestedTable (const RefIdColumn* column,
RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const;
virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column,
const RefIdData& data, int index) const;
virtual QVariant getNestedData (const RefIdColumn *column,
const RefIdData& data, int index, int subRowIndex, int subColIndex) const;
virtual void setNestedData (const RefIdColumn *column,
RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const;
virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const;
virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const;
};
struct EnchantableColumns : public InventoryColumns
{
const RefIdColumn *mEnchantment;
@ -485,7 +546,6 @@ namespace CSMWorld
struct ActorColumns : public NameColumns
{
const RefIdColumn *mHasAi;
const RefIdColumn *mHello;
const RefIdColumn *mFlee;
const RefIdColumn *mFight;
@ -531,9 +591,7 @@ namespace CSMWorld
data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter<RecordT>::getType())));
RecordT record2 = record.get();
if (column==mActors.mHasAi)
record2.mHasAI = value.toInt();
else if (column==mActors.mHello)
if (column==mActors.mHello)
record2.mAiData.mHello = value.toInt();
else if (column==mActors.mFlee)
record2.mAiData.mFlee = value.toInt();
@ -659,12 +717,11 @@ namespace CSMWorld
{
std::map<const RefIdColumn *, unsigned int> mFlags;
const RefIdColumn *mType;
const RefIdColumn *mSoul;
const RefIdColumn *mScale;
const RefIdColumn *mOriginal;
const RefIdColumn *mCombat;
const RefIdColumn *mMagic;
const RefIdColumn *mStealth;
const RefIdColumn *mAttributes;
const RefIdColumn *mAttacks;
const RefIdColumn *mMisc;
CreatureColumns (const ActorColumns& actorColumns);
};
@ -908,6 +965,97 @@ namespace CSMWorld
virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const;
};
class CreatureAttributesRefIdAdapter : public NestedRefIdAdapterBase
{
public:
CreatureAttributesRefIdAdapter ();
virtual void addNestedRow (const RefIdColumn *column,
RefIdData& data, int index, int position) const;
virtual void removeNestedRow (const RefIdColumn *column,
RefIdData& data, int index, int rowToRemove) const;
virtual void setNestedTable (const RefIdColumn* column,
RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const;
virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column,
const RefIdData& data, int index) const;
virtual QVariant getNestedData (const RefIdColumn *column,
const RefIdData& data, int index, int subRowIndex, int subColIndex) const;
virtual void setNestedData (const RefIdColumn *column,
RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const;
virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const;
virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const;
};
class CreatureAttackRefIdAdapter : public NestedRefIdAdapterBase
{
public:
CreatureAttackRefIdAdapter ();
virtual void addNestedRow (const RefIdColumn *column,
RefIdData& data, int index, int position) const;
virtual void removeNestedRow (const RefIdColumn *column,
RefIdData& data, int index, int rowToRemove) const;
virtual void setNestedTable (const RefIdColumn* column,
RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const;
virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column,
const RefIdData& data, int index) const;
virtual QVariant getNestedData (const RefIdColumn *column,
const RefIdData& data, int index, int subRowIndex, int subColIndex) const;
virtual void setNestedData (const RefIdColumn *column,
RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const;
virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const;
virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const;
};
class CreatureMiscRefIdAdapter : public NestedRefIdAdapterBase
{
CreatureMiscRefIdAdapter (const CreatureMiscRefIdAdapter&);
CreatureMiscRefIdAdapter& operator= (const CreatureMiscRefIdAdapter&);
public:
CreatureMiscRefIdAdapter ();
virtual ~CreatureMiscRefIdAdapter();
virtual void addNestedRow (const RefIdColumn *column,
RefIdData& data, int index, int position) const;
virtual void removeNestedRow (const RefIdColumn *column,
RefIdData& data, int index, int rowToRemove) const;
virtual void setNestedTable (const RefIdColumn* column,
RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const;
virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column,
const RefIdData& data, int index) const;
virtual QVariant getNestedData (const RefIdColumn *column,
const RefIdData& data, int index, int subRowIndex, int subColIndex) const;
virtual void setNestedData (const RefIdColumn *column,
RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const;
virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const;
virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const;
};
template<typename ESXRecordT>
class EffectsListAdapter;
@ -1348,6 +1496,8 @@ namespace CSMWorld
virtual ~ActorAiRefIdAdapter() {}
// FIXME: should check if the AI package type is already in the list and use a default
// that wasn't used already (in extreme case do not add anything at all?
virtual void addNestedRow (const RefIdColumn *column,
RefIdData& data, int index, int position) const
{
@ -1431,6 +1581,7 @@ namespace CSMWorld
switch (subColIndex)
{
case 0:
// FIXME: should more than one AI package type be allowed? Check vanilla
switch (content.mType)
{
case ESM::AI_Wander: return 0;
@ -1458,47 +1609,52 @@ namespace CSMWorld
else
return QVariant();
case 4: // wander idle
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:
case 11:
if (content.mType == ESM::AI_Wander)
{
return static_cast<int>(content.mWander.mIdle[0]); // FIXME:
}
return static_cast<int>(content.mWander.mIdle[subColIndex-4]);
else
return QVariant();
case 5: // wander repeat
case 12: // wander repeat
if (content.mType == ESM::AI_Wander)
return content.mWander.mShouldRepeat != 0;
else
return QVariant();
case 6: // activate name
case 13: // activate name
if (content.mType == ESM::AI_Activate)
return QString(content.mActivate.mName.toString().c_str());
else
return QVariant();
case 7: // target id
case 14: // target id
if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
return QString(content.mTarget.mId.toString().c_str());
else
return QVariant();
case 8: // target cell
case 15: // target cell
if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
return QString::fromUtf8(content.mCellName.c_str());
else
return QVariant();
case 9:
case 16:
if (content.mType == ESM::AI_Travel)
return content.mTravel.mX;
else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
return content.mTarget.mX;
else
return QVariant();
case 10:
case 17:
if (content.mType == ESM::AI_Travel)
return content.mTravel.mY;
else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
return content.mTarget.mY;
else
return QVariant();
case 11:
case 18:
if (content.mType == ESM::AI_Travel)
return content.mTravel.mZ;
else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
@ -1528,11 +1684,12 @@ namespace CSMWorld
case 0: // ai package type
switch (value.toInt())
{
case 0: content.mType = ESM::AI_Wander;
case 1: content.mType = ESM::AI_Travel;
case 2: content.mType = ESM::AI_Follow;
case 3: content.mType = ESM::AI_Escort;
case 4: content.mType = ESM::AI_Activate;
case 0: content.mType = ESM::AI_Wander; break;
case 1: content.mType = ESM::AI_Travel; break;
case 2: content.mType = ESM::AI_Follow; break;
case 3: content.mType = ESM::AI_Escort; break;
case 4: content.mType = ESM::AI_Activate; break;
default: return; // return without saving
}
break; // always save
@ -1541,6 +1698,8 @@ namespace CSMWorld
content.mWander.mDistance = static_cast<short>(value.toInt());
else
return; // return without saving
break; // always save
case 2:
if (content.mType == ESM::AI_Wander ||
content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
@ -1552,62 +1711,77 @@ namespace CSMWorld
content.mWander.mTimeOfDay = static_cast<unsigned char>(value.toInt());
else
return; // return without saving
break; // always save
case 4:
if (content.mType == ESM::AI_Wander)
break; // FIXME: idle
else
return; // return without saving
case 5:
if (content.mType == ESM::AI_Wander)
{
content.mWander.mShouldRepeat = static_cast<unsigned char>(value.toInt());
break;
}
case 6: // NAME32
if (content.mType == ESM::AI_Activate)
{
content.mActivate.mName.assign(value.toString().toUtf8().constData());
break;
}
else
return; // return without saving
case 7: // NAME32
if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
{
content.mTarget.mId.assign(value.toString().toUtf8().constData());
break;
}
else
return; // return without saving
case 6:
case 7:
case 8:
if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
{
content.mCellName = std::string(value.toString().toUtf8().constData());
break;
}
else
return; // return without saving
case 9:
if (content.mType == ESM::AI_Travel)
content.mTravel.mZ = value.toFloat();
else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
content.mTarget.mZ = value.toFloat();
else
return; // return without saving
case 10:
if (content.mType == ESM::AI_Travel)
content.mTravel.mZ = value.toFloat();
else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
content.mTarget.mZ = value.toFloat();
else
return; // return without saving
case 11:
if (content.mType == ESM::AI_Wander)
content.mWander.mIdle[subColIndex-4] = static_cast<unsigned char>(value.toInt());
else
return; // return without saving
break; // always save
case 12:
if (content.mType == ESM::AI_Wander)
content.mWander.mShouldRepeat = static_cast<unsigned char>(value.toInt());
else
return; // return without saving
break; // always save
case 13: // NAME32
if (content.mType == ESM::AI_Activate)
content.mActivate.mName.assign(value.toString().toUtf8().constData());
else
return; // return without saving
break; // always save
case 14: // NAME32
if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
content.mTarget.mId.assign(value.toString().toUtf8().constData());
else
return; // return without saving
break; // always save
case 15:
if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
content.mCellName = std::string(value.toString().toUtf8().constData());
else
return; // return without saving
break; // always save
case 16:
if (content.mType == ESM::AI_Travel)
content.mTravel.mZ = value.toFloat();
else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
content.mTarget.mZ = value.toFloat();
else
return; // return without saving
break; // always save
case 17:
if (content.mType == ESM::AI_Travel)
content.mTravel.mZ = value.toFloat();
else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
content.mTarget.mZ = value.toFloat();
else
return; // return without saving
break; // always save
case 18:
if (content.mType == ESM::AI_Travel)
content.mTravel.mZ = value.toFloat();
else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
content.mTarget.mZ = value.toFloat();
else
return; // return without saving
break; // always save
default:
throw std::runtime_error("Trying to access non-existing column in the nested table!");
}
@ -1617,7 +1791,7 @@ namespace CSMWorld
virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const
{
return 12;
return 19;
}
virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const
@ -1810,7 +1984,7 @@ namespace CSMWorld
int index) const
{
if (column==mLevList.mLevList || column == mLevList.mNestedListLevList)
return true; // to show nested tables in dialogue subview, see IdTree::hasChildren()
return QVariant::fromValue(ColumnBase::TableEdit_Full);
return BaseRefIdAdapter<RecordT>::getData (column, data, index);
}

View file

@ -72,6 +72,21 @@ CSMWorld::RefIdCollection::RefIdCollection(const CSMWorld::Data& data)
mColumns.push_back (RefIdColumn (Columns::ColumnId_CoinValue, ColumnBase::Display_Integer));
inventoryColumns.mValue = &mColumns.back();
IngredientColumns ingredientColumns (inventoryColumns);
mColumns.push_back (RefIdColumn (Columns::ColumnId_EffectList,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue));
ingredientColumns.mEffects = &mColumns.back();
std::map<UniversalId::Type, NestedRefIdAdapterBase*> ingredientEffectsMap;
ingredientEffectsMap.insert(std::make_pair(UniversalId::Type_Ingredient,
new IngredEffectRefIdAdapter ()));
mNestedAdapters.push_back (std::make_pair(&mColumns.back(), ingredientEffectsMap));
mColumns.back().addColumn(
new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_IngredEffectId));
mColumns.back().addColumn(
new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_EffectSkill));
mColumns.back().addColumn(
new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_EffectAttribute));
// nested table
PotionColumns potionColumns (inventoryColumns);
mColumns.push_back (RefIdColumn (Columns::ColumnId_EffectList,
@ -84,9 +99,9 @@ CSMWorld::RefIdCollection::RefIdCollection(const CSMWorld::Data& data)
mColumns.back().addColumn(
new NestedChildColumn (Columns::ColumnId_EffectId, ColumnBase::Display_EffectId));
mColumns.back().addColumn(
new NestedChildColumn (Columns::ColumnId_SkillImpact, ColumnBase::Display_SkillImpact));
new NestedChildColumn (Columns::ColumnId_Skill, ColumnBase::Display_EffectSkill));
mColumns.back().addColumn(
new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute));
new NestedChildColumn (Columns::ColumnId_Attribute, ColumnBase::Display_EffectAttribute));
mColumns.back().addColumn(
new NestedChildColumn (Columns::ColumnId_EffectRange, ColumnBase::Display_EffectRange));
mColumns.back().addColumn(
@ -114,8 +129,6 @@ CSMWorld::RefIdCollection::RefIdCollection(const CSMWorld::Data& data)
ActorColumns actorsColumns (nameColumns);
mColumns.push_back (RefIdColumn (Columns::ColumnId_Ai, ColumnBase::Display_Boolean));
actorsColumns.mHasAi = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_AiHello, ColumnBase::Display_Integer));
actorsColumns.mHello = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_AiFlee, ColumnBase::Display_Integer));
@ -205,8 +218,24 @@ CSMWorld::RefIdCollection::RefIdCollection(const CSMWorld::Data& data)
new RefIdColumn (Columns::ColumnId_AiDuration, CSMWorld::ColumnBase::Display_Integer));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_AiWanderToD, CSMWorld::ColumnBase::Display_Integer));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_AiWanderIdle, CSMWorld::ColumnBase::Display_Integer));
new RefIdColumn (Columns::ColumnId_Idle1, CSMWorld::ColumnBase::Display_Integer));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_Idle2, CSMWorld::ColumnBase::Display_Integer));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_Idle3, CSMWorld::ColumnBase::Display_Integer));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_Idle4, CSMWorld::ColumnBase::Display_Integer));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_Idle5, CSMWorld::ColumnBase::Display_Integer));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_Idle6, CSMWorld::ColumnBase::Display_Integer));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_Idle7, CSMWorld::ColumnBase::Display_Integer));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_Idle8, CSMWorld::ColumnBase::Display_Integer));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_AiWanderRepeat, CSMWorld::ColumnBase::Display_Boolean));
mColumns.back().addColumn(
@ -307,21 +336,10 @@ CSMWorld::RefIdCollection::RefIdCollection(const CSMWorld::Data& data)
mColumns.push_back (RefIdColumn (Columns::ColumnId_CreatureType, ColumnBase::Display_CreatureType));
creatureColumns.mType = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_SoulPoints, ColumnBase::Display_Integer));
creatureColumns.mSoul = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Scale, ColumnBase::Display_Float));
creatureColumns.mScale = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_OriginalCreature, ColumnBase::Display_Creature));
creatureColumns.mOriginal = &mColumns.back();
mColumns.push_back (
RefIdColumn (Columns::ColumnId_CombatState, ColumnBase::Display_Integer));
creatureColumns.mCombat = &mColumns.back();
mColumns.push_back (
RefIdColumn (Columns::ColumnId_MagicState, ColumnBase::Display_Integer));
creatureColumns.mMagic = &mColumns.back();
mColumns.push_back (
RefIdColumn (Columns::ColumnId_StealthState, ColumnBase::Display_Integer));
creatureColumns.mStealth = &mColumns.back();
static const struct
{
@ -360,6 +378,59 @@ CSMWorld::RefIdCollection::RefIdCollection(const CSMWorld::Data& data)
creatureColumns.mFlags.insert (std::make_pair (respawn, ESM::Creature::Respawn));
// Nested table
mColumns.push_back(RefIdColumn (Columns::ColumnId_CreatureAttributes,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue));
creatureColumns.mAttributes = &mColumns.back();
std::map<UniversalId::Type, NestedRefIdAdapterBase*> creaAttrMap;
creaAttrMap.insert(std::make_pair(UniversalId::Type_Creature, new CreatureAttributesRefIdAdapter()));
mNestedAdapters.push_back (std::make_pair(&mColumns.back(), creaAttrMap));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_Attribute, CSMWorld::ColumnBase::Display_Attribute, false, false));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_AttributeValue, CSMWorld::ColumnBase::Display_Integer));
// Nested table
mColumns.push_back(RefIdColumn (Columns::ColumnId_CreatureAttack,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue));
creatureColumns.mAttacks = &mColumns.back();
std::map<UniversalId::Type, NestedRefIdAdapterBase*> attackMap;
attackMap.insert(std::make_pair(UniversalId::Type_Creature, new CreatureAttackRefIdAdapter()));
mNestedAdapters.push_back (std::make_pair(&mColumns.back(), attackMap));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_CreatureAttack, CSMWorld::ColumnBase::Display_Integer, false, false));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_MinAttack, CSMWorld::ColumnBase::Display_Integer));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_MaxAttack, CSMWorld::ColumnBase::Display_Integer));
// Nested list
mColumns.push_back(RefIdColumn (Columns::ColumnId_CreatureMisc,
ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_List));
creatureColumns.mMisc = &mColumns.back();
std::map<UniversalId::Type, NestedRefIdAdapterBase*> creaMiscMap;
creaMiscMap.insert(std::make_pair(UniversalId::Type_Creature, new CreatureMiscRefIdAdapter()));
mNestedAdapters.push_back (std::make_pair(&mColumns.back(), creaMiscMap));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_Level, CSMWorld::ColumnBase::Display_Integer,
ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_Refresh));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_Health, CSMWorld::ColumnBase::Display_Integer));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_Mana, CSMWorld::ColumnBase::Display_Integer));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_Fatigue, CSMWorld::ColumnBase::Display_Integer));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_SoulPoints, CSMWorld::ColumnBase::Display_Integer));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_CombatState, CSMWorld::ColumnBase::Display_Integer));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_MagicState, CSMWorld::ColumnBase::Display_Integer));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_StealthState, CSMWorld::ColumnBase::Display_Integer));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_Gold, CSMWorld::ColumnBase::Display_Integer));
mColumns.push_back (RefIdColumn (Columns::ColumnId_OpenSound, ColumnBase::Display_Sound));
const RefIdColumn *openSound = &mColumns.back();
@ -449,7 +520,7 @@ CSMWorld::RefIdCollection::RefIdCollection(const CSMWorld::Data& data)
attrMap.insert(std::make_pair(UniversalId::Type_Npc, new NpcAttributesRefIdAdapter(data)));
mNestedAdapters.push_back (std::make_pair(&mColumns.back(), attrMap));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_NpcAttributes, CSMWorld::ColumnBase::Display_String, false, false));
new RefIdColumn (Columns::ColumnId_Attribute, CSMWorld::ColumnBase::Display_Attribute, false, false));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_UChar, CSMWorld::ColumnBase::Display_Integer));
@ -461,7 +532,7 @@ CSMWorld::RefIdCollection::RefIdCollection(const CSMWorld::Data& data)
skillsMap.insert(std::make_pair(UniversalId::Type_Npc, new NpcSkillsRefIdAdapter(data)));
mNestedAdapters.push_back (std::make_pair(&mColumns.back(), skillsMap));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_NpcSkills, CSMWorld::ColumnBase::Display_String, false, false));
new RefIdColumn (Columns::ColumnId_Skill, CSMWorld::ColumnBase::Display_SkillId, false, false));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_UChar, CSMWorld::ColumnBase::Display_Integer));
@ -473,16 +544,16 @@ CSMWorld::RefIdCollection::RefIdCollection(const CSMWorld::Data& data)
miscMap.insert(std::make_pair(UniversalId::Type_Npc, new NpcMiscRefIdAdapter(data)));
mNestedAdapters.push_back (std::make_pair(&mColumns.back(), miscMap));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_NpcLevel, CSMWorld::ColumnBase::Display_Integer,
new RefIdColumn (Columns::ColumnId_Level, CSMWorld::ColumnBase::Display_Integer,
ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_Refresh));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_NpcFactionID, CSMWorld::ColumnBase::Display_Integer));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_NpcHealth, CSMWorld::ColumnBase::Display_Integer));
new RefIdColumn (Columns::ColumnId_Health, CSMWorld::ColumnBase::Display_Integer));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_NpcMana, CSMWorld::ColumnBase::Display_Integer));
new RefIdColumn (Columns::ColumnId_Mana, CSMWorld::ColumnBase::Display_Integer));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_NpcFatigue, CSMWorld::ColumnBase::Display_Integer));
new RefIdColumn (Columns::ColumnId_Fatigue, CSMWorld::ColumnBase::Display_Integer));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_NpcDisposition, CSMWorld::ColumnBase::Display_Integer));
mColumns.back().addColumn(
@ -490,7 +561,7 @@ CSMWorld::RefIdCollection::RefIdCollection(const CSMWorld::Data& data)
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_NpcRank, CSMWorld::ColumnBase::Display_Integer));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_NpcGold, CSMWorld::ColumnBase::Display_Integer));
new RefIdColumn (Columns::ColumnId_Gold, CSMWorld::ColumnBase::Display_Integer));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_NpcPersistence, CSMWorld::ColumnBase::Display_Boolean));
@ -606,7 +677,7 @@ CSMWorld::RefIdCollection::RefIdCollection(const CSMWorld::Data& data)
mAdapters.insert (std::make_pair (UniversalId::Type_Door,
new DoorRefIdAdapter (nameColumns, openSound, closeSound)));
mAdapters.insert (std::make_pair (UniversalId::Type_Ingredient,
new InventoryRefIdAdapter<ESM::Ingredient> (UniversalId::Type_Ingredient, inventoryColumns)));
new IngredientRefIdAdapter (ingredientColumns)));
mAdapters.insert (std::make_pair (UniversalId::Type_CreatureLevelledList,
new LevelledListRefIdAdapter<ESM::CreatureLevList> (
UniversalId::Type_CreatureLevelledList, levListColumns)));
@ -924,3 +995,8 @@ const CSMWorld::NestedRefIdAdapterBase& CSMWorld::RefIdCollection::getNestedAdap
}
throw std::runtime_error("No such column in the nestedadapters");
}
void CSMWorld::RefIdCollection::copyTo (int index, RefIdCollection& target) const
{
mData.copyTo (index, target.mData);
}

View file

@ -140,6 +140,7 @@ namespace CSMWorld
void save (int index, ESM::ESMWriter& writer) const;
const RefIdData& getDataSet() const; //I can't figure out a better name for this one :(
void copyTo (int index, RefIdCollection& target) const;
};
}

View file

@ -1,6 +1,7 @@
#include "refiddata.hpp"
#include <cassert>
#include <memory>
#include <components/misc/stringops.hpp>
@ -344,7 +345,7 @@ const CSMWorld::RefIdDataContainer< ESM::Static >& CSMWorld::RefIdData::getStati
return mStatics;
}
void CSMWorld::RefIdData::insertRecord(CSMWorld::RecordBase& record, CSMWorld::UniversalId::Type type, const std::string& id)
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);
@ -357,3 +358,16 @@ void CSMWorld::RefIdData::insertRecord(CSMWorld::RecordBase& record, CSMWorld::U
mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (id),
LocalIndex (iter->second->getSize()-1, type)));
}
void CSMWorld::RefIdData::copyTo (int index, RefIdData& target) const
{
LocalIndex localIndex = globalToLocalIndex (index);
RefIdDataContainerBase *source = mRecordContainers.find (localIndex.second)->second;
std::string id = source->getId (localIndex.first);
std::auto_ptr<CSMWorld::RecordBase> newRecord (source->getRecord (localIndex.first).modifiedCopy());
target.insertRecord (*newRecord, localIndex.second, id);
}

View file

@ -210,7 +210,8 @@ namespace CSMWorld
void erase (int index, int count);
void insertRecord(CSMWorld::RecordBase& record, CSMWorld::UniversalId::Type type, const std::string& id);
void insertRecord (CSMWorld::RecordBase& record, CSMWorld::UniversalId::Type type,
const std::string& id);
const RecordBase& getRecord (const LocalIndex& index) const;
@ -252,11 +253,9 @@ namespace CSMWorld
const RefIdDataContainer<ESM::Probe >& getProbes() const;
const RefIdDataContainer<ESM::Repair>& getRepairs() const;
const RefIdDataContainer<ESM::Static>& getStatics() const;
void copyTo (int index, RefIdData& target) const;
};
}
#endif

View file

@ -39,8 +39,6 @@ char CSMWorld::ScriptContext::getGlobalType (const std::string& name) const
std::pair<char, bool> CSMWorld::ScriptContext::getMemberType (const std::string& name,
const std::string& id) const
{
/// \todo invalidate locals cache on change to scripts
std::string id2 = Misc::StringUtils::lowerCase (id);
int index = mData.getScripts().searchId (id2);
@ -120,3 +118,18 @@ void CSMWorld::ScriptContext::clear()
mIdsUpdated = false;
mLocals.clear();
}
bool CSMWorld::ScriptContext::clearLocals (const std::string& script)
{
std::map<std::string, Compiler::Locals>::iterator iter =
mLocals.find (Misc::StringUtils::lowerCase (script));
if (iter!=mLocals.end())
{
mLocals.erase (iter);
mIdsUpdated = false;
return true;
}
return false;
}

View file

@ -46,6 +46,9 @@ namespace CSMWorld
void clear();
///< Remove all cached data.
/// \return Were there any locals that needed clearing?
bool clearLocals (const std::string& script);
};
}

View file

@ -63,6 +63,7 @@ void CSVDoc::AdjusterWidget::setName (const QString& name, bool addon)
QString message;
mValid = (!name.isEmpty());
bool warning = false;
if (!mValid)
{
@ -105,13 +106,14 @@ void CSVDoc::AdjusterWidget::setName (const QString& name, bool addon)
{
/// \todo add an user setting to make this an error.
message += "<p>A file with the same name already exists. If you continue, it will be overwritten.";
warning = true;
}
}
}
mMessage->setText (message);
mIcon->setPixmap (style()->standardIcon (
mValid ? QStyle::SP_MessageBoxInformation : QStyle::SP_MessageBoxWarning).
mValid ? (warning ? QStyle::SP_MessageBoxWarning : QStyle::SP_MessageBoxInformation) : QStyle::SP_MessageBoxCritical).
pixmap (QSize (16, 16)));
emit stateChanged (mValid);

View file

@ -55,3 +55,11 @@ void CSVDoc::FileWidget::extensionLabelIsVisible(bool visible)
{
mType->setVisible(visible);
}
void CSVDoc::FileWidget::setName (const std::string& text)
{
QString text2 = QString::fromUtf8 (text.c_str());
mInput->setText (text2);
textChanged (text2);
}

View file

@ -3,6 +3,8 @@
#include <QWidget>
#include <string>
class QLabel;
class QString;
class QLineEdit;
@ -29,6 +31,8 @@ namespace CSVDoc
void extensionLabelIsVisible(bool visible);
void setName (const std::string& text);
private slots:
void textChanged (const QString& text);

View file

@ -19,6 +19,7 @@ void CSVDoc::Operation::updateLabel (int threads)
case CSMDoc::State_Saving: name = "saving"; break;
case CSMDoc::State_Verifying: name = "verifying"; break;
case CSMDoc::State_Searching: name = "searching"; break;
case CSMDoc::State_Merging: name = "merging"; break;
}
std::ostringstream stream;
@ -122,7 +123,7 @@ void CSVDoc::Operation::setBarColor (int type)
bottomColor = "#9ECB2D"; //green gloss
break;
case CSMDoc::State_Compiling:
case CSMDoc::State_Merging:
topColor = "#F3E2C7";
midTopColor = "#C19E67";

View file

@ -83,6 +83,10 @@ void CSVDoc::View::setupFileMenu()
connect (mVerify, SIGNAL (triggered()), this, SLOT (verify()));
file->addAction (mVerify);
mMerge = new QAction (tr ("Merge"), this);
connect (mMerge, SIGNAL (triggered()), this, SLOT (merge()));
file->addAction (mMerge);
QAction *loadErrors = new QAction (tr ("Load Error Log"), this);
connect (loadErrors, SIGNAL (triggered()), this, SLOT (loadErrorLog()));
file->addAction (loadErrors);
@ -418,6 +422,9 @@ void CSVDoc::View::updateActions()
mGlobalDebugProfileMenu->updateActions (running);
mStopDebug->setEnabled (running);
mMerge->setEnabled (mDocument->getContentFiles().size()>1 &&
!(mDocument->getState() & CSMDoc::State_Merging));
}
CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews)
@ -467,6 +474,8 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to
mOperations = new Operations;
addDockWidget (Qt::BottomDockWidgetArea, mOperations);
setContextMenuPolicy(Qt::NoContextMenu);
updateTitle();
setupUi();
@ -510,6 +519,7 @@ void CSVDoc::View::updateDocumentState()
static const int operations[] =
{
CSMDoc::State_Saving, CSMDoc::State_Verifying, CSMDoc::State_Searching,
CSMDoc::State_Merging,
-1 // end marker
};
@ -1053,3 +1063,8 @@ void CSVDoc::View::updateScrollbar()
else
mSubViewWindow.setMinimumWidth(0);
}
void CSVDoc::View::merge()
{
emit mergeDocument (mDocument);
}

View file

@ -43,6 +43,7 @@ namespace CSVDoc
QAction *mVerify;
QAction *mShowStatusBar;
QAction *mStopDebug;
QAction *mMerge;
std::vector<QAction *> mEditingActions;
Operations *mOperations;
SubViewFactoryManager mSubViewFactory;
@ -117,9 +118,6 @@ namespace CSVDoc
Operations *getOperations() const;
/// Function called by view manager when user preferences are updated
void updateEditorSetting (const QString &, const QString &);
protected:
virtual void moveEvent(QMoveEvent * event);
@ -137,6 +135,8 @@ namespace CSVDoc
void editSettingsRequest();
void mergeDocument (CSMDoc::Document *document);
public slots:
void addSubView (const CSMWorld::UniversalId& id, const std::string& hint = "");
@ -251,6 +251,8 @@ namespace CSVDoc
void saveWindowState();
void moveScrollBarToEnd(int min, int max);
void merge();
};
}

View file

@ -97,14 +97,16 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager)
{ CSMWorld::ColumnBase::Display_Gender, CSMWorld::Columns::ColumnId_Gender, true },
{ CSMWorld::ColumnBase::Display_SoundGeneratorType, CSMWorld::Columns::ColumnId_SoundGeneratorType, false },
{ CSMWorld::ColumnBase::Display_School, CSMWorld::Columns::ColumnId_School, false },
{ CSMWorld::ColumnBase::Display_SkillImpact, CSMWorld::Columns::ColumnId_SkillImpact, true },
{ CSMWorld::ColumnBase::Display_SkillId, CSMWorld::Columns::ColumnId_Skill, true },
{ CSMWorld::ColumnBase::Display_EffectRange, CSMWorld::Columns::ColumnId_EffectRange, false },
{ CSMWorld::ColumnBase::Display_EffectId, CSMWorld::Columns::ColumnId_EffectId, false },
{ CSMWorld::ColumnBase::Display_PartRefType, CSMWorld::Columns::ColumnId_PartRefType, false },
{ CSMWorld::ColumnBase::Display_AiPackageType, CSMWorld::Columns::ColumnId_AiPackageType, false },
{ CSMWorld::ColumnBase::Display_InfoCondFunc, CSMWorld::Columns::ColumnId_InfoCondFunc, false },
{ CSMWorld::ColumnBase::Display_InfoCondComp, CSMWorld::Columns::ColumnId_InfoCondComp, false },
{ CSMWorld::ColumnBase::Display_RaceSkill, CSMWorld::Columns::ColumnId_RaceSkill, true },
{ CSMWorld::ColumnBase::Display_IngredEffectId, CSMWorld::Columns::ColumnId_EffectId, true },
{ CSMWorld::ColumnBase::Display_EffectSkill, CSMWorld::Columns::ColumnId_Skill, false },
{ CSMWorld::ColumnBase::Display_EffectAttribute, CSMWorld::Columns::ColumnId_Attribute, false },
};
for (std::size_t i=0; i<sizeof (sMapping)/sizeof (Mapping); ++i)
@ -173,6 +175,7 @@ CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document)
connect (view, SIGNAL (newAddonRequest ()), this, SIGNAL (newAddonRequest()));
connect (view, SIGNAL (loadDocumentRequest ()), this, SIGNAL (loadDocumentRequest()));
connect (view, SIGNAL (editSettingsRequest()), this, SIGNAL (editSettingsRequest()));
connect (view, SIGNAL (mergeDocument (CSMDoc::Document *)), this, SIGNAL (mergeDocument (CSMDoc::Document *)));
connect (&CSMSettings::UserSettings::instance(),
SIGNAL (userSettingUpdated(const QString &, const QStringList &)),

View file

@ -77,6 +77,8 @@ namespace CSVDoc
void editSettingsRequest();
void mergeDocument (CSMDoc::Document *document);
public slots:
void exitApplication (CSVDoc::View *view);

View file

@ -5,14 +5,17 @@
#include <QApplication>
#include "../../model/world/data.hpp"
#include "../../model/world/idtablebase.hpp"
#include "../../model/world/columns.hpp"
CSVFilter::EditWidget::EditWidget (CSMWorld::Data& data, QWidget *parent)
: QLineEdit (parent), mParser (data)
: QLineEdit (parent), mParser (data), mIsEmpty(true)
{
mPalette = palette();
connect (this, SIGNAL (textChanged (const QString&)), this, SLOT (textChanged (const QString&)));
QAbstractItemModel *model = data.getTableModel (CSMWorld::UniversalId::Type_Filters);
const CSMWorld::IdTableBase *model =
static_cast<const CSMWorld::IdTableBase *> (data.getTableModel (CSMWorld::UniversalId::Type_Filters));
connect (model, SIGNAL (dataChanged (const QModelIndex &, const QModelIndex&)),
this, SLOT (filterDataChanged (const QModelIndex &, const QModelIndex&)),
@ -23,10 +26,23 @@ CSVFilter::EditWidget::EditWidget (CSMWorld::Data& data, QWidget *parent)
connect (model, SIGNAL (rowsInserted (const QModelIndex&, int, int)),
this, SLOT (filterRowsInserted (const QModelIndex&, int, int)),
Qt::QueuedConnection);
mStateColumnIndex = model->findColumnIndex(CSMWorld::Columns::ColumnId_Modification);
mDescColumnIndex = model->findColumnIndex(CSMWorld::Columns::ColumnId_Description);
}
void CSVFilter::EditWidget::textChanged (const QString& text)
{
//no need to parse and apply filter if it was empty and now is empty too.
//e.g. - we modifiing content of filter with already opened some other (big) tables.
if (text.length() == 0){
if (mIsEmpty)
return;
else
mIsEmpty = true;
}else
mIsEmpty = false;
if (mParser.parse (text.toUtf8().constData()))
{
setPalette (mPalette);
@ -45,7 +61,9 @@ void CSVFilter::EditWidget::textChanged (const QString& text)
void CSVFilter::EditWidget::filterDataChanged (const QModelIndex& topLeft,
const QModelIndex& bottomRight)
{
textChanged (text());
for (int i = topLeft.column(); i <= bottomRight.column(); ++i)
if (i != mStateColumnIndex && i != mDescColumnIndex)
textChanged (text());
}
void CSVFilter::EditWidget::filterRowsRemoved (const QModelIndex& parent, int start, int end)

View file

@ -25,6 +25,9 @@ namespace CSVFilter
CSMFilter::Parser mParser;
QPalette mPalette;
bool mIsEmpty;
int mStateColumnIndex;
int mDescColumnIndex;
public:

View file

@ -33,7 +33,7 @@ bool CSVRender::Cell::addObjects (int start, int end)
bool modified = false;
const CSMWorld::RefCollection& collection = mData.getReferences();
for (int i=start; i<=end; ++i)
{
std::string cell = Misc::StringUtils::lowerCase (collection.getRecord (i).get().mCell);
@ -70,20 +70,22 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager,
int landIndex = land.searchId(mId);
if (landIndex != -1)
{
const ESM::Land* esmLand = land.getRecord(mId).get().mLand.get();
if(esmLand && esmLand->mDataTypes&ESM::Land::DATA_VHGT)
const ESM::Land& esmLand = land.getRecord(mId).get();
if (esmLand.getLandData (ESM::Land::DATA_VHGT))
{
mTerrain.reset(new Terrain::TerrainGrid(sceneManager, new TerrainStorage(mData), Element_Terrain, true,
Terrain::Align_XY));
mTerrain->loadCell(esmLand->mX,
esmLand->mY);
mTerrain->loadCell(esmLand.mX,
esmLand.mY);
float verts = ESM::Land::LAND_SIZE;
float worldsize = ESM::Land::REAL_SIZE;
mX = esmLand->mX;
mY = esmLand->mY;
mX = esmLand.mX;
mY = esmLand.mY;
mPhysics->addHeightField(sceneManager,
esmLand->mLandData->mHeights, mX, mY, 0, worldsize / (verts-1), verts);
esmLand.getLandData(ESM::Land::DATA_VHGT)->mHeights, mX, mY, 0, worldsize / (verts-1), verts);
}
}
}

View file

@ -8,7 +8,7 @@ namespace CSVRender
{
}
ESM::Land* TerrainStorage::getLand(int cellX, int cellY)
const ESM::Land* TerrainStorage::getLand(int cellX, int cellY)
{
std::ostringstream stream;
stream << "#" << cellX << " " << cellY;
@ -19,11 +19,10 @@ namespace CSVRender
if (index == -1)
return NULL;
ESM::Land* land = mData.getLand().getRecord(index).get().mLand.get();
const ESM::Land& land = mData.getLand().getRecord(index).get();
int mask = ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX;
if (!land->isDataLoaded(mask))
land->loadData(mask);
return land;
land.loadData (mask);
return &land;
}
const ESM::LandTexture* TerrainStorage::getLandTexture(int index, short plugin)

View file

@ -18,7 +18,7 @@ namespace CSVRender
private:
const CSMWorld::Data& mData;
virtual ESM::Land* getLand (int cellX, int cellY);
virtual const ESM::Land* getLand (int cellX, int cellY);
virtual const ESM::LandTexture* getLandTexture(int index, short plugin);
virtual void getBounds(float& minX, float& maxX, float& minY, float& maxY);

View file

@ -0,0 +1,142 @@
#include "merge.hpp"
#include <QVBoxLayout>
#include <QDialogButtonBox>
#include <QSplitter>
#include <QPushButton>
#include <QListWidget>
#include <QLabel>
#include <QKeyEvent>
#include "../../model/doc/document.hpp"
#include "../../model/doc/documentmanager.hpp"
#include "../doc/filewidget.hpp"
#include "../doc/adjusterwidget.hpp"
void CSVTools::Merge::keyPressEvent (QKeyEvent *event)
{
if (event->key()==Qt::Key_Escape)
{
event->accept();
cancel();
}
else
QWidget::keyPressEvent (event);
}
CSVTools::Merge::Merge (CSMDoc::DocumentManager& documentManager, QWidget *parent)
: QWidget (parent), mDocument (0), mDocumentManager (documentManager)
{
setWindowTitle ("Merge Content Files into a new Game File");
QVBoxLayout *mainLayout = new QVBoxLayout;
setLayout (mainLayout);
QSplitter *splitter = new QSplitter (Qt::Horizontal, this);
mainLayout->addWidget (splitter, 1);
// left panel (files to be merged)
QWidget *left = new QWidget (this);
left->setContentsMargins (0, 0, 0, 0);
splitter->addWidget (left);
QVBoxLayout *leftLayout = new QVBoxLayout;
left->setLayout (leftLayout);
leftLayout->addWidget (new QLabel ("Files to be merged", this));
mFiles = new QListWidget (this);
leftLayout->addWidget (mFiles, 1);
// right panel (new game file)
QWidget *right = new QWidget (this);
right->setContentsMargins (0, 0, 0, 0);
splitter->addWidget (right);
QVBoxLayout *rightLayout = new QVBoxLayout;
rightLayout->setAlignment (Qt::AlignTop);
right->setLayout (rightLayout);
rightLayout->addWidget (new QLabel ("New game file", this));
mNewFile = new CSVDoc::FileWidget (this);
mNewFile->setType (false);
mNewFile->extensionLabelIsVisible (true);
rightLayout->addWidget (mNewFile);
mAdjuster = new CSVDoc::AdjusterWidget (this);
rightLayout->addWidget (mAdjuster);
connect (mNewFile, SIGNAL (nameChanged (const QString&, bool)),
mAdjuster, SLOT (setName (const QString&, bool)));
connect (mAdjuster, SIGNAL (stateChanged (bool)), this, SLOT (stateChanged (bool)));
// buttons
QDialogButtonBox *buttons = new QDialogButtonBox (QDialogButtonBox::Cancel, Qt::Horizontal, this);
connect (buttons->button (QDialogButtonBox::Cancel), SIGNAL (clicked()), this, SLOT (cancel()));
mOkay = new QPushButton ("Merge", this);
connect (mOkay, SIGNAL (clicked()), this, SLOT (accept()));
mOkay->setDefault (true);
buttons->addButton (mOkay, QDialogButtonBox::AcceptRole);
mainLayout->addWidget (buttons);
}
void CSVTools::Merge::configure (CSMDoc::Document *document)
{
mDocument = document;
mNewFile->setName ("");
// content files
while (mFiles->count())
delete mFiles->takeItem (0);
std::vector<boost::filesystem::path> files = document->getContentFiles();
for (std::vector<boost::filesystem::path>::const_iterator iter (files.begin());
iter!=files.end(); ++iter)
mFiles->addItem (QString::fromUtf8 (iter->filename().string().c_str()));
}
void CSVTools::Merge::setLocalData (const boost::filesystem::path& localData)
{
mAdjuster->setLocalData (localData);
}
CSMDoc::Document *CSVTools::Merge::getDocument() const
{
return mDocument;
}
void CSVTools::Merge::cancel()
{
mDocument = 0;
hide();
}
void CSVTools::Merge::accept()
{
if ((mDocument->getState() & CSMDoc::State_Merging)==0)
{
std::vector< boost::filesystem::path > files (1, mAdjuster->getPath());
std::auto_ptr<CSMDoc::Document> target (
mDocumentManager.makeDocument (files, files[0], true));
mDocument->runMerge (target);
hide();
}
}
void CSVTools::Merge::stateChanged (bool valid)
{
mOkay->setEnabled (valid);
}

View file

@ -0,0 +1,61 @@
#ifndef CSV_TOOLS_REPORTTABLE_H
#define CSV_TOOLS_REPORTTABLE_H
#include <QWidget>
#include <boost/filesystem/path.hpp>
class QPushButton;
class QListWidget;
namespace CSMDoc
{
class Document;
class DocumentManager;
}
namespace CSVDoc
{
class FileWidget;
class AdjusterWidget;
}
namespace CSVTools
{
class Merge : public QWidget
{
Q_OBJECT
CSMDoc::Document *mDocument;
QPushButton *mOkay;
QListWidget *mFiles;
CSVDoc::FileWidget *mNewFile;
CSVDoc::AdjusterWidget *mAdjuster;
CSMDoc::DocumentManager& mDocumentManager;
void keyPressEvent (QKeyEvent *event);
public:
Merge (CSMDoc::DocumentManager& documentManager, QWidget *parent = 0);
/// Configure dialogue for a new merge
void configure (CSMDoc::Document *document);
void setLocalData (const boost::filesystem::path& localData);
CSMDoc::Document *getDocument() const;
public slots:
void cancel();
private slots:
void accept();
void stateChanged (bool valid);
};
}
#endif

View file

@ -35,7 +35,7 @@ void CSVWidget::DropLineEdit::dropEvent(QDropEvent *event)
if (CSVWorld::DragDropUtils::canAcceptData(*event, mDropType))
{
CSMWorld::UniversalId id = CSVWorld::DragDropUtils::getAcceptedData(*event, mDropType);
setText(QString::fromUtf8(id.getId().c_str()));
setText(QString::fromUtf8(id.getId().c_str()));
emit tableMimeDataDropped(id, CSVWorld::DragDropUtils::getTableMimeData(*event)->getDocumentPtr());
}
}

View file

@ -564,8 +564,22 @@ void CSVWorld::EditWidget::remake(int row)
static_cast<CSMWorld::UniversalId::Type> (mTable->data (mTable->index (row, typeColumn)).toInt()),
mTable->data (mTable->index (row, idColumn)).toString().toUtf8().constData());
bool editable = mTable->index(row, i).data().type() != QVariant::UserType;
NestedTable* table = new NestedTable(mDocument, id, mNestedModels.back(), this, editable);
bool editable = true;
bool fixedRows = false;
QVariant v = mTable->index(row, i).data();
if (v.canConvert<CSMWorld::ColumnBase::TableEditModes>())
{
assert (QString(v.typeName()) == "CSMWorld::ColumnBase::TableEditModes");
if (v.value<CSMWorld::ColumnBase::TableEditModes>() == CSMWorld::ColumnBase::TableEdit_None)
editable = false;
else if (v.value<CSMWorld::ColumnBase::TableEditModes>() == CSMWorld::ColumnBase::TableEdit_FixedRows)
fixedRows = true;
}
NestedTable* table =
new NestedTable(mDocument, id, mNestedModels.back(), this, editable, fixedRows);
table->resizeColumnsToContents();
if (!editable)
{
table->setEditTriggers(QAbstractItemView::NoEditTriggers);
@ -588,7 +602,7 @@ void CSVWorld::EditWidget::remake(int row)
new QLabel (mTable->headerData (i, Qt::Horizontal, Qt::DisplayRole).toString(), mMainWidget);
label->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed);
if(mTable->index(row, i).data().type() == QVariant::UserType)
if(!editable)
label->setEnabled(false);
tablesLayout->addWidget(label);

View file

@ -47,6 +47,16 @@ std::string CSVWorld::GenericCreator::getId() const
return mId->text().toUtf8().constData();
}
std::string CSVWorld::GenericCreator::getIdValidatorResult() const
{
std::string errors;
if (!mId->hasAcceptableInput())
errors = mValidator->getError();
return errors;
}
void CSVWorld::GenericCreator::configureCreateCommand (CSMWorld::CreateCommand& command) const {}
void CSVWorld::GenericCreator::pushCommand (std::auto_ptr<CSMWorld::CreateCommand> command,

View file

@ -60,6 +60,8 @@ namespace CSVWorld
virtual std::string getId() const;
virtual std::string getIdValidatorResult() const;
/// Allow subclasses to add additional data to \a command.
virtual void configureCreateCommand (CSMWorld::CreateCommand& command) const;

View file

@ -17,9 +17,12 @@ CSVWorld::NestedTable::NestedTable(CSMDoc::Document& document,
CSMWorld::UniversalId id,
CSMWorld::NestedTableProxyModel* model,
QWidget* parent,
bool editable)
bool editable,
bool fixedRows)
: DragRecordTable(document, parent),
mEditIdAction(0),
mAddNewRowAction(NULL),
mRemoveRowAction(NULL),
mEditIdAction(NULL),
mModel(model)
{
mDispatcher = new CSMWorld::CommandDispatcher (document, id, this);
@ -53,15 +56,18 @@ CSVWorld::NestedTable::NestedTable(CSMDoc::Document& document,
if (editable)
{
mAddNewRowAction = new QAction (tr ("Add new row"), this);
if (!fixedRows)
{
mAddNewRowAction = new QAction (tr ("Add new row"), this);
connect(mAddNewRowAction, SIGNAL(triggered()),
this, SLOT(addNewRowActionTriggered()));
connect(mAddNewRowAction, SIGNAL(triggered()),
this, SLOT(addNewRowActionTriggered()));
mRemoveRowAction = new QAction (tr ("Remove row"), this);
mRemoveRowAction = new QAction (tr ("Remove row"), this);
connect(mRemoveRowAction, SIGNAL(triggered()),
this, SLOT(removeRowActionTriggered()));
connect(mRemoveRowAction, SIGNAL(triggered()),
this, SLOT(removeRowActionTriggered()));
}
mEditIdAction = new TableEditIdAction(*this, this);
connect(mEditIdAction, SIGNAL(triggered()), this, SLOT(editCell()));
@ -92,10 +98,13 @@ void CSVWorld::NestedTable::contextMenuEvent (QContextMenuEvent *event)
menu.addSeparator();
}
if (selectionModel()->selectedRows().size() == 1)
menu.addAction(mRemoveRowAction);
if (mAddNewRowAction && mRemoveRowAction)
{
if (selectionModel()->selectedRows().size() == 1)
menu.addAction(mRemoveRowAction);
menu.addAction(mAddNewRowAction);
menu.addAction(mAddNewRowAction);
}
menu.exec (event->globalPos());
}

View file

@ -39,7 +39,8 @@ namespace CSVWorld
CSMWorld::UniversalId id,
CSMWorld::NestedTableProxyModel* model,
QWidget* parent = NULL,
bool editable = true);
bool editable = true,
bool fixedRows = false);
virtual std::vector<CSMWorld::UniversalId> getDraggedRecords() const;

View file

@ -181,7 +181,7 @@ namespace CSVWorld
}
void PhysicsSystem::addHeightField(Ogre::SceneManager *sceneManager,
float* heights, int x, int y, float yoffset, float triSize, float sqrtVerts)
const float* heights, int x, int y, float yoffset, float triSize, float sqrtVerts)
{
std::string name = "HeightField_"
+ QString::number(x).toStdString() + "_" + QString::number(y).toStdString();

View file

@ -63,7 +63,7 @@ namespace CSVWorld
void moveSceneNodes(const std::string sceneNodeName, const Ogre::Vector3 &position);
void addHeightField(Ogre::SceneManager *sceneManager,
float* heights, int x, int y, float yoffset, float triSize, float sqrtVerts);
const float* heights, int x, int y, float yoffset, float triSize, float sqrtVerts);
void removeHeightField(Ogre::SceneManager *sceneManager, int x, int y);

View file

@ -132,11 +132,6 @@ void CSVWorld::SceneSubView::setEditLock (bool locked)
}
void CSVWorld::SceneSubView::updateEditorSetting(const QString &settingName, const QString &settingValue)
{
}
void CSVWorld::SceneSubView::setStatusBar (bool show)
{
mBottom->setStatusBar (show);
@ -247,8 +242,6 @@ void CSVWorld::SceneSubView::replaceToolbarAndWorldspace (CSVRender::WorldspaceW
mToolbar = toolbar;
connect (mScene, SIGNAL (focusToolbarRequest()), mToolbar, SLOT (setFocus()));
connect (this, SIGNAL (updateSceneUserSetting(const QString &, const QStringList &)),
mScene, SLOT (updateUserSetting(const QString &, const QStringList &)));
connect (mToolbar, SIGNAL (focusSceneRequest()), mScene, SLOT (setFocus()));
mLayout->addWidget (mToolbar, 0);
@ -257,8 +250,3 @@ void CSVWorld::SceneSubView::replaceToolbarAndWorldspace (CSVRender::WorldspaceW
mScene->selectDefaultNavigationMode();
setFocusProxy (mScene);
}
void CSVWorld::SceneSubView::updateUserSetting (const QString &key, const QStringList &list)
{
emit updateSceneUserSetting(key, list);
}

View file

@ -52,8 +52,6 @@ namespace CSVWorld
virtual void setEditLock (bool locked);
virtual void updateEditorSetting (const QString& key, const QString& value);
virtual void setStatusBar (bool show);
virtual void useHint (const std::string& hint);
@ -83,14 +81,6 @@ namespace CSVWorld
void cellSelectionChanged (const CSMWorld::UniversalId& id);
void handleDrop(const std::vector<CSMWorld::UniversalId>& data);
public slots:
void updateUserSetting (const QString &, const QStringList &);
signals:
void updateSceneUserSetting (const QString &, const QStringList &);
};
}

View file

@ -131,6 +131,11 @@ void CSVWorld::ScriptErrorTable::clear()
setRowCount (0);
}
bool CSVWorld::ScriptErrorTable::clearLocals (const std::string& script)
{
return mContext.clearLocals (script);
}
void CSVWorld::ScriptErrorTable::cellClicked (int row, int column)
{
if (item (row, 1))

View file

@ -44,6 +44,11 @@ namespace CSVWorld
void clear();
/// Clear local variable cache for \a script.
///
/// \return Were there any locals that needed clearing?
bool clearLocals (const std::string& script);
private slots:
void cellClicked (int row, int column);

View file

@ -89,6 +89,7 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc:
*document.getData().getTableModel (CSMWorld::UniversalId::Type_Scripts));
mColumn = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_ScriptText);
mIdColumn = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Id);
mStateColumn = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Modification);
QString source = mModel->data (mModel->getModelIndex (id.getId(), mColumn)).toString();
@ -197,26 +198,41 @@ void CSVWorld::ScriptSubView::useHint (const std::string& hint)
if (hint.empty())
return;
if (hint[0]=='l')
{
std::istringstream stream (hint.c_str()+1);
char ignore;
int line;
int column;
if (stream >> ignore >> line >> column)
unsigned line = 0, column = 0;
char c;
std::istringstream stream (hint.c_str()+1);
switch(hint[0]){
case 'R':
case 'r':
{
QTextCursor cursor = mEditor->textCursor();
QModelIndex index = mModel->getModelIndex (getUniversalId().getId(), mColumn);
QString source = mModel->data (index).toString();
unsigned pos, dummy;
if (!(stream >> c >> dummy >> pos) )
return;
cursor.movePosition (QTextCursor::Start);
if (cursor.movePosition (QTextCursor::Down, QTextCursor::MoveAnchor, line))
cursor.movePosition (QTextCursor::Right, QTextCursor::MoveAnchor, column);
mEditor->setFocus();
mEditor->setTextCursor (cursor);
for (unsigned i = 0; i <= pos; ++i){
if (source[i] == '\n'){
++line;
column = i+1;
}
}
column = pos - column;
break;
}
case 'l':
if (!(stream >> c >> line >> column))
return;
}
QTextCursor cursor = mEditor->textCursor();
cursor.movePosition (QTextCursor::Start);
if (cursor.movePosition (QTextCursor::Down, QTextCursor::MoveAnchor, line))
cursor.movePosition (QTextCursor::Right, QTextCursor::MoveAnchor, column);
mEditor->setFocus();
mEditor->setTextCursor (cursor);
}
void CSVWorld::ScriptSubView::textChanged()
@ -241,6 +257,15 @@ void CSVWorld::ScriptSubView::dataChanged (const QModelIndex& topLeft, const QMo
ScriptEdit::ChangeLock lock (*mEditor);
bool updateRequired = false;
for (int i=topLeft.row(); i<=bottomRight.row(); ++i)
{
std::string id = mModel->data (mModel->index (i, mIdColumn)).toString().toUtf8().constData();
if (mErrors->clearLocals (id))
updateRequired = true;
}
QModelIndex index = mModel->getModelIndex (getUniversalId().getId(), mColumn);
if (index.row()>=topLeft.row() && index.row()<=bottomRight.row())
@ -256,13 +281,28 @@ void CSVWorld::ScriptSubView::dataChanged (const QModelIndex& topLeft, const QMo
mEditor->setPlainText (source);
mEditor->setTextCursor (cursor);
recompile();
updateRequired = true;
}
}
if (updateRequired)
recompile();
}
void CSVWorld::ScriptSubView::rowsAboutToBeRemoved (const QModelIndex& parent, int start, int end)
{
bool updateRequired = false;
for (int i=start; i<=end; ++i)
{
std::string id = mModel->data (mModel->index (i, mIdColumn)).toString().toUtf8().constData();
if (mErrors->clearLocals (id))
updateRequired = true;
}
if (updateRequired)
recompile();
QModelIndex index = mModel->getModelIndex (getUniversalId().getId(), mColumn);
if (!parent.isValid() && index.row()>=start && index.row()<=end)

View file

@ -38,6 +38,7 @@ namespace CSVWorld
CSMDoc::Document& mDocument;
CSMWorld::IdTable *mModel;
int mColumn;
int mIdColumn;
int mStateColumn;
TableBottomBox *mBottom;
RecordButtonBar *mButtons;

View file

@ -0,0 +1,20 @@
#include "startscriptcreator.hpp"
CSVWorld::StartScriptCreator::StartScriptCreator(CSMWorld::Data &data, QUndoStack &undoStack, const CSMWorld::UniversalId &id, bool relaxedIdRules):
GenericCreator (data, undoStack, id, true)
{}
std::string CSVWorld::StartScriptCreator::getErrors() const
{
std::string errors;
errors = getIdValidatorResult();
if (errors.length() > 0)
return errors;
else if (getData().getScripts().searchId(getId()) == -1)
errors = "Script ID not found";
else if (getData().getStartScripts().searchId(getId()) > -1 )
errors = "Script with this ID already registered as Start Script";
return errors;
}

View file

@ -0,0 +1,25 @@
#ifndef STARTSCRIPTCREATOR_HPP
#define STARTSCRIPTCREATOR_HPP
#include "genericcreator.hpp"
namespace CSVWorld {
class StartScriptCreator : public GenericCreator
{
Q_OBJECT
public:
StartScriptCreator(CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id, bool relaxedIdRules = false);
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.
};
}
#endif // STARTSCRIPTCREATOR_HPP

View file

@ -10,6 +10,7 @@
#include "cellcreator.hpp"
#include "referenceablecreator.hpp"
#include "referencecreator.hpp"
#include "startscriptcreator.hpp"
#include "scenesubview.hpp"
#include "dialoguecreator.hpp"
#include "infocreator.hpp"
@ -53,6 +54,9 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
manager.add (sTableTypes[i],
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<GenericCreator> >);
manager.add (CSMWorld::UniversalId::Type_StartScripts,
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<StartScriptCreator> >);
manager.add (CSMWorld::UniversalId::Type_Cells,
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<CellCreator> >);
@ -125,7 +129,6 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
CSMWorld::UniversalId::Type_BodyPart,
CSMWorld::UniversalId::Type_SoundGen,
CSMWorld::UniversalId::Type_Pathgrid,
CSMWorld::UniversalId::Type_StartScript,
CSMWorld::UniversalId::Type_None // end marker
};
@ -135,6 +138,10 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView,
CreatorFactory<GenericCreator> > (false));
manager.add (CSMWorld::UniversalId::Type_StartScript,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView,
CreatorFactory<StartScriptCreator> > (false));
manager.add (CSMWorld::UniversalId::Type_Skill,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, NullCreatorFactory > (false));

View file

@ -7,21 +7,21 @@ int argcData;
extern "C" void releaseArgv();
void releaseArgv() {
delete[] argvData;
delete[] argvData;
}
JNIEXPORT void JNICALL Java_ui_activity_GameActivity_commandLine(JNIEnv *env,
jobject obj, jint argc, jobjectArray stringArray) {
jboolean iscopy;
argcData = (int) argc;
argvData = new const char *[argcData + 1];
argvData[0] = "openmw";
for (int i = 1; i < argcData + 1; i++) {
jstring string = (jstring) (env)->GetObjectArrayElement(stringArray,
i - 1);
argvData[i] = (env)->GetStringUTFChars(string, &iscopy);
(env)->DeleteLocalRef(string);
}
(env)->DeleteLocalRef(stringArray);
jobject obj, jint argc, jobjectArray stringArray) {
jboolean iscopy;
argcData = (int) argc;
argvData = new const char *[argcData + 1];
argvData[0] = "openmw";
for (int i = 1; i < argcData + 1; i++) {
jstring string = (jstring) (env)->GetObjectArrayElement(stringArray,
i - 1);
argvData[i] = (env)->GetStringUTFChars(string, &iscopy);
(env)->DeleteLocalRef(string);
}
(env)->DeleteLocalRef(stringArray);
}

View file

@ -16,22 +16,22 @@ extern const char **argvData;
void releaseArgv();
int Java_org_libsdl_app_SDLActivity_nativeInit(JNIEnv* env, jclass cls,
jobject obj) {
jobject obj) {
SDL_Android_Init(env, cls);
SDL_Android_Init(env, cls);
SDL_SetMainReady();
SDL_SetMainReady();
/* Run the application code! */
/* Run the application code! */
int status;
int status;
status = main(argcData+1, argvData);
releaseArgv();
/* Do not issue an exit or the whole application will terminate instead of just the SDL thread */
/* exit(status); */
status = main(argcData+1, argvData);
releaseArgv();
/* Do not issue an exit or the whole application will terminate instead of just the SDL thread */
/* exit(status); */
return status;
return status;
}
#endif /* __ANDROID__ */

View file

@ -37,8 +37,8 @@ static const char pipe_err[] = "!!! Failed to create pipe\n";
static const char fork_err[] = "!!! Failed to fork debug process\n";
static const char exec_err[] = "!!! Failed to exec debug process\n";
#ifndef PATH_MAX /* Not all platforms (GNU Hurd) have this. */
# define PATH_MAX 256
#ifndef PATH_MAX /* Not all platforms (GNU Hurd) have this. */
# define PATH_MAX 256
#endif
static char argv0[PATH_MAX];

View file

@ -807,27 +807,25 @@ namespace MWClass
const ESM::CreatureState& state2 = dynamic_cast<const ESM::CreatureState&> (state);
ensureCustomData(ptr);
// If we do the following instead we get a sizable speedup, but this causes compatibility issues
// with 0.30 savegames, where some state in CreatureStats was not saved yet,
// and therefore needs to be loaded from ESM records. TODO: re-enable this in a future release.
/*
if (!ptr.getRefData().getCustomData())
if (state.mVersion > 0)
{
// Create a CustomData, but don't fill it from ESM records (not needed)
std::auto_ptr<CreatureCustomData> data (new CreatureCustomData);
if (!ptr.getRefData().getCustomData())
{
// Create a CustomData, but don't fill it from ESM records (not needed)
std::auto_ptr<CreatureCustomData> data (new CreatureCustomData);
MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
if (ref->mBase->mFlags & ESM::Creature::Weapon)
data->mContainerStore = new MWWorld::InventoryStore();
else
data->mContainerStore = new MWWorld::ContainerStore();
if (ref->mBase->mFlags & ESM::Creature::Weapon)
data->mContainerStore = new MWWorld::InventoryStore();
else
data->mContainerStore = new MWWorld::ContainerStore();
ptr.getRefData().setCustomData (data.release());
ptr.getRefData().setCustomData (data.release());
}
}
*/
else
ensureCustomData(ptr); // in openmw 0.30 savegames not all state was saved yet, so need to load it regardless.
CreatureCustomData& customData = dynamic_cast<CreatureCustomData&> (*ptr.getRefData().getCustomData());

View file

@ -1103,18 +1103,17 @@ namespace MWClass
const ESM::NpcState& state2 = dynamic_cast<const ESM::NpcState&> (state);
ensureCustomData(ptr);
// If we do the following instead we get a sizable speedup, but this causes compatibility issues
// with 0.30 savegames, where some state in CreatureStats was not saved yet,
// and therefore needs to be loaded from ESM records. TODO: re-enable this in a future release.
/*
if (!ptr.getRefData().getCustomData())
if (state.mVersion > 0)
{
// Create a CustomData, but don't fill it from ESM records (not needed)
std::auto_ptr<NpcCustomData> data (new NpcCustomData);
ptr.getRefData().setCustomData (data.release());
if (!ptr.getRefData().getCustomData())
{
// Create a CustomData, but don't fill it from ESM records (not needed)
std::auto_ptr<NpcCustomData> data (new NpcCustomData);
ptr.getRefData().setCustomData (data.release());
}
}
*/
else
ensureCustomData(ptr); // in openmw 0.30 savegames not all state was saved yet, so need to load it regardless.
NpcCustomData& customData = dynamic_cast<NpcCustomData&> (*ptr.getRefData().getCustomData());

View file

@ -18,9 +18,9 @@ namespace
float accumulated_time=0,parent_time = pit->Is_Root() ? CProfileManager::Get_Time_Since_Reset() : pit->Get_Current_Parent_Total_Time();
int i,j;
int frames_since_reset = CProfileManager::Get_Frame_Count_Since_Reset();
for (i=0;i<spacing;i++) os << ".";
for (i=0;i<spacing;i++) os << ".";
os << "----------------------------------\n";
for (i=0;i<spacing;i++) os << ".";
for (i=0;i<spacing;i++) os << ".";
std::string s = "Profiling: "+
std::string(pit->Get_Current_Parent_Name())+" (total running time: "+MyGUI::utility::toString(parent_time,3)+" ms) ---\n";
os << s;
@ -35,7 +35,7 @@ namespace
accumulated_time += current_total_time;
float fraction = parent_time > SIMD_EPSILON ? (current_total_time / parent_time) * 100 : 0.f;
for (j=0;j<spacing;j++) os << ".";
for (j=0;j<spacing;j++) os << ".";
double ms = (current_total_time / (double)frames_since_reset);
s = MyGUI::utility::toString(i)+" -- "+pit->Get_Current_Name()+" ("+MyGUI::utility::toString(fraction,2)+" %) :: "+MyGUI::utility::toString(ms,3)+" ms / frame ("+MyGUI::utility::toString(pit->Get_Current_Total_Calls())+" calls)\n";
os << s;
@ -47,7 +47,7 @@ namespace
{
os << "what's wrong\n";
}
for (i=0;i<spacing;i++) os << ".";
for (i=0;i<spacing;i++) os << ".";
double unaccounted= parent_time > SIMD_EPSILON ? ((parent_time - accumulated_time) / parent_time) * 100 : 0.f;
s = "Unaccounted: ("+MyGUI::utility::toString(unaccounted,3)+" %) :: "+MyGUI::utility::toString(parent_time - accumulated_time,3)+" ms\n";
os << s;

View file

@ -106,7 +106,7 @@ namespace MWGui
static std::string sSchoolNames[6];
int mHorizontalScrollIndex;
int mHorizontalScrollIndex;
float mDelay;

View file

@ -607,7 +607,7 @@ namespace MWGui
controller->eventRepeatClick += newDelegate(this, &MWScrollBar::repeatClick);
controller->setEnabled(mEnableRepeat);
controller->setRepeat(mRepeatTriggerTime, mRepeatStepTime);
MyGUI::ControllerManager::getInstance().addItem(this, controller);
MyGUI::ControllerManager::getInstance().addItem(this, controller);
}
void MWScrollBar::onDecreaseButtonReleased(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id)
@ -623,7 +623,7 @@ namespace MWGui
controller->eventRepeatClick += newDelegate(this, &MWScrollBar::repeatClick);
controller->setEnabled(mEnableRepeat);
controller->setRepeat(mRepeatTriggerTime, mRepeatStepTime);
MyGUI::ControllerManager::getInstance().addItem(this, controller);
MyGUI::ControllerManager::getInstance().addItem(this, controller);
}
void MWScrollBar::onIncreaseButtonReleased(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id)

View file

@ -159,9 +159,9 @@ namespace MWInput
mControlSwitch["playerviewswitch"] = true;
mControlSwitch["vanitymode"] = true;
/* Joystick Init */
/* Joystick Init */
//Load controller mappings
// Load controller mappings
#if SDL_VERSION_ATLEAST(2,0,2)
if(controllerBindingsFile!="")
{
@ -169,10 +169,10 @@ namespace MWInput
}
#endif
//Open all presently connected sticks
int numSticks = SDL_NumJoysticks();
for(int i = 0; i < numSticks; i++)
{
// Open all presently connected sticks
int numSticks = SDL_NumJoysticks();
for(int i = 0; i < numSticks; i++)
{
if(SDL_IsGameController(i))
{
SDL_ControllerDeviceEvent evt;
@ -183,7 +183,7 @@ namespace MWInput
{
//ICS_LOG(std::string("Unusable controller plugged in: ")+SDL_JoystickNameForIndex(i));
}
}
}
}
void InputManager::clear()

View file

@ -65,7 +65,7 @@ namespace
Ogre::Vector3 dir = to - from;
dir.z = 0;
dir.normalise();
float verticalOffset = 200; // instead of '200' here we want the height of the actor
float verticalOffset = 200; // instead of '200' here we want the height of the actor
Ogre::Vector3 _from = from + dir*offsetXY + Ogre::Vector3::UNIT_Z * verticalOffset;
// cast up-down ray and find height in world space of hit

View file

@ -83,6 +83,9 @@ namespace MWRender
land->loadData(mask);
}
const ESM::Land::LandData *landData =
land ? land->getLandData (ESM::Land::DATA_WNAM) : 0;
for (int cellY=0; cellY<mCellSize; ++cellY)
{
for (int cellX=0; cellX<mCellSize; ++cellX)
@ -90,15 +93,14 @@ namespace MWRender
int vertexX = static_cast<int>(float(cellX)/float(mCellSize) * 9);
int vertexY = static_cast<int>(float(cellY) / float(mCellSize) * 9);
int texelX = (x-mMinX) * mCellSize + cellX;
int texelY = (mHeight-1) - ((y-mMinY) * mCellSize + cellY);
unsigned char r,g,b;
float y = 0;
if (land && land->mDataTypes & ESM::Land::DATA_WNAM)
y = (land->mLandData->mWnam[vertexY * 9 + vertexX] << 4) / 2048.f;
if (landData)
y = (landData->mWnam[vertexY * 9 + vertexX] << 4) / 2048.f;
else
y = (SCHAR_MIN << 4) / 2048.f;
if (y < 0)

View file

@ -50,7 +50,7 @@ namespace MWRender
maxY += 1;
}
ESM::Land* TerrainStorage::getLand(int cellX, int cellY)
const ESM::Land* TerrainStorage::getLand(int cellX, int cellY)
{
const MWWorld::ESMStore &esmStore =
MWBase::Environment::get().getWorld()->getStore();

View file

@ -10,7 +10,7 @@ namespace MWRender
class TerrainStorage : public ESMTerrain::Storage
{
private:
virtual ESM::Land* getLand (int cellX, int cellY);
virtual const ESM::Land* getLand (int cellX, int cellY);
virtual const ESM::LandTexture* getLandTexture(int index, short plugin);
public:

View file

@ -28,9 +28,6 @@ void MWState::Character::addSlot (const boost::filesystem::path& path, const std
ESM::ESMReader reader;
reader.open (slot.mPath.string());
if (reader.getFormat()>ESM::Header::CurrentFormat)
return; // format is too new -> ignore
if (reader.getRecName()!=ESM::REC_SAVE)
return; // invalid save file -> ignore

View file

@ -201,7 +201,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
++iter)
writer.addMaster (*iter, 0); // not using the size information anyway -> use value of 0
writer.setFormat (ESM::Header::CurrentFormat);
writer.setFormat (ESM::SavedGame::sCurrentFormat);
// all unused
writer.setVersion(0);
@ -310,8 +310,6 @@ void MWState::StateManager::loadGame(const std::string& filepath)
// have to peek into the save file to get the player name
ESM::ESMReader reader;
reader.open (filepath);
if (reader.getFormat()>ESM::Header::CurrentFormat)
return; // format is too new -> ignore
if (reader.getRecName()!=ESM::REC_SAVE)
return; // invalid save file -> ignore
reader.getRecHeader();
@ -333,6 +331,9 @@ void MWState::StateManager::loadGame (const Character *character, const std::str
ESM::ESMReader reader;
reader.open (filepath);
if (reader.getFormat() > ESM::SavedGame::sCurrentFormat)
throw std::runtime_error("This save file was created using a newer version of OpenMW and is thus not supported. Please upgrade to the newest OpenMW version to load this file.");
std::map<int, int> contentFileMap = buildContentFileIndexMap (reader);
Loading::Listener& listener = *MWBase::Environment::get().getWindowManager()->getLoadingScreen();

View file

@ -660,7 +660,7 @@ namespace MWWorld
return MovementSolver::traceDown(ptr, mEngine, maxHeight);
}
void PhysicsSystem::addHeightField (float* heights,
void PhysicsSystem::addHeightField (const float* heights,
int x, int y, float yoffset,
float triSize, float sqrtVerts)
{

View file

@ -42,7 +42,7 @@ namespace MWWorld
void addActor (const MWWorld::Ptr& ptr, const std::string& mesh);
void addHeightField (float* heights,
void addHeightField (const float* heights,
int x, int y, float yoffset,
float triSize, float sqrtVerts);

View file

@ -236,16 +236,10 @@ namespace MWWorld
// Actually only VHGT is needed here, but we'll need the rest for rendering anyway.
// Load everything now to reduce IO overhead.
const int flags = ESM::Land::DATA_VCLR|ESM::Land::DATA_VHGT|ESM::Land::DATA_VNML|ESM::Land::DATA_VTEX;
if (!land->isDataLoaded(flags))
land->loadData(flags);
mPhysics->addHeightField (
land->mLandData->mHeights,
cell->getCell()->getGridX(),
cell->getCell()->getGridY(),
0,
worldsize / (verts-1),
verts)
;
const ESM::Land::LandData *data = land->getLandData (flags);
mPhysics->addHeightField (data->mHeights, cell->getCell()->getGridX(), cell->getCell()->getGridY(),
0, worldsize / (verts-1), verts);
}
}

View file

@ -287,7 +287,7 @@ namespace MWWorld
if (mPlayer)
{
mPlayer->clear();
mPlayer->clear();
mPlayer->setCell(0);
mPlayer->getPlayer().getRefData() = RefData();
mPlayer->set(mStore.get<ESM::NPC>().find ("player"));

View file

@ -182,11 +182,12 @@ IF (MYGUI_FOUND)
IF (NOT MYGUI_FIND_QUIETLY)
MESSAGE(STATUS "MyGUI version: ${MYGUI_VERSION}")
ENDIF (NOT MYGUI_FIND_QUIETLY)
ELSE (MYGUI_FOUND)
IF (MYGUI_FIND_REQUIRED)
MESSAGE(FATAL_ERROR "Could not find MYGUI")
ENDIF (MYGUI_FIND_REQUIRED)
ENDIF (MYGUI_FOUND)
include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(MyGUI DEFAULT_MSG
MYGUI_INCLUDE_DIRS
FREETYPE_LIBRARIES
MYGUI_LIBRARIES)
CMAKE_POLICY(POP)

View file

@ -652,6 +652,13 @@ namespace Compiler
return true;
}
if (code ==Scanner::S_plus && mNextOperand)
{
// Also unary, but +, just ignore it
mTokenLoc = loc;
return true;
}
if (code==Scanner::S_open)
{
if (mNextOperand)

View file

@ -44,7 +44,7 @@ namespace Compiler
namespace Gui
{
void registerExtensions (Extensions& extensions);
void registerExtensions (Extensions& extensions);
}
namespace Misc

View file

@ -65,7 +65,6 @@ namespace Compiler
if (mState==BeginState && keyword==Scanner::K_begin)
{
mState = NameState;
scanner.allowNameStartingwithDigit();
return true;
}
@ -112,7 +111,6 @@ namespace Compiler
scanner.scan (mScriptParser);
mState = EndNameState;
scanner.allowNameStartingwithDigit();
return true;
}

View file

@ -555,7 +555,7 @@ namespace Compiler
}
if (mAllowExpression && mState==BeginState &&
(code==Scanner::S_open || code==Scanner::S_minus))
(code==Scanner::S_open || code==Scanner::S_minus || code==Scanner::S_plus))
{
scanner.putbackSpecial (code, loc);
parseExpression (scanner, loc);

Some files were not shown because too many files have changed in this diff Show more