mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-16 17:19:56 +00:00
Merge branch 'master' into pathgrid-edit
This commit is contained in:
commit
6d5899361e
94 changed files with 1455 additions and 769 deletions
|
@ -31,7 +31,7 @@ before_script:
|
|||
script:
|
||||
- cd ./build
|
||||
- if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then make -j4; fi
|
||||
- if [ "$COVERITY_SCAN_BRANCH" != 1 ] && ["${TRAVIS_OS_NAME}" = "osx"]; then make package; 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
|
||||
notifications:
|
||||
|
|
|
@ -39,6 +39,7 @@ Programmers
|
|||
Eli2
|
||||
Emanuel Guével (potatoesmaster)
|
||||
eroen
|
||||
Evgeniy Mineev (sandstranger)
|
||||
Fil Krynicki (filkry)
|
||||
Gašper Sedej
|
||||
gugus/gus
|
||||
|
@ -91,7 +92,6 @@ Programmers
|
|||
Rohit Nirmal
|
||||
Roman Melnik (Kromgart)
|
||||
Roman Proskuryakov (humbug)
|
||||
sandstranger
|
||||
Sandy Carter (bwrsandman)
|
||||
Scott Howard
|
||||
Sebastian Wick (swick)
|
||||
|
|
|
@ -672,6 +672,7 @@ if (WIN32)
|
|||
4193 # #pragma warning(pop) : no matching '#pragma warning(push)'
|
||||
4251 # class 'XXXX' needs to have dll-interface to be used by clients of class 'YYYY'
|
||||
4275 # non dll-interface struct 'XXXX' used as base for dll-interface class 'YYYY'
|
||||
4315 # undocumented, 'this' pointer for member might not be aligned (OgreMemoryStlAllocator.h)
|
||||
|
||||
# caused by boost
|
||||
4191 # 'type cast' : unsafe conversion (1.56, thread_primitives.hpp, normally off)
|
||||
|
@ -679,6 +680,7 @@ if (WIN32)
|
|||
# OpenMW specific warnings
|
||||
4099 # Type mismatch, declared class or struct is defined with other type
|
||||
4100 # Unreferenced formal parameter (-Wunused-parameter)
|
||||
4101 # Unreferenced local variable (-Wunused-variable)
|
||||
4127 # Conditional expression is constant
|
||||
4242 # Storing value in a variable of a smaller type, possible loss of data
|
||||
4244 # Storing value of one type in variable of another (size_t in int, for example)
|
||||
|
@ -700,14 +702,16 @@ if (WIN32)
|
|||
# boost::wave has a few issues with signed / unsigned conversions, so we suppress those here
|
||||
set(SHINY_WARNINGS "${WARNINGS} /wd4245")
|
||||
set_target_properties(shiny PROPERTIES COMPILE_FLAGS "${SHINY_WARNINGS} ${MT_BUILD}")
|
||||
# there's an unreferenced local variable in the ogre platform, suppress it
|
||||
set(SHINY_OGRE_WARNINGS "${WARNINGS} /wd4101")
|
||||
set_target_properties(shiny.OgrePlatform PROPERTIES COMPILE_FLAGS "${SHINY_OGRE_WARNINGS} ${MT_BUILD}")
|
||||
set_target_properties(shiny.OgrePlatform PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
|
||||
set_target_properties(sdl4ogre PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
|
||||
# oics uses tinyxml, which has an initialized but unused variable
|
||||
set(OICS_WARNINGS "${WARNINGS} /wd4189")
|
||||
set_target_properties(oics PROPERTIES COMPILE_FLAGS "${OICS_WARNINGS} ${MT_BUILD}")
|
||||
set_target_properties(components PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
|
||||
set_target_properties(ogre-ffmpeg-videoplayer PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
|
||||
if (BUILD_MYGUI_PLUGIN)
|
||||
set_target_properties(Plugin_MyGUI_OpenMW_Resources PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
|
||||
endif (BUILD_MYGUI_PLUGIN)
|
||||
if (BUILD_LAUNCHER)
|
||||
set_target_properties(openmw-launcher PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
|
||||
endif (BUILD_LAUNCHER)
|
||||
|
@ -726,6 +730,9 @@ if (WIN32)
|
|||
set(OPENCS_WARNINGS "${WARNINGS} ${MT_BUILD} /wd4435")
|
||||
set_target_properties(openmw-cs PROPERTIES COMPILE_FLAGS ${OPENCS_WARNINGS})
|
||||
endif (BUILD_OPENCS)
|
||||
if (BUILD_ESSIMPORTER)
|
||||
set_target_properties(openmw-essimporter PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
|
||||
endif (BUILD_ESSIMPORTER)
|
||||
if (BUILD_MWINIIMPORTER)
|
||||
set_target_properties(openmw-iniimporter PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
|
||||
endif (BUILD_MWINIIMPORTER)
|
||||
|
|
|
@ -43,13 +43,17 @@ namespace ESSImport
|
|||
float mMagicEffects[27]; // Effect attributes: https://wiki.openmw.org/index.php?title=Research:Magic#Effect_attributes
|
||||
unsigned char mUnknown4[4];
|
||||
unsigned int mGoldPool;
|
||||
unsigned char mUnknown5[4];
|
||||
unsigned char mCountDown; // seen the same value as in ACSC.mCorpseClearCountdown, maybe
|
||||
// this one is for respawning?
|
||||
unsigned char mUnknown5[3];
|
||||
};
|
||||
struct ACSC
|
||||
{
|
||||
unsigned char mUnknown1[17];
|
||||
unsigned char mFlags; // ACSCFlags
|
||||
unsigned char mUnknown2[94];
|
||||
unsigned char mUnknown2[22];
|
||||
unsigned char mCorpseClearCountdown; // hours?
|
||||
unsigned char mUnknown3[71];
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
|
|
|
@ -14,10 +14,10 @@ namespace ESSImport
|
|||
float scale;
|
||||
esm.getHNOT(scale, "XSCL");
|
||||
|
||||
// FIXME: use AiPackageList, need to fix getSubName()
|
||||
|
||||
while (esm.isNextSub("AI_W") || esm.isNextSub("AI_E") || esm.isNextSub("AI_T") || esm.isNextSub("AI_F")
|
||||
|| esm.isNextSub("AI_A"))
|
||||
esm.skipHSub();
|
||||
mAiPackages.add(esm);
|
||||
|
||||
mInventory.load(esm);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define OPENMW_ESSIMPORT_CREC_H
|
||||
|
||||
#include "importinventory.hpp"
|
||||
#include <components/esm/aipackage.hpp>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
|
@ -17,6 +18,7 @@ namespace ESSImport
|
|||
int mIndex;
|
||||
|
||||
Inventory mInventory;
|
||||
ESM::AIPackageList mAiPackages;
|
||||
|
||||
void load(ESM::ESMReader& esm);
|
||||
};
|
||||
|
|
|
@ -9,10 +9,9 @@ namespace ESSImport
|
|||
{
|
||||
esm.getHNT(mNPDT, "NPDT");
|
||||
|
||||
// FIXME: use AiPackageList, need to fix getSubName()
|
||||
while (esm.isNextSub("AI_W") || esm.isNextSub("AI_E") || esm.isNextSub("AI_T") || esm.isNextSub("AI_F")
|
||||
|| esm.isNextSub("AI_A"))
|
||||
esm.skipHSub();
|
||||
mAiPackages.add(esm);
|
||||
|
||||
mInventory.load(esm);
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ namespace ESSImport
|
|||
} mNPDT;
|
||||
|
||||
Inventory mInventory;
|
||||
ESM::AIPackageList mAiPackages;
|
||||
|
||||
void load(ESM::ESMReader &esm);
|
||||
};
|
||||
|
|
|
@ -61,6 +61,7 @@ Launcher::MainDialog::MainDialog(QWidget *parent)
|
|||
QString revision(OPENMW_VERSION_COMMITHASH);
|
||||
QString tag(OPENMW_VERSION_TAGHASH);
|
||||
|
||||
versionLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
|
||||
if (!revision.isEmpty() && !tag.isEmpty())
|
||||
{
|
||||
if (revision == tag) {
|
||||
|
@ -238,24 +239,8 @@ void Launcher::MainDialog::changePage(QListWidgetItem *current, QListWidgetItem
|
|||
current = previous;
|
||||
|
||||
int currentIndex = iconWidget->row(current);
|
||||
// int previousIndex = iconWidget->row(previous);
|
||||
|
||||
pagesWidget->setCurrentIndex(currentIndex);
|
||||
|
||||
// DataFilesPage *previousPage = dynamic_cast<DataFilesPage *>(pagesWidget->widget(previousIndex));
|
||||
// DataFilesPage *currentPage = dynamic_cast<DataFilesPage *>(pagesWidget->widget(currentIndex));
|
||||
|
||||
// //special call to update/save data files page list view when it's displayed/hidden.
|
||||
// if (previousPage)
|
||||
// {
|
||||
// if (previousPage->objectName() == "DataFilesPage")
|
||||
// previousPage->saveSettings();
|
||||
// }
|
||||
// else if (currentPage)
|
||||
// {
|
||||
// if (currentPage->objectName() == "DataFilesPage")
|
||||
// currentPage->loadSettings();
|
||||
// }
|
||||
mSettingsPage->resetProgressBar();
|
||||
}
|
||||
|
||||
bool Launcher::MainDialog::setupLauncherSettings()
|
||||
|
|
|
@ -39,6 +39,7 @@ Launcher::SettingsPage::SettingsPage(Files::ConfigurationManager &cfg,
|
|||
|
||||
mWizardInvoker = new ProcessInvoker();
|
||||
mImporterInvoker = new ProcessInvoker();
|
||||
resetProgressBar();
|
||||
|
||||
connect(mWizardInvoker->getProcess(), SIGNAL(started()),
|
||||
this, SLOT(wizardStarted()));
|
||||
|
@ -94,7 +95,7 @@ Launcher::SettingsPage::~SettingsPage()
|
|||
|
||||
void Launcher::SettingsPage::on_wizardButton_clicked()
|
||||
{
|
||||
saveSettings();
|
||||
mMain->writeSettings();
|
||||
|
||||
if (!mWizardInvoker->startProcess(QLatin1String("openmw-wizard"), false))
|
||||
return;
|
||||
|
@ -102,7 +103,7 @@ void Launcher::SettingsPage::on_wizardButton_clicked()
|
|||
|
||||
void Launcher::SettingsPage::on_importerButton_clicked()
|
||||
{
|
||||
saveSettings();
|
||||
mMain->writeSettings();
|
||||
|
||||
// Create the file if it doesn't already exist, else the importer will fail
|
||||
QString path(QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()));
|
||||
|
@ -141,8 +142,13 @@ void Launcher::SettingsPage::on_importerButton_clicked()
|
|||
|
||||
qDebug() << "arguments " << arguments;
|
||||
|
||||
// start the progress bar as a "bouncing ball"
|
||||
progressBar->setMaximum(0);
|
||||
progressBar->setValue(0);
|
||||
if (!mImporterInvoker->startProcess(QLatin1String("openmw-iniimporter"), arguments, false))
|
||||
return;
|
||||
{
|
||||
resetProgressBar();
|
||||
}
|
||||
}
|
||||
|
||||
void Launcher::SettingsPage::on_browseButton_clicked()
|
||||
|
@ -197,38 +203,35 @@ void Launcher::SettingsPage::importerStarted()
|
|||
void Launcher::SettingsPage::importerFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||
{
|
||||
if (exitCode != 0 || exitStatus == QProcess::CrashExit)
|
||||
return;
|
||||
|
||||
// Importer may have changed settings, so refresh
|
||||
mMain->reloadSettings();
|
||||
|
||||
// Import selected data files from openmw.cfg
|
||||
if (addonsCheckBox->isChecked())
|
||||
{
|
||||
// Because we've reloaded settings, the current content list matches content in OpenMW.cfg
|
||||
QString oldContentListName = mLauncherSettings.getCurrentContentListName();
|
||||
if (mProfileDialog->exec() == QDialog::Accepted)
|
||||
{
|
||||
// remove the current content list to prevent duplication
|
||||
//... except, not allowed to delete the Default content list
|
||||
if (oldContentListName.compare(DataFilesPage::mDefaultContentListName) != 0)
|
||||
{
|
||||
mLauncherSettings.removeContentList(oldContentListName);
|
||||
}
|
||||
resetProgressBar();
|
||||
|
||||
const QString newContentListName(mProfileDialog->lineEdit()->text());
|
||||
const QStringList files(mGameSettings.getContentList());
|
||||
mLauncherSettings.setCurrentContentListName(newContentListName);
|
||||
mLauncherSettings.setContentList(newContentListName, files);
|
||||
QMessageBox msgBox;
|
||||
msgBox.setWindowTitle(tr("Importer finished"));
|
||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||
msgBox.setIcon(QMessageBox::Warning);
|
||||
msgBox.setText(tr("Failed to import settings from INI file."));
|
||||
msgBox.exec();
|
||||
}
|
||||
else
|
||||
{
|
||||
// indicate progress finished
|
||||
progressBar->setMaximum(1);
|
||||
progressBar->setValue(1);
|
||||
|
||||
// Make DataFiles Page load the new content list.
|
||||
mMain->reloadSettings();
|
||||
}
|
||||
// Importer may have changed settings, so refresh
|
||||
mMain->reloadSettings();
|
||||
}
|
||||
|
||||
importerButton->setEnabled(true);
|
||||
}
|
||||
|
||||
void Launcher::SettingsPage::resetProgressBar()
|
||||
{
|
||||
// set progress bar to 0 %
|
||||
progressBar->reset();
|
||||
}
|
||||
|
||||
void Launcher::SettingsPage::updateOkButton(const QString &text)
|
||||
{
|
||||
// We do this here because we need to access the profiles
|
||||
|
|
|
@ -29,6 +29,9 @@ namespace Launcher
|
|||
|
||||
void saveSettings();
|
||||
bool loadSettings();
|
||||
|
||||
/// set progress bar on page to 0%
|
||||
void resetProgressBar();
|
||||
|
||||
private slots:
|
||||
|
||||
|
@ -57,7 +60,6 @@ namespace Launcher
|
|||
MainDialog *mMain;
|
||||
TextInputDialog *mProfileDialog;
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
#include <sstream>
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/version.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
|
||||
namespace bfs = boost::filesystem;
|
||||
|
@ -660,7 +661,7 @@ std::string MwIniImporter::numberToString(int n) {
|
|||
return str.str();
|
||||
}
|
||||
|
||||
MwIniImporter::multistrmap MwIniImporter::loadIniFile(const std::string& filename) const {
|
||||
MwIniImporter::multistrmap MwIniImporter::loadIniFile(const boost::filesystem::path& filename) const {
|
||||
std::cout << "load ini file: " << filename << std::endl;
|
||||
|
||||
std::string section("");
|
||||
|
@ -719,7 +720,7 @@ MwIniImporter::multistrmap MwIniImporter::loadIniFile(const std::string& filenam
|
|||
return map;
|
||||
}
|
||||
|
||||
MwIniImporter::multistrmap MwIniImporter::loadCfgFile(const std::string& filename) {
|
||||
MwIniImporter::multistrmap MwIniImporter::loadCfgFile(const boost::filesystem::path& filename) {
|
||||
std::cout << "load cfg file: " << filename << std::endl;
|
||||
|
||||
MwIniImporter::multistrmap map;
|
||||
|
@ -825,10 +826,14 @@ void MwIniImporter::importArchives(multistrmap &cfg, const multistrmap &ini) con
|
|||
}
|
||||
}
|
||||
|
||||
void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini) const {
|
||||
std::vector<std::string> contentFiles;
|
||||
void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini, const boost::filesystem::path& iniFilename) const {
|
||||
std::vector<std::pair<std::time_t, std::string> > contentFiles;
|
||||
std::string baseGameFile("Game Files:GameFile");
|
||||
std::string gameFile("");
|
||||
std::time_t defaultTime = 0;
|
||||
|
||||
// assume the Game Files are all in a "Data Files" directory under the directory holding Morrowind.ini
|
||||
const boost::filesystem::path gameFilesDir(iniFilename.parent_path() /= "Data Files");
|
||||
|
||||
multistrmap::const_iterator it = ini.begin();
|
||||
for(int i=0; it != ini.end(); i++) {
|
||||
|
@ -845,18 +850,20 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini) co
|
|||
Misc::StringUtils::toLower(filetype);
|
||||
|
||||
if(filetype.compare("esm") == 0 || filetype.compare("esp") == 0) {
|
||||
contentFiles.push_back(*entry);
|
||||
boost::filesystem::path filepath(gameFilesDir);
|
||||
filepath /= *entry;
|
||||
contentFiles.push_back(std::make_pair(lastWriteTime(filepath, defaultTime), *entry));
|
||||
}
|
||||
}
|
||||
|
||||
gameFile = "";
|
||||
}
|
||||
|
||||
cfg.erase("content");
|
||||
cfg.insert( std::make_pair("content", std::vector<std::string>() ) );
|
||||
|
||||
for(std::vector<std::string>::const_iterator it=contentFiles.begin(); it!=contentFiles.end(); ++it) {
|
||||
cfg["content"].push_back(*it);
|
||||
// this will sort files by time order first, then alphabetical (maybe), I suspect non ASCII filenames will be stuffed.
|
||||
sort(contentFiles.begin(), contentFiles.end());
|
||||
for(std::vector<std::pair<std::time_t, std::string> >::const_iterator it=contentFiles.begin(); it!=contentFiles.end(); ++it) {
|
||||
cfg["content"].push_back(it->second);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -873,3 +880,27 @@ void MwIniImporter::setInputEncoding(const ToUTF8::FromType &encoding)
|
|||
{
|
||||
mEncoding = encoding;
|
||||
}
|
||||
|
||||
std::time_t MwIniImporter::lastWriteTime(const boost::filesystem::path& filename, std::time_t defaultTime)
|
||||
{
|
||||
std::time_t writeTime(defaultTime);
|
||||
if (boost::filesystem::exists(filename))
|
||||
{
|
||||
// FixMe: remove #if when Boost dependency for Linux builds updated
|
||||
// This allows Linux to build until then
|
||||
#if (BOOST_VERSION >= 104800)
|
||||
// need to resolve any symlinks so that we get time of file, not symlink
|
||||
boost::filesystem::path resolved = boost::filesystem::canonical(filename);
|
||||
#else
|
||||
boost::filesystem::path resolved = filename;
|
||||
#endif
|
||||
writeTime = boost::filesystem::last_write_time(resolved);
|
||||
std::cout << "content file: " << resolved << " timestamp = (" << writeTime <<
|
||||
") " << asctime(localtime(&writeTime)) << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "content file: " << filename << " not found" << std::endl;
|
||||
}
|
||||
return writeTime;
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
#include <vector>
|
||||
#include <exception>
|
||||
#include <iosfwd>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
#include <components/to_utf8/to_utf8.hpp>
|
||||
|
||||
|
@ -17,17 +18,22 @@ class MwIniImporter {
|
|||
MwIniImporter();
|
||||
void setInputEncoding(const ToUTF8::FromType& encoding);
|
||||
void setVerbose(bool verbose);
|
||||
multistrmap loadIniFile(const std::string& filename) const;
|
||||
static multistrmap loadCfgFile(const std::string& filename);
|
||||
multistrmap loadIniFile(const boost::filesystem::path& filename) const;
|
||||
static multistrmap loadCfgFile(const boost::filesystem::path& filename);
|
||||
void merge(multistrmap &cfg, const multistrmap &ini) const;
|
||||
void mergeFallback(multistrmap &cfg, const multistrmap &ini) const;
|
||||
void importGameFiles(multistrmap &cfg, const multistrmap &ini) const;
|
||||
void importGameFiles(multistrmap &cfg, const multistrmap &ini,
|
||||
const boost::filesystem::path& iniFilename) const;
|
||||
void importArchives(multistrmap &cfg, const multistrmap &ini) const;
|
||||
static void writeToFile(std::ostream &out, const multistrmap &cfg);
|
||||
|
||||
private:
|
||||
static void insertMultistrmap(multistrmap &cfg, const std::string& key, const std::string& value);
|
||||
static std::string numberToString(int n);
|
||||
|
||||
/// \return file's "last modified time", used in original MW to determine plug-in load order
|
||||
static std::time_t lastWriteTime(const boost::filesystem::path& filename, std::time_t defaultTime);
|
||||
|
||||
bool mVerbose;
|
||||
strmap mMergeMap;
|
||||
std::vector<std::string> mMergeFallback;
|
||||
|
|
|
@ -93,8 +93,8 @@ int wmain(int argc, wchar_t *wargv[]) {
|
|||
|
||||
bpo::notify(vm);
|
||||
|
||||
std::string iniFile = vm["ini"].as<std::string>();
|
||||
std::string cfgFile = vm["cfg"].as<std::string>();
|
||||
boost::filesystem::path iniFile(vm["ini"].as<std::string>());
|
||||
boost::filesystem::path cfgFile(vm["cfg"].as<std::string>());
|
||||
|
||||
// if no output is given, write back to cfg file
|
||||
std::string outputFile(vm["output"].as<std::string>());
|
||||
|
@ -123,7 +123,7 @@ int wmain(int argc, wchar_t *wargv[]) {
|
|||
importer.mergeFallback(cfg, ini);
|
||||
|
||||
if(vm.count("game-files")) {
|
||||
importer.importGameFiles(cfg, ini);
|
||||
importer.importGameFiles(cfg, ini, iniFile);
|
||||
}
|
||||
|
||||
if(!vm.count("no-archives")) {
|
||||
|
|
|
@ -58,9 +58,6 @@ CSMDoc::Operation *CSMTools::Tools::getVerifier()
|
|||
mandatoryIds.push_back ("GameHour");
|
||||
mandatoryIds.push_back ("Month");
|
||||
mandatoryIds.push_back ("PCRace");
|
||||
mandatoryIds.push_back ("PCVampire");
|
||||
mandatoryIds.push_back ("PCWerewolf");
|
||||
mandatoryIds.push_back ("PCYear");
|
||||
|
||||
mVerifier->appendStage (new MandatoryIdStage (mData.getGlobals(),
|
||||
CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Globals), mandatoryIds));
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <string>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
|
@ -72,8 +73,11 @@ void CSVDoc::AdjusterWidget::setName (const QString& name, bool addon)
|
|||
{
|
||||
boost::filesystem::path path (name.toUtf8().data());
|
||||
|
||||
bool isLegacyPath = (path.extension() == ".esm" ||
|
||||
path.extension() == ".esp");
|
||||
std::string extension = path.extension().string();
|
||||
boost::algorithm::to_lower(extension);
|
||||
|
||||
bool isLegacyPath = (extension == ".esm" ||
|
||||
extension == ".esp");
|
||||
|
||||
bool isFilePathChanged = (path.parent_path().string() != mLocalData.string());
|
||||
|
||||
|
|
|
@ -96,7 +96,7 @@ QWidget *CSVDoc::StartupDialogue::createTools()
|
|||
|
||||
CSVDoc::StartupDialogue::StartupDialogue() : mWidth (0), mColumn (2)
|
||||
{
|
||||
setWindowTitle ("Open CS");
|
||||
setWindowTitle ("OpenMW-CS");
|
||||
|
||||
QVBoxLayout *layout = new QVBoxLayout (this);
|
||||
|
||||
|
|
|
@ -268,6 +268,8 @@ namespace MWBase
|
|||
virtual MWWorld::Ptr getFacedObject() = 0;
|
||||
///< Return pointer to the object the player is looking at, if it is within activation range
|
||||
|
||||
virtual float getMaxActivationDistance() = 0;
|
||||
|
||||
/// Returns a pointer to the object the provided object would hit (if within the
|
||||
/// specified distance), and the point where the hit occurs. This will attempt to
|
||||
/// use the "Head" node, or alternatively the "Bip01 Head" node as a basis.
|
||||
|
@ -551,7 +553,7 @@ namespace MWBase
|
|||
virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const Ogre::Vector3& worldPos) = 0;
|
||||
|
||||
virtual void explodeSpell (const Ogre::Vector3& origin, const ESM::EffectList& effects,
|
||||
const MWWorld::Ptr& caster, int rangeType, const std::string& id, const std::string& sourceName) = 0;
|
||||
const MWWorld::Ptr& caster, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName) = 0;
|
||||
|
||||
virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor) = 0;
|
||||
|
||||
|
|
|
@ -671,4 +671,14 @@ namespace MWGui
|
|||
mEnemyHealthTimer = -1;
|
||||
}
|
||||
|
||||
void HUD::customMarkerCreated(MyGUI::Widget *marker)
|
||||
{
|
||||
marker->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMapClicked);
|
||||
}
|
||||
|
||||
void HUD::doorMarkerCreated(MyGUI::Widget *marker)
|
||||
{
|
||||
marker->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMapClicked);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -119,6 +119,10 @@ namespace MWGui
|
|||
void onMagicClicked(MyGUI::Widget* _sender);
|
||||
void onMapClicked(MyGUI::Widget* _sender);
|
||||
|
||||
// LocalMapBase
|
||||
virtual void customMarkerCreated(MyGUI::Widget* marker);
|
||||
virtual void doorMarkerCreated(MyGUI::Widget* marker);
|
||||
|
||||
void updateEnemyHealthBar();
|
||||
|
||||
void updatePositions();
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace MWGui
|
|||
{
|
||||
JailScreen::JailScreen()
|
||||
: WindowBase("openmw_jail_screen.layout"),
|
||||
mTimeAdvancer(0.0125),
|
||||
mTimeAdvancer(0.01),
|
||||
mDays(1),
|
||||
mFadeTimeRemaining(0)
|
||||
{
|
||||
|
@ -39,7 +39,7 @@ namespace MWGui
|
|||
mFadeTimeRemaining = 0.5;
|
||||
|
||||
setVisible(false);
|
||||
mProgressBar->setScrollRange(days*24+1);
|
||||
mProgressBar->setScrollRange(100+1);
|
||||
mProgressBar->setScrollPosition(0);
|
||||
mProgressBar->setTrackSize(0);
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ namespace MWGui
|
|||
MWBase::Environment::get().getWorld()->teleportToClosestMarker(player, "prisonmarker");
|
||||
|
||||
setVisible(true);
|
||||
mTimeAdvancer.run(mDays*24);
|
||||
mTimeAdvancer.run(100);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -199,7 +199,7 @@ struct JournalViewModelImpl : JournalViewModel
|
|||
|
||||
};
|
||||
|
||||
void visitQuestNames (bool active_only, boost::function <void (const std::string&)> visitor) const
|
||||
void visitQuestNames (bool active_only, boost::function <void (const std::string&, bool)> visitor) const
|
||||
{
|
||||
MWBase::Journal * journal = MWBase::Environment::get ().getJournal ();
|
||||
|
||||
|
@ -231,7 +231,7 @@ struct JournalViewModelImpl : JournalViewModel
|
|||
if (visitedQuests.find(quest.getName()) != visitedQuests.end())
|
||||
continue;
|
||||
|
||||
visitor (quest.getName());
|
||||
visitor (quest.getName(), isFinished);
|
||||
|
||||
visitedQuests.insert(quest.getName());
|
||||
}
|
||||
|
|
|
@ -67,8 +67,8 @@ namespace MWGui
|
|||
/// returns true if their are no journal entries to display
|
||||
virtual bool isEmpty () const = 0;
|
||||
|
||||
/// walks the active and optionally completed, quests providing the name
|
||||
virtual void visitQuestNames (bool active_only, boost::function <void (const std::string&)> visitor) const = 0;
|
||||
/// walks the active and optionally completed, quests providing the name and completed status
|
||||
virtual void visitQuestNames (bool active_only, boost::function <void (const std::string&, bool)> visitor) const = 0;
|
||||
|
||||
/// walks over the journal entries related to all quests with the given name
|
||||
/// If \a questName is empty, simply visits all journal entries
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <utility>
|
||||
|
||||
#include <MyGUI_TextBox.h>
|
||||
#include <MyGUI_Button.h>
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/function.hpp>
|
||||
|
@ -428,11 +429,24 @@ namespace
|
|||
AddNamesToList(Gui::MWList* list) : mList(list) {}
|
||||
|
||||
Gui::MWList* mList;
|
||||
void operator () (const std::string& name)
|
||||
void operator () (const std::string& name, bool finished=false)
|
||||
{
|
||||
mList->addItem(name);
|
||||
}
|
||||
};
|
||||
struct SetNamesInactive
|
||||
{
|
||||
SetNamesInactive(Gui::MWList* list) : mList(list) {}
|
||||
|
||||
Gui::MWList* mList;
|
||||
void operator () (const std::string& name, bool finished)
|
||||
{
|
||||
if (finished)
|
||||
{
|
||||
mList->getItemWidget(name)->setStateSelected(true);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void notifyQuests(MyGUI::Widget* _sender)
|
||||
{
|
||||
|
@ -453,6 +467,12 @@ namespace
|
|||
mModel->visitQuestNames(!mAllQuests, add);
|
||||
|
||||
list->adjustSize();
|
||||
|
||||
if (mAllQuests)
|
||||
{
|
||||
SetNamesInactive setInactive(list);
|
||||
mModel->visitQuestNames(!mAllQuests, setInactive);
|
||||
}
|
||||
}
|
||||
|
||||
void notifyShowAll(MyGUI::Widget* _sender)
|
||||
|
|
|
@ -102,6 +102,31 @@ namespace MWGui
|
|||
updateSpells();
|
||||
}
|
||||
|
||||
void SpellWindow::askDeleteSpell(const std::string &spellId)
|
||||
{
|
||||
// delete spell, if allowed
|
||||
const ESM::Spell* spell =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(spellId);
|
||||
|
||||
if (spell->mData.mFlags & ESM::Spell::F_Always
|
||||
|| spell->mData.mType == ESM::Spell::ST_Power)
|
||||
{
|
||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sDeleteSpellError}");
|
||||
}
|
||||
else
|
||||
{
|
||||
// ask for confirmation
|
||||
mSpellToDelete = spellId;
|
||||
ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog();
|
||||
std::string question = MWBase::Environment::get().getWindowManager()->getGameSettingString("sQuestionDeleteSpell", "Delete %s?");
|
||||
question = boost::str(boost::format(question) % spell->mName);
|
||||
dialog->open(question);
|
||||
dialog->eventOkClicked.clear();
|
||||
dialog->eventOkClicked += MyGUI::newDelegate(this, &SpellWindow::onDeleteSpellAccept);
|
||||
dialog->eventCancelClicked.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void SpellWindow::onModelIndexSelected(SpellModel::ModelIndex index)
|
||||
{
|
||||
const Spell& spell = mSpellView->getModel()->getItem(index);
|
||||
|
@ -111,43 +136,19 @@ namespace MWGui
|
|||
}
|
||||
else
|
||||
{
|
||||
onSpellSelected(spell.mId);
|
||||
if (MyGUI::InputManager::getInstance().isShiftPressed())
|
||||
askDeleteSpell(spell.mId);
|
||||
else
|
||||
onSpellSelected(spell.mId);
|
||||
}
|
||||
}
|
||||
|
||||
void SpellWindow::onSpellSelected(const std::string& spellId)
|
||||
{
|
||||
if (MyGUI::InputManager::getInstance().isShiftPressed())
|
||||
{
|
||||
// delete spell, if allowed
|
||||
const ESM::Spell* spell =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(spellId);
|
||||
|
||||
if (spell->mData.mFlags & ESM::Spell::F_Always
|
||||
|| spell->mData.mType == ESM::Spell::ST_Power)
|
||||
{
|
||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sDeleteSpellError}");
|
||||
}
|
||||
else
|
||||
{
|
||||
// ask for confirmation
|
||||
mSpellToDelete = spellId;
|
||||
ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog();
|
||||
std::string question = MWBase::Environment::get().getWindowManager()->getGameSettingString("sQuestionDeleteSpell", "Delete %s?");
|
||||
question = boost::str(boost::format(question) % spell->mName);
|
||||
dialog->open(question);
|
||||
dialog->eventOkClicked.clear();
|
||||
dialog->eventOkClicked += MyGUI::newDelegate(this, &SpellWindow::onDeleteSpellAccept);
|
||||
dialog->eventCancelClicked.clear();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player);
|
||||
store.setSelectedEnchantItem(store.end());
|
||||
MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player)));
|
||||
}
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player);
|
||||
store.setSelectedEnchantItem(store.end());
|
||||
MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player)));
|
||||
|
||||
updateSpells();
|
||||
}
|
||||
|
@ -184,6 +185,10 @@ namespace MWGui
|
|||
return;
|
||||
selected = (selected + itemcount) % itemcount;
|
||||
|
||||
onModelIndexSelected(selected);
|
||||
const Spell& spell = mSpellView->getModel()->getItem(selected);
|
||||
if (spell.mType == Spell::Type_EnchantedItem)
|
||||
onEnchantedItemSelected(spell.mItem, spell.mActive);
|
||||
else
|
||||
onSpellSelected(spell.mId);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ namespace MWGui
|
|||
void onSpellSelected(const std::string& spellId);
|
||||
void onModelIndexSelected(SpellModel::ModelIndex index);
|
||||
void onDeleteSpellAccept();
|
||||
void askDeleteSpell(const std::string& spellId);
|
||||
|
||||
virtual void onPinToggled();
|
||||
virtual void onTitleDoubleClicked();
|
||||
|
|
|
@ -207,16 +207,6 @@ namespace MWMechanics
|
|||
const MWWorld::Class& actorClass = actor.getClass();
|
||||
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||
|
||||
// can't fight if attacker can't go where target is. E.g. A fish can't attack person on land.
|
||||
if (!actorClass.isNpc() && !MWMechanics::isEnvironmentCompatible(actor, target))
|
||||
{
|
||||
actorClass.getCreatureStats(actor).setAttackingOrSpell(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//Update every frame
|
||||
bool& combatMove = storage.mCombatMove;
|
||||
|
@ -476,6 +466,19 @@ namespace MWMechanics
|
|||
// for distant combat we should know if target is in LOS even if distToTarget < rangeAttack
|
||||
bool inLOS = distantCombat ? world->getLOS(actor, target) : true;
|
||||
|
||||
// can't fight if attacker can't go where target is. E.g. A fish can't attack person on land.
|
||||
if (distToTarget >= rangeAttack
|
||||
&& !actorClass.isNpc() && !MWMechanics::isEnvironmentCompatible(actor, target))
|
||||
{
|
||||
// TODO: start fleeing?
|
||||
movement.mPosition[0] = 0;
|
||||
movement.mPosition[1] = 0;
|
||||
movement.mPosition[2] = 0;
|
||||
readyToAttack = false;
|
||||
actorClass.getCreatureStats(actor).setAttackingOrSpell(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
// (within attack dist) || (not quite attack dist while following)
|
||||
if(inLOS && (distToTarget < rangeAttack || (distToTarget <= rangeFollow && followTarget && !isStuck)))
|
||||
{
|
||||
|
|
|
@ -72,6 +72,8 @@ namespace MWMechanics
|
|||
// Used by effect management classes (ActiveSpells, InventoryStore, Spells) to list active effect sources for GUI display
|
||||
struct EffectSourceVisitor
|
||||
{
|
||||
virtual ~EffectSourceVisitor() { }
|
||||
|
||||
virtual void visit (MWMechanics::EffectKey key,
|
||||
const std::string& sourceName, const std::string& sourceId, int casterActorId,
|
||||
float magnitude, float remainingTime = -1, float totalTime = -1) = 0;
|
||||
|
|
|
@ -309,9 +309,11 @@ namespace MWMechanics
|
|||
for (std::vector<ESM::ENAMstruct>::const_iterator iter (effects.mList.begin());
|
||||
iter!=effects.mList.end(); ++iter)
|
||||
{
|
||||
if (iter->mRange != range)
|
||||
continue;
|
||||
found = true;
|
||||
if (iter->mRange == range)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
return;
|
||||
|
@ -592,6 +594,7 @@ namespace MWMechanics
|
|||
value.restore(magnitude);
|
||||
target.getClass().getCreatureStats(target).setAttribute(attribute, value);
|
||||
}
|
||||
// TODO: refactor the effect tick functions in Actors so they can be reused here
|
||||
else if (effectId == ESM::MagicEffect::DamageHealth)
|
||||
{
|
||||
applyDynamicStatsEffect(0, target, magnitude * -1);
|
||||
|
@ -681,7 +684,7 @@ namespace MWMechanics
|
|||
void CastSpell::applyDynamicStatsEffect(int attribute, const MWWorld::Ptr& target, float magnitude)
|
||||
{
|
||||
DynamicStat<float> value = target.getClass().getCreatureStats(target).getDynamic(attribute);
|
||||
value.modify(magnitude);
|
||||
value.setCurrent(value.getCurrent()+magnitude, attribute == 2);
|
||||
target.getClass().getCreatureStats(target).setDynamic(attribute, value);
|
||||
}
|
||||
|
||||
|
@ -766,8 +769,7 @@ namespace MWMechanics
|
|||
|
||||
if (!mTarget.isEmpty())
|
||||
{
|
||||
if (!mTarget.getClass().isActor() || !mTarget.getClass().getCreatureStats(mTarget).isDead())
|
||||
inflict(mTarget, mCaster, enchantment->mEffects, ESM::RT_Touch);
|
||||
inflict(mTarget, mCaster, enchantment->mEffects, ESM::RT_Touch);
|
||||
}
|
||||
|
||||
std::string projectileModel;
|
||||
|
@ -851,10 +853,7 @@ namespace MWMechanics
|
|||
|
||||
if (!mTarget.isEmpty())
|
||||
{
|
||||
if (!mTarget.getClass().isActor() || !mTarget.getClass().getCreatureStats(mTarget).isDead())
|
||||
{
|
||||
inflict(mTarget, mCaster, spell->mEffects, ESM::RT_Touch);
|
||||
}
|
||||
inflict(mTarget, mCaster, spell->mEffects, ESM::RT_Touch);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -51,6 +51,10 @@ namespace MWMechanics
|
|||
|
||||
}
|
||||
|
||||
UpdateSummonedCreatures::~UpdateSummonedCreatures()
|
||||
{
|
||||
}
|
||||
|
||||
void UpdateSummonedCreatures::visit(EffectKey key, const std::string &sourceName, const std::string &sourceId, int casterActorId, float magnitude, float remainingTime, float totalTime)
|
||||
{
|
||||
if (isSummoningEffect(key.mId) && magnitude > 0)
|
||||
|
|
|
@ -14,6 +14,7 @@ namespace MWMechanics
|
|||
struct UpdateSummonedCreatures : public EffectSourceVisitor
|
||||
{
|
||||
UpdateSummonedCreatures(const MWWorld::Ptr& actor);
|
||||
virtual ~UpdateSummonedCreatures();
|
||||
|
||||
virtual void visit (MWMechanics::EffectKey key,
|
||||
const std::string& sourceName, const std::string& sourceId, int casterActorId,
|
||||
|
|
|
@ -120,14 +120,12 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b
|
|||
// Set default texture filtering options
|
||||
TextureFilterOptions tfo;
|
||||
std::string filter = Settings::Manager::getString("texture filtering", "General");
|
||||
#ifndef ANDROID
|
||||
|
||||
if (filter == "anisotropic") tfo = TFO_ANISOTROPIC;
|
||||
else if (filter == "trilinear") tfo = TFO_TRILINEAR;
|
||||
else if (filter == "bilinear") tfo = TFO_BILINEAR;
|
||||
else /*if (filter == "none")*/ tfo = TFO_NONE;
|
||||
#else
|
||||
tfo = TFO_NONE;
|
||||
#endif
|
||||
|
||||
MaterialManager::getSingleton().setDefaultTextureFiltering(tfo);
|
||||
MaterialManager::getSingleton().setDefaultAnisotropy( (filter == "anisotropic") ? Settings::Manager::getInt("anisotropy", "General") : 1 );
|
||||
|
||||
|
|
|
@ -113,7 +113,7 @@ void RippleSimulation::update(float dt, Ogre::Vector2 position)
|
|||
position.z = 0; // Z is set by the Scene Node
|
||||
rotSpeed = mRippleRotSpeed;
|
||||
rotation = Ogre::Radian(Ogre::Math::RangeRandom(-Ogre::Math::PI, Ogre::Math::PI));
|
||||
created->setDimensions(50,50);
|
||||
created->setDimensions(mParticleSystem->getDefaultWidth(), mParticleSystem->getDefaultHeight());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,16 +1,39 @@
|
|||
#include "actiontrap.hpp"
|
||||
|
||||
#include "../mwmechanics/spellcasting.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
||||
namespace MWWorld
|
||||
{
|
||||
|
||||
void ActionTrap::executeImp(const Ptr &actor)
|
||||
{
|
||||
MWMechanics::CastSpell cast(mTrapSource, actor);
|
||||
cast.mHitPosition = Ogre::Vector3(actor.getRefData().getPosition().pos);
|
||||
cast.cast(mSpellId);
|
||||
Ogre::Vector3 actorPosition(actor.getRefData().getPosition().pos);
|
||||
Ogre::Vector3 trapPosition(mTrapSource.getRefData().getPosition().pos);
|
||||
float activationDistance = MWBase::Environment::get().getWorld()->getMaxActivationDistance();
|
||||
|
||||
// GUI calcs if object in activation distance include object and player geometry
|
||||
const float fudgeFactor = 1.25f;
|
||||
|
||||
// Hack: if actor is beyond activation range, then assume actor is using telekinesis
|
||||
// to open door/container.
|
||||
// Note, can't just detonate the trap at the trapped object's location and use the blast
|
||||
// radius, because for most trap spells this is 1 foot, much less than the activation distance.
|
||||
if (trapPosition.distance(actorPosition) < (activationDistance * fudgeFactor))
|
||||
{
|
||||
// assume actor touched trap
|
||||
MWMechanics::CastSpell cast(mTrapSource, actor);
|
||||
cast.mHitPosition = actorPosition;
|
||||
cast.cast(mSpellId);
|
||||
}
|
||||
else
|
||||
{
|
||||
// assume telekinesis used
|
||||
MWMechanics::CastSpell cast(mTrapSource, mTrapSource);
|
||||
cast.mHitPosition = trapPosition;
|
||||
cast.cast(mSpellId);
|
||||
}
|
||||
mTrapSource.getCellRef().setTrap("");
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <typeinfo>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include "livecellref.hpp"
|
||||
|
@ -181,7 +183,12 @@ namespace MWWorld
|
|||
|
||||
template <class T>
|
||||
CellRefList<T>& get() {
|
||||
throw std::runtime_error ("Storage for this type not exist in cells");
|
||||
throw std::runtime_error ("Storage for type " + std::string(typeid(T).name())+ " does not exist in cells");
|
||||
}
|
||||
|
||||
template <class T>
|
||||
const CellRefList<T>& getReadOnly() {
|
||||
throw std::runtime_error ("Read Only CellRefList access not available for type " + std::string(typeid(T).name()) );
|
||||
}
|
||||
|
||||
bool isPointConnected(const int start, const int end) const;
|
||||
|
@ -357,6 +364,12 @@ namespace MWWorld
|
|||
return mWeapons;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline const CellRefList<ESM::Door>& CellStore::getReadOnly<ESM::Door>()
|
||||
{
|
||||
return mDoors;
|
||||
}
|
||||
|
||||
bool operator== (const CellStore& left, const CellStore& right);
|
||||
bool operator!= (const CellStore& left, const CellStore& right);
|
||||
}
|
||||
|
|
|
@ -33,11 +33,11 @@ namespace MWWorld
|
|||
MWScript::Locals mLocals; // if we find the overhead of heaving a locals
|
||||
// object in the refdata of refs without a script,
|
||||
// we can make this a pointer later.
|
||||
bool mDeleted; // separate delete flag used for deletion by a content file
|
||||
bool mHasLocals;
|
||||
bool mEnabled;
|
||||
int mCount; // 0: deleted
|
||||
|
||||
bool mDeleted; // separate delete flag used for deletion by a content file
|
||||
|
||||
ESM::Position mPosition;
|
||||
|
||||
|
|
|
@ -230,7 +230,7 @@ namespace MWWorld
|
|||
cell->getCell()->getGridX(),
|
||||
cell->getCell()->getGridY()
|
||||
);
|
||||
if (land) {
|
||||
if (land && land->mDataTypes&ESM::Land::DATA_VHGT) {
|
||||
// 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;
|
||||
|
|
|
@ -423,6 +423,19 @@ namespace MWWorld
|
|||
globals["werewolfclawmult"] = ESM::Variant(25.f);
|
||||
globals["pcknownwerewolf"] = ESM::Variant(0);
|
||||
|
||||
// following should exist in all versions of MW, but not necessarily in TCs
|
||||
globals["gamehour"] = ESM::Variant(0.f);
|
||||
globals["timescale"] = ESM::Variant(30.f);
|
||||
globals["day"] = ESM::Variant(1);
|
||||
globals["month"] = ESM::Variant(1);
|
||||
globals["year"] = ESM::Variant(1);
|
||||
globals["pcrace"] = ESM::Variant(0);
|
||||
globals["pchascrimegold"] = ESM::Variant(0);
|
||||
globals["pchasgolddiscount"] = ESM::Variant(0);
|
||||
globals["crimegolddiscount"] = ESM::Variant(0);
|
||||
globals["crimegoldturnin"] = ESM::Variant(0);
|
||||
globals["pchasturnin"] = ESM::Variant(0);
|
||||
|
||||
for (std::map<std::string, ESM::Variant>::iterator it = gmst.begin(); it != gmst.end(); ++it)
|
||||
{
|
||||
if (!mStore.get<ESM::GameSetting>().search(it->first))
|
||||
|
@ -2784,18 +2797,45 @@ namespace MWWorld
|
|||
{
|
||||
if (cell->isExterior())
|
||||
return false;
|
||||
MWWorld::CellRefList<ESM::Door>& doors = cell->get<ESM::Door>();
|
||||
CellRefList<ESM::Door>::List& refList = doors.mList;
|
||||
|
||||
// Check if any door in the cell leads to an exterior directly
|
||||
for (CellRefList<ESM::Door>::List::iterator it = refList.begin(); it != refList.end(); ++it)
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::Door>& ref = *it;
|
||||
if (ref.mRef.getTeleport() && ref.mRef.getDestCell().empty())
|
||||
{
|
||||
ESM::Position pos = ref.mRef.getDoorDest();
|
||||
result = Ogre::Vector3(pos.pos);
|
||||
return true;
|
||||
// Search for a 'nearest' exterior, counting each cell between the starting
|
||||
// cell and the exterior as a distance of 1. Will fail for isolated interiors.
|
||||
std::set< std::string >checkedCells;
|
||||
std::set< std::string >currentCells;
|
||||
std::set< std::string >nextCells;
|
||||
nextCells.insert( cell->getCell()->mName );
|
||||
|
||||
while ( !nextCells.empty() ) {
|
||||
currentCells = nextCells;
|
||||
nextCells.clear();
|
||||
for( std::set< std::string >::const_iterator i = currentCells.begin(); i != currentCells.end(); ++i ) {
|
||||
MWWorld::CellStore *next = getInterior( *i );
|
||||
if ( !next ) continue;
|
||||
|
||||
const MWWorld::CellRefList<ESM::Door>& doors = next->getReadOnly<ESM::Door>();
|
||||
const CellRefList<ESM::Door>::List& refList = doors.mList;
|
||||
|
||||
// Check if any door in the cell leads to an exterior directly
|
||||
for (CellRefList<ESM::Door>::List::const_iterator it = refList.begin(); it != refList.end(); ++it)
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Door>& ref = *it;
|
||||
if (!ref.mRef.getTeleport()) continue;
|
||||
|
||||
if (ref.mRef.getDestCell().empty())
|
||||
{
|
||||
ESM::Position pos = ref.mRef.getDoorDest();
|
||||
result = Ogre::Vector3(pos.pos);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string dest = ref.mRef.getDestCell();
|
||||
if ( !checkedCells.count(dest) && !currentCells.count(dest) )
|
||||
nextCells.insert(dest);
|
||||
}
|
||||
}
|
||||
|
||||
checkedCells.insert( *i );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2803,33 +2843,102 @@ namespace MWWorld
|
|||
return false;
|
||||
}
|
||||
|
||||
void World::teleportToClosestMarker (const MWWorld::Ptr& ptr,
|
||||
const std::string& id)
|
||||
MWWorld::Ptr World::getClosestMarker( const MWWorld::Ptr &ptr, const std::string &id )
|
||||
{
|
||||
Ogre::Vector3 worldPos;
|
||||
if (!findInteriorPositionInWorldSpace(ptr.getCell(), worldPos))
|
||||
worldPos = mPlayer->getLastKnownExteriorPosition();
|
||||
if ( ptr.getCell()->isExterior() ) {
|
||||
return getClosestMarkerFromExteriorPosition(mPlayer->getLastKnownExteriorPosition(), id);
|
||||
}
|
||||
|
||||
// Search for a 'nearest' marker, counting each cell between the starting
|
||||
// cell and the exterior as a distance of 1. If an exterior is found, jump
|
||||
// to the nearest exterior marker, without further interior searching.
|
||||
std::set< std::string >checkedCells;
|
||||
std::set< std::string >currentCells;
|
||||
std::set< std::string >nextCells;
|
||||
MWWorld::Ptr closestMarker;
|
||||
|
||||
nextCells.insert( ptr.getCell()->getCell()->mName );
|
||||
while ( !nextCells.empty() ) {
|
||||
currentCells = nextCells;
|
||||
nextCells.clear();
|
||||
for( std::set< std::string >::const_iterator i = currentCells.begin(); i != currentCells.end(); ++i ) {
|
||||
MWWorld::CellStore *next = getInterior( *i );
|
||||
checkedCells.insert( *i );
|
||||
if ( !next ) continue;
|
||||
|
||||
closestMarker = next->search( id );
|
||||
if ( !closestMarker.isEmpty() )
|
||||
{
|
||||
return closestMarker;
|
||||
}
|
||||
|
||||
const MWWorld::CellRefList<ESM::Door>& doors = next->getReadOnly<ESM::Door>();
|
||||
const CellRefList<ESM::Door>::List& doorList = doors.mList;
|
||||
|
||||
// Check if any door in the cell leads to an exterior directly
|
||||
for (CellRefList<ESM::Door>::List::const_iterator it = doorList.begin(); it != doorList.end(); ++it)
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Door>& ref = *it;
|
||||
|
||||
if (!ref.mRef.getTeleport()) continue;
|
||||
|
||||
if (ref.mRef.getDestCell().empty())
|
||||
{
|
||||
Ogre::Vector3 worldPos = Ogre::Vector3(ref.mRef.getDoorDest().pos);
|
||||
return getClosestMarkerFromExteriorPosition(worldPos, id);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string dest = ref.mRef.getDestCell();
|
||||
if ( !checkedCells.count(dest) && !currentCells.count(dest) )
|
||||
nextCells.insert(dest);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return MWWorld::Ptr();
|
||||
}
|
||||
|
||||
MWWorld::Ptr World::getClosestMarkerFromExteriorPosition( const Ogre::Vector3 worldPos, const std::string &id ) {
|
||||
MWWorld::Ptr closestMarker;
|
||||
float closestDistance = FLT_MAX;
|
||||
|
||||
std::vector<MWWorld::Ptr> markers;
|
||||
mCells.getExteriorPtrs(id, markers);
|
||||
|
||||
for (std::vector<MWWorld::Ptr>::iterator it = markers.begin(); it != markers.end(); ++it)
|
||||
for (std::vector<MWWorld::Ptr>::iterator it2 = markers.begin(); it2 != markers.end(); ++it2)
|
||||
{
|
||||
ESM::Position pos = it->getRefData().getPosition();
|
||||
ESM::Position pos = it2->getRefData().getPosition();
|
||||
Ogre::Vector3 markerPos = Ogre::Vector3(pos.pos);
|
||||
float distance = worldPos.squaredDistance(markerPos);
|
||||
if (distance < closestDistance)
|
||||
{
|
||||
closestDistance = distance;
|
||||
closestMarker = *it;
|
||||
closestMarker = *it2;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MWWorld::ActionTeleport action("", closestMarker.getRefData().getPosition());
|
||||
return closestMarker;
|
||||
}
|
||||
|
||||
|
||||
void World::teleportToClosestMarker (const MWWorld::Ptr& ptr,
|
||||
const std::string& id)
|
||||
{
|
||||
MWWorld::Ptr closestMarker = getClosestMarker( ptr, id );
|
||||
|
||||
if ( closestMarker.isEmpty() )
|
||||
{
|
||||
std::cerr << "Failed to teleport: no closest marker found" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string cellName;
|
||||
if ( !closestMarker.mCell->isExterior() )
|
||||
cellName = closestMarker.mCell->getCell()->mName;
|
||||
|
||||
MWWorld::ActionTeleport action(cellName, closestMarker.getRefData().getPosition());
|
||||
action.execute(ptr);
|
||||
}
|
||||
|
||||
|
@ -2978,31 +3087,26 @@ namespace MWWorld
|
|||
|
||||
void World::confiscateStolenItems(const Ptr &ptr)
|
||||
{
|
||||
Ogre::Vector3 playerPos;
|
||||
if (!findInteriorPositionInWorldSpace(ptr.getCell(), playerPos))
|
||||
playerPos = mPlayer->getLastKnownExteriorPosition();
|
||||
|
||||
MWWorld::Ptr closestChest;
|
||||
float closestDistance = FLT_MAX;
|
||||
|
||||
//Find closest stolen_goods chest
|
||||
std::vector<MWWorld::Ptr> chests;
|
||||
mCells.getInteriorPtrs("stolen_goods", chests);
|
||||
|
||||
Ogre::Vector3 chestPos;
|
||||
for (std::vector<MWWorld::Ptr>::iterator it = chests.begin(); it != chests.end(); ++it)
|
||||
MWWorld::Ptr prisonMarker = getClosestMarker( ptr, "prisonmarker" );
|
||||
if ( prisonMarker.isEmpty() )
|
||||
{
|
||||
if (!findInteriorPositionInWorldSpace(it->getCell(), chestPos))
|
||||
continue;
|
||||
|
||||
float distance = playerPos.squaredDistance(chestPos);
|
||||
if (distance < closestDistance)
|
||||
{
|
||||
closestDistance = distance;
|
||||
closestChest = *it;
|
||||
}
|
||||
std::cerr << "Failed to confiscate items: no closest prison marker found." << std::endl;
|
||||
return;
|
||||
}
|
||||
std::string prisonName = prisonMarker.mRef->mRef.getDestCell();
|
||||
if ( prisonName.empty() )
|
||||
{
|
||||
std::cerr << "Failed to confiscate items: prison marker not linked to prison interior" << std::endl;
|
||||
return;
|
||||
}
|
||||
MWWorld::CellStore *prison = getInterior( prisonName );
|
||||
if ( !prison )
|
||||
{
|
||||
std::cerr << "Failed to confiscate items: failed to load cell " << prisonName << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
MWWorld::Ptr closestChest = prison->search( "stolen_goods" );
|
||||
if (!closestChest.isEmpty()) //Found a close chest
|
||||
{
|
||||
MWBase::Environment::get().getMechanicsManager()->confiscateStolenItems(ptr, closestChest);
|
||||
|
@ -3108,7 +3212,7 @@ namespace MWWorld
|
|||
mRendering->spawnEffect(model, textureOverride, worldPos);
|
||||
}
|
||||
|
||||
void World::explodeSpell(const Vector3 &origin, const ESM::EffectList &effects, const Ptr &caster, int rangeType,
|
||||
void World::explodeSpell(const Vector3 &origin, const ESM::EffectList &effects, const Ptr &caster, ESM::RangeType rangeType,
|
||||
const std::string& id, const std::string& sourceName)
|
||||
{
|
||||
std::map<MWWorld::Ptr, std::vector<ESM::ENAMstruct> > toApply;
|
||||
|
@ -3167,7 +3271,7 @@ namespace MWWorld
|
|||
cast.mStack = false;
|
||||
ESM::EffectList effects;
|
||||
effects.mList = apply->second;
|
||||
cast.inflict(apply->first, caster, effects, (ESM::RangeType)rangeType, false, true);
|
||||
cast.inflict(apply->first, caster, effects, rangeType, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -115,7 +115,6 @@ namespace MWWorld
|
|||
void performUpdateSceneQueries ();
|
||||
void getFacedHandle(std::string& facedHandle, float maxDistance, bool ignorePlayer=true);
|
||||
|
||||
float getMaxActivationDistance ();
|
||||
float getNpcActivationDistance ();
|
||||
float getObjectActivationDistance ();
|
||||
|
||||
|
@ -151,6 +150,9 @@ namespace MWWorld
|
|||
|
||||
float feetToGameUnits(float feet);
|
||||
|
||||
MWWorld::Ptr getClosestMarker( const MWWorld::Ptr &ptr, const std::string &id );
|
||||
MWWorld::Ptr getClosestMarkerFromExteriorPosition( const Ogre::Vector3 worldPos, const std::string &id );
|
||||
|
||||
public:
|
||||
|
||||
World (OEngine::Render::OgreRenderer& renderer,
|
||||
|
@ -363,6 +365,8 @@ namespace MWWorld
|
|||
virtual MWWorld::Ptr safePlaceObject(const MWWorld::Ptr& ptr, MWWorld::CellStore* cell, ESM::Position pos);
|
||||
///< place an object in a "safe" location (ie not in the void, etc). Makes a copy of the Ptr.
|
||||
|
||||
virtual float getMaxActivationDistance();
|
||||
|
||||
virtual void indexToPosition (int cellX, int cellY, float &x, float &y, bool centre = false)
|
||||
const;
|
||||
///< Convert cell numbers to position.
|
||||
|
@ -633,7 +637,7 @@ namespace MWWorld
|
|||
virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const Ogre::Vector3& worldPos);
|
||||
|
||||
virtual void explodeSpell (const Ogre::Vector3& origin, const ESM::EffectList& effects,
|
||||
const MWWorld::Ptr& caster, int rangeType, const std::string& id, const std::string& sourceName);
|
||||
const MWWorld::Ptr& caster, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName);
|
||||
|
||||
virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor);
|
||||
|
||||
|
|
|
@ -105,6 +105,12 @@ void Config::LauncherSettings::setContentList(const GameSettings& gameSettings)
|
|||
// obtain content list from game settings (if present)
|
||||
const QStringList files(gameSettings.getContentList());
|
||||
|
||||
// if openmw.cfg has no content, exit so we don't create an empty content list.
|
||||
if (files.isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// if any existing profile in launcher matches the content list, make that profile the default
|
||||
foreach(const QString &listName, getContentLists())
|
||||
{
|
||||
|
|
|
@ -110,15 +110,15 @@ Qt::ItemFlags ContentSelectorModel::ContentModel::flags(const QModelIndex &index
|
|||
if (!file)
|
||||
return Qt::NoItemFlags;
|
||||
|
||||
//game files can always be checked
|
||||
//game files are not shown
|
||||
if (file->isGameFile())
|
||||
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable;
|
||||
return Qt::NoItemFlags;
|
||||
|
||||
Qt::ItemFlags returnFlags;
|
||||
bool allDependenciesFound = true;
|
||||
bool gamefileChecked = false;
|
||||
|
||||
//addon can be checked if its gamefile is and all other dependencies exist
|
||||
// addon can be checked if its gamefile is
|
||||
// ... special case, addon with no dependency can be used with any gamefile.
|
||||
bool gamefileChecked = (file->gameFiles().count() == 0);
|
||||
foreach (const QString &fileName, file->gameFiles())
|
||||
{
|
||||
bool depFound = false;
|
||||
|
@ -144,16 +144,11 @@ Qt::ItemFlags ContentSelectorModel::ContentModel::flags(const QModelIndex &index
|
|||
if (gamefileChecked || !(dependency->isGameFile()))
|
||||
break;
|
||||
}
|
||||
|
||||
allDependenciesFound = allDependenciesFound && depFound;
|
||||
}
|
||||
|
||||
if (gamefileChecked)
|
||||
{
|
||||
if (allDependenciesFound)
|
||||
returnFlags = returnFlags | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled;
|
||||
else
|
||||
returnFlags = Qt::ItemIsSelectable;
|
||||
returnFlags = Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled;
|
||||
}
|
||||
|
||||
return returnFlags;
|
||||
|
@ -467,6 +462,14 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path)
|
|||
file->setFilePath (info.absoluteFilePath());
|
||||
file->setDescription(QString::fromUtf8(fileReader.getDesc().c_str()));
|
||||
|
||||
// HACK
|
||||
// Load order constraint of Bloodmoon.esm needing Tribunal.esm is missing
|
||||
// from the file supplied by Bethesda, so we have to add it ourselves
|
||||
if (file->fileName().compare("Bloodmoon.esm", Qt::CaseInsensitive) == 0)
|
||||
{
|
||||
file->addGameFile(QString::fromUtf8("Tribunal.esm"));
|
||||
}
|
||||
|
||||
// Put the file in the table
|
||||
addFile(file);
|
||||
|
||||
|
@ -481,6 +484,19 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path)
|
|||
sortFiles();
|
||||
}
|
||||
|
||||
QStringList ContentSelectorModel::ContentModel::gameFiles() const
|
||||
{
|
||||
QStringList gameFiles;
|
||||
foreach(const ContentSelectorModel::EsmFile *file, mFiles)
|
||||
{
|
||||
if (file->isGameFile())
|
||||
{
|
||||
gameFiles.append(file->fileName());
|
||||
}
|
||||
}
|
||||
return gameFiles;
|
||||
}
|
||||
|
||||
void ContentSelectorModel::ContentModel::sortFiles()
|
||||
{
|
||||
//first, sort the model such that all dependencies are ordered upstream (gamefile) first.
|
||||
|
@ -536,13 +552,13 @@ bool ContentSelectorModel::ContentModel::isLoadOrderError(const EsmFile *file) c
|
|||
return mPluginsWithLoadOrderError.contains(file->filePath());
|
||||
}
|
||||
|
||||
void ContentSelectorModel::ContentModel::setContentList(const QStringList &fileList, bool isChecked)
|
||||
void ContentSelectorModel::ContentModel::setContentList(const QStringList &fileList)
|
||||
{
|
||||
mPluginsWithLoadOrderError.clear();
|
||||
int previousPosition = -1;
|
||||
foreach (const QString &filepath, fileList)
|
||||
{
|
||||
if (setCheckState(filepath, isChecked))
|
||||
if (setCheckState(filepath, true))
|
||||
{
|
||||
// as necessary, move plug-ins in visible list to match sequence of supplied filelist
|
||||
const EsmFile* file = item(filepath);
|
||||
|
@ -581,7 +597,7 @@ void ContentSelectorModel::ContentModel::checkForLoadOrderErrors()
|
|||
QList<ContentSelectorModel::LoadOrderError> ContentSelectorModel::ContentModel::checkForLoadOrderErrors(const EsmFile *file, int row) const
|
||||
{
|
||||
QList<LoadOrderError> errors = QList<LoadOrderError>();
|
||||
foreach(QString dependentfileName, file->gameFiles())
|
||||
foreach(const QString &dependentfileName, file->gameFiles())
|
||||
{
|
||||
const EsmFile* dependentFile = item(dependentfileName);
|
||||
|
||||
|
|
|
@ -47,11 +47,12 @@ namespace ContentSelectorModel
|
|||
|
||||
QModelIndex indexFromItem(const EsmFile *item) const;
|
||||
const EsmFile *item(const QString &name) const;
|
||||
QStringList gameFiles() const;
|
||||
|
||||
bool isEnabled (QModelIndex index) const;
|
||||
bool isChecked(const QString &filepath) const;
|
||||
bool setCheckState(const QString &filepath, bool isChecked);
|
||||
void setContentList(const QStringList &fileList, bool isChecked);
|
||||
void setContentList(const QStringList &fileList);
|
||||
ContentFileList checkedItems() const;
|
||||
void uncheckAll();
|
||||
|
||||
|
|
|
@ -62,6 +62,13 @@ QByteArray ContentSelectorModel::EsmFile::encodedData() const
|
|||
return encodedData;
|
||||
}
|
||||
|
||||
bool ContentSelectorModel::EsmFile::isGameFile() const
|
||||
{
|
||||
return (mGameFiles.size() == 0) &&
|
||||
(mFileName.endsWith(QLatin1String(".esm"), Qt::CaseInsensitive) ||
|
||||
mFileName.endsWith(QLatin1String(".omwgame"), Qt::CaseInsensitive));
|
||||
}
|
||||
|
||||
QVariant ContentSelectorModel::EsmFile::fileProperty(const FileProperty prop) const
|
||||
{
|
||||
switch (prop)
|
||||
|
|
|
@ -64,7 +64,7 @@ namespace ContentSelectorModel
|
|||
.arg(mGameFiles.join(", "));
|
||||
}
|
||||
|
||||
inline bool isGameFile() const { return (mGameFiles.size() == 0); }
|
||||
bool isGameFile() const;
|
||||
QByteArray encodedData() const;
|
||||
|
||||
public:
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <QGridLayout>
|
||||
#include <QMessageBox>
|
||||
#include <QModelIndex>
|
||||
#include <QDir>
|
||||
#include <assert.h>
|
||||
|
||||
ContentSelectorView::ContentSelector::ContentSelector(QWidget *parent) :
|
||||
|
@ -33,13 +34,7 @@ void ContentSelectorView::ContentSelector::buildGameFileView()
|
|||
{
|
||||
ui.gameFileView->setVisible (true);
|
||||
|
||||
mGameFileProxyModel = new QSortFilterProxyModel(this);
|
||||
mGameFileProxyModel->setFilterRegExp(QString::number((int)ContentSelectorModel::ContentType_GameFile));
|
||||
mGameFileProxyModel->setFilterRole (Qt::UserRole);
|
||||
mGameFileProxyModel->setSourceModel (mContentModel);
|
||||
|
||||
ui.gameFileView->setPlaceholderText(QString("Select a game file..."));
|
||||
ui.gameFileView->setModel(mGameFileProxyModel);
|
||||
|
||||
connect (ui.gameFileView, SIGNAL (currentIndexChanged(int)),
|
||||
this, SLOT (slotCurrentGameFileIndexChanged(int)));
|
||||
|
@ -113,7 +108,7 @@ void ContentSelectorView::ContentSelector::setContentList(const QStringList &lis
|
|||
slotCurrentGameFileIndexChanged (ui.gameFileView->currentIndex());
|
||||
}
|
||||
else
|
||||
mContentModel->setContentList(list, true);
|
||||
mContentModel->setContentList(list);
|
||||
}
|
||||
|
||||
ContentSelectorModel::ContentFileList
|
||||
|
@ -129,6 +124,15 @@ void ContentSelectorView::ContentSelector::addFiles(const QString &path)
|
|||
{
|
||||
mContentModel->addFiles(path);
|
||||
|
||||
// add any game files to the combo box
|
||||
foreach(const QString gameFileName, mContentModel->gameFiles())
|
||||
{
|
||||
if (ui.gameFileView->findText(gameFileName) == -1)
|
||||
{
|
||||
ui.gameFileView->addItem(gameFileName);
|
||||
}
|
||||
}
|
||||
|
||||
if (ui.gameFileView->currentIndex() != -1)
|
||||
ui.gameFileView->setCurrentIndex(-1);
|
||||
|
||||
|
@ -150,29 +154,33 @@ void ContentSelectorView::ContentSelector::slotCurrentGameFileIndexChanged(int i
|
|||
{
|
||||
static int oldIndex = -1;
|
||||
|
||||
QAbstractItemModel *const model = ui.gameFileView->model();
|
||||
QSortFilterProxyModel *proxy = dynamic_cast<QSortFilterProxyModel *>(model);
|
||||
|
||||
if (proxy)
|
||||
proxy->setDynamicSortFilter(false);
|
||||
|
||||
if (index != oldIndex)
|
||||
{
|
||||
if (oldIndex > -1)
|
||||
model->setData(model->index(oldIndex, 0), false, Qt::UserRole + 1);
|
||||
{
|
||||
setGameFileSelected(oldIndex, false);
|
||||
}
|
||||
|
||||
oldIndex = index;
|
||||
|
||||
model->setData(model->index(index, 0), true, Qt::UserRole + 1);
|
||||
setGameFileSelected(index, true);
|
||||
mContentModel->checkForLoadOrderErrors();
|
||||
}
|
||||
|
||||
if (proxy)
|
||||
proxy->setDynamicSortFilter(true);
|
||||
|
||||
emit signalCurrentGamefileIndexChanged (index);
|
||||
}
|
||||
|
||||
void ContentSelectorView::ContentSelector::setGameFileSelected(int index, bool selected)
|
||||
{
|
||||
QString fileName = ui.gameFileView->itemText(index);
|
||||
const ContentSelectorModel::EsmFile* file = mContentModel->item(fileName);
|
||||
if (file != NULL)
|
||||
{
|
||||
QModelIndex index(mContentModel->indexFromItem(file));
|
||||
mContentModel->setData(index, selected, Qt::UserRole + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void ContentSelectorView::ContentSelector::slotAddonTableItemActivated(const QModelIndex &index)
|
||||
{
|
||||
QModelIndex sourceIndex = mAddonProxyModel->mapToSource (index);
|
||||
|
|
|
@ -19,7 +19,6 @@ namespace ContentSelectorView
|
|||
protected:
|
||||
|
||||
ContentSelectorModel::ContentModel *mContentModel;
|
||||
QSortFilterProxyModel *mGameFileProxyModel;
|
||||
QSortFilterProxyModel *mAddonProxyModel;
|
||||
|
||||
public:
|
||||
|
@ -52,6 +51,7 @@ namespace ContentSelectorView
|
|||
void buildContentModel();
|
||||
void buildGameFileView();
|
||||
void buildAddonView();
|
||||
void setGameFileSelected(int index, bool selected);
|
||||
|
||||
signals:
|
||||
void signalCurrentGamefileIndexChanged (int);
|
||||
|
|
|
@ -41,29 +41,6 @@ namespace ESM
|
|||
|
||||
}
|
||||
|
||||
void AIPackageList::load(ESMReader &esm)
|
||||
{
|
||||
mList.clear();
|
||||
while (esm.hasMoreSubs()) {
|
||||
// initialize every iteration
|
||||
esm.getSubName();
|
||||
switch (esm.retSubName().val)
|
||||
{
|
||||
case AI_Wander:
|
||||
case AI_Activate:
|
||||
case AI_Escort:
|
||||
case AI_Follow:
|
||||
case AI_Travel:
|
||||
case AI_CNDT:
|
||||
|
||||
add(esm);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AIPackageList::save(ESMWriter &esm) const
|
||||
{
|
||||
typedef std::vector<AIPackage>::const_iterator PackageIter;
|
||||
|
|
|
@ -94,9 +94,6 @@ namespace ESM
|
|||
/// Add a single AIPackage, assumes subrecord name was already read
|
||||
void add(ESMReader &esm);
|
||||
|
||||
/// TODO: remove this method. The ESM format does not guarantee that all AI packages follow one another
|
||||
void load(ESMReader &esm);
|
||||
|
||||
void save(ESMWriter &esm) const;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -8,13 +8,18 @@ namespace ESM {
|
|||
void EffectList::load(ESMReader &esm)
|
||||
{
|
||||
mList.clear();
|
||||
ENAMstruct s;
|
||||
while (esm.isNextSub("ENAM")) {
|
||||
esm.getHT(s, 24);
|
||||
mList.push_back(s);
|
||||
add(esm);
|
||||
}
|
||||
}
|
||||
|
||||
void EffectList::add(ESMReader &esm)
|
||||
{
|
||||
ENAMstruct s;
|
||||
esm.getHT(s, 24);
|
||||
mList.push_back(s);
|
||||
}
|
||||
|
||||
void EffectList::save(ESMWriter &esm) const
|
||||
{
|
||||
for (std::vector<ENAMstruct>::const_iterator it = mList.begin(); it != mList.end(); ++it) {
|
||||
|
|
|
@ -29,11 +29,15 @@ namespace ESM
|
|||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
/// EffectList, ENAM subrecord
|
||||
struct EffectList
|
||||
{
|
||||
|
||||
std::vector<ENAMstruct> mList;
|
||||
|
||||
/// Load one effect, assumes subrecord name was already read
|
||||
void add(ESMReader &esm);
|
||||
|
||||
/// Load all effects
|
||||
void load(ESMReader &esm);
|
||||
void save(ESMWriter &esm) const;
|
||||
};
|
||||
|
|
|
@ -8,18 +8,34 @@ namespace ESM
|
|||
{
|
||||
unsigned int Activator::sRecordId = REC_ACTI;
|
||||
|
||||
void Activator::load(ESMReader &esm)
|
||||
{
|
||||
mModel = esm.getHNString("MODL");
|
||||
mName = esm.getHNOString("FNAM");
|
||||
mScript = esm.getHNOString("SCRI");
|
||||
}
|
||||
void Activator::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNCString("MODL", mModel);
|
||||
esm.writeHNOCString("FNAM", mName);
|
||||
esm.writeHNOCString("SCRI", mScript);
|
||||
}
|
||||
void Activator::load(ESMReader &esm)
|
||||
{
|
||||
while (esm.hasMoreSubs())
|
||||
{
|
||||
esm.getSubName();
|
||||
uint32_t name = esm.retSubName().val;
|
||||
switch (name)
|
||||
{
|
||||
case ESM::FourCC<'M','O','D','L'>::value:
|
||||
mModel = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'F','N','A','M'>::value:
|
||||
mName = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'S','C','R','I'>::value:
|
||||
mScript = esm.getHString();
|
||||
break;
|
||||
default:
|
||||
esm.fail("Unknown subrecord");
|
||||
}
|
||||
}
|
||||
}
|
||||
void Activator::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNCString("MODL", mModel);
|
||||
esm.writeHNOCString("FNAM", mName);
|
||||
esm.writeHNOCString("SCRI", mScript);
|
||||
}
|
||||
|
||||
void Activator::blank()
|
||||
{
|
||||
|
|
|
@ -8,24 +8,51 @@ namespace ESM
|
|||
{
|
||||
unsigned int Potion::sRecordId = REC_ALCH;
|
||||
|
||||
void Potion::load(ESMReader &esm)
|
||||
{
|
||||
mModel = esm.getHNOString("MODL");
|
||||
mIcon = esm.getHNOString("TEXT"); // not ITEX here for some reason
|
||||
mScript = esm.getHNOString("SCRI");
|
||||
mName = esm.getHNOString("FNAM");
|
||||
esm.getHNT(mData, "ALDT", 12);
|
||||
mEffects.load(esm);
|
||||
}
|
||||
void Potion::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNCString("MODL", mModel);
|
||||
esm.writeHNOCString("TEXT", mIcon);
|
||||
esm.writeHNOCString("SCRI", mScript);
|
||||
esm.writeHNOCString("FNAM", mName);
|
||||
esm.writeHNT("ALDT", mData, 12);
|
||||
mEffects.save(esm);
|
||||
}
|
||||
void Potion::load(ESMReader &esm)
|
||||
{
|
||||
mEffects.mList.clear();
|
||||
bool hasData = false;
|
||||
while (esm.hasMoreSubs())
|
||||
{
|
||||
esm.getSubName();
|
||||
uint32_t name = esm.retSubName().val;
|
||||
switch (name)
|
||||
{
|
||||
case ESM::FourCC<'M','O','D','L'>::value:
|
||||
mModel = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'T','E','X','T'>::value: // not ITEX here for some reason
|
||||
mIcon = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'S','C','R','I'>::value:
|
||||
mScript = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'F','N','A','M'>::value:
|
||||
mName = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'A','L','D','T'>::value:
|
||||
esm.getHT(mData, 12);
|
||||
hasData = true;
|
||||
break;
|
||||
case ESM::FourCC<'E','N','A','M'>::value:
|
||||
mEffects.add(esm);
|
||||
break;
|
||||
default:
|
||||
esm.fail("Unknown subrecord");
|
||||
}
|
||||
}
|
||||
if (!hasData)
|
||||
esm.fail("Missing ALDT");
|
||||
}
|
||||
void Potion::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNCString("MODL", mModel);
|
||||
esm.writeHNOCString("TEXT", mIcon);
|
||||
esm.writeHNOCString("SCRI", mScript);
|
||||
esm.writeHNOCString("FNAM", mName);
|
||||
esm.writeHNT("ALDT", mData, 12);
|
||||
mEffects.save(esm);
|
||||
}
|
||||
|
||||
void Potion::blank()
|
||||
{
|
||||
|
|
|
@ -10,25 +10,35 @@ namespace ESM
|
|||
|
||||
void Apparatus::load(ESMReader &esm)
|
||||
{
|
||||
// we will not treat duplicated subrecords as errors here
|
||||
bool hasData = false;
|
||||
while (esm.hasMoreSubs())
|
||||
{
|
||||
esm.getSubName();
|
||||
NAME subName = esm.retSubName();
|
||||
|
||||
if (subName == "MODL")
|
||||
mModel = esm.getHString();
|
||||
else if (subName == "FNAM")
|
||||
mName = esm.getHString();
|
||||
else if (subName == "AADT")
|
||||
esm.getHT(mData);
|
||||
else if (subName == "SCRI")
|
||||
mScript = esm.getHString();
|
||||
else if (subName == "ITEX")
|
||||
mIcon = esm.getHString();
|
||||
else
|
||||
esm.fail("wrong subrecord type " + subName.toString() + " for APPA record");
|
||||
uint32_t name = esm.retSubName().val;
|
||||
switch (name)
|
||||
{
|
||||
case ESM::FourCC<'M','O','D','L'>::value:
|
||||
mModel = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'F','N','A','M'>::value:
|
||||
mName = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'A','A','D','T'>::value:
|
||||
esm.getHT(mData);
|
||||
hasData = true;
|
||||
break;
|
||||
case ESM::FourCC<'S','C','R','I'>::value:
|
||||
mScript = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'I','T','E','X'>::value:
|
||||
mIcon = esm.getHString();
|
||||
break;
|
||||
default:
|
||||
esm.fail("Unknown subrecord");
|
||||
}
|
||||
}
|
||||
if (!hasData)
|
||||
esm.fail("Missing AADT");
|
||||
}
|
||||
|
||||
void Apparatus::save(ESMWriter &esm) const
|
||||
|
|
|
@ -11,9 +11,30 @@ namespace ESM
|
|||
|
||||
void BodyPart::load(ESMReader &esm)
|
||||
{
|
||||
mModel = esm.getHNString("MODL");
|
||||
mRace = esm.getHNOString("FNAM");
|
||||
esm.getHNT(mData, "BYDT", 4);
|
||||
bool hasData = false;
|
||||
while (esm.hasMoreSubs())
|
||||
{
|
||||
esm.getSubName();
|
||||
uint32_t name = esm.retSubName().val;
|
||||
switch (name)
|
||||
{
|
||||
case ESM::FourCC<'M','O','D','L'>::value:
|
||||
mModel = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'F','N','A','M'>::value:
|
||||
mRace = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'B','Y','D','T'>::value:
|
||||
esm.getHT(mData, 4);
|
||||
hasData = true;
|
||||
break;
|
||||
default:
|
||||
esm.fail("Unknown subrecord");
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasData)
|
||||
esm.fail("Missing BYDT subrecord");
|
||||
}
|
||||
void BodyPart::save(ESMWriter &esm) const
|
||||
{
|
||||
|
|
|
@ -10,11 +10,29 @@ namespace ESM
|
|||
|
||||
void BirthSign::load(ESMReader &esm)
|
||||
{
|
||||
mName = esm.getHNOString("FNAM");
|
||||
mTexture = esm.getHNOString("TNAM");
|
||||
mDescription = esm.getHNOString("DESC");
|
||||
|
||||
mPowers.load(esm);
|
||||
mPowers.mList.clear();
|
||||
while (esm.hasMoreSubs())
|
||||
{
|
||||
esm.getSubName();
|
||||
uint32_t name = esm.retSubName().val;
|
||||
switch (name)
|
||||
{
|
||||
case ESM::FourCC<'F','N','A','M'>::value:
|
||||
mName = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'T','N','A','M'>::value:
|
||||
mTexture = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'D','E','S','C'>::value:
|
||||
mDescription = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'N','P','C','S'>::value:
|
||||
mPowers.add(esm);
|
||||
break;
|
||||
default:
|
||||
esm.fail("Unknown subrecord");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BirthSign::save(ESMWriter &esm) const
|
||||
|
|
|
@ -10,17 +10,17 @@ namespace ESM
|
|||
{
|
||||
unsigned int Class::sRecordId = REC_CLAS;
|
||||
|
||||
const Class::Specialization Class::sSpecializationIds[3] = {
|
||||
Class::Combat,
|
||||
Class::Magic,
|
||||
Class::Stealth
|
||||
};
|
||||
const Class::Specialization Class::sSpecializationIds[3] = {
|
||||
Class::Combat,
|
||||
Class::Magic,
|
||||
Class::Stealth
|
||||
};
|
||||
|
||||
const char *Class::sGmstSpecializationIds[3] = {
|
||||
"sSpecializationCombat",
|
||||
"sSpecializationMagic",
|
||||
"sSpecializationStealth"
|
||||
};
|
||||
const char *Class::sGmstSpecializationIds[3] = {
|
||||
"sSpecializationCombat",
|
||||
"sSpecializationMagic",
|
||||
"sSpecializationStealth"
|
||||
};
|
||||
|
||||
|
||||
int& Class::CLDTstruct::getSkill (int index, bool major)
|
||||
|
@ -39,22 +39,40 @@ const char *Class::sGmstSpecializationIds[3] = {
|
|||
return mSkills[index][major ? 1 : 0];
|
||||
}
|
||||
|
||||
void Class::load(ESMReader &esm)
|
||||
{
|
||||
mName = esm.getHNOString("FNAM");
|
||||
esm.getHNT(mData, "CLDT", 60);
|
||||
|
||||
if (mData.mIsPlayable > 1)
|
||||
esm.fail("Unknown bool value");
|
||||
|
||||
mDescription = esm.getHNOString("DESC");
|
||||
}
|
||||
void Class::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNOCString("FNAM", mName);
|
||||
esm.writeHNT("CLDT", mData, 60);
|
||||
esm.writeHNOString("DESC", mDescription);
|
||||
}
|
||||
void Class::load(ESMReader &esm)
|
||||
{
|
||||
bool hasData = false;
|
||||
while (esm.hasMoreSubs())
|
||||
{
|
||||
esm.getSubName();
|
||||
uint32_t name = esm.retSubName().val;
|
||||
switch (name)
|
||||
{
|
||||
case ESM::FourCC<'F','N','A','M'>::value:
|
||||
mName = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'C','L','D','T'>::value:
|
||||
esm.getHT(mData, 60);
|
||||
if (mData.mIsPlayable > 1)
|
||||
esm.fail("Unknown bool value");
|
||||
hasData = true;
|
||||
break;
|
||||
case ESM::FourCC<'D','E','S','C'>::value:
|
||||
mDescription = esm.getHString();
|
||||
break;
|
||||
default:
|
||||
esm.fail("Unknown subrecord");
|
||||
}
|
||||
}
|
||||
if (!hasData)
|
||||
esm.fail("Missing CLDT subrecord");
|
||||
}
|
||||
void Class::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNOCString("FNAM", mName);
|
||||
esm.writeHNT("CLDT", mData, 60);
|
||||
esm.writeHNOString("DESC", mDescription);
|
||||
}
|
||||
|
||||
void Class::blank()
|
||||
{
|
||||
|
|
|
@ -7,60 +7,79 @@
|
|||
namespace ESM
|
||||
{
|
||||
|
||||
void InventoryList::add(ESMReader &esm)
|
||||
{
|
||||
ContItem ci;
|
||||
esm.getHT(ci, 36);
|
||||
mList.push_back(ci);
|
||||
}
|
||||
|
||||
void InventoryList::load(ESMReader &esm)
|
||||
{
|
||||
mList.clear();
|
||||
while (esm.isNextSub("NPCO"))
|
||||
void InventoryList::add(ESMReader &esm)
|
||||
{
|
||||
add(esm);
|
||||
ContItem ci;
|
||||
esm.getHT(ci, 36);
|
||||
mList.push_back(ci);
|
||||
}
|
||||
}
|
||||
|
||||
void InventoryList::save(ESMWriter &esm) const
|
||||
{
|
||||
for (std::vector<ContItem>::const_iterator it = mList.begin(); it != mList.end(); ++it)
|
||||
void InventoryList::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNT("NPCO", *it, 36);
|
||||
for (std::vector<ContItem>::const_iterator it = mList.begin(); it != mList.end(); ++it)
|
||||
{
|
||||
esm.writeHNT("NPCO", *it, 36);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int Container::sRecordId = REC_CONT;
|
||||
|
||||
void Container::load(ESMReader &esm)
|
||||
{
|
||||
mModel = esm.getHNString("MODL");
|
||||
mName = esm.getHNOString("FNAM");
|
||||
esm.getHNT(mWeight, "CNDT", 4);
|
||||
esm.getHNT(mFlags, "FLAG", 4);
|
||||
void Container::load(ESMReader &esm)
|
||||
{
|
||||
mInventory.mList.clear();
|
||||
bool hasWeight = false;
|
||||
bool hasFlags = false;
|
||||
while (esm.hasMoreSubs())
|
||||
{
|
||||
esm.getSubName();
|
||||
uint32_t name = esm.retSubName().val;
|
||||
switch (name)
|
||||
{
|
||||
case ESM::FourCC<'M','O','D','L'>::value:
|
||||
mModel = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'F','N','A','M'>::value:
|
||||
mName = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'C','N','D','T'>::value:
|
||||
esm.getHT(mWeight, 4);
|
||||
hasWeight = true;
|
||||
break;
|
||||
case ESM::FourCC<'F','L','A','G'>::value:
|
||||
esm.getHT(mFlags, 4);
|
||||
if (mFlags & 0xf4)
|
||||
esm.fail("Unknown flags");
|
||||
if (!(mFlags & 0x8))
|
||||
esm.fail("Flag 8 not set");
|
||||
hasFlags = true;
|
||||
break;
|
||||
case ESM::FourCC<'S','C','R','I'>::value:
|
||||
mScript = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'N','P','C','O'>::value:
|
||||
mInventory.add(esm);
|
||||
break;
|
||||
default:
|
||||
esm.fail("Unknown subrecord");
|
||||
}
|
||||
}
|
||||
if (!hasWeight)
|
||||
esm.fail("Missing CNDT subrecord");
|
||||
if (!hasFlags)
|
||||
esm.fail("Missing FLAG subrecord");
|
||||
}
|
||||
|
||||
if (mFlags & 0xf4)
|
||||
esm.fail("Unknown flags");
|
||||
if (!(mFlags & 0x8))
|
||||
esm.fail("Flag 8 not set");
|
||||
void Container::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNCString("MODL", mModel);
|
||||
esm.writeHNOCString("FNAM", mName);
|
||||
esm.writeHNT("CNDT", mWeight, 4);
|
||||
esm.writeHNT("FLAG", mFlags, 4);
|
||||
|
||||
mScript = esm.getHNOString("SCRI");
|
||||
esm.writeHNOCString("SCRI", mScript);
|
||||
|
||||
mInventory.load(esm);
|
||||
}
|
||||
|
||||
void Container::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNCString("MODL", mModel);
|
||||
esm.writeHNOCString("FNAM", mName);
|
||||
esm.writeHNT("CNDT", mWeight, 4);
|
||||
esm.writeHNT("FLAG", mFlags, 4);
|
||||
|
||||
esm.writeHNOCString("SCRI", mScript);
|
||||
|
||||
mInventory.save(esm);
|
||||
}
|
||||
mInventory.save(esm);
|
||||
}
|
||||
|
||||
void Container::blank()
|
||||
{
|
||||
|
|
|
@ -22,6 +22,7 @@ struct ContItem
|
|||
NAME32 mItem;
|
||||
};
|
||||
|
||||
/// InventoryList, NPCO subrecord
|
||||
struct InventoryList
|
||||
{
|
||||
std::vector<ContItem> mList;
|
||||
|
@ -29,8 +30,6 @@ struct InventoryList
|
|||
/// Load one item, assumes subrecord name is already read
|
||||
void add(ESMReader &esm);
|
||||
|
||||
/// TODO: remove this method, the ESM format doesn't guarantee that all ContItems follow one another
|
||||
void load(ESMReader &esm);
|
||||
void save(ESMWriter &esm) const;
|
||||
};
|
||||
|
||||
|
|
|
@ -8,55 +8,94 @@ namespace ESM {
|
|||
|
||||
unsigned int Creature::sRecordId = REC_CREA;
|
||||
|
||||
void Creature::load(ESMReader &esm)
|
||||
{
|
||||
mPersistent = esm.getRecordFlags() & 0x0400;
|
||||
|
||||
mModel = esm.getHNString("MODL");
|
||||
mOriginal = esm.getHNOString("CNAM");
|
||||
mName = esm.getHNOString("FNAM");
|
||||
mScript = esm.getHNOString("SCRI");
|
||||
|
||||
esm.getHNT(mData, "NPDT", 96);
|
||||
|
||||
esm.getHNT(mFlags, "FLAG");
|
||||
mScale = 1.0;
|
||||
esm.getHNOT(mScale, "XSCL");
|
||||
|
||||
mInventory.load(esm);
|
||||
mSpells.load(esm);
|
||||
|
||||
if (esm.isNextSub("AIDT"))
|
||||
void Creature::load(ESMReader &esm)
|
||||
{
|
||||
esm.getHExact(&mAiData, sizeof(mAiData));
|
||||
mHasAI = true;
|
||||
}
|
||||
else
|
||||
mPersistent = esm.getRecordFlags() & 0x0400;
|
||||
|
||||
mAiPackage.mList.clear();
|
||||
mInventory.mList.clear();
|
||||
mSpells.mList.clear();
|
||||
|
||||
mScale = 1.f;
|
||||
mHasAI = false;
|
||||
|
||||
mAiPackage.load(esm);
|
||||
esm.skipRecord();
|
||||
}
|
||||
|
||||
void Creature::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNCString("MODL", mModel);
|
||||
esm.writeHNOCString("CNAM", mOriginal);
|
||||
esm.writeHNOCString("FNAM", mName);
|
||||
esm.writeHNOCString("SCRI", mScript);
|
||||
esm.writeHNT("NPDT", mData, 96);
|
||||
esm.writeHNT("FLAG", mFlags);
|
||||
if (mScale != 1.0) {
|
||||
esm.writeHNT("XSCL", mScale);
|
||||
bool hasNpdt = false;
|
||||
bool hasFlags = false;
|
||||
while (esm.hasMoreSubs())
|
||||
{
|
||||
esm.getSubName();
|
||||
uint32_t name = esm.retSubName().val;
|
||||
switch (name)
|
||||
{
|
||||
case ESM::FourCC<'M','O','D','L'>::value:
|
||||
mModel = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'C','N','A','M'>::value:
|
||||
mOriginal = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'F','N','A','M'>::value:
|
||||
mName = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'S','C','R','I'>::value:
|
||||
mScript = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'N','P','D','T'>::value:
|
||||
esm.getHT(mData, 96);
|
||||
hasNpdt = true;
|
||||
break;
|
||||
case ESM::FourCC<'F','L','A','G'>::value:
|
||||
esm.getHT(mFlags);
|
||||
hasFlags = true;
|
||||
break;
|
||||
case ESM::FourCC<'X','S','C','L'>::value:
|
||||
esm.getHT(mScale);
|
||||
break;
|
||||
case ESM::FourCC<'N','P','C','O'>::value:
|
||||
mInventory.add(esm);
|
||||
break;
|
||||
case ESM::FourCC<'N','P','C','S'>::value:
|
||||
mSpells.add(esm);
|
||||
break;
|
||||
case ESM::FourCC<'A','I','D','T'>::value:
|
||||
esm.getHExact(&mAiData, sizeof(mAiData));
|
||||
mHasAI = true;
|
||||
break;
|
||||
case AI_Wander:
|
||||
case AI_Activate:
|
||||
case AI_Escort:
|
||||
case AI_Follow:
|
||||
case AI_Travel:
|
||||
case AI_CNDT:
|
||||
mAiPackage.add(esm);
|
||||
break;
|
||||
default:
|
||||
esm.fail("Unknown subrecord");
|
||||
}
|
||||
}
|
||||
if (!hasNpdt)
|
||||
esm.fail("Missing NPDT subrecord");
|
||||
if (!hasFlags)
|
||||
esm.fail("Missing FLAG subrecord");
|
||||
}
|
||||
|
||||
mInventory.save(esm);
|
||||
mSpells.save(esm);
|
||||
if (mHasAI) {
|
||||
esm.writeHNT("AIDT", mAiData, sizeof(mAiData));
|
||||
void Creature::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNCString("MODL", mModel);
|
||||
esm.writeHNOCString("CNAM", mOriginal);
|
||||
esm.writeHNOCString("FNAM", mName);
|
||||
esm.writeHNOCString("SCRI", mScript);
|
||||
esm.writeHNT("NPDT", mData, 96);
|
||||
esm.writeHNT("FLAG", mFlags);
|
||||
if (mScale != 1.0) {
|
||||
esm.writeHNT("XSCL", mScale);
|
||||
}
|
||||
|
||||
mInventory.save(esm);
|
||||
mSpells.save(esm);
|
||||
if (mHasAI) {
|
||||
esm.writeHNT("AIDT", mAiData, sizeof(mAiData));
|
||||
}
|
||||
mAiPackage.save(esm);
|
||||
}
|
||||
mAiPackage.save(esm);
|
||||
}
|
||||
|
||||
void Creature::blank()
|
||||
{
|
||||
|
|
|
@ -10,8 +10,28 @@ namespace ESM
|
|||
|
||||
void Enchantment::load(ESMReader &esm)
|
||||
{
|
||||
esm.getHNT(mData, "ENDT", 16);
|
||||
mEffects.load(esm);
|
||||
mEffects.mList.clear();
|
||||
bool hasData = false;
|
||||
while (esm.hasMoreSubs())
|
||||
{
|
||||
esm.getSubName();
|
||||
uint32_t name = esm.retSubName().val;
|
||||
switch (name)
|
||||
{
|
||||
case ESM::FourCC<'E','N','D','T'>::value:
|
||||
esm.getHT(mData, 16);
|
||||
hasData = true;
|
||||
break;
|
||||
case ESM::FourCC<'E','N','A','M'>::value:
|
||||
mEffects.add(esm);
|
||||
break;
|
||||
default:
|
||||
esm.fail("Unknown subrecord");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasData)
|
||||
esm.fail("Missing ENDT subrecord");
|
||||
}
|
||||
|
||||
void Enchantment::save(ESMWriter &esm) const
|
||||
|
|
|
@ -28,27 +28,46 @@ namespace ESM
|
|||
|
||||
void Faction::load(ESMReader &esm)
|
||||
{
|
||||
mName = esm.getHNOString("FNAM");
|
||||
mReactions.clear();
|
||||
for (int i=0;i<10;++i)
|
||||
mRanks[i].clear();
|
||||
|
||||
// Read rank names. These are optional.
|
||||
int i = 0;
|
||||
while (esm.isNextSub("RNAM") && i < 10)
|
||||
mRanks[i++] = esm.getHString();
|
||||
|
||||
// Main data struct
|
||||
esm.getHNT(mData, "FADT", 240);
|
||||
|
||||
if (mData.mIsHidden > 1)
|
||||
esm.fail("Unknown flag!");
|
||||
|
||||
// Read faction response values
|
||||
int rankCounter=0;
|
||||
bool hasData = false;
|
||||
while (esm.hasMoreSubs())
|
||||
{
|
||||
std::string faction = esm.getHNString("ANAM");
|
||||
int reaction;
|
||||
esm.getHNT(reaction, "INTV");
|
||||
mReactions[faction] = reaction;
|
||||
esm.getSubName();
|
||||
uint32_t name = esm.retSubName().val;
|
||||
switch (name)
|
||||
{
|
||||
case ESM::FourCC<'F','N','A','M'>::value:
|
||||
mName = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'R','N','A','M'>::value:
|
||||
if (rankCounter >= 10)
|
||||
esm.fail("Rank out of range");
|
||||
mRanks[rankCounter++] = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'F','A','D','T'>::value:
|
||||
esm.getHT(mData, 240);
|
||||
if (mData.mIsHidden > 1)
|
||||
esm.fail("Unknown flag!");
|
||||
hasData = true;
|
||||
break;
|
||||
case ESM::FourCC<'A','N','A','M'>::value:
|
||||
{
|
||||
std::string faction = esm.getHString();
|
||||
int reaction;
|
||||
esm.getHNT(reaction, "INTV");
|
||||
mReactions[faction] = reaction;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
esm.fail("Unknown subrecord");
|
||||
}
|
||||
}
|
||||
if (!hasData)
|
||||
esm.fail("Missing FADT subrecord");
|
||||
}
|
||||
void Faction::save(ESMWriter &esm) const
|
||||
{
|
||||
|
|
|
@ -8,45 +8,71 @@ namespace ESM
|
|||
{
|
||||
unsigned int Ingredient::sRecordId = REC_INGR;
|
||||
|
||||
void Ingredient::load(ESMReader &esm)
|
||||
{
|
||||
mModel = esm.getHNString("MODL");
|
||||
mName = esm.getHNOString("FNAM");
|
||||
esm.getHNT(mData, "IRDT", 56);
|
||||
mScript = esm.getHNOString("SCRI");
|
||||
mIcon = esm.getHNOString("ITEX");
|
||||
// horrible hack to fix broken data in records
|
||||
for (int i=0; i<4; ++i)
|
||||
void Ingredient::load(ESMReader &esm)
|
||||
{
|
||||
if (mData.mEffectID[i] != 85 &&
|
||||
mData.mEffectID[i] != 22 &&
|
||||
mData.mEffectID[i] != 17 &&
|
||||
mData.mEffectID[i] != 79 &&
|
||||
mData.mEffectID[i] != 74)
|
||||
bool hasData = false;
|
||||
while (esm.hasMoreSubs())
|
||||
{
|
||||
mData.mAttributes[i] = -1;
|
||||
esm.getSubName();
|
||||
uint32_t name = esm.retSubName().val;
|
||||
switch (name)
|
||||
{
|
||||
case ESM::FourCC<'M','O','D','L'>::value:
|
||||
mModel = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'F','N','A','M'>::value:
|
||||
mName = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'I','R','D','T'>::value:
|
||||
esm.getHT(mData, 56);
|
||||
hasData = true;
|
||||
break;
|
||||
case ESM::FourCC<'S','C','R','I'>::value:
|
||||
mScript = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'I','T','E','X'>::value:
|
||||
mIcon = esm.getHString();
|
||||
break;
|
||||
default:
|
||||
esm.fail("Unknown subrecord");
|
||||
}
|
||||
}
|
||||
|
||||
// is this relevant in cycle from 0 to 4?
|
||||
if (mData.mEffectID[i] != 89 &&
|
||||
mData.mEffectID[i] != 26 &&
|
||||
mData.mEffectID[i] != 21 &&
|
||||
mData.mEffectID[i] != 83 &&
|
||||
mData.mEffectID[i] != 78)
|
||||
if (!hasData)
|
||||
esm.fail("Missing IRDT subrecord");
|
||||
|
||||
// horrible hack to fix broken data in records
|
||||
for (int i=0; i<4; ++i)
|
||||
{
|
||||
mData.mSkills[i] = -1;
|
||||
if (mData.mEffectID[i] != 85 &&
|
||||
mData.mEffectID[i] != 22 &&
|
||||
mData.mEffectID[i] != 17 &&
|
||||
mData.mEffectID[i] != 79 &&
|
||||
mData.mEffectID[i] != 74)
|
||||
{
|
||||
mData.mAttributes[i] = -1;
|
||||
}
|
||||
|
||||
// is this relevant in cycle from 0 to 4?
|
||||
if (mData.mEffectID[i] != 89 &&
|
||||
mData.mEffectID[i] != 26 &&
|
||||
mData.mEffectID[i] != 21 &&
|
||||
mData.mEffectID[i] != 83 &&
|
||||
mData.mEffectID[i] != 78)
|
||||
{
|
||||
mData.mSkills[i] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Ingredient::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNCString("MODL", mModel);
|
||||
esm.writeHNOCString("FNAM", mName);
|
||||
esm.writeHNT("IRDT", mData, 56);
|
||||
esm.writeHNOCString("SCRI", mScript);
|
||||
esm.writeHNOCString("ITEX", mIcon);
|
||||
}
|
||||
void Ingredient::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNCString("MODL", mModel);
|
||||
esm.writeHNOCString("FNAM", mName);
|
||||
esm.writeHNT("IRDT", mData, 56);
|
||||
esm.writeHNOCString("SCRI", mScript);
|
||||
esm.writeHNOCString("ITEX", mIcon);
|
||||
}
|
||||
|
||||
void Ingredient::blank()
|
||||
{
|
||||
|
|
|
@ -7,49 +7,51 @@
|
|||
namespace ESM
|
||||
{
|
||||
|
||||
void LevelledListBase::load(ESMReader &esm)
|
||||
{
|
||||
esm.getHNT(mFlags, "DATA");
|
||||
esm.getHNT(mChanceNone, "NNAM");
|
||||
|
||||
if (esm.isNextSub("INDX"))
|
||||
void LevelledListBase::load(ESMReader &esm)
|
||||
{
|
||||
int len;
|
||||
esm.getHT(len);
|
||||
mList.resize(len);
|
||||
}
|
||||
else
|
||||
{
|
||||
esm.skipRecord();
|
||||
return;
|
||||
}
|
||||
esm.getHNT(mFlags, "DATA");
|
||||
esm.getHNT(mChanceNone, "NNAM");
|
||||
|
||||
// If this levelled list was already loaded by a previous content file,
|
||||
// we overwrite the list. Merging lists should probably be left to external tools,
|
||||
// with the limited amount of information there is in the records, all merging methods
|
||||
// will be flawed in some way. For a proper fix the ESM format would have to be changed
|
||||
// to actually track list changes instead of including the whole list for every file
|
||||
// that does something with that list.
|
||||
if (esm.isNextSub("INDX"))
|
||||
{
|
||||
int len;
|
||||
esm.getHT(len);
|
||||
mList.resize(len);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Original engine ignores rest of the record, even if there are items following
|
||||
mList.clear();
|
||||
esm.skipRecord();
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < mList.size(); i++)
|
||||
{
|
||||
LevelItem &li = mList[i];
|
||||
li.mId = esm.getHNString(mRecName);
|
||||
esm.getHNT(li.mLevel, "INTV");
|
||||
}
|
||||
}
|
||||
void LevelledListBase::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNT("DATA", mFlags);
|
||||
esm.writeHNT("NNAM", mChanceNone);
|
||||
esm.writeHNT<int>("INDX", mList.size());
|
||||
// If this levelled list was already loaded by a previous content file,
|
||||
// we overwrite the list. Merging lists should probably be left to external tools,
|
||||
// with the limited amount of information there is in the records, all merging methods
|
||||
// will be flawed in some way. For a proper fix the ESM format would have to be changed
|
||||
// to actually track list changes instead of including the whole list for every file
|
||||
// that does something with that list.
|
||||
|
||||
for (std::vector<LevelItem>::const_iterator it = mList.begin(); it != mList.end(); ++it)
|
||||
{
|
||||
esm.writeHNCString(mRecName, it->mId);
|
||||
esm.writeHNT("INTV", it->mLevel);
|
||||
for (size_t i = 0; i < mList.size(); i++)
|
||||
{
|
||||
LevelItem &li = mList[i];
|
||||
li.mId = esm.getHNString(mRecName);
|
||||
esm.getHNT(li.mLevel, "INTV");
|
||||
}
|
||||
}
|
||||
void LevelledListBase::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNT("DATA", mFlags);
|
||||
esm.writeHNT("NNAM", mChanceNone);
|
||||
esm.writeHNT<int>("INDX", mList.size());
|
||||
|
||||
for (std::vector<LevelItem>::const_iterator it = mList.begin(); it != mList.end(); ++it)
|
||||
{
|
||||
esm.writeHNCString(mRecName, it->mId);
|
||||
esm.writeHNT("INTV", it->mLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LevelledListBase::blank()
|
||||
{
|
||||
|
|
|
@ -8,25 +8,50 @@ namespace ESM
|
|||
{
|
||||
unsigned int Light::sRecordId = REC_LIGH;
|
||||
|
||||
void Light::load(ESMReader &esm)
|
||||
{
|
||||
mModel = esm.getHNOString("MODL");
|
||||
mName = esm.getHNOString("FNAM");
|
||||
mIcon = esm.getHNOString("ITEX");
|
||||
assert(sizeof(mData) == 24);
|
||||
esm.getHNT(mData, "LHDT", 24);
|
||||
mScript = esm.getHNOString("SCRI");
|
||||
mSound = esm.getHNOString("SNAM");
|
||||
}
|
||||
void Light::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNCString("MODL", mModel);
|
||||
esm.writeHNOCString("FNAM", mName);
|
||||
esm.writeHNOCString("ITEX", mIcon);
|
||||
esm.writeHNT("LHDT", mData, 24);
|
||||
esm.writeHNOCString("SCRI", mScript);
|
||||
esm.writeHNOCString("SNAM", mSound);
|
||||
}
|
||||
void Light::load(ESMReader &esm)
|
||||
{
|
||||
bool hasData = false;
|
||||
while (esm.hasMoreSubs())
|
||||
{
|
||||
esm.getSubName();
|
||||
uint32_t name = esm.retSubName().val;
|
||||
switch (name)
|
||||
{
|
||||
case ESM::FourCC<'M','O','D','L'>::value:
|
||||
mModel = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'F','N','A','M'>::value:
|
||||
mName = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'I','T','E','X'>::value:
|
||||
mIcon = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'L','H','D','T'>::value:
|
||||
esm.getHT(mData, 24);
|
||||
hasData = true;
|
||||
break;
|
||||
case ESM::FourCC<'S','C','R','I'>::value:
|
||||
mScript = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'S','N','A','M'>::value:
|
||||
mSound = esm.getHString();
|
||||
break;
|
||||
default:
|
||||
esm.fail("Unknown subrecord");
|
||||
}
|
||||
}
|
||||
if (!hasData)
|
||||
esm.fail("Missing LHDT subrecord");
|
||||
}
|
||||
void Light::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNCString("MODL", mModel);
|
||||
esm.writeHNOCString("FNAM", mName);
|
||||
esm.writeHNOCString("ITEX", mIcon);
|
||||
esm.writeHNT("LHDT", mData, 24);
|
||||
esm.writeHNOCString("SCRI", mScript);
|
||||
esm.writeHNOCString("SNAM", mSound);
|
||||
}
|
||||
|
||||
void Light::blank()
|
||||
{
|
||||
|
|
|
@ -8,26 +8,48 @@ namespace ESM
|
|||
{
|
||||
unsigned int Lockpick::sRecordId = REC_LOCK;
|
||||
|
||||
void Lockpick::load(ESMReader &esm)
|
||||
{
|
||||
mModel = esm.getHNString("MODL");
|
||||
mName = esm.getHNOString("FNAM");
|
||||
void Lockpick::load(ESMReader &esm)
|
||||
{
|
||||
bool hasData = true;
|
||||
while (esm.hasMoreSubs())
|
||||
{
|
||||
esm.getSubName();
|
||||
uint32_t name = esm.retSubName().val;
|
||||
switch (name)
|
||||
{
|
||||
case ESM::FourCC<'M','O','D','L'>::value:
|
||||
mModel = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'F','N','A','M'>::value:
|
||||
mName = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'L','K','D','T'>::value:
|
||||
esm.getHT(mData, 16);
|
||||
hasData = true;
|
||||
break;
|
||||
case ESM::FourCC<'S','C','R','I'>::value:
|
||||
mScript = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'I','T','E','X'>::value:
|
||||
mIcon = esm.getHString();
|
||||
break;
|
||||
default:
|
||||
esm.fail("Unknown subrecord");
|
||||
}
|
||||
}
|
||||
if (!hasData)
|
||||
esm.fail("Missing LKDT subrecord");
|
||||
}
|
||||
|
||||
esm.getHNT(mData, "LKDT", 16);
|
||||
void Lockpick::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNCString("MODL", mModel);
|
||||
esm.writeHNOCString("FNAM", mName);
|
||||
|
||||
mScript = esm.getHNOString("SCRI");
|
||||
mIcon = esm.getHNOString("ITEX");
|
||||
}
|
||||
|
||||
void Lockpick::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNCString("MODL", mModel);
|
||||
esm.writeHNOCString("FNAM", mName);
|
||||
|
||||
esm.writeHNT("LKDT", mData, 16);
|
||||
esm.writeHNOString("SCRI", mScript);
|
||||
esm.writeHNOCString("ITEX", mIcon);
|
||||
}
|
||||
esm.writeHNT("LKDT", mData, 16);
|
||||
esm.writeHNOString("SCRI", mScript);
|
||||
esm.writeHNOCString("ITEX", mIcon);
|
||||
}
|
||||
|
||||
void Lockpick::blank()
|
||||
{
|
||||
|
|
|
@ -246,7 +246,7 @@ void MagicEffect::load(ESMReader &esm)
|
|||
mDescription = esm.getHString();
|
||||
break;
|
||||
default:
|
||||
esm.fail("Unknown subrecord " + esm.retSubName().toString());
|
||||
esm.fail("Unknown subrecord");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,9 +57,9 @@ struct MagicEffect
|
|||
// Glow color for enchanted items with this effect
|
||||
int mRed, mGreen, mBlue;
|
||||
|
||||
float mUnknown1;
|
||||
float mUnknown1; // Called "Size X" in CS
|
||||
float mSpeed; // Speed of fired projectile
|
||||
float mUnknown2;
|
||||
float mUnknown2; // Called "Size Cap" in CS
|
||||
}; // 36 bytes
|
||||
|
||||
static const std::map<short,std::string> sNames;
|
||||
|
|
|
@ -99,7 +99,7 @@ namespace ESM
|
|||
mAiPackage.add(esm);
|
||||
break;
|
||||
default:
|
||||
esm.fail("Unknown subrecord " + esm.retSubName().toString());
|
||||
esm.fail("Unknown subrecord");
|
||||
}
|
||||
}
|
||||
if (!hasNpdt)
|
||||
|
|
|
@ -8,26 +8,48 @@ namespace ESM
|
|||
{
|
||||
unsigned int Probe::sRecordId = REC_PROB;
|
||||
|
||||
void Probe::load(ESMReader &esm)
|
||||
{
|
||||
mModel = esm.getHNString("MODL");
|
||||
mName = esm.getHNOString("FNAM");
|
||||
void Probe::load(ESMReader &esm)
|
||||
{
|
||||
bool hasData = true;
|
||||
while (esm.hasMoreSubs())
|
||||
{
|
||||
esm.getSubName();
|
||||
uint32_t name = esm.retSubName().val;
|
||||
switch (name)
|
||||
{
|
||||
case ESM::FourCC<'M','O','D','L'>::value:
|
||||
mModel = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'F','N','A','M'>::value:
|
||||
mName = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'P','B','D','T'>::value:
|
||||
esm.getHT(mData, 16);
|
||||
hasData = true;
|
||||
break;
|
||||
case ESM::FourCC<'S','C','R','I'>::value:
|
||||
mScript = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'I','T','E','X'>::value:
|
||||
mIcon = esm.getHString();
|
||||
break;
|
||||
default:
|
||||
esm.fail("Unknown subrecord");
|
||||
}
|
||||
}
|
||||
if (!hasData)
|
||||
esm.fail("Missing PBDT subrecord");
|
||||
}
|
||||
|
||||
esm.getHNT(mData, "PBDT", 16);
|
||||
void Probe::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNCString("MODL", mModel);
|
||||
esm.writeHNOCString("FNAM", mName);
|
||||
|
||||
mScript = esm.getHNOString("SCRI");
|
||||
mIcon = esm.getHNOString("ITEX");
|
||||
}
|
||||
|
||||
void Probe::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNCString("MODL", mModel);
|
||||
esm.writeHNOCString("FNAM", mName);
|
||||
|
||||
esm.writeHNT("PBDT", mData, 16);
|
||||
esm.writeHNOString("SCRI", mScript);
|
||||
esm.writeHNOCString("ITEX", mIcon);
|
||||
}
|
||||
esm.writeHNT("PBDT", mData, 16);
|
||||
esm.writeHNOString("SCRI", mScript);
|
||||
esm.writeHNOCString("ITEX", mIcon);
|
||||
}
|
||||
|
||||
void Probe::blank()
|
||||
{
|
||||
|
|
|
@ -43,7 +43,7 @@ void Race::load(ESMReader &esm)
|
|||
mPowers.add(esm);
|
||||
break;
|
||||
default:
|
||||
esm.fail("Unknown subrecord " + esm.retSubName().toString());
|
||||
esm.fail("Unknown subrecord");
|
||||
}
|
||||
}
|
||||
if (!hasData)
|
||||
|
|
|
@ -10,13 +10,35 @@ namespace ESM
|
|||
|
||||
void Repair::load(ESMReader &esm)
|
||||
{
|
||||
mModel = esm.getHNString("MODL");
|
||||
mName = esm.getHNOString("FNAM");
|
||||
|
||||
esm.getHNT(mData, "RIDT", 16);
|
||||
|
||||
mScript = esm.getHNOString("SCRI");
|
||||
mIcon = esm.getHNOString("ITEX");
|
||||
bool hasData = true;
|
||||
while (esm.hasMoreSubs())
|
||||
{
|
||||
esm.getSubName();
|
||||
uint32_t name = esm.retSubName().val;
|
||||
switch (name)
|
||||
{
|
||||
case ESM::FourCC<'M','O','D','L'>::value:
|
||||
mModel = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'F','N','A','M'>::value:
|
||||
mName = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'R','I','D','T'>::value:
|
||||
esm.getHT(mData, 16);
|
||||
hasData = true;
|
||||
break;
|
||||
case ESM::FourCC<'S','C','R','I'>::value:
|
||||
mScript = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'I','T','E','X'>::value:
|
||||
mIcon = esm.getHString();
|
||||
break;
|
||||
default:
|
||||
esm.fail("Unknown subrecord");
|
||||
}
|
||||
}
|
||||
if (!hasData)
|
||||
esm.fail("Missing RIDT subrecord");
|
||||
}
|
||||
|
||||
void Repair::save(ESMWriter &esm) const
|
||||
|
|
|
@ -9,17 +9,7 @@ namespace ESM
|
|||
|
||||
unsigned int Script::sRecordId = REC_SCPT;
|
||||
|
||||
void Script::load(ESMReader &esm)
|
||||
{
|
||||
SCHD data;
|
||||
esm.getHNT(data, "SCHD", 52);
|
||||
mData = data.mData;
|
||||
mId = data.mName.toString();
|
||||
|
||||
mVarNames.clear();
|
||||
|
||||
// List of local variables
|
||||
if (esm.isNextSub("SCVR"))
|
||||
void Script::loadSCVR(ESMReader &esm)
|
||||
{
|
||||
int s = mData.mStringTableSize;
|
||||
|
||||
|
@ -66,58 +56,70 @@ void Script::load(ESMReader &esm)
|
|||
}
|
||||
}
|
||||
|
||||
// Script mData
|
||||
if (esm.isNextSub("SCDT"))
|
||||
void Script::load(ESMReader &esm)
|
||||
{
|
||||
mScriptData.resize(mData.mScriptDataSize);
|
||||
esm.getHExact(&mScriptData[0], mScriptData.size());
|
||||
}
|
||||
SCHD data;
|
||||
esm.getHNT(data, "SCHD", 52);
|
||||
mData = data.mData;
|
||||
mId = data.mName.toString();
|
||||
|
||||
// Script text
|
||||
mScriptText = esm.getHNOString("SCTX");
|
||||
mVarNames.clear();
|
||||
|
||||
// NOTE: A minor hack/workaround...
|
||||
//
|
||||
// MAO_Containers.esp from Morrowind Acoustic Overhaul has SCVR records
|
||||
// at the end (see Bug #1849). Since OpenMW does not use SCVR subrecords
|
||||
// for variable names just skip these as a quick fix. An alternative
|
||||
// solution would be to decode and validate SCVR subrecords even if they
|
||||
// appear here.
|
||||
if (esm.isNextSub("SCVR")) {
|
||||
esm.skipHSub();
|
||||
}
|
||||
}
|
||||
void Script::save(ESMWriter &esm) const
|
||||
{
|
||||
std::string varNameString;
|
||||
if (!mVarNames.empty())
|
||||
for (std::vector<std::string>::const_iterator it = mVarNames.begin(); it != mVarNames.end(); ++it)
|
||||
varNameString.append(*it);
|
||||
|
||||
SCHD data;
|
||||
memset(&data, 0, sizeof(data));
|
||||
|
||||
data.mData = mData;
|
||||
memcpy(data.mName.name, mId.c_str(), mId.size());
|
||||
|
||||
esm.writeHNT("SCHD", data, 52);
|
||||
|
||||
if (!mVarNames.empty())
|
||||
{
|
||||
esm.startSubRecord("SCVR");
|
||||
for (std::vector<std::string>::const_iterator it = mVarNames.begin(); it != mVarNames.end(); ++it)
|
||||
while (esm.hasMoreSubs())
|
||||
{
|
||||
esm.writeHCString(*it);
|
||||
esm.getSubName();
|
||||
uint32_t name = esm.retSubName().val;
|
||||
switch (name)
|
||||
{
|
||||
case ESM::FourCC<'S','C','V','R'>::value:
|
||||
// list of local variables
|
||||
loadSCVR(esm);
|
||||
break;
|
||||
case ESM::FourCC<'S','C','D','T'>::value:
|
||||
// compiled script
|
||||
mScriptData.resize(mData.mScriptDataSize);
|
||||
esm.getHExact(&mScriptData[0], mScriptData.size());
|
||||
break;
|
||||
case ESM::FourCC<'S','C','T','X'>::value:
|
||||
mScriptText = esm.getHString();
|
||||
break;
|
||||
default:
|
||||
esm.fail("Unknown subrecord");
|
||||
}
|
||||
}
|
||||
esm.endRecord("SCVR");
|
||||
}
|
||||
|
||||
esm.startSubRecord("SCDT");
|
||||
esm.write(reinterpret_cast<const char * >(&mScriptData[0]), mData.mScriptDataSize);
|
||||
esm.endRecord("SCDT");
|
||||
void Script::save(ESMWriter &esm) const
|
||||
{
|
||||
std::string varNameString;
|
||||
if (!mVarNames.empty())
|
||||
for (std::vector<std::string>::const_iterator it = mVarNames.begin(); it != mVarNames.end(); ++it)
|
||||
varNameString.append(*it);
|
||||
|
||||
esm.writeHNOString("SCTX", mScriptText);
|
||||
}
|
||||
SCHD data;
|
||||
memset(&data, 0, sizeof(data));
|
||||
|
||||
data.mData = mData;
|
||||
memcpy(data.mName.name, mId.c_str(), mId.size());
|
||||
|
||||
esm.writeHNT("SCHD", data, 52);
|
||||
|
||||
if (!mVarNames.empty())
|
||||
{
|
||||
esm.startSubRecord("SCVR");
|
||||
for (std::vector<std::string>::const_iterator it = mVarNames.begin(); it != mVarNames.end(); ++it)
|
||||
{
|
||||
esm.writeHCString(*it);
|
||||
}
|
||||
esm.endRecord("SCVR");
|
||||
}
|
||||
|
||||
esm.startSubRecord("SCDT");
|
||||
esm.write(reinterpret_cast<const char * >(&mScriptData[0]), mData.mScriptDataSize);
|
||||
esm.endRecord("SCDT");
|
||||
|
||||
esm.writeHNOString("SCTX", mScriptText);
|
||||
}
|
||||
|
||||
void Script::blank()
|
||||
{
|
||||
|
|
|
@ -53,6 +53,9 @@ public:
|
|||
|
||||
void blank();
|
||||
///< Set record to default state (does not touch the ID/index).
|
||||
|
||||
private:
|
||||
void loadSCVR(ESMReader &esm);
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -129,23 +129,47 @@ namespace ESM
|
|||
|
||||
unsigned int Skill::sRecordId = REC_SKIL;
|
||||
|
||||
void Skill::load(ESMReader &esm)
|
||||
{
|
||||
esm.getHNT(mIndex, "INDX");
|
||||
esm.getHNT(mData, "SKDT", 24);
|
||||
mDescription = esm.getHNOString("DESC");
|
||||
void Skill::load(ESMReader &esm)
|
||||
{
|
||||
bool hasIndex = false;
|
||||
bool hasData = false;
|
||||
while (esm.hasMoreSubs())
|
||||
{
|
||||
esm.getSubName();
|
||||
uint32_t name = esm.retSubName().val;
|
||||
switch (name)
|
||||
{
|
||||
case ESM::FourCC<'I','N','D','X'>::value:
|
||||
esm.getHT(mIndex);
|
||||
hasIndex = true;
|
||||
break;
|
||||
case ESM::FourCC<'S','K','D','T'>::value:
|
||||
esm.getHT(mData, 24);
|
||||
hasData = true;
|
||||
break;
|
||||
case ESM::FourCC<'D','E','S','C'>::value:
|
||||
mDescription = esm.getHString();
|
||||
break;
|
||||
default:
|
||||
esm.fail("Unknown subrecord");
|
||||
}
|
||||
}
|
||||
if (!hasIndex)
|
||||
esm.fail("Missing INDX");
|
||||
if (!hasData)
|
||||
esm.fail("Missing SKDT");
|
||||
|
||||
// create an ID from the index and the name (only used in the editor and likely to change in the
|
||||
// future)
|
||||
mId = indexToId (mIndex);
|
||||
}
|
||||
// create an ID from the index and the name (only used in the editor and likely to change in the
|
||||
// future)
|
||||
mId = indexToId (mIndex);
|
||||
}
|
||||
|
||||
void Skill::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNT("INDX", mIndex);
|
||||
esm.writeHNT("SKDT", mData, 24);
|
||||
esm.writeHNOString("DESC", mDescription);
|
||||
}
|
||||
void Skill::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNT("INDX", mIndex);
|
||||
esm.writeHNT("SKDT", mData, 24);
|
||||
esm.writeHNOString("DESC", mDescription);
|
||||
}
|
||||
|
||||
void Skill::blank()
|
||||
{
|
||||
|
|
|
@ -8,19 +8,38 @@ namespace ESM
|
|||
{
|
||||
unsigned int SoundGenerator::sRecordId = REC_SNDG;
|
||||
|
||||
void SoundGenerator::load(ESMReader &esm)
|
||||
{
|
||||
esm.getHNT(mType, "DATA", 4);
|
||||
|
||||
mCreature = esm.getHNOString("CNAM");
|
||||
mSound = esm.getHNOString("SNAM");
|
||||
}
|
||||
void SoundGenerator::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNT("DATA", mType, 4);
|
||||
esm.writeHNOCString("CNAM", mCreature);
|
||||
esm.writeHNOCString("SNAM", mSound);
|
||||
}
|
||||
void SoundGenerator::load(ESMReader &esm)
|
||||
{
|
||||
bool hasData = false;
|
||||
while (esm.hasMoreSubs())
|
||||
{
|
||||
esm.getSubName();
|
||||
uint32_t name = esm.retSubName().val;
|
||||
switch (name)
|
||||
{
|
||||
case ESM::FourCC<'D','A','T','A'>::value:
|
||||
esm.getHT(mType, 4);
|
||||
hasData = true;
|
||||
break;
|
||||
case ESM::FourCC<'C','N','A','M'>::value:
|
||||
mCreature = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'S','N','A','M'>::value:
|
||||
mSound = esm.getHString();
|
||||
break;
|
||||
default:
|
||||
esm.fail("Unknown subrecord");
|
||||
}
|
||||
}
|
||||
if (!hasData)
|
||||
esm.fail("Missing DATA");
|
||||
}
|
||||
void SoundGenerator::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNT("DATA", mType, 4);
|
||||
esm.writeHNOCString("CNAM", mCreature);
|
||||
esm.writeHNOCString("SNAM", mSound);
|
||||
}
|
||||
|
||||
void SoundGenerator::blank()
|
||||
{
|
||||
|
|
|
@ -8,22 +8,35 @@ namespace ESM
|
|||
{
|
||||
unsigned int Sound::sRecordId = REC_SOUN;
|
||||
|
||||
void Sound::load(ESMReader &esm)
|
||||
{
|
||||
mSound = esm.getHNOString("FNAM");
|
||||
esm.getHNT(mData, "DATA", 3);
|
||||
/*
|
||||
cout << "vol=" << (int)data.volume
|
||||
<< " min=" << (int)data.minRange
|
||||
<< " max=" << (int)data.maxRange
|
||||
<< endl;
|
||||
*/
|
||||
}
|
||||
void Sound::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNOCString("FNAM", mSound);
|
||||
esm.writeHNT("DATA", mData, 3);
|
||||
}
|
||||
void Sound::load(ESMReader &esm)
|
||||
{
|
||||
bool hasData = false;
|
||||
while (esm.hasMoreSubs())
|
||||
{
|
||||
esm.getSubName();
|
||||
uint32_t name = esm.retSubName().val;
|
||||
switch (name)
|
||||
{
|
||||
case ESM::FourCC<'F','N','A','M'>::value:
|
||||
mSound = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'D','A','T','A'>::value:
|
||||
esm.getHT(mData, 3);
|
||||
hasData = true;
|
||||
break;
|
||||
default:
|
||||
esm.fail("Unknown subrecord");
|
||||
}
|
||||
}
|
||||
if (!hasData)
|
||||
esm.fail("Missing DATA");
|
||||
}
|
||||
|
||||
void Sound::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNOCString("FNAM", mSound);
|
||||
esm.writeHNT("DATA", mData, 3);
|
||||
}
|
||||
|
||||
void Sound::blank()
|
||||
{
|
||||
|
|
|
@ -8,40 +8,41 @@ namespace ESM
|
|||
{
|
||||
unsigned int Spell::sRecordId = REC_SPEL;
|
||||
|
||||
void Spell::load(ESMReader &esm)
|
||||
{
|
||||
bool hasData = false;
|
||||
while (esm.hasMoreSubs())
|
||||
void Spell::load(ESMReader &esm)
|
||||
{
|
||||
esm.getSubName();
|
||||
uint32_t val = esm.retSubName().val;
|
||||
|
||||
switch (val)
|
||||
mEffects.mList.clear();
|
||||
bool hasData = false;
|
||||
while (esm.hasMoreSubs())
|
||||
{
|
||||
case ESM::FourCC<'F','N','A','M'>::value:
|
||||
mName = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'S','P','D','T'>::value:
|
||||
esm.getHT(mData, 12);
|
||||
hasData = true;
|
||||
break;
|
||||
case ESM::FourCC<'E','N','A','M'>::value:
|
||||
ENAMstruct s;
|
||||
esm.getHT(s, 24);
|
||||
mEffects.mList.push_back(s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasData)
|
||||
esm.fail("Missing SPDT subrecord");
|
||||
}
|
||||
esm.getSubName();
|
||||
uint32_t val = esm.retSubName().val;
|
||||
|
||||
void Spell::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNOCString("FNAM", mName);
|
||||
esm.writeHNT("SPDT", mData, 12);
|
||||
mEffects.save(esm);
|
||||
}
|
||||
switch (val)
|
||||
{
|
||||
case ESM::FourCC<'F','N','A','M'>::value:
|
||||
mName = esm.getHString();
|
||||
break;
|
||||
case ESM::FourCC<'S','P','D','T'>::value:
|
||||
esm.getHT(mData, 12);
|
||||
hasData = true;
|
||||
break;
|
||||
case ESM::FourCC<'E','N','A','M'>::value:
|
||||
ENAMstruct s;
|
||||
esm.getHT(s, 24);
|
||||
mEffects.mList.push_back(s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasData)
|
||||
esm.fail("Missing SPDT subrecord");
|
||||
}
|
||||
|
||||
void Spell::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNOCString("FNAM", mName);
|
||||
esm.writeHNT("SPDT", mData, 12);
|
||||
mEffects.save(esm);
|
||||
}
|
||||
|
||||
void Spell::blank()
|
||||
{
|
||||
|
|
|
@ -8,15 +8,37 @@ namespace ESM
|
|||
{
|
||||
unsigned int StartScript::sRecordId = REC_SSCR;
|
||||
|
||||
void StartScript::load(ESMReader &esm)
|
||||
{
|
||||
mData = esm.getHNString("DATA");
|
||||
mScript = esm.getHNString("NAME");
|
||||
}
|
||||
void StartScript::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNString("DATA", mData);
|
||||
esm.writeHNString("NAME", mScript);
|
||||
}
|
||||
void StartScript::load(ESMReader &esm)
|
||||
{
|
||||
bool hasData = false;
|
||||
bool hasName = false;
|
||||
while (esm.hasMoreSubs())
|
||||
{
|
||||
esm.getSubName();
|
||||
uint32_t name = esm.retSubName().val;
|
||||
switch (name)
|
||||
{
|
||||
case ESM::FourCC<'D','A','T','A'>::value:
|
||||
mData = esm.getHString();
|
||||
hasData = true;
|
||||
break;
|
||||
case ESM::FourCC<'N','A','M','E'>::value:
|
||||
mScript = esm.getHString();
|
||||
hasName = true;
|
||||
break;
|
||||
default:
|
||||
esm.fail("Unknown subrecord");
|
||||
}
|
||||
}
|
||||
if (!hasData)
|
||||
esm.fail("Missing DATA");
|
||||
if (!hasName)
|
||||
esm.fail("Missing NAME");
|
||||
}
|
||||
void StartScript::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNString("DATA", mData);
|
||||
esm.writeHNString("NAME", mScript);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,15 +8,16 @@ namespace ESM
|
|||
{
|
||||
unsigned int Static::sRecordId = REC_STAT;
|
||||
|
||||
void Static::load(ESMReader &esm)
|
||||
{
|
||||
mPersistent = esm.getRecordFlags() & 0x0400;
|
||||
mModel = esm.getHNString("MODL");
|
||||
}
|
||||
void Static::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNCString("MODL", mModel);
|
||||
}
|
||||
void Static::load(ESMReader &esm)
|
||||
{
|
||||
mPersistent = esm.getRecordFlags() & 0x0400;
|
||||
|
||||
mModel = esm.getHNString("MODL");
|
||||
}
|
||||
void Static::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNCString("MODL", mModel);
|
||||
}
|
||||
|
||||
void Static::blank()
|
||||
{
|
||||
|
|
|
@ -50,8 +50,8 @@ namespace ESM
|
|||
NAME32 mPlayerName;
|
||||
};
|
||||
GMDT mGameData; // Used in .ess savegames only
|
||||
std::vector<unsigned char> mSCRD; // Used in .ess savegames only, screenshot?
|
||||
std::vector<unsigned char> mSCRS; // Used in .ess savegames only, screenshot?
|
||||
std::vector<unsigned char> mSCRD; // Used in .ess savegames only, unknown
|
||||
std::vector<unsigned char> mSCRS; // Used in .ess savegames only, screenshot
|
||||
|
||||
Data mData;
|
||||
int mFormat;
|
||||
|
|
|
@ -5,14 +5,6 @@
|
|||
|
||||
namespace ESM {
|
||||
|
||||
void SpellList::load(ESMReader &esm)
|
||||
{
|
||||
mList.clear();
|
||||
while (esm.isNextSub("NPCS")) {
|
||||
add(esm);
|
||||
}
|
||||
}
|
||||
|
||||
void SpellList::add(ESMReader &esm)
|
||||
{
|
||||
mList.push_back(esm.getHString());
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace ESM
|
|||
|
||||
/** A list of references to spells and spell effects. This is shared
|
||||
between the records BSGN, NPC and RACE.
|
||||
NPCS subrecord.
|
||||
*/
|
||||
struct SpellList
|
||||
{
|
||||
|
@ -22,9 +23,6 @@ namespace ESM
|
|||
/// Load one spell, assumes the subrecord name was already read
|
||||
void add(ESMReader &esm);
|
||||
|
||||
/// Load all spells
|
||||
/// TODO: remove this method, the ESM format doesn't guarantee that all spell subrecords follow one another
|
||||
void load(ESMReader &esm);
|
||||
void save(ESMWriter &esm) const;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ char const * Buffer::getData()
|
|||
}
|
||||
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_libsdl_app_SDLActivity_getPathToJni(JNIEnv *env, jobject obj, jstring prompt)
|
||||
JNIEXPORT void JNICALL Java_ui_activity_GameActivity_getPathToJni(JNIEnv *env, jobject obj, jstring prompt)
|
||||
{
|
||||
jboolean iscopy;
|
||||
Buffer::setData((env)->GetStringUTFChars(prompt, &iscopy));
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||
#include <jni.h>
|
||||
|
||||
#ifndef _Included_org_libsdl_app_SDLActivity_getPathToJni
|
||||
#define _Included_org_libsdl_app_SDLActivity_getPathToJni
|
||||
#ifndef _Included_ui_activity_GameActivity_getPathToJni
|
||||
#define _Included_ui_activity_GameActivity_getPathToJni
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
@ -11,7 +11,7 @@ extern "C" {
|
|||
* Method: getPathToJni
|
||||
* Signature: (I)I
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_org_libsdl_app_SDLActivity_getPathToJni(JNIEnv *env, jobject obj, jstring prompt);
|
||||
JNIEXPORT void JNICALL Java_ui_activity_GameActivity_getPathToJni(JNIEnv *env, jobject obj, jstring prompt);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
1
components/nif/.gitignore
vendored
1
components/nif/.gitignore
vendored
|
@ -1 +0,0 @@
|
|||
old_d
|
|
@ -152,9 +152,9 @@ namespace Gui
|
|||
eventWidgetSelected(_sender);
|
||||
}
|
||||
|
||||
MyGUI::Widget* MWList::getItemWidget(const std::string& name)
|
||||
MyGUI::Button *MWList::getItemWidget(const std::string& name)
|
||||
{
|
||||
return mScrollView->findWidget (getName() + "_item_" + name);
|
||||
return mScrollView->findWidget (getName() + "_item_" + name)->castType<MyGUI::Button>();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ namespace Gui
|
|||
std::string getItemNameAt(unsigned int at); ///< \attention if there are separators, this method will return "" at the place where the separator is
|
||||
void clear();
|
||||
|
||||
MyGUI::Widget* getItemWidget(const std::string& name);
|
||||
MyGUI::Button* getItemWidget(const std::string& name);
|
||||
///< get widget for an item name, useful to set up tooltip
|
||||
|
||||
virtual void setPropertyOverride(const std::string& _key, const std::string& _value);
|
||||
|
|
|
@ -243,7 +243,9 @@
|
|||
}
|
||||
|
||||
#else
|
||||
|
||||
#if NORMAL_MAP && SH_GLSLES
|
||||
mat3 transpose( mat3 m);
|
||||
#endif
|
||||
// ----------------------------------- FRAGMENT ------------------------------------------
|
||||
|
||||
#if UNDERWATER
|
||||
|
@ -376,13 +378,13 @@
|
|||
float3 binormal = cross(tangentPassthrough.xyz, normal.xyz);
|
||||
float3x3 tbn = float3x3(tangentPassthrough.xyz, binormal, normal.xyz);
|
||||
|
||||
#if SH_GLSL
|
||||
#if SH_GLSL || SH_GLSLES
|
||||
tbn = transpose(tbn);
|
||||
#endif
|
||||
|
||||
float4 normalTex = shSample(normalMap, UV.xy);
|
||||
|
||||
normal = normalize (shMatrixMult( transpose(tbn), normalTex.xyz * 2 - 1 ));
|
||||
normal = normalize (shMatrixMult( transpose(tbn), normalTex.xyz * 2.0 - float3 (1.0,1.0,1.0) ));
|
||||
#endif
|
||||
|
||||
#if ENV_MAP || SPECULAR || PARALLAX
|
||||
|
@ -576,5 +578,14 @@
|
|||
// prevent negative colour output (for example with negative lights)
|
||||
shOutputColour(0).xyz = max(shOutputColour(0).xyz, float3(0.0,0.0,0.0));
|
||||
}
|
||||
#if NORMAL_MAP && SH_GLSLES
|
||||
mat3 transpose(mat3 m){
|
||||
return mat3(
|
||||
m[0][0],m[1][0],m[2][0],
|
||||
m[0][1],m[1][1],m[2][1],
|
||||
m[0][2],m[1][2],m[2][2]
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
particle_system openmw/Ripples
|
||||
{
|
||||
material openmw/Ripple
|
||||
particle_width 50
|
||||
particle_height 50
|
||||
particle_width 30
|
||||
particle_height 30
|
||||
// To make the particles move with the scene node when the waterlevel changes
|
||||
local_space true
|
||||
quota 300
|
||||
|
@ -17,7 +17,7 @@ particle_system openmw/Ripples
|
|||
|
||||
affector Scaler
|
||||
{
|
||||
rate 100
|
||||
rate 120
|
||||
}
|
||||
|
||||
affector Rotator
|
||||
|
|
|
@ -221,6 +221,9 @@
|
|||
#if UNDERWATER
|
||||
#include "underwater.h"
|
||||
#endif
|
||||
#if NORMAL_MAP && SH_GLSLES
|
||||
mat3 transpose(mat3 m);
|
||||
#endif
|
||||
|
||||
SH_BEGIN_PROGRAM
|
||||
|
||||
|
@ -319,7 +322,7 @@ shUniform(float4, cameraPos) @shAutoConstant(cameraPos, camera_position)
|
|||
|
||||
// derive final matrix
|
||||
float3x3 tbn = float3x3(tangent, binormal, normal);
|
||||
#if SH_GLSL
|
||||
#if SH_GLSL || SH_GLSLES
|
||||
tbn = transpose(tbn);
|
||||
#endif
|
||||
#endif
|
||||
|
@ -492,5 +495,13 @@ albedo = shLerp(albedo, diffuseTex, blendValues@shPropertyString(blendmap_compon
|
|||
shOutputColour(0).a = 1.0-previousAlpha;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if NORMAL_MAP && SH_GLSLES
|
||||
mat3 transpose(mat3 m){
|
||||
return mat3(
|
||||
m[0][0],m[1][0],m[2][0],
|
||||
m[0][1],m[1][1],m[2][1],
|
||||
m[0][2],m[1][2],m[2][2]
|
||||
);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -112,7 +112,8 @@
|
|||
<Property key="ImageTexture" value="textures\compass.dds"/>
|
||||
</Widget>
|
||||
|
||||
<Widget type="Button" skin="" position="0 0 1536 1536" name="MiniMapButton" align="Right Bottom">
|
||||
<Widget type="Button" skin="" position_real="0 0 1 1" name="MiniMapButton" align="Stretch">
|
||||
<Property key="Depth" value="10"/>
|
||||
</Widget>
|
||||
|
||||
</Widget>
|
||||
|
|
|
@ -28,9 +28,9 @@
|
|||
<State name="normal" colour="#{fontcolour=journal_topic}" shift="0"/>
|
||||
<State name="highlighted" colour="#{fontcolour=journal_topic_over}" shift="0"/>
|
||||
<State name="pushed" colour="#{fontcolour=journal_topic_pressed}" shift="0"/>
|
||||
<State name="normal_checked" colour="#{fontcolour=journal_topic_pressed}" shift="0"/>
|
||||
<State name="highlighted_checked" colour="#{fontcolour=journal_topic_pressed}" shift="0"/>
|
||||
<State name="pushed_checked" colour="#{fontcolour=journal_topic_pressed}" shift="0"/>
|
||||
<State name="normal_checked" colour="0.2 0.2 0.2" shift="0"/>
|
||||
<State name="highlighted_checked" colour="0.4 0.4 0.4" shift="0"/>
|
||||
<State name="pushed_checked" colour="0.5 0.5 0.5" shift="0"/>
|
||||
</BasisSkin>
|
||||
</Resource>
|
||||
</MyGUI>
|
||||
|
|
|
@ -235,7 +235,9 @@
|
|||
|
||||
<!-- Player skills, factions, birthsign and reputation -->
|
||||
<Widget type="Widget" skin="MW_Box" position="8 8 248 292" align="Left Stretch" name="Skills">
|
||||
<Widget type="ScrollView" skin="MW_ScrollView" position="4 4 240 284" align="Left Top Stretch" name="SkillView"/>
|
||||
<Widget type="ScrollView" skin="MW_ScrollView" position="4 4 240 284" align="Left Top Stretch" name="SkillView">
|
||||
<Property key="CanvasAlign" value="Left Top"/>
|
||||
</Widget>
|
||||
</Widget>
|
||||
|
||||
</Widget>
|
||||
|
|
|
@ -131,6 +131,13 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QProgressBar" name="progressBar">
|
||||
<property name="maximum">
|
||||
<number>4</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
|
|
Loading…
Reference in a new issue