forked from mirror/openmw-tes3mp
Merge remote-tracking branch 'OpenMW/master' into FixLoadOrderReset
Fixed Conflict: components/contentselector/model/contentmodel.cpp
This commit is contained in:
commit
9d6efcecff
211 changed files with 2679 additions and 1628 deletions
|
@ -6,4 +6,4 @@ export CC=clang
|
|||
brew tap openmw/openmw
|
||||
brew update
|
||||
brew unlink boost
|
||||
brew install cmake openmw-mygui openmw-bullet openmw-sdl2 openmw-ffmpeg pkg-config qt unshield
|
||||
brew install openmw-mygui openmw-bullet openmw-sdl2 openmw-ffmpeg qt unshield
|
||||
|
|
|
@ -20,29 +20,13 @@ set(OPENMW_VERSION_TAGHASH "")
|
|||
|
||||
set(OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}")
|
||||
|
||||
set(GIT_CHECKOUT FALSE)
|
||||
if(EXISTS ${PROJECT_SOURCE_DIR}/.git)
|
||||
if(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/shallow)
|
||||
find_package(Git)
|
||||
|
||||
if(GIT_FOUND)
|
||||
include(GetGitRevisionDescription)
|
||||
get_git_tag_revision(TAGHASH --tags --max-count=1)
|
||||
get_git_head_revision(REFSPEC COMMITHASH)
|
||||
git_describe(VERSION --tags ${TAGHASH})
|
||||
|
||||
string(REGEX MATCH "^openmw-[^0-9]*[0-9]+\\.[0-9]+\\.[0-9]+.*" MATCH "${VERSION}")
|
||||
if(MATCH)
|
||||
string(REGEX REPLACE "^openmw-([0-9]+)\\..*" "\\1" GIT_VERSION_MAJOR "${VERSION}")
|
||||
string(REGEX REPLACE "^openmw-[0-9]+\\.([0-9]+).*" "\\1" GIT_VERSION_MINOR "${VERSION}")
|
||||
string(REGEX REPLACE "^openmw-[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" GIT_VERSION_RELEASE "${VERSION}")
|
||||
|
||||
set(OPENMW_VERSION_COMMITHASH "${COMMITHASH}")
|
||||
set(OPENMW_VERSION_TAGHASH "${TAGHASH}")
|
||||
|
||||
message(STATUS "OpenMW version ${OPENMW_VERSION}")
|
||||
else(MATCH)
|
||||
message(WARNING "Failed to get valid version information from Git")
|
||||
endif(MATCH)
|
||||
set(GIT_CHECKOUT TRUE)
|
||||
else(GIT_FOUND)
|
||||
message(WARNING "Git executable not found")
|
||||
endif(GIT_FOUND)
|
||||
|
@ -870,4 +854,3 @@ if (DOXYGEN_FOUND)
|
|||
WORKING_DIRECTORY ${OpenMW_BINARY_DIR}
|
||||
COMMENT "Generating documentation for the github-pages at ${DOXYGEN_PAGES_OUTPUT_DIR}" VERBATIM)
|
||||
endif ()
|
||||
|
||||
|
|
|
@ -150,22 +150,15 @@ int extractAll(Bsa::BSAFile& bsa, Arguments& info);
|
|||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
try
|
||||
{
|
||||
Arguments info;
|
||||
if(!parseOptions (argc, argv, info))
|
||||
return 1;
|
||||
|
||||
// Open file
|
||||
Bsa::BSAFile bsa;
|
||||
try
|
||||
{
|
||||
bsa.open(info.filename);
|
||||
}
|
||||
catch(std::exception &e)
|
||||
{
|
||||
std::cout << "ERROR reading BSA archive '" << info.filename
|
||||
<< "'\nDetails:\n" << e.what() << std::endl;
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (info.mode == "list")
|
||||
return list(bsa, info);
|
||||
|
@ -178,6 +171,12 @@ int main(int argc, char** argv)
|
|||
std::cout << "Unsupported mode. That is not supposed to happen." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
std::cerr << "ERROR reading BSA archive\nDetails:\n" << e.what() << std::endl;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
int list(Bsa::BSAFile& bsa, Arguments& info)
|
||||
|
@ -189,9 +188,11 @@ int list(Bsa::BSAFile& bsa, Arguments& info)
|
|||
if(info.longformat)
|
||||
{
|
||||
// Long format
|
||||
std::ios::fmtflags f(std::cout.flags());
|
||||
std::cout << std::setw(50) << std::left << files[i].name;
|
||||
std::cout << std::setw(8) << std::left << std::dec << files[i].fileSize;
|
||||
std::cout << "@ 0x" << std::hex << files[i].offset << std::endl;
|
||||
std::cout.flags(f);
|
||||
}
|
||||
else
|
||||
std::cout << files[i].name << std::endl;
|
||||
|
|
|
@ -203,6 +203,8 @@ int comp(Arguments& info);
|
|||
|
||||
int main(int argc, char**argv)
|
||||
{
|
||||
try
|
||||
{
|
||||
Arguments info;
|
||||
if(!parseOptions (argc, argv, info))
|
||||
return 1;
|
||||
|
@ -218,6 +220,12 @@ int main(int argc, char**argv)
|
|||
std::cout << "Invalid or no mode specified, dying horribly. Have a nice day." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
std::cerr << "ERROR: " << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -273,8 +281,10 @@ void printRaw(ESM::ESMReader &esm)
|
|||
esm.getSubName();
|
||||
esm.skipHSub();
|
||||
n = esm.retSubName();
|
||||
std::ios::fmtflags f(std::cout.flags());
|
||||
std::cout << " " << n.toString() << " - " << esm.getSubSize()
|
||||
<< " bytes @ 0x" << std::hex << offs << "\n";
|
||||
std::cout.flags(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -159,6 +159,9 @@ bool Launcher::GraphicsPage::loadSettings()
|
|||
if (mGraphicsSettings.value(QString("Video/fullscreen")) == QLatin1String("true"))
|
||||
fullScreenCheckBox->setCheckState(Qt::Checked);
|
||||
|
||||
if (mGraphicsSettings.value(QString("Video/window border")) == QLatin1String("true"))
|
||||
windowBorderCheckBox->setCheckState(Qt::Checked);
|
||||
|
||||
int aaIndex = antiAliasingComboBox->findText(mGraphicsSettings.value(QString("Video/antialiasing")));
|
||||
if (aaIndex != -1)
|
||||
antiAliasingComboBox->setCurrentIndex(aaIndex);
|
||||
|
@ -193,6 +196,9 @@ void Launcher::GraphicsPage::saveSettings()
|
|||
fullScreenCheckBox->checkState() ? mGraphicsSettings.setValue(QString("Video/fullscreen"), QString("true"))
|
||||
: mGraphicsSettings.setValue(QString("Video/fullscreen"), QString("false"));
|
||||
|
||||
windowBorderCheckBox->checkState() ? mGraphicsSettings.setValue(QString("Video/window border"), QString("true"))
|
||||
: mGraphicsSettings.setValue(QString("Video/window border"), QString("false"));
|
||||
|
||||
mGraphicsSettings.setValue(QString("Video/antialiasing"), antiAliasingComboBox->currentText());
|
||||
mGraphicsSettings.setValue(QString("Video/render system"), rendererComboBox->currentText());
|
||||
|
||||
|
@ -331,10 +337,12 @@ void Launcher::GraphicsPage::slotFullScreenChanged(int state)
|
|||
customRadioButton->setEnabled(false);
|
||||
customWidthSpinBox->setEnabled(false);
|
||||
customHeightSpinBox->setEnabled(false);
|
||||
windowBorderCheckBox->setEnabled(false);
|
||||
} else {
|
||||
customRadioButton->setEnabled(true);
|
||||
customWidthSpinBox->setEnabled(true);
|
||||
customHeightSpinBox->setEnabled(true);
|
||||
windowBorderCheckBox->setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#include <iostream>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QTextCodec>
|
||||
#include <QDir>
|
||||
|
@ -15,6 +17,8 @@
|
|||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
try
|
||||
{
|
||||
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software");
|
||||
SDL_SetMainReady();
|
||||
if (SDL_Init(SDL_INIT_VIDEO) != 0)
|
||||
|
@ -55,13 +59,19 @@ int main(int argc, char *argv[])
|
|||
if (!mainWin.showFirstRunDialog())
|
||||
return 0;
|
||||
|
||||
// if (!mainWin.setup()) {
|
||||
// return 0;
|
||||
// }
|
||||
// if (!mainWin.setup()) {
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
mainWin.show();
|
||||
|
||||
int returnValue = app.exec();
|
||||
SDL_Quit();
|
||||
return returnValue;
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
std::cerr << "ERROR: " << e.what() << std::endl;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,13 +47,13 @@ void ProfilesComboBox::setEditEnabled(bool editable)
|
|||
|
||||
void ProfilesComboBox::slotTextChanged(const QString &text)
|
||||
{
|
||||
QPalette *palette = new QPalette();
|
||||
palette->setColor(QPalette::Text,Qt::red);
|
||||
QPalette palette;
|
||||
palette.setColor(QPalette::Text,Qt::red);
|
||||
|
||||
int index = findText(text);
|
||||
|
||||
if (text.isEmpty() || (index != -1 && index != currentIndex())) {
|
||||
lineEdit()->setPalette(*palette);
|
||||
lineEdit()->setPalette(palette);
|
||||
} else {
|
||||
lineEdit()->setPalette(QApplication::palette());
|
||||
}
|
||||
|
|
|
@ -59,13 +59,13 @@ void Launcher::TextInputDialog::setOkButtonEnabled(bool enabled)
|
|||
QPushButton *okButton = mButtonBox->button(QDialogButtonBox::Ok);
|
||||
okButton->setEnabled(enabled);
|
||||
|
||||
QPalette *palette = new QPalette();
|
||||
palette->setColor(QPalette::Text, Qt::red);
|
||||
QPalette palette;
|
||||
palette.setColor(QPalette::Text, Qt::red);
|
||||
|
||||
if (enabled) {
|
||||
mLineEdit->setPalette(QApplication::palette());
|
||||
} else {
|
||||
// Existing profile name, make the text red
|
||||
mLineEdit->setPalette(*palette);
|
||||
mLineEdit->setPalette(palette);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,6 +56,9 @@ int wmain(int argc, wchar_t *wargv[]) {
|
|||
char **argv = converter.get();
|
||||
boost::filesystem::path::imbue(boost::locale::generator().generate(""));
|
||||
#endif
|
||||
|
||||
try
|
||||
{
|
||||
bpo::options_description desc("Syntax: mwiniimporter <options> inifile configfile\nAllowed options");
|
||||
bpo::positional_options_description p_desc;
|
||||
desc.add_options()
|
||||
|
@ -76,25 +79,12 @@ int wmain(int argc, wchar_t *wargv[]) {
|
|||
|
||||
bpo::variables_map vm;
|
||||
|
||||
try
|
||||
{
|
||||
bpo::parsed_options parsed = bpo::command_line_parser(argc, argv)
|
||||
.options(desc)
|
||||
.positional(p_desc)
|
||||
.run();
|
||||
|
||||
bpo::store(parsed, vm);
|
||||
}
|
||||
catch(boost::program_options::unknown_option & x)
|
||||
{
|
||||
std::cerr << "ERROR: " << x.what() << std::endl;
|
||||
return false;
|
||||
}
|
||||
catch(boost::program_options::invalid_command_line_syntax & x)
|
||||
{
|
||||
std::cerr << "ERROR: " << x.what() << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(vm.count("help") || !vm.count("ini") || !vm.count("cfg")) {
|
||||
std::cout << desc;
|
||||
|
@ -143,6 +133,10 @@ int wmain(int argc, wchar_t *wargv[]) {
|
|||
std::cout << "write to: " << outputFile << std::endl;
|
||||
bfs::ofstream file((bfs::path(outputFile)));
|
||||
importer.writeToFile(file, cfg);
|
||||
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
std::cerr << "ERROR: " << e.what() << std::endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -236,6 +236,7 @@ void CS::Editor::showSettings()
|
|||
if (mSettings.isHidden())
|
||||
mSettings.show();
|
||||
|
||||
mSettings.move (QCursor::pos());
|
||||
mSettings.raise();
|
||||
mSettings.activateWindow();
|
||||
}
|
||||
|
|
|
@ -46,6 +46,8 @@ class Application : public QApplication
|
|||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
try
|
||||
{
|
||||
Q_INIT_RESOURCE (resources);
|
||||
|
||||
qRegisterMetaType<std::string> ("std::string");
|
||||
|
@ -57,7 +59,7 @@ int main(int argc, char *argv[])
|
|||
|
||||
Application application (argc, argv);
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
#ifdef Q_OS_MAC
|
||||
QDir dir(QCoreApplication::applicationDirPath());
|
||||
if (dir.dirName() == "MacOS") {
|
||||
dir.cdUp();
|
||||
|
@ -74,7 +76,7 @@ int main(int argc, char *argv[])
|
|||
QStringList libraryPaths;
|
||||
libraryPaths << pluginsPath.path() << QCoreApplication::applicationDirPath();
|
||||
application.setLibraryPaths(libraryPaths);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
application.setWindowIcon (QIcon (":./opencs.png"));
|
||||
|
||||
|
@ -87,6 +89,12 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
|
||||
shinyFactory = editor.setupGraphics();
|
||||
|
||||
return editor.run();
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
std::cerr << "ERROR: " << e.what() << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -223,7 +223,14 @@ void CSMWorld::ContainerRefIdAdapter::setData (const RefIdColumn *column, RefIdD
|
|||
}
|
||||
|
||||
CSMWorld::CreatureColumns::CreatureColumns (const ActorColumns& actorColumns)
|
||||
: ActorColumns (actorColumns)
|
||||
: ActorColumns (actorColumns),
|
||||
mType(NULL),
|
||||
mSoul(NULL),
|
||||
mScale(NULL),
|
||||
mOriginal(NULL),
|
||||
mCombat(NULL),
|
||||
mMagic(NULL),
|
||||
mStealth(NULL)
|
||||
{}
|
||||
|
||||
CSMWorld::CreatureRefIdAdapter::CreatureRefIdAdapter (const CreatureColumns& columns)
|
||||
|
@ -431,7 +438,14 @@ void CSMWorld::MiscRefIdAdapter::setData (const RefIdColumn *column, RefIdData&
|
|||
InventoryRefIdAdapter<ESM::Miscellaneous>::setData (column, data, index, value);
|
||||
}
|
||||
|
||||
CSMWorld::NpcColumns::NpcColumns (const ActorColumns& actorColumns) : ActorColumns (actorColumns) {}
|
||||
CSMWorld::NpcColumns::NpcColumns (const ActorColumns& actorColumns)
|
||||
: ActorColumns (actorColumns),
|
||||
mRace(NULL),
|
||||
mClass(NULL),
|
||||
mFaction(NULL),
|
||||
mHair(NULL),
|
||||
mHead(NULL)
|
||||
{}
|
||||
|
||||
CSMWorld::NpcRefIdAdapter::NpcRefIdAdapter (const NpcColumns& columns)
|
||||
: ActorRefIdAdapter<ESM::NPC> (UniversalId::Type_Npc, columns), mColumns (columns)
|
||||
|
|
|
@ -131,6 +131,7 @@ namespace
|
|||
}
|
||||
|
||||
CSMWorld::UniversalId::UniversalId (const std::string& universalId)
|
||||
: mIndex(0)
|
||||
{
|
||||
std::string::size_type index = universalId.find (':');
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#include "adjusterwidget.hpp"
|
||||
|
||||
CSVDoc::FileDialog::FileDialog(QWidget *parent) :
|
||||
QDialog(parent), mSelector (0), mFileWidget (0), mAdjusterWidget (0), mDialogBuilt(false)
|
||||
QDialog(parent), mSelector (0), mFileWidget (0), mAdjusterWidget (0), mDialogBuilt(false), mAction(ContentAction_Undefined)
|
||||
{
|
||||
ui.setupUi (this);
|
||||
resize(400, 400);
|
||||
|
|
|
@ -18,7 +18,7 @@ void CSVDoc::LoadingDocument::closeEvent (QCloseEvent *event)
|
|||
}
|
||||
|
||||
CSVDoc::LoadingDocument::LoadingDocument (CSMDoc::Document *document)
|
||||
: mDocument (document), mAborted (false), mMessages (0)
|
||||
: mDocument (document), mAborted (false), mMessages (0), mTotalRecords (0)
|
||||
{
|
||||
setWindowTitle (("Opening " + document->getSavePath().filename().string()).c_str());
|
||||
|
||||
|
@ -104,7 +104,7 @@ void CSVDoc::LoadingDocument::nextRecord (int records)
|
|||
void CSVDoc::LoadingDocument::abort (const std::string& error)
|
||||
{
|
||||
mAborted = true;
|
||||
mError->setText (QString::fromUtf8 (("Loading failed: " + error).c_str()));
|
||||
mError->setText (QString::fromUtf8 (("<font color=red>Loading failed: " + error + "</font>").c_str()));
|
||||
mButtons->setStandardButtons (QDialogButtonBox::Close);
|
||||
}
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ bool CSVRender::Cell::addObjects (int start, int end)
|
|||
|
||||
CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager,
|
||||
const std::string& id, boost::shared_ptr<CSVWorld::PhysicsSystem> physics, const Ogre::Vector3& origin)
|
||||
: mData (data), mId (Misc::StringUtils::lowerCase (id)), mSceneMgr(sceneManager), mPhysics(physics)
|
||||
: mData (data), mId (Misc::StringUtils::lowerCase (id)), mSceneMgr(sceneManager), mPhysics(physics), mX(0), mY(0)
|
||||
{
|
||||
mCellNode = sceneManager->getRootSceneNode()->createChildSceneNode();
|
||||
mCellNode->setPosition (origin);
|
||||
|
@ -76,16 +76,15 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager,
|
|||
const CSMWorld::IdCollection<CSMWorld::Land>& land = mData.getLand();
|
||||
int landIndex = land.searchId(mId);
|
||||
if (landIndex != -1)
|
||||
{
|
||||
const ESM::Land* esmLand = land.getRecord(mId).get().mLand.get();
|
||||
if(esmLand)
|
||||
{
|
||||
mTerrain.reset(new Terrain::TerrainGrid(sceneManager, new TerrainStorage(mData), Element_Terrain, true,
|
||||
Terrain::Align_XY));
|
||||
|
||||
const ESM::Land* esmLand = land.getRecord(mId).get().mLand.get();
|
||||
mTerrain->loadCell(esmLand->mX,
|
||||
esmLand->mY);
|
||||
|
||||
if(esmLand)
|
||||
{
|
||||
float verts = ESM::Land::LAND_SIZE;
|
||||
float worldsize = ESM::Land::REAL_SIZE;
|
||||
mX = esmLand->mX;
|
||||
|
@ -98,6 +97,7 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager,
|
|||
|
||||
CSVRender::Cell::~Cell()
|
||||
{
|
||||
if (mTerrain.get())
|
||||
mPhysics->removeHeightField(mSceneMgr, mX, mY);
|
||||
|
||||
for (std::map<std::string, Object *>::iterator iter (mObjects.begin());
|
||||
|
|
|
@ -346,7 +346,7 @@ namespace CSVRender
|
|||
//plane X, upvector Y, mOffset x : x-z plane, wheel closer/further
|
||||
std::pair<Ogre::Vector3, Ogre::Vector3> MouseState::planeAxis()
|
||||
{
|
||||
bool screenCoord = true;
|
||||
const bool screenCoord = true;
|
||||
Ogre::Vector3 dir = getCamera()->getDerivedDirection();
|
||||
|
||||
QString wheelDir = "Closer/Further";
|
||||
|
|
|
@ -76,7 +76,7 @@ add_openmw_dir (mwmechanics
|
|||
mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects
|
||||
drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor
|
||||
aiescort aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting
|
||||
disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction
|
||||
disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction actor summoning
|
||||
)
|
||||
|
||||
add_openmw_dir (mwstate
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/ptrace.h>
|
||||
|
@ -29,6 +28,7 @@
|
|||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
#define UNUSED(x) (void)(x)
|
||||
|
||||
static const char crash_switch[] = "--cc-handle-crash";
|
||||
|
||||
|
@ -160,7 +160,11 @@ static void gdb_info(pid_t pid)
|
|||
printf("Executing: %s\n", cmd_buf);
|
||||
fflush(stdout);
|
||||
|
||||
system(cmd_buf);
|
||||
{ /* another special exception for "ignoring return value..." */
|
||||
int unused;
|
||||
unused = system(cmd_buf);
|
||||
UNUSED(unused);
|
||||
}
|
||||
/* Clean up */
|
||||
remove(respfile);
|
||||
}
|
||||
|
@ -406,7 +410,13 @@ int cc_install_handlers(int argc, char **argv, int num_signals, int *signals, co
|
|||
snprintf(argv0, sizeof(argv0), "%s", argv[0]);
|
||||
else
|
||||
{
|
||||
getcwd(argv0, sizeof(argv0));
|
||||
{
|
||||
/* we don't want to disable "ignoring return value" warnings, so we make
|
||||
* a special exception here. */
|
||||
char * unused;
|
||||
unused = getcwd(argv0, sizeof(argv0));
|
||||
UNUSED(unused);
|
||||
}
|
||||
retval = strlen(argv0);
|
||||
snprintf(argv0+retval, sizeof(argv0)-retval, "/%s", argv[0]);
|
||||
}
|
||||
|
|
|
@ -208,6 +208,8 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager)
|
|||
|
||||
OMW::Engine::~Engine()
|
||||
{
|
||||
if (mOgre)
|
||||
mOgre->restoreWindowGammaRamp();
|
||||
mEnvironment.cleanup();
|
||||
delete mScriptContext;
|
||||
delete mOgre;
|
||||
|
@ -350,6 +352,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
|||
|
||||
OEngine::Render::WindowSettings windowSettings;
|
||||
windowSettings.fullscreen = settings.getBool("fullscreen", "Video");
|
||||
windowSettings.window_border = settings.getBool("window border", "Video");
|
||||
windowSettings.window_x = settings.getInt("resolution x", "Video");
|
||||
windowSettings.window_y = settings.getInt("resolution y", "Video");
|
||||
windowSettings.screen = settings.getInt("screen", "Video");
|
||||
|
@ -381,6 +384,8 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
|||
// Create sound system
|
||||
mEnvironment.setSoundManager (new MWSound::SoundManager(mUseSound));
|
||||
|
||||
mOgre->setWindowGammaContrast(Settings::Manager::getFloat("gamma", "General"), Settings::Manager::getFloat("contrast", "General"));
|
||||
|
||||
if (!mSkipMenu)
|
||||
{
|
||||
std::string logo = mFallbackMap["Movies_Company_Logo"];
|
||||
|
@ -467,9 +472,13 @@ void OMW::Engine::go()
|
|||
// Play some good 'ol tunes
|
||||
MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore"));
|
||||
|
||||
// start in main menu
|
||||
if (!mSkipMenu)
|
||||
if (!mSaveGameFile.empty())
|
||||
{
|
||||
MWBase::Environment::get().getStateManager()->loadGame(mSaveGameFile);
|
||||
}
|
||||
else if (!mSkipMenu)
|
||||
{
|
||||
// start in main menu
|
||||
MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu);
|
||||
try
|
||||
{
|
||||
|
@ -508,6 +517,11 @@ void OMW::Engine::activate()
|
|||
if (MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||
return;
|
||||
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
if (player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0
|
||||
|| player.getClass().getCreatureStats(player).getKnockedDown())
|
||||
return;
|
||||
|
||||
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getFacedObject();
|
||||
|
||||
if (ptr.isEmpty())
|
||||
|
@ -613,3 +627,8 @@ void OMW::Engine::enableFontExport(bool exportFonts)
|
|||
{
|
||||
mExportFonts = exportFonts;
|
||||
}
|
||||
|
||||
void OMW::Engine::setSaveGameFile(const std::string &savegame)
|
||||
{
|
||||
mSaveGameFile = savegame;
|
||||
}
|
||||
|
|
|
@ -83,6 +83,7 @@ namespace OMW
|
|||
bool mScriptConsoleMode;
|
||||
std::string mStartupScript;
|
||||
int mActivationDistanceOverride;
|
||||
std::string mSaveGameFile;
|
||||
// Grab mouse?
|
||||
bool mGrab;
|
||||
|
||||
|
@ -204,6 +205,9 @@ namespace OMW
|
|||
|
||||
void enableFontExport(bool exportFonts);
|
||||
|
||||
/// Set the save game file to load after initialising the engine.
|
||||
void setSaveGameFile(const std::string& savegame);
|
||||
|
||||
private:
|
||||
Files::ConfigurationManager& mCfgMgr;
|
||||
};
|
||||
|
|
|
@ -152,6 +152,9 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
|||
("script-blacklist-use", bpo::value<bool>()->implicit_value(true)
|
||||
->default_value(true), "enable script blacklisting")
|
||||
|
||||
("load-savegame", bpo::value<std::string>()->default_value(""),
|
||||
"load a save game file on game startup")
|
||||
|
||||
("skip-menu", bpo::value<bool>()->implicit_value(true)
|
||||
->default_value(false), "skip main menu on game startup")
|
||||
|
||||
|
@ -274,6 +277,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
|||
engine.setWarningsMode (variables["script-warn"].as<int>());
|
||||
engine.setScriptBlacklist (variables["script-blacklist"].as<StringsVector>());
|
||||
engine.setScriptBlacklistUse (variables["script-blacklist-use"].as<bool>());
|
||||
engine.setSaveGameFile (variables["load-savegame"].as<std::string>());
|
||||
|
||||
// other settings
|
||||
engine.setSoundUsage(!variables["no-sound"].as<bool>());
|
||||
|
|
|
@ -113,21 +113,19 @@ namespace MWBase
|
|||
OT_Theft, // Taking items owned by an NPC or a faction you are not a member of
|
||||
OT_Assault, // Attacking a peaceful NPC
|
||||
OT_Murder, // Murdering a peaceful NPC
|
||||
OT_Trespassing, // Staying in a cell you are not allowed in (where is this defined?)
|
||||
OT_Trespassing, // Picking the lock of an owned door/chest
|
||||
OT_SleepingInOwnedBed, // Sleeping in a bed owned by an NPC or a faction you are not a member of
|
||||
OT_Pickpocket // Entering pickpocket mode, leaving it, and being detected. Any items stolen are a separate crime (Theft)
|
||||
};
|
||||
/**
|
||||
* @brief Commit a crime. If any actors witness the crime and report it,
|
||||
* reportCrime will be called automatically.
|
||||
* @note victim may be empty
|
||||
* @param arg Depends on \a type, e.g. for Theft, the value of the item that was stolen.
|
||||
* @return was the crime reported?
|
||||
* @param victimAware Is the victim already aware of the crime?
|
||||
* If this parameter is false, it will be determined by a line-of-sight and awareness check.
|
||||
* @return was the crime seen?
|
||||
*/
|
||||
virtual bool commitCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim,
|
||||
OffenseType type, int arg=0) = 0;
|
||||
virtual void reportCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim,
|
||||
OffenseType type, int arg=0) = 0;
|
||||
OffenseType type, int arg=0, bool victimAware=false) = 0;
|
||||
/// @return false if the attack was considered a "friendly hit" and forgiven
|
||||
virtual bool actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker) = 0;
|
||||
/// Utility to check if taking this item is illegal and calling commitCrime if so
|
||||
|
@ -199,9 +197,7 @@ namespace MWBase
|
|||
|
||||
virtual void clear() = 0;
|
||||
|
||||
/// @param bias Can be used to add an additional aggression bias towards the target,
|
||||
/// making it more likely for the function to return true.
|
||||
virtual bool isAggressive (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target, int bias=0, bool ignoreDistance=false) = 0;
|
||||
virtual bool isAggressive (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target) = 0;
|
||||
|
||||
/// Resurrects the player if necessary
|
||||
virtual void keepPlayerAlive() = 0;
|
||||
|
|
|
@ -62,10 +62,13 @@ namespace MWBase
|
|||
///
|
||||
/// \note Slot must belong to the current character.
|
||||
|
||||
virtual void loadGame (const MWState::Character *character, const MWState::Slot *slot) = 0;
|
||||
///< Load a saved game file from \a slot.
|
||||
///
|
||||
/// \note \a slot must belong to \a character.
|
||||
virtual void loadGame (const std::string& filepath) = 0;
|
||||
///< Load a saved game directly from the given file path. This will search the CharacterManager
|
||||
/// for a Character containing this save file, and set this Character current if one was found.
|
||||
/// Otherwise, a new Character will be created.
|
||||
|
||||
virtual void loadGame (const MWState::Character *character, const std::string& filepath) = 0;
|
||||
///< Load a saved game file belonging to the given character.
|
||||
|
||||
///Simple saver, writes over the file if already existing
|
||||
/** Used for quick save and autosave **/
|
||||
|
|
|
@ -546,7 +546,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, const std::string& id, const std::string& sourceName) = 0;
|
||||
const MWWorld::Ptr& caster, int rangeType, const std::string& id, const std::string& sourceName) = 0;
|
||||
|
||||
virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor) = 0;
|
||||
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
||||
#include "../mwworld//cellstore.hpp"
|
||||
#include "../mwworld/cellstore.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "../mwworld/physicssystem.hpp"
|
||||
#include "../mwworld/action.hpp"
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "../mwworld/actionequip.hpp"
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
#include "../mwworld/cellstore.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
#include "../mwworld/physicssystem.hpp"
|
||||
#include "../mwworld/nullaction.hpp"
|
||||
#include "../mwworld/containerstore.hpp"
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "../mwworld/actionread.hpp"
|
||||
#include "../mwworld/failedaction.hpp"
|
||||
#include "../mwworld/cellstore.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
#include "../mwworld/physicssystem.hpp"
|
||||
|
||||
#include "../mwrender/objects.hpp"
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "../mwworld/actionequip.hpp"
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
#include "../mwworld/cellstore.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
#include "../mwworld/physicssystem.hpp"
|
||||
#include "../mwworld/nullaction.hpp"
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "../mwworld/containerstore.hpp"
|
||||
#include "../mwworld/customdata.hpp"
|
||||
#include "../mwworld/cellstore.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
#include "../mwworld/actionopen.hpp"
|
||||
#include "../mwworld/actiontrap.hpp"
|
||||
#include "../mwworld/physicssystem.hpp"
|
||||
|
@ -59,7 +60,7 @@ namespace MWClass
|
|||
ptr.get<ESM::Container>();
|
||||
|
||||
data->mContainerStore.fill(
|
||||
ref->mBase->mInventory, ptr.getCellRef().getOwner(), ptr.getCellRef().getFaction(), MWBase::Environment::get().getWorld()->getStore());
|
||||
ref->mBase->mInventory, ptr.getCellRef().getOwner(), ptr.getCellRef().getFaction(), ptr.getCellRef().getFactionRank(), MWBase::Environment::get().getWorld()->getStore());
|
||||
|
||||
// store
|
||||
ptr.getRefData().setCustomData (data.release());
|
||||
|
@ -81,7 +82,7 @@ namespace MWClass
|
|||
MWWorld::LiveCellRef<ESM::Container> *ref = ptr.get<ESM::Container>();
|
||||
const ESM::InventoryList& list = ref->mBase->mInventory;
|
||||
MWWorld::ContainerStore& store = getContainerStore(ptr);
|
||||
store.restock(list, ptr, ptr.getCellRef().getOwner(), ptr.getCellRef().getFaction());
|
||||
store.restock(list, ptr, ptr.getCellRef().getOwner(), ptr.getCellRef().getFaction(), ptr.getCellRef().getFactionRank());
|
||||
}
|
||||
|
||||
void Container::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
|
||||
|
|
|
@ -139,7 +139,7 @@ namespace MWClass
|
|||
// store
|
||||
ptr.getRefData().setCustomData(data.release());
|
||||
|
||||
getContainerStore(ptr).fill(ref->mBase->mInventory, getId(ptr), "",
|
||||
getContainerStore(ptr).fill(ref->mBase->mInventory, getId(ptr), "", -1,
|
||||
MWBase::Environment::get().getWorld()->getStore());
|
||||
|
||||
if (ref->mBase->mFlags & ESM::Creature::Weapon)
|
||||
|
@ -288,7 +288,7 @@ namespace MWClass
|
|||
}
|
||||
|
||||
float damage = min + (max - min) * stats.getAttackStrength();
|
||||
|
||||
bool healthdmg = true;
|
||||
if (!weapon.isEmpty())
|
||||
{
|
||||
const unsigned char *attack = NULL;
|
||||
|
@ -321,10 +321,14 @@ namespace MWClass
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (isBipedal(ptr))
|
||||
{
|
||||
MWMechanics::getHandToHandDamage(ptr, victim, damage, healthdmg);
|
||||
}
|
||||
|
||||
MWMechanics::applyElementalShields(ptr, victim);
|
||||
|
||||
if (!weapon.isEmpty() && MWMechanics::blockMeleeAttack(ptr, victim, weapon, damage))
|
||||
if (MWMechanics::blockMeleeAttack(ptr, victim, weapon, damage))
|
||||
damage = 0;
|
||||
|
||||
if (damage > 0)
|
||||
|
@ -332,7 +336,7 @@ namespace MWClass
|
|||
|
||||
MWMechanics::diseaseContact(victim, ptr);
|
||||
|
||||
victim.getClass().onHit(victim, damage, true, weapon, ptr, true);
|
||||
victim.getClass().onHit(victim, damage, healthdmg, weapon, ptr, true);
|
||||
}
|
||||
|
||||
void Creature::onHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object, const MWWorld::Ptr &attacker, bool successful) const
|
||||
|
@ -678,7 +682,6 @@ namespace MWClass
|
|||
if(type >= 0)
|
||||
{
|
||||
std::vector<const ESM::SoundGenerator*> sounds;
|
||||
std::vector<const ESM::SoundGenerator*> fallbacksounds;
|
||||
|
||||
MWWorld::LiveCellRef<ESM::Creature>* ref = ptr.get<ESM::Creature>();
|
||||
|
||||
|
@ -689,16 +692,15 @@ namespace MWClass
|
|||
{
|
||||
if (type == sound->mType && !sound->mCreature.empty() && (Misc::StringUtils::ciEqual(ourId, sound->mCreature)))
|
||||
sounds.push_back(&*sound);
|
||||
if (type == sound->mType && sound->mCreature.empty())
|
||||
fallbacksounds.push_back(&*sound);
|
||||
++sound;
|
||||
}
|
||||
if(!sounds.empty())
|
||||
return sounds[(int)(rand()/(RAND_MAX+1.0)*sounds.size())]->mSound;
|
||||
if (!fallbacksounds.empty())
|
||||
return fallbacksounds[(int)(rand()/(RAND_MAX+1.0)*fallbacksounds.size())]->mSound;
|
||||
}
|
||||
|
||||
if (type == ESM::SoundGenerator::Land)
|
||||
return "Body Fall Large";
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
|
@ -888,7 +890,7 @@ namespace MWClass
|
|||
MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
|
||||
const ESM::InventoryList& list = ref->mBase->mInventory;
|
||||
MWWorld::ContainerStore& store = getContainerStore(ptr);
|
||||
store.restock(list, ptr, ptr.getCellRef().getRefId(), ptr.getCellRef().getFaction());
|
||||
store.restock(list, ptr, ptr.getCellRef().getRefId(), "", -1);
|
||||
}
|
||||
|
||||
int Creature::getBaseFightRating(const MWWorld::Ptr &ptr) const
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/soundmanager.hpp"
|
||||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "../mwworld/nullaction.hpp"
|
||||
|
@ -15,6 +16,7 @@
|
|||
#include "../mwworld/actionteleport.hpp"
|
||||
#include "../mwworld/actiondoor.hpp"
|
||||
#include "../mwworld/cellstore.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
#include "../mwworld/physicssystem.hpp"
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
#include "../mwworld/actiontrap.hpp"
|
||||
|
@ -22,7 +24,7 @@
|
|||
|
||||
#include "../mwgui/tooltips.hpp"
|
||||
|
||||
#include "../mwrender/objects.hpp"
|
||||
#include "../mwrender/actors.hpp"
|
||||
#include "../mwrender/renderinginterface.hpp"
|
||||
|
||||
namespace
|
||||
|
@ -51,7 +53,8 @@ namespace MWClass
|
|||
{
|
||||
const std::string model = getModel(ptr);
|
||||
if (!model.empty()) {
|
||||
renderingInterface.getObjects().insertModel(ptr, model);
|
||||
MWRender::Actors& actors = renderingInterface.getActors();
|
||||
actors.insertActivator(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,6 +73,8 @@ namespace MWClass
|
|||
MWBase::Environment::get().getWorld()->activateDoor(ptr, customData.mDoorState);
|
||||
}
|
||||
}
|
||||
|
||||
MWBase::Environment::get().getMechanicsManager()->add(ptr);
|
||||
}
|
||||
|
||||
std::string Door::getModel(const MWWorld::Ptr &ptr) const
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "../mwworld/ptr.hpp"
|
||||
#include "../mwworld/actiontake.hpp"
|
||||
#include "../mwworld/cellstore.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
#include "../mwworld/physicssystem.hpp"
|
||||
#include "../mwworld/actioneat.hpp"
|
||||
#include "../mwworld/nullaction.hpp"
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/soundmanager.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "../mwworld/actiontake.hpp"
|
||||
|
@ -22,6 +23,7 @@
|
|||
#include "../mwgui/tooltips.hpp"
|
||||
|
||||
#include "../mwrender/objects.hpp"
|
||||
#include "../mwrender/actors.hpp"
|
||||
#include "../mwrender/renderinginterface.hpp"
|
||||
|
||||
namespace
|
||||
|
@ -54,13 +56,12 @@ namespace MWClass
|
|||
|
||||
void Light::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
|
||||
{
|
||||
const std::string model = getModel(ptr);
|
||||
|
||||
MWWorld::LiveCellRef<ESM::Light> *ref =
|
||||
ptr.get<ESM::Light>();
|
||||
|
||||
// Insert even if model is empty, so that the light is added
|
||||
renderingInterface.getObjects().insertModel(ptr, model, false, !(ref->mBase->mData.mFlags & ESM::Light::OffDefault));
|
||||
MWRender::Actors& actors = renderingInterface.getActors();
|
||||
actors.insertActivator(ptr, !(ref->mBase->mData.mFlags & ESM::Light::OffDefault));
|
||||
}
|
||||
|
||||
void Light::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const
|
||||
|
@ -78,6 +79,8 @@ namespace MWClass
|
|||
MWBase::Environment::get().getSoundManager()->playSound3D(ptr, ref->mBase->mSound, 1.0, 1.0,
|
||||
MWBase::SoundManager::Play_TypeSfx,
|
||||
MWBase::SoundManager::Play_Loop);
|
||||
|
||||
MWBase::Environment::get().getMechanicsManager()->add(ptr);
|
||||
}
|
||||
|
||||
std::string Light::getModel(const MWWorld::Ptr &ptr) const
|
||||
|
|
|
@ -403,7 +403,7 @@ namespace MWClass
|
|||
}
|
||||
|
||||
// inventory
|
||||
data->mInventoryStore.fill(ref->mBase->mInventory, getId(ptr), "",
|
||||
data->mInventoryStore.fill(ref->mBase->mInventory, getId(ptr), "", -1,
|
||||
MWBase::Environment::get().getWorld()->getStore());
|
||||
|
||||
data->mNpcStats.setGoldPool(gold);
|
||||
|
@ -577,34 +577,7 @@ namespace MWClass
|
|||
}
|
||||
else
|
||||
{
|
||||
// Note: MCP contains an option to include Strength in hand-to-hand damage
|
||||
// calculations. Some mods recommend using it, so we may want to include am
|
||||
// option for it.
|
||||
float minstrike = store.find("fMinHandToHandMult")->getFloat();
|
||||
float maxstrike = store.find("fMaxHandToHandMult")->getFloat();
|
||||
damage = stats.getSkill(weapskill).getModified();
|
||||
damage *= minstrike + ((maxstrike-minstrike)*stats.getAttackStrength());
|
||||
|
||||
healthdmg = (otherstats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0)
|
||||
|| otherstats.getKnockedDown();
|
||||
if(stats.isWerewolf())
|
||||
{
|
||||
healthdmg = true;
|
||||
// GLOB instead of GMST because it gets updated during a quest
|
||||
damage *= world->getGlobalFloat("werewolfclawmult");
|
||||
}
|
||||
if(healthdmg)
|
||||
damage *= store.find("fHandtoHandHealthPer")->getFloat();
|
||||
|
||||
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
||||
if(stats.isWerewolf())
|
||||
{
|
||||
const ESM::Sound *sound = world->getStore().get<ESM::Sound>().searchRandom("WolfHit");
|
||||
if(sound)
|
||||
sndMgr->playSound3D(victim, sound->mId, 1.0f, 1.0f);
|
||||
}
|
||||
else
|
||||
sndMgr->playSound3D(victim, "Hand To Hand Hit", 1.0f, 1.0f);
|
||||
MWMechanics::getHandToHandDamage(ptr, victim, damage, healthdmg);
|
||||
}
|
||||
if(ptr.getRefData().getHandle() == "player")
|
||||
{
|
||||
|
@ -641,7 +614,7 @@ namespace MWClass
|
|||
|
||||
MWMechanics::applyElementalShields(ptr, victim);
|
||||
|
||||
if (!weapon.isEmpty() && MWMechanics::blockMeleeAttack(ptr, victim, weapon, damage))
|
||||
if (MWMechanics::blockMeleeAttack(ptr, victim, weapon, damage))
|
||||
damage = 0;
|
||||
|
||||
if (healthdmg && damage > 0)
|
||||
|
@ -1376,7 +1349,7 @@ namespace MWClass
|
|||
MWWorld::LiveCellRef<ESM::NPC> *ref = ptr.get<ESM::NPC>();
|
||||
const ESM::InventoryList& list = ref->mBase->mInventory;
|
||||
MWWorld::ContainerStore& store = getContainerStore(ptr);
|
||||
store.restock(list, ptr, ptr.getCellRef().getRefId(), ptr.getCellRef().getFaction());
|
||||
store.restock(list, ptr, ptr.getCellRef().getRefId(), "", -1);
|
||||
}
|
||||
|
||||
int Npc::getBaseFightRating (const MWWorld::Ptr& ptr) const
|
||||
|
@ -1384,4 +1357,9 @@ namespace MWClass
|
|||
MWWorld::LiveCellRef<ESM::NPC> *ref = ptr.get<ESM::NPC>();
|
||||
return ref->mBase->mAiData.mFight;
|
||||
}
|
||||
|
||||
bool Npc::isBipedal(const MWWorld::Ptr &ptr) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -182,6 +182,8 @@ namespace MWClass
|
|||
return true;
|
||||
}
|
||||
|
||||
virtual bool isBipedal (const MWWorld::Ptr &ptr) const;
|
||||
|
||||
virtual void respawn (const MWWorld::Ptr& ptr) const;
|
||||
|
||||
virtual void restock (const MWWorld::Ptr& ptr) const;
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "../mwworld/actiontake.hpp"
|
||||
#include "../mwworld/actionapply.hpp"
|
||||
#include "../mwworld/cellstore.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
#include "../mwworld/containerstore.hpp"
|
||||
#include "../mwworld/physicssystem.hpp"
|
||||
#include "../mwworld/nullaction.hpp"
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "../mwworld/actionequip.hpp"
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
#include "../mwworld/cellstore.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
#include "../mwworld/physicssystem.hpp"
|
||||
#include "../mwworld/nullaction.hpp"
|
||||
|
||||
|
@ -385,7 +386,7 @@ namespace MWClass
|
|||
|
||||
std::pair<int, std::string> Weapon::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const
|
||||
{
|
||||
if (ptr.getCellRef().getCharge() == 0)
|
||||
if (hasItemHealth(ptr) && ptr.getCellRef().getCharge() == 0)
|
||||
return std::make_pair(0, "#{sInventoryMessage1}");
|
||||
|
||||
std::pair<std::vector<int>, bool> slots_ = ptr.getClass().getEquipmentSlots(ptr);
|
||||
|
|
|
@ -126,7 +126,7 @@ bool MWDialogue::Filter::testPlayer (const ESM::DialInfo& info) const
|
|||
if (!info.mCell.empty())
|
||||
{
|
||||
// supports partial matches, just like getPcCell
|
||||
const std::string& playerCell = player.getCell()->getCell()->mName;
|
||||
const std::string& playerCell = MWBase::Environment::get().getWorld()->getCellName(player.getCell());
|
||||
bool match = playerCell.length()>=info.mCell.length() &&
|
||||
Misc::StringUtils::ciEqual(playerCell.substr (0, info.mCell.length()), info.mCell);
|
||||
if (!match)
|
||||
|
@ -417,6 +417,21 @@ int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) con
|
|||
return value;
|
||||
}
|
||||
|
||||
case SelectWrapper::Function_CreatureTargetted:
|
||||
|
||||
{
|
||||
MWWorld::Ptr target;
|
||||
mActor.getClass().getCreatureStats(mActor).getAiSequence().getCombatTarget(target);
|
||||
if (target)
|
||||
{
|
||||
if (target.getClass().isNpc() && target.getClass().getNpcStats(target).isWerewolf())
|
||||
return 2;
|
||||
if (target.getTypeName() == typeid(ESM::Creature).name())
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
default:
|
||||
|
||||
throw std::runtime_error ("unknown integer select function");
|
||||
|
@ -451,7 +466,8 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co
|
|||
|
||||
case SelectWrapper::Function_NotCell:
|
||||
|
||||
return !Misc::StringUtils::ciEqual(mActor.getCell()->getCell()->mName, select.getName());
|
||||
return !Misc::StringUtils::ciEqual(MWBase::Environment::get().getWorld()->getCellName(mActor.getCell())
|
||||
, select.getName());
|
||||
|
||||
case SelectWrapper::Function_NotLocal:
|
||||
{
|
||||
|
@ -531,10 +547,6 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co
|
|||
return MWBase::Environment::get().getMechanicsManager()->isAggressive(mActor,
|
||||
MWBase::Environment::get().getWorld()->getPlayerPtr());
|
||||
|
||||
case SelectWrapper::Function_CreatureTargetted:
|
||||
|
||||
return mActor.getClass().getCreatureStats (mActor).getCreatureTargetted();
|
||||
|
||||
case SelectWrapper::Function_Werewolf:
|
||||
|
||||
return mActor.getClass().getNpcStats (mActor).isWerewolf();
|
||||
|
|
|
@ -205,6 +205,7 @@ MWDialogue::SelectWrapper::Type MWDialogue::SelectWrapper::getType() const
|
|||
Function_Reputation, Function_FactionRankDiff,
|
||||
Function_WerewolfKills,
|
||||
Function_RankLow, Function_RankHigh,
|
||||
Function_CreatureTargetted,
|
||||
Function_None // end marker
|
||||
};
|
||||
|
||||
|
@ -225,7 +226,6 @@ MWDialogue::SelectWrapper::Type MWDialogue::SelectWrapper::getType() const
|
|||
Function_PcVampire, Function_TalkedToPc,
|
||||
Function_Alarmed, Function_Detected,
|
||||
Function_Attacked, Function_ShouldAttack,
|
||||
Function_CreatureTargetted,
|
||||
Function_Werewolf,
|
||||
Function_None // end marker
|
||||
};
|
||||
|
|
|
@ -11,6 +11,9 @@
|
|||
#include "../mwmechanics/magiceffects.hpp"
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include <components/esm/records.hpp>
|
||||
|
||||
#include "inventoryitemmodel.hpp"
|
||||
#include "sortfilteritemmodel.hpp"
|
||||
|
|
|
@ -2,11 +2,13 @@
|
|||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include <components/esm/records.hpp>
|
||||
#include <components/misc/resourcehelpers.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include "widgets.hpp"
|
||||
|
||||
|
@ -80,8 +82,6 @@ namespace MWGui
|
|||
if (Misc::StringUtils::ciEqual(*mBirthList->getItemDataAt<std::string>(i), birthId))
|
||||
{
|
||||
mBirthList->setIndexSelected(i);
|
||||
MyGUI::Button* okButton;
|
||||
getWidget(okButton, "OKButton");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -116,9 +116,6 @@ namespace MWGui
|
|||
if (_index == MyGUI::ITEM_NONE)
|
||||
return;
|
||||
|
||||
MyGUI::Button* okButton;
|
||||
getWidget(okButton, "OKButton");
|
||||
|
||||
const std::string *birthId = mBirthList->getItemDataAt<std::string>(_index);
|
||||
if (Misc::StringUtils::ciEqual(mCurrentBirthId, *birthId))
|
||||
return;
|
||||
|
|
|
@ -639,7 +639,8 @@ namespace
|
|||
MyGUI::Vertex* vertices, RenderXform const & renderXform) :
|
||||
mZ(Z), mOrigin (left, top),
|
||||
mFont (font), mVertices (vertices),
|
||||
mRenderXform (renderXform)
|
||||
mRenderXform (renderXform),
|
||||
mC(0)
|
||||
{
|
||||
mVertexColourType = MyGUI::RenderManager::getInstance().getVertexFormat();
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "../mwmechanics/npcstats.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/fallback.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
|
|
@ -3,12 +3,23 @@
|
|||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include "tooltips.hpp"
|
||||
|
||||
#undef min
|
||||
#undef max
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
bool sortClasses(const std::pair<std::string, std::string>& left, const std::pair<std::string, std::string>& right)
|
||||
{
|
||||
return left.second.compare(right.second) < 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
|
||||
|
@ -129,8 +140,6 @@ namespace MWGui
|
|||
if (Misc::StringUtils::ciEqual(*mClassList->getItemDataAt<std::string>(i), classId))
|
||||
{
|
||||
mClassList->setIndexSelected(i);
|
||||
MyGUI::Button* okButton;
|
||||
getWidget(okButton, "OKButton");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -165,9 +174,6 @@ namespace MWGui
|
|||
if (_index == MyGUI::ITEM_NONE)
|
||||
return;
|
||||
|
||||
MyGUI::Button* okButton;
|
||||
getWidget(okButton, "OKButton");
|
||||
|
||||
const std::string *classId = mClassList->getItemDataAt<std::string>(_index);
|
||||
if (Misc::StringUtils::ciEqual(mCurrentClassId, *classId))
|
||||
return;
|
||||
|
@ -184,7 +190,7 @@ namespace MWGui
|
|||
|
||||
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
||||
|
||||
int index = 0;
|
||||
std::vector<std::pair<std::string, std::string> > items; // class id, class name
|
||||
MWWorld::Store<ESM::Class>::iterator it = store.get<ESM::Class>().begin();
|
||||
for (; it != store.get<ESM::Class>().end(); ++it)
|
||||
{
|
||||
|
@ -192,8 +198,15 @@ namespace MWGui
|
|||
if (!playable) // Only display playable classes
|
||||
continue;
|
||||
|
||||
const std::string &id = it->mId;
|
||||
mClassList->addItem(it->mName, id);
|
||||
items.push_back(std::make_pair(it->mId, it->mName));
|
||||
}
|
||||
std::sort(items.begin(), items.end(), sortClasses);
|
||||
|
||||
int index = 0;
|
||||
for (std::vector<std::pair<std::string, std::string> >::const_iterator it = items.begin(); it != items.end(); ++it)
|
||||
{
|
||||
const std::string &id = it->first;
|
||||
mClassList->addItem(it->second, id);
|
||||
if (mCurrentClassId.empty())
|
||||
{
|
||||
mCurrentClassId = id;
|
||||
|
@ -770,6 +783,7 @@ namespace MWGui
|
|||
|
||||
SelectSkillDialog::SelectSkillDialog()
|
||||
: WindowModal("openmw_chargen_select_skill.layout")
|
||||
, mSkillId(ESM::Skill::Block)
|
||||
{
|
||||
// Centre dialog
|
||||
center();
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
#ifndef MWGUI_CLASS_H
|
||||
#define MWGUI_CLASS_H
|
||||
|
||||
|
||||
#include <components/esm/attr.hpp>
|
||||
#include <components/esm/loadclas.hpp>
|
||||
#include "widgets.hpp"
|
||||
#include "windowbase.hpp"
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
|
@ -101,8 +102,20 @@ namespace MWGui
|
|||
it->second->listIdentifier (mNames);
|
||||
}
|
||||
|
||||
// exterior cell names aren't technically identifiers, but since the COC function accepts them,
|
||||
// we should list them too
|
||||
for (MWWorld::Store<ESM::Cell>::iterator it = store.get<ESM::Cell>().extBegin();
|
||||
it != store.get<ESM::Cell>().extEnd(); ++it)
|
||||
{
|
||||
if (!it->mName.empty())
|
||||
mNames.push_back(it->mName);
|
||||
}
|
||||
|
||||
// sort
|
||||
std::sort (mNames.begin(), mNames.end());
|
||||
|
||||
// remove duplicates
|
||||
mNames.erase( std::unique( mNames.begin(), mNames.end() ), mNames.end() );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -301,10 +301,9 @@ namespace MWGui
|
|||
MWMechanics::Pickpocket pickpocket(player, mPtr);
|
||||
if (pickpocket.finish())
|
||||
{
|
||||
MWBase::Environment::get().getMechanicsManager()->reportCrime(
|
||||
player, mPtr, MWBase::MechanicsManager::OT_Pickpocket);
|
||||
MWBase::Environment::get().getMechanicsManager()->commitCrime(
|
||||
player, mPtr, MWBase::MechanicsManager::OT_Pickpocket, 0, true);
|
||||
MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container);
|
||||
MWBase::Environment::get().getDialogueManager()->say(mPtr, "Thief");
|
||||
mPickpocketDetected = true;
|
||||
return;
|
||||
}
|
||||
|
@ -384,10 +383,9 @@ namespace MWGui
|
|||
if (pickpocket.pick(item.mBase, count))
|
||||
{
|
||||
int value = item.mBase.getClass().getValue(item.mBase) * count;
|
||||
MWBase::Environment::get().getMechanicsManager()->reportCrime(
|
||||
player, MWWorld::Ptr(), MWBase::MechanicsManager::OT_Theft, value);
|
||||
MWBase::Environment::get().getMechanicsManager()->commitCrime(
|
||||
player, MWWorld::Ptr(), MWBase::MechanicsManager::OT_Theft, value, true);
|
||||
MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container);
|
||||
MWBase::Environment::get().getDialogueManager()->say(mPtr, "Thief");
|
||||
mPickpocketDetected = true;
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/containerstore.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include "../mwdialogue/dialoguemanagerimp.hpp"
|
||||
|
||||
|
@ -415,20 +416,11 @@ namespace MWGui
|
|||
MWMechanics::CreatureStats &sellerStats = mPtr.getClass().getCreatureStats(mPtr);
|
||||
float delay = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fBarterGoldResetDelay")->getFloat();
|
||||
|
||||
// Gold is restocked every 24h
|
||||
if (MWBase::Environment::get().getWorld()->getTimeStamp() >= sellerStats.getLastRestockTime() + delay)
|
||||
{
|
||||
sellerStats.setGoldPool(mPtr.getClass().getBaseGold(mPtr));
|
||||
|
||||
mPtr.getClass().restock(mPtr);
|
||||
|
||||
// Also restock any containers owned by this merchant, which are also available to buy in the trade window
|
||||
std::vector<MWWorld::Ptr> itemSources;
|
||||
MWBase::Environment::get().getWorld()->getContainersOwnedBy(mPtr, itemSources);
|
||||
for (std::vector<MWWorld::Ptr>::iterator it = itemSources.begin(); it != itemSources.end(); ++it)
|
||||
{
|
||||
it->getClass().restock(*it);
|
||||
}
|
||||
|
||||
sellerStats.setLastRestockTime(MWBase::Environment::get().getWorld()->getTimeStamp());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <iomanip>
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <components/esm/records.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
@ -11,6 +12,7 @@
|
|||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/containerstore.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include "itemselection.hpp"
|
||||
#include "container.hpp"
|
||||
|
@ -109,7 +111,7 @@ namespace MWGui
|
|||
mCharge->setCaption(boost::lexical_cast<std::string>(mEnchanting.getGemCharge()));
|
||||
|
||||
std::stringstream castCost;
|
||||
castCost << mEnchanting.getCastCost();
|
||||
castCost << mEnchanting.getEffectiveCastCost();
|
||||
mCastCost->setCaption(castCost.str());
|
||||
|
||||
mPrice->setCaption(boost::lexical_cast<std::string>(mEnchanting.getEnchantPrice()));
|
||||
|
@ -118,19 +120,19 @@ namespace MWGui
|
|||
{
|
||||
case ESM::Enchantment::CastOnce:
|
||||
mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastOnce","Cast Once"));
|
||||
mAddEffectDialog.constantEffect=false;
|
||||
setConstantEffect(false);
|
||||
break;
|
||||
case ESM::Enchantment::WhenStrikes:
|
||||
mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastWhenStrikes", "When Strikes"));
|
||||
mAddEffectDialog.constantEffect=false;
|
||||
setConstantEffect(false);
|
||||
break;
|
||||
case ESM::Enchantment::WhenUsed:
|
||||
mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastWhenUsed", "When Used"));
|
||||
mAddEffectDialog.constantEffect=false;
|
||||
setConstantEffect(false);
|
||||
break;
|
||||
case ESM::Enchantment::ConstantEffect:
|
||||
mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastConstant", "Cast Constant"));
|
||||
mAddEffectDialog.constantEffect=true;
|
||||
setConstantEffect(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -281,6 +283,7 @@ namespace MWGui
|
|||
{
|
||||
mEnchanting.nextCastStyle();
|
||||
updateLabels();
|
||||
updateEffectsView();
|
||||
}
|
||||
|
||||
void EnchantingDialog::onBuyButtonClicked(MyGUI::Widget* sender)
|
||||
|
@ -338,9 +341,8 @@ namespace MWGui
|
|||
if (msg.find("%s") != std::string::npos)
|
||||
msg.replace(msg.find("%s"), 2, item.getClass().getName(item));
|
||||
MWBase::Environment::get().getWindowManager()->messageBox(msg);
|
||||
MWBase::Environment::get().getDialogueManager()->say(mPtr, "Thief");
|
||||
MWBase::Environment::get().getMechanicsManager()->reportCrime(player, mPtr, MWBase::MechanicsManager::OT_Theft,
|
||||
item.getClass().getValue(item));
|
||||
MWBase::Environment::get().getMechanicsManager()->commitCrime(player, mPtr, MWBase::MechanicsManager::OT_Theft,
|
||||
item.getClass().getValue(item), true);
|
||||
MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Enchanting);
|
||||
MWBase::Environment::get().getDialogueManager()->goodbyeSelected();
|
||||
return;
|
||||
|
|
|
@ -7,8 +7,10 @@
|
|||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/soundmanager.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include "../mwmechanics/creaturestats.hpp"
|
||||
#include "../mwmechanics/npcstats.hpp"
|
||||
|
@ -162,7 +164,7 @@ namespace MWGui
|
|||
getWidget(mTriangleCounter, "TriangleCounter");
|
||||
getWidget(mBatchCounter, "BatchCounter");
|
||||
|
||||
LocalMapBase::init(mMinimap, mCompass);
|
||||
LocalMapBase::init(mMinimap, mCompass, Settings::Manager::getInt("local map hud widget size", "Map"));
|
||||
|
||||
mMainWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onWorldClicked);
|
||||
mMainWidget->eventMouseMove += MyGUI::newDelegate(this, &HUD::onWorldMouseOver);
|
||||
|
@ -618,6 +620,11 @@ namespace MWGui
|
|||
// Health is usually cast to int before displaying. Actors die whenever they are < 1 health.
|
||||
// Therefore any value < 1 should show as an empty health bar. We do the same in statswindow :)
|
||||
mEnemyHealth->setProgressPosition(int(stats.getHealth().getCurrent()) / stats.getHealth().getModified() * 100);
|
||||
|
||||
static const float fNPCHealthBarFade = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fNPCHealthBarFade")->getFloat();
|
||||
if (fNPCHealthBarFade > 0.f)
|
||||
mEnemyHealth->setAlpha(std::max(0.f, std::min(1.f, mEnemyHealthTimer/fNPCHealthBarFade)));
|
||||
|
||||
}
|
||||
|
||||
void HUD::update()
|
||||
|
@ -639,7 +646,7 @@ namespace MWGui
|
|||
void HUD::setEnemy(const MWWorld::Ptr &enemy)
|
||||
{
|
||||
mEnemyActorId = enemy.getClass().getCreatureStats(enemy).getActorId();
|
||||
mEnemyHealthTimer = 5;
|
||||
mEnemyHealthTimer = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fNPCHealthBarTime")->getFloat();
|
||||
if (!mEnemyHealth->getVisible())
|
||||
mWeaponSpellBox->setPosition(mWeaponSpellBox->getPosition() - MyGUI::IntPoint(0,20));
|
||||
mEnemyHealth->setVisible(true);
|
||||
|
|
|
@ -56,11 +56,11 @@ void ItemView::layoutWidgets()
|
|||
int x = 0;
|
||||
int y = 0;
|
||||
MyGUI::Widget* dragArea = mScrollView->getChildAt(0);
|
||||
int maxHeight = dragArea->getHeight();
|
||||
int maxHeight = mScrollView->getHeight();
|
||||
|
||||
int rows = maxHeight/42;
|
||||
rows = std::max(rows, 1);
|
||||
bool showScrollbar = std::ceil(dragArea->getChildCount()/float(rows)) > mScrollView->getWidth()/42;
|
||||
bool showScrollbar = int(std::ceil(dragArea->getChildCount()/float(rows))) > mScrollView->getWidth()/42;
|
||||
if (showScrollbar)
|
||||
maxHeight -= 18;
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ namespace MWGui
|
|||
|
||||
getWidget(mLoadingText, "LoadingText");
|
||||
getWidget(mProgressBar, "ProgressBar");
|
||||
getWidget(mLoadingBox, "LoadingBox");
|
||||
|
||||
mProgressBar->setScrollViewPage(1);
|
||||
|
||||
|
@ -46,6 +47,11 @@ namespace MWGui
|
|||
void LoadingScreen::setLabel(const std::string &label)
|
||||
{
|
||||
mLoadingText->setCaptionWithReplacing(label);
|
||||
int padding = mLoadingBox->getWidth() - mLoadingText->getWidth();
|
||||
MyGUI::IntSize size(mLoadingText->getTextSize().width+padding, mLoadingBox->getHeight());
|
||||
size.width = std::max(300, size.width);
|
||||
mLoadingBox->setSize(size);
|
||||
mLoadingBox->setPosition(mMainWidget->getWidth()/2 - mLoadingBox->getWidth()/2, mLoadingBox->getTop());
|
||||
}
|
||||
|
||||
LoadingScreen::~LoadingScreen()
|
||||
|
|
|
@ -47,6 +47,8 @@ namespace MWGui
|
|||
|
||||
size_t mProgress;
|
||||
|
||||
MyGUI::Widget* mLoadingBox;
|
||||
|
||||
MyGUI::TextBox* mLoadingText;
|
||||
MyGUI::ScrollBar* mProgressBar;
|
||||
BackgroundImage* mBackgroundImage;
|
||||
|
|
|
@ -176,6 +176,8 @@ namespace MWGui
|
|||
int screenHeight = viewSize.height;
|
||||
mVideoBackground->setSize(screenWidth, screenHeight);
|
||||
|
||||
if (mVideo->getVideoHeight() > 0)
|
||||
{
|
||||
double imageaspect = static_cast<double>(mVideo->getVideoWidth())/mVideo->getVideoHeight();
|
||||
|
||||
int leftPadding = std::max(0.0, (screenWidth - screenHeight * imageaspect) / 2);
|
||||
|
@ -183,6 +185,7 @@ namespace MWGui
|
|||
|
||||
mVideo->setCoord(leftPadding, topPadding,
|
||||
screenWidth - leftPadding*2, screenHeight - topPadding*2);
|
||||
}
|
||||
|
||||
mVideo->setVisible(true);
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include "../mwworld/player.hpp"
|
||||
#include "../mwworld/cellstore.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include "../mwrender/globalmap.hpp"
|
||||
|
||||
|
@ -22,8 +23,6 @@
|
|||
namespace
|
||||
{
|
||||
|
||||
const int widgetSize = 512;
|
||||
|
||||
const int cellSize = 8192;
|
||||
|
||||
enum LocalMapWidgetDepth
|
||||
|
@ -164,6 +163,7 @@ namespace MWGui
|
|||
, mCompass(NULL)
|
||||
, mMarkerUpdateTimer(0.0f)
|
||||
, mCustomMarkers(markers)
|
||||
, mMapWidgetSize(0)
|
||||
{
|
||||
mCustomMarkers.eventMarkersChanged += MyGUI::newDelegate(this, &LocalMapBase::updateCustomMarkers);
|
||||
}
|
||||
|
@ -173,26 +173,28 @@ namespace MWGui
|
|||
mCustomMarkers.eventMarkersChanged -= MyGUI::newDelegate(this, &LocalMapBase::updateCustomMarkers);
|
||||
}
|
||||
|
||||
void LocalMapBase::init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass)
|
||||
void LocalMapBase::init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, int mapWidgetSize)
|
||||
{
|
||||
mLocalMap = widget;
|
||||
mCompass = compass;
|
||||
mMapWidgetSize = mapWidgetSize;
|
||||
|
||||
mLocalMap->setCanvasSize(mMapWidgetSize*3, mMapWidgetSize*3);
|
||||
|
||||
mCompass->setDepth(Local_CompassLayer);
|
||||
mCompass->setNeedMouseFocus(false);
|
||||
|
||||
// create 3x3 map widgets, 512x512 each, holding a 1024x1024 texture each
|
||||
for (int mx=0; mx<3; ++mx)
|
||||
{
|
||||
for (int my=0; my<3; ++my)
|
||||
{
|
||||
MyGUI::ImageBox* map = mLocalMap->createWidget<MyGUI::ImageBox>("ImageBox",
|
||||
MyGUI::IntCoord(mx*widgetSize, my*widgetSize, widgetSize, widgetSize),
|
||||
MyGUI::IntCoord(mx*mMapWidgetSize, my*mMapWidgetSize, mMapWidgetSize, mMapWidgetSize),
|
||||
MyGUI::Align::Top | MyGUI::Align::Left);
|
||||
map->setDepth(Local_MapLayer);
|
||||
|
||||
MyGUI::ImageBox* fog = mLocalMap->createWidget<MyGUI::ImageBox>("ImageBox",
|
||||
MyGUI::IntCoord(mx*widgetSize, my*widgetSize, widgetSize, widgetSize),
|
||||
MyGUI::IntCoord(mx*mMapWidgetSize, my*mMapWidgetSize, mMapWidgetSize, mMapWidgetSize),
|
||||
MyGUI::Align::Top | MyGUI::Align::Left);
|
||||
fog->setDepth(Local_FogLayer);
|
||||
|
||||
|
@ -258,8 +260,8 @@ namespace MWGui
|
|||
markerPos.cellX = cellX;
|
||||
markerPos.cellY = cellY;
|
||||
|
||||
widgetPos = MyGUI::IntPoint(nX * widgetSize + (1+cellDx) * widgetSize,
|
||||
nY * widgetSize - (cellDy-1) * widgetSize);
|
||||
widgetPos = MyGUI::IntPoint(nX * mMapWidgetSize + (1+cellDx) * mMapWidgetSize,
|
||||
nY * mMapWidgetSize - (cellDy-1) * mMapWidgetSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -271,8 +273,8 @@ namespace MWGui
|
|||
markerPos.cellY = cellY;
|
||||
|
||||
// Image space is -Y up, cells are Y up
|
||||
widgetPos = MyGUI::IntPoint(nX * widgetSize + (1+(cellX-mCurX)) * widgetSize,
|
||||
nY * widgetSize + (1-(cellY-mCurY)) * widgetSize);
|
||||
widgetPos = MyGUI::IntPoint(nX * mMapWidgetSize + (1+(cellX-mCurX)) * mMapWidgetSize,
|
||||
nY * mMapWidgetSize + (1-(cellY-mCurY)) * mMapWidgetSize);
|
||||
}
|
||||
|
||||
markerPos.nX = nX;
|
||||
|
@ -425,9 +427,9 @@ namespace MWGui
|
|||
|
||||
void LocalMapBase::setPlayerPos(int cellX, int cellY, const float nx, const float ny)
|
||||
{
|
||||
MyGUI::IntPoint pos(widgetSize+nx*widgetSize-16, widgetSize+ny*widgetSize-16);
|
||||
pos.left += (cellX - mCurX) * widgetSize;
|
||||
pos.top -= (cellY - mCurY) * widgetSize;
|
||||
MyGUI::IntPoint pos(mMapWidgetSize+nx*mMapWidgetSize-16, mMapWidgetSize+ny*mMapWidgetSize-16);
|
||||
pos.left += (cellX - mCurX) * mMapWidgetSize;
|
||||
pos.top -= (cellY - mCurY) * mMapWidgetSize;
|
||||
|
||||
if (pos != mCompass->getPosition())
|
||||
{
|
||||
|
@ -612,8 +614,7 @@ namespace MWGui
|
|||
mEventBoxLocal->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart);
|
||||
mEventBoxLocal->eventMouseButtonDoubleClick += MyGUI::newDelegate(this, &MapWindow::onMapDoubleClicked);
|
||||
|
||||
LocalMapBase::init(mLocalMap, mPlayerArrowLocal);
|
||||
}
|
||||
LocalMapBase::init(mLocalMap, mPlayerArrowLocal, Settings::Manager::getInt("local map widget size", "Map")); }
|
||||
|
||||
void MapWindow::onNoteEditOk()
|
||||
{
|
||||
|
@ -657,10 +658,10 @@ namespace MWGui
|
|||
MyGUI::IntPoint clickedPos = MyGUI::InputManager::getInstance().getMousePosition();
|
||||
|
||||
MyGUI::IntPoint widgetPos = clickedPos - mEventBoxLocal->getAbsolutePosition();
|
||||
int x = int(widgetPos.left/float(widgetSize))-1;
|
||||
int y = (int(widgetPos.top/float(widgetSize))-1)*-1;
|
||||
float nX = widgetPos.left/float(widgetSize) - int(widgetPos.left/float(widgetSize));
|
||||
float nY = widgetPos.top/float(widgetSize) - int(widgetPos.top/float(widgetSize));
|
||||
int x = int(widgetPos.left/float(mMapWidgetSize))-1;
|
||||
int y = (int(widgetPos.top/float(mMapWidgetSize))-1)*-1;
|
||||
float nX = widgetPos.left/float(mMapWidgetSize) - int(widgetPos.left/float(mMapWidgetSize));
|
||||
float nY = widgetPos.top/float(mMapWidgetSize) - int(widgetPos.top/float(mMapWidgetSize));
|
||||
x += mCurX;
|
||||
y += mCurY;
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ namespace MWGui
|
|||
public:
|
||||
LocalMapBase(CustomMarkerCollection& markers);
|
||||
virtual ~LocalMapBase();
|
||||
void init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass);
|
||||
void init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, int mapWidgetSize);
|
||||
|
||||
void setCellPrefix(const std::string& prefix);
|
||||
void setActiveCell(const int x, const int y, bool interior=false);
|
||||
|
@ -99,6 +99,8 @@ namespace MWGui
|
|||
bool mChanged;
|
||||
bool mFogOfWar;
|
||||
|
||||
int mMapWidgetSize;
|
||||
|
||||
// Stores markers that were placed by a player. May be shared between multiple map views.
|
||||
CustomMarkerCollection& mCustomMarkers;
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "../mwworld/inventorystore.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/player.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/format.hpp>
|
||||
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
|
@ -20,6 +21,12 @@ namespace
|
|||
else
|
||||
return index;
|
||||
}
|
||||
|
||||
bool sortRaces(const std::pair<std::string, std::string>& left, const std::pair<std::string, std::string>& right)
|
||||
{
|
||||
return left.second.compare(right.second) < 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace MWGui
|
||||
|
@ -122,7 +129,7 @@ namespace MWGui
|
|||
|
||||
mPreview.reset(new MWRender::RaceSelectionPreview());
|
||||
mPreview->setup();
|
||||
mPreview->update (0);
|
||||
mPreview->update (mCurrentAngle);
|
||||
|
||||
const ESM::NPC proto = mPreview->getPrototype();
|
||||
setRaceId(proto.mRace);
|
||||
|
@ -143,8 +150,11 @@ namespace MWGui
|
|||
mPreviewImage->setImageTexture (textureName);
|
||||
|
||||
mPreviewDirty = true;
|
||||
}
|
||||
|
||||
size_t initialPos = mHeadRotate->getScrollRange()/2+mHeadRotate->getScrollRange()/10;
|
||||
mHeadRotate->setScrollPosition(initialPos);
|
||||
onHeadRotate(mHeadRotate, initialPos);
|
||||
}
|
||||
|
||||
void RaceDialog::setRaceId(const std::string &raceId)
|
||||
{
|
||||
|
@ -156,8 +166,6 @@ namespace MWGui
|
|||
if (Misc::StringUtils::ciEqual(*mRaceList->getItemDataAt<std::string>(i), raceId))
|
||||
{
|
||||
mRaceList->setIndexSelected(i);
|
||||
MyGUI::Button* okButton;
|
||||
getWidget(okButton, "OKButton");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -191,10 +199,9 @@ namespace MWGui
|
|||
void RaceDialog::onHeadRotate(MyGUI::ScrollBar* scroll, size_t _position)
|
||||
{
|
||||
float angle = (float(_position) / (scroll->getScrollRange()-1) - 0.5) * 3.14 * 2;
|
||||
float diff = angle - mCurrentAngle;
|
||||
mPreview->update (diff);
|
||||
mPreview->update (angle);
|
||||
mPreviewDirty = true;
|
||||
mCurrentAngle += diff;
|
||||
mCurrentAngle = angle;
|
||||
}
|
||||
|
||||
void RaceDialog::onSelectPreviousGender(MyGUI::Widget*)
|
||||
|
@ -242,8 +249,6 @@ namespace MWGui
|
|||
if (_index == MyGUI::ITEM_NONE)
|
||||
return;
|
||||
|
||||
MyGUI::Button* okButton;
|
||||
getWidget(okButton, "OKButton");
|
||||
const std::string *raceId = mRaceList->getItemDataAt<std::string>(_index);
|
||||
if (Misc::StringUtils::ciEqual(mCurrentRaceId, *raceId))
|
||||
return;
|
||||
|
@ -345,8 +350,7 @@ namespace MWGui
|
|||
const MWWorld::Store<ESM::Race> &races =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>();
|
||||
|
||||
|
||||
int index = 0;
|
||||
std::vector<std::pair<std::string, std::string> > items; // ID, name
|
||||
MWWorld::Store<ESM::Race>::iterator it = races.begin();
|
||||
for (; it != races.end(); ++it)
|
||||
{
|
||||
|
@ -354,8 +358,15 @@ namespace MWGui
|
|||
if (!playable) // Only display playable races
|
||||
continue;
|
||||
|
||||
mRaceList->addItem(it->mName, it->mId);
|
||||
if (Misc::StringUtils::ciEqual(it->mId, mCurrentRaceId))
|
||||
items.push_back(std::make_pair(it->mId, it->mName));
|
||||
}
|
||||
std::sort(items.begin(), items.end(), sortRaces);
|
||||
|
||||
int index = 0;
|
||||
for (std::vector<std::pair<std::string, std::string> >::const_iterator it = items.begin(); it != items.end(); ++it)
|
||||
{
|
||||
mRaceList->addItem(it->second, it->first);
|
||||
if (Misc::StringUtils::ciEqual(it->first, mCurrentRaceId))
|
||||
mRaceList->setIndexSelected(index);
|
||||
++index;
|
||||
}
|
||||
|
|
|
@ -3,12 +3,15 @@
|
|||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/format.hpp>
|
||||
|
||||
#include <components/esm/records.hpp>
|
||||
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
|
||||
#include "../mwworld/containerstore.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include "../mwmechanics/creaturestats.hpp"
|
||||
#include "../mwmechanics/npcstats.hpp"
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include "tooltips.hpp"
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#ifndef MWGUI_REVIEW_H
|
||||
#define MWGUI_REVIEW_H
|
||||
|
||||
#include <components/esm/attr.hpp>
|
||||
#include <components/esm/loadclas.hpp>
|
||||
#include "windowbase.hpp"
|
||||
#include "widgets.hpp"
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include "../mwstate/character.hpp"
|
||||
|
||||
|
@ -245,7 +246,7 @@ namespace MWGui
|
|||
else
|
||||
{
|
||||
assert (mCurrentCharacter && mCurrentSlot);
|
||||
MWBase::Environment::get().getStateManager()->loadGame (mCurrentCharacter, mCurrentSlot);
|
||||
MWBase::Environment::get().getStateManager()->loadGame (mCurrentCharacter, mCurrentSlot->mPath.string());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -304,7 +305,7 @@ namespace MWGui
|
|||
mOkButton->setEnabled(pos != MyGUI::ITEM_NONE || mSaving);
|
||||
mDeleteButton->setEnabled(pos != MyGUI::ITEM_NONE);
|
||||
|
||||
if (pos == MyGUI::ITEM_NONE)
|
||||
if (pos == MyGUI::ITEM_NONE || !mCurrentCharacter)
|
||||
{
|
||||
mCurrentSlot = NULL;
|
||||
mInfoText->setCaption("");
|
||||
|
|
|
@ -166,6 +166,7 @@ namespace MWGui
|
|||
getWidget(mResolutionList, "ResolutionList");
|
||||
getWidget(mFullscreenButton, "FullscreenButton");
|
||||
getWidget(mVSyncButton, "VSyncButton");
|
||||
getWidget(mWindowBorderButton, "WindowBorderButton");
|
||||
getWidget(mFPSButton, "FPSButton");
|
||||
getWidget(mFOVSlider, "FOVSlider");
|
||||
getWidget(mAnisotropySlider, "AnisotropySlider");
|
||||
|
@ -181,6 +182,20 @@ namespace MWGui
|
|||
getWidget(mRefractionButton, "RefractionButton");
|
||||
getWidget(mDifficultySlider, "DifficultySlider");
|
||||
|
||||
#ifndef WIN32
|
||||
// hide gamma controls since it currently does not work under Linux
|
||||
MyGUI::ScrollBar *gammaSlider;
|
||||
getWidget(gammaSlider, "GammaSlider");
|
||||
gammaSlider->setVisible(false);
|
||||
MyGUI::TextBox *textBox;
|
||||
getWidget(textBox, "GammaText");
|
||||
textBox->setVisible(false);
|
||||
getWidget(textBox, "GammaTextDark");
|
||||
textBox->setVisible(false);
|
||||
getWidget(textBox, "GammaTextLight");
|
||||
textBox->setVisible(false);
|
||||
#endif
|
||||
|
||||
mMainWidget->castType<MyGUI::Window>()->eventWindowChangeCoord += MyGUI::newDelegate(this, &SettingsWindow::onWindowResize);
|
||||
|
||||
mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onOkButtonClicked);
|
||||
|
@ -239,6 +254,8 @@ namespace MWGui
|
|||
MyGUI::TextBox* diffText;
|
||||
getWidget(diffText, "DifficultyText");
|
||||
diffText->setCaptionWithReplacing("#{sDifficulty} (" + boost::lexical_cast<std::string>(int(Settings::Manager::getInt("difficulty", "Game"))) + ")");
|
||||
|
||||
mWindowBorderButton->setEnabled(!Settings::Manager::getBool("fullscreen", "Video"));
|
||||
}
|
||||
|
||||
void SettingsWindow::onOkButtonClicked(MyGUI::Widget* _sender)
|
||||
|
@ -354,6 +371,8 @@ namespace MWGui
|
|||
_sender->castType<MyGUI::Button>()->setCaption(off);
|
||||
return;
|
||||
}
|
||||
|
||||
mWindowBorderButton->setEnabled(!newState);
|
||||
}
|
||||
|
||||
if (getSettingType(_sender) == checkButtonType)
|
||||
|
|
|
@ -28,6 +28,7 @@ namespace MWGui
|
|||
MyGUI::ListBox* mResolutionList;
|
||||
MyGUI::Button* mFullscreenButton;
|
||||
MyGUI::Button* mVSyncButton;
|
||||
MyGUI::Button* mWindowBorderButton;
|
||||
MyGUI::Button* mFPSButton;
|
||||
MyGUI::ScrollBar* mFOVSlider;
|
||||
MyGUI::ScrollBar* mDifficultySlider;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include "sortfilteritemmodel.hpp"
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
#include <components/esm/loadalch.hpp>
|
||||
#include <components/esm/loadappa.hpp>
|
||||
#include <components/esm/loadarmo.hpp>
|
||||
|
@ -52,9 +54,10 @@ namespace
|
|||
|
||||
if (left.mBase.getTypeName() == right.mBase.getTypeName())
|
||||
{
|
||||
int cmp = left.mBase.getClass().getName(left.mBase).compare(
|
||||
right.mBase.getClass().getName(right.mBase));
|
||||
return cmp < 0;
|
||||
std::string leftName = Misc::StringUtils::lowerCase(left.mBase.getClass().getName(left.mBase));
|
||||
std::string rightName = Misc::StringUtils::lowerCase(right.mBase.getClass().getName(right.mBase));
|
||||
|
||||
return leftName.compare(rightName) < 0;
|
||||
}
|
||||
else
|
||||
return compareType(left.mBase.getTypeName(), right.mBase.getTypeName());
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include <components/misc/resourcehelpers.hpp>
|
||||
#include <components/esm/records.hpp>
|
||||
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/soundmanager.hpp"
|
||||
|
@ -12,6 +13,7 @@
|
|||
|
||||
#include "../mwworld/containerstore.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include "../mwmechanics/spellcasting.hpp"
|
||||
#include "../mwmechanics/spells.hpp"
|
||||
|
@ -40,6 +42,7 @@ namespace MWGui
|
|||
: WindowModal("openmw_edit_effect.layout")
|
||||
, mEditing(false)
|
||||
, mMagicEffect(NULL)
|
||||
, mConstantEffect(false)
|
||||
{
|
||||
getWidget(mCancelButton, "CancelButton");
|
||||
getWidget(mOkButton, "OkButton");
|
||||
|
@ -69,7 +72,11 @@ namespace MWGui
|
|||
mMagnitudeMaxSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &EditEffectDialog::onMagnitudeMaxChanged);
|
||||
mDurationSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &EditEffectDialog::onDurationChanged);
|
||||
mAreaSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &EditEffectDialog::onAreaChanged);
|
||||
constantEffect=false;
|
||||
}
|
||||
|
||||
void EditEffectDialog::setConstantEffect(bool constant)
|
||||
{
|
||||
mConstantEffect = constant;
|
||||
}
|
||||
|
||||
void EditEffectDialog::open()
|
||||
|
@ -90,8 +97,8 @@ namespace MWGui
|
|||
void EditEffectDialog::newEffect (const ESM::MagicEffect *effect)
|
||||
{
|
||||
bool allowSelf = effect->mData.mFlags & ESM::MagicEffect::CastSelf;
|
||||
bool allowTouch = (effect->mData.mFlags & ESM::MagicEffect::CastTouch) && !constantEffect;
|
||||
bool allowTarget = (effect->mData.mFlags & ESM::MagicEffect::CastTarget) && !constantEffect;
|
||||
bool allowTouch = (effect->mData.mFlags & ESM::MagicEffect::CastTouch) && !mConstantEffect;
|
||||
bool allowTarget = (effect->mData.mFlags & ESM::MagicEffect::CastTarget) && !mConstantEffect;
|
||||
|
||||
if (!allowSelf && !allowTouch && !allowTarget)
|
||||
return; // TODO: Show an error message popup?
|
||||
|
@ -181,7 +188,7 @@ namespace MWGui
|
|||
mMagnitudeBox->setVisible (true);
|
||||
curY += mMagnitudeBox->getSize().height;
|
||||
}
|
||||
if (!(mMagicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)&&constantEffect==false)
|
||||
if (!(mMagicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)&&mConstantEffect==false)
|
||||
{
|
||||
mDurationBox->setPosition(mDurationBox->getPosition().left, curY);
|
||||
mDurationBox->setVisible (true);
|
||||
|
@ -202,8 +209,8 @@ namespace MWGui
|
|||
// cycle through range types until we find something that's allowed
|
||||
// does not handle the case where nothing is allowed (this should be prevented before opening the Add Effect dialog)
|
||||
bool allowSelf = mMagicEffect->mData.mFlags & ESM::MagicEffect::CastSelf;
|
||||
bool allowTouch = (mMagicEffect->mData.mFlags & ESM::MagicEffect::CastTouch) && !constantEffect;
|
||||
bool allowTarget = (mMagicEffect->mData.mFlags & ESM::MagicEffect::CastTarget) && !constantEffect;
|
||||
bool allowTouch = (mMagicEffect->mData.mFlags & ESM::MagicEffect::CastTouch) && !mConstantEffect;
|
||||
bool allowTarget = (mMagicEffect->mData.mFlags & ESM::MagicEffect::CastTarget) && !mConstantEffect;
|
||||
if (mEffect.mRange == ESM::RT_Self && !allowSelf)
|
||||
mEffect.mRange = (mEffect.mRange+1)%3;
|
||||
if (mEffect.mRange == ESM::RT_Touch && !allowTouch)
|
||||
|
@ -371,7 +378,7 @@ namespace MWGui
|
|||
MWMechanics::CreatureStats& npcStats = mPtr.getClass().getCreatureStats(mPtr);
|
||||
npcStats.setGoldPool(npcStats.getGoldPool() + price);
|
||||
|
||||
MWBase::Environment::get().getSoundManager()->playSound ("Item Gold Up", 1.0, 1.0);
|
||||
MWBase::Environment::get().getSoundManager()->playSound ("Mysticism Hit", 1.0, 1.0);
|
||||
|
||||
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->createRecord(mSpell);
|
||||
|
||||
|
@ -379,8 +386,6 @@ namespace MWGui
|
|||
MWMechanics::Spells& spells = stats.getSpells();
|
||||
spells.add (spell->mId);
|
||||
|
||||
MWBase::Environment::get().getSoundManager()->playSound ("Item Gold Up", 1.0, 1.0);
|
||||
|
||||
MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_SpellCreation);
|
||||
}
|
||||
|
||||
|
@ -468,6 +473,7 @@ namespace MWGui
|
|||
, mSelectedEffect(0)
|
||||
, mSelectedKnownEffectId(0)
|
||||
, mType(type)
|
||||
, mConstantEffect(false)
|
||||
{
|
||||
mAddEffectDialog.eventEffectAdded += MyGUI::newDelegate(this, &EffectEditorBase::onEffectAdded);
|
||||
mAddEffectDialog.eventEffectModified += MyGUI::newDelegate(this, &EffectEditorBase::onEffectModified);
|
||||
|
@ -592,14 +598,6 @@ namespace MWGui
|
|||
|
||||
int buttonId = *sender->getUserData<int>();
|
||||
mSelectedKnownEffectId = mButtonMapping[buttonId];
|
||||
for (std::vector<ESM::ENAMstruct>::const_iterator it = mEffects.begin(); it != mEffects.end(); ++it)
|
||||
{
|
||||
if (it->mEffectID == mSelectedKnownEffectId)
|
||||
{
|
||||
MWBase::Environment::get().getWindowManager()->messageBox ("#{sOnetypeEffectMessage}");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const ESM::MagicEffect* effect =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(mSelectedKnownEffectId);
|
||||
|
@ -622,6 +620,15 @@ namespace MWGui
|
|||
}
|
||||
else
|
||||
{
|
||||
for (std::vector<ESM::ENAMstruct>::const_iterator it = mEffects.begin(); it != mEffects.end(); ++it)
|
||||
{
|
||||
if (it->mEffectID == mSelectedKnownEffectId)
|
||||
{
|
||||
MWBase::Environment::get().getWindowManager()->messageBox ("#{sOnetypeEffectMessage}");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mAddEffectDialog.newEffect(effect);
|
||||
}
|
||||
}
|
||||
|
@ -658,6 +665,7 @@ namespace MWGui
|
|||
params.mMagnMax = it->mMagnMax;
|
||||
params.mRange = it->mRange;
|
||||
params.mArea = it->mArea;
|
||||
params.mIsConstant = mConstantEffect;
|
||||
|
||||
MyGUI::Button* button = mUsedEffectsView->createWidget<MyGUI::Button>("", MyGUI::IntCoord(0, size.height, 0, 24), MyGUI::Align::Default);
|
||||
button->setUserData(i);
|
||||
|
@ -702,4 +710,10 @@ namespace MWGui
|
|||
mAddEffectDialog.editEffect (mEffects[id]);
|
||||
mAddEffectDialog.setVisible (true);
|
||||
}
|
||||
|
||||
void EffectEditorBase::setConstantEffect(bool constant)
|
||||
{
|
||||
mAddEffectDialog.setConstantEffect(constant);
|
||||
mConstantEffect = constant;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#ifndef MWGUI_SPELLCREATION_H
|
||||
#define MWGUI_SPELLCREATION_H
|
||||
|
||||
#include <components/esm/loadmgef.hpp>
|
||||
#include <components/esm/loadspel.hpp>
|
||||
#include <components/widgets/list.hpp>
|
||||
|
||||
#include "windowbase.hpp"
|
||||
|
@ -21,12 +23,13 @@ namespace MWGui
|
|||
virtual void open();
|
||||
virtual void exit();
|
||||
|
||||
void setConstantEffect(bool constant);
|
||||
|
||||
void setSkill(int skill);
|
||||
void setAttribute(int attribute);
|
||||
|
||||
void newEffect (const ESM::MagicEffect* effect);
|
||||
void editEffect (ESM::ENAMstruct effect);
|
||||
bool constantEffect;
|
||||
typedef MyGUI::delegates::CMultiDelegate1<ESM::ENAMstruct> EventHandle_Effect;
|
||||
|
||||
EventHandle_Effect eventEffectAdded;
|
||||
|
@ -80,6 +83,8 @@ namespace MWGui
|
|||
ESM::ENAMstruct mOldEffect;
|
||||
|
||||
const ESM::MagicEffect* mMagicEffect;
|
||||
|
||||
bool mConstantEffect;
|
||||
};
|
||||
|
||||
|
||||
|
@ -95,6 +100,8 @@ namespace MWGui
|
|||
EffectEditorBase(Type type);
|
||||
virtual ~EffectEditorBase();
|
||||
|
||||
void setConstantEffect(bool constant);
|
||||
|
||||
protected:
|
||||
std::map<int, short> mButtonMapping; // maps button ID to effect ID
|
||||
|
||||
|
@ -108,6 +115,8 @@ namespace MWGui
|
|||
int mSelectedEffect;
|
||||
short mSelectedKnownEffectId;
|
||||
|
||||
bool mConstantEffect;
|
||||
|
||||
std::vector<ESM::ENAMstruct> mEffects;
|
||||
|
||||
void onEffectAdded(ESM::ENAMstruct effect);
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
#include <components/esm/loadmgef.hpp>
|
||||
#include <components/misc/resourcehelpers.hpp>
|
||||
|
||||
#include "../mwbase/world.hpp"
|
||||
|
@ -12,6 +13,7 @@
|
|||
#include "../mwbase/windowmanager.hpp"
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
|
||||
#include "../mwmechanics/creaturestats.hpp"
|
||||
|
@ -23,8 +25,8 @@ namespace MWGui
|
|||
{
|
||||
|
||||
void EffectSourceVisitor::visit (MWMechanics::EffectKey key,
|
||||
const std::string& sourceName, int casterActorId,
|
||||
float magnitude, float remainingTime)
|
||||
const std::string& sourceName, const std::string& sourceId, int casterActorId,
|
||||
float magnitude, float remainingTime, float totalTime)
|
||||
{
|
||||
MagicEffectInfo newEffectSource;
|
||||
newEffectSource.mKey = key;
|
||||
|
@ -32,6 +34,7 @@ namespace MWGui
|
|||
newEffectSource.mPermanent = mIsPermanent;
|
||||
newEffectSource.mRemainingTime = remainingTime;
|
||||
newEffectSource.mSource = sourceName;
|
||||
newEffectSource.mTotalTime = totalTime;
|
||||
|
||||
mEffectSources[key.mId].push_back(newEffectSource);
|
||||
}
|
||||
|
@ -67,10 +70,11 @@ namespace MWGui
|
|||
MWBase::Environment::get().getWorld ()->getStore ().get<ESM::MagicEffect>().find(it->first);
|
||||
|
||||
float remainingDuration = 0;
|
||||
float totalDuration = 0;
|
||||
|
||||
std::string sourcesDescription;
|
||||
|
||||
const float fadeTime = 5.f;
|
||||
static const float fadeTime = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fMagicStartIconBlink")->getFloat();
|
||||
|
||||
for (std::vector<MagicEffectInfo>::const_iterator effectIt = it->second.begin();
|
||||
effectIt != it->second.end(); ++effectIt)
|
||||
|
@ -80,9 +84,15 @@ namespace MWGui
|
|||
|
||||
// if at least one of the effect sources is permanent, the effect will never wear off
|
||||
if (effectIt->mPermanent)
|
||||
{
|
||||
remainingDuration = fadeTime;
|
||||
totalDuration = fadeTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
remainingDuration = std::max(remainingDuration, effectIt->mRemainingTime);
|
||||
totalDuration = std::max(totalDuration, effectIt->mTotalTime);
|
||||
}
|
||||
|
||||
sourcesDescription += effectIt->mSource;
|
||||
|
||||
|
@ -158,7 +168,8 @@ namespace MWGui
|
|||
ToolTipInfo* tooltipInfo = image->getUserData<ToolTipInfo>();
|
||||
tooltipInfo->text = sourcesDescription;
|
||||
|
||||
// Fade out during the last 5 seconds
|
||||
// Fade out
|
||||
if (totalDuration >= fadeTime && fadeTime > 0.f)
|
||||
image->setAlpha(std::min(remainingDuration/fadeTime, 1.f));
|
||||
}
|
||||
else if (mWidgetMap.find(it->first) != mWidgetMap.end())
|
||||
|
|
|
@ -26,12 +26,14 @@ namespace MWGui
|
|||
MagicEffectInfo()
|
||||
: mPermanent(false)
|
||||
, mMagnitude(0)
|
||||
, mRemainingTime(0)
|
||||
, mRemainingTime(0.f)
|
||||
, mTotalTime(0.f)
|
||||
{}
|
||||
std::string mSource; // display name for effect source (e.g. potion name)
|
||||
MWMechanics::EffectKey mKey;
|
||||
int mMagnitude;
|
||||
float mRemainingTime;
|
||||
float mTotalTime;
|
||||
bool mPermanent; // the effect is permanent
|
||||
};
|
||||
|
||||
|
@ -45,8 +47,8 @@ namespace MWGui
|
|||
virtual ~EffectSourceVisitor() {}
|
||||
|
||||
virtual void visit (MWMechanics::EffectKey key,
|
||||
const std::string& sourceName, int casterActorId,
|
||||
float magnitude, float remainingTime = -1);
|
||||
const std::string& sourceName, const std::string& sourceId, int casterActorId,
|
||||
float magnitude, float remainingTime = -1, float totalTime = -1);
|
||||
};
|
||||
|
||||
class SpellIcons
|
||||
|
|
|
@ -21,8 +21,10 @@ namespace
|
|||
if (left.mType != right.mType)
|
||||
return left.mType < right.mType;
|
||||
|
||||
int cmp = left.mName.compare(right.mName);
|
||||
return cmp < 0;
|
||||
std::string leftName = Misc::StringUtils::lowerCase(left.mName);
|
||||
std::string rightName = Misc::StringUtils::lowerCase(right.mName);
|
||||
|
||||
return leftName.compare(rightName) < 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -101,9 +103,7 @@ namespace MWGui
|
|||
&& item.getClass().canBeEquipped(item, mActor).first == 0)
|
||||
continue;
|
||||
|
||||
float enchantCost = enchant->mData.mCost;
|
||||
int eSkill = mActor.getClass().getSkill(mActor, ESM::Skill::Enchant);
|
||||
int castCost = std::max(1.f, enchantCost - (enchantCost / 100) * (eSkill - 10));
|
||||
int castCost = MWMechanics::getEffectiveEnchantmentCastCost(enchant->mData.mCost, mActor);
|
||||
|
||||
std::string cost = boost::lexical_cast<std::string>(castCost);
|
||||
int currentCharge = int(item.getCellRef().getEnchantmentCharge());
|
||||
|
|
|
@ -26,6 +26,7 @@ namespace MWGui
|
|||
Spell()
|
||||
: mSelected(false)
|
||||
, mActive(false)
|
||||
, mType(Type_Spell)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include "../mwmechanics/spellcasting.hpp"
|
||||
#include "../mwmechanics/spells.hpp"
|
||||
|
|
|
@ -342,10 +342,14 @@ namespace MWGui
|
|||
{
|
||||
MyGUI::TextBox* skillNameWidget;
|
||||
|
||||
skillNameWidget = mSkillView->createWidget<MyGUI::TextBox>("SandText", coord1 + MyGUI::IntSize(coord2.width, 0), MyGUI::Align::Default);
|
||||
skillNameWidget = mSkillView->createWidget<MyGUI::TextBox>("SandText", coord1, MyGUI::Align::Default);
|
||||
|
||||
skillNameWidget->setCaption(text);
|
||||
skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel);
|
||||
|
||||
int textWidth = skillNameWidget->getTextSize().width;
|
||||
skillNameWidget->setSize(textWidth, skillNameWidget->getHeight());
|
||||
|
||||
mSkillWidgets.push_back(skillNameWidget);
|
||||
|
||||
coord1.top += sLineHeight;
|
||||
|
|
|
@ -61,13 +61,7 @@ namespace MWGui
|
|||
|
||||
void TextInputDialog::onTextAccepted(MyGUI::Edit* _sender)
|
||||
{
|
||||
if (mTextEdit->getCaption() == "")
|
||||
{
|
||||
MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage37}");
|
||||
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget (mTextEdit);
|
||||
}
|
||||
else
|
||||
eventDone(this);
|
||||
onOkClicked(_sender);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "../mwbase/windowmanager.hpp"
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
#include "../mwmechanics/spellcasting.hpp"
|
||||
|
||||
#include "mapwindow.hpp"
|
||||
|
|
|
@ -7,6 +7,12 @@
|
|||
|
||||
#include "widgets.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
class Class;
|
||||
struct Race;
|
||||
}
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
// Info about tooltip that is supplied by the MWWorld::Class object
|
||||
|
|
|
@ -94,6 +94,20 @@ namespace MWGui
|
|||
setCoord(400, 0, 400, 300);
|
||||
}
|
||||
|
||||
void TradeWindow::restock()
|
||||
{
|
||||
// Restock items on the actor inventory
|
||||
mPtr.getClass().restock(mPtr);
|
||||
|
||||
// Also restock any containers owned by this merchant, which are also available to buy in the trade window
|
||||
std::vector<MWWorld::Ptr> itemSources;
|
||||
MWBase::Environment::get().getWorld()->getContainersOwnedBy(mPtr, itemSources);
|
||||
for (std::vector<MWWorld::Ptr>::iterator it = itemSources.begin(); it != itemSources.end(); ++it)
|
||||
{
|
||||
it->getClass().restock(*it);
|
||||
}
|
||||
}
|
||||
|
||||
void TradeWindow::startTrade(const MWWorld::Ptr& actor)
|
||||
{
|
||||
mPtr = actor;
|
||||
|
@ -101,6 +115,8 @@ namespace MWGui
|
|||
mCurrentBalance = 0;
|
||||
mCurrentMerchantOffer = 0;
|
||||
|
||||
restock();
|
||||
|
||||
std::vector<MWWorld::Ptr> itemSources;
|
||||
MWBase::Environment::get().getWorld()->getContainersOwnedBy(actor, itemSources);
|
||||
|
||||
|
@ -290,10 +306,9 @@ namespace MWGui
|
|||
if (msg.find("%s") != std::string::npos)
|
||||
msg.replace(msg.find("%s"), 2, it->mBase.getClass().getName(it->mBase));
|
||||
MWBase::Environment::get().getWindowManager()->messageBox(msg);
|
||||
MWBase::Environment::get().getDialogueManager()->say(mPtr, "Thief");
|
||||
MWBase::Environment::get().getMechanicsManager()->reportCrime(player, mPtr, MWBase::MechanicsManager::OT_Theft,
|
||||
MWBase::Environment::get().getMechanicsManager()->commitCrime(player, mPtr, MWBase::MechanicsManager::OT_Theft,
|
||||
it->mBase.getClass().getValue(it->mBase)
|
||||
* it->mCount);
|
||||
* it->mCount, true);
|
||||
onCancelButtonClicked(mCancelButton);
|
||||
MWBase::Environment::get().getDialogueManager()->goodbyeSelected();
|
||||
return;
|
||||
|
|
|
@ -98,6 +98,8 @@ namespace MWGui
|
|||
virtual void onReferenceUnavailable();
|
||||
|
||||
int getMerchantGold();
|
||||
|
||||
void restock();
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/containerstore.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include "../mwmechanics/npcstats.hpp"
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/cellstore.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include "../mwmechanics/creaturestats.hpp"
|
||||
#include "../mwmechanics/npcstats.hpp"
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "widgets.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
|
@ -446,7 +447,7 @@ namespace MWGui
|
|||
// constant effects have no duration and no target
|
||||
if (!mEffectParams.mIsConstant)
|
||||
{
|
||||
if (mEffectParams.mDuration >= 0 && !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration))
|
||||
if (mEffectParams.mDuration > 0 && !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration))
|
||||
{
|
||||
spellLine += " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sfor", "") + " " + boost::lexical_cast<std::string>(mEffectParams.mDuration) + ((mEffectParams.mDuration == 1) ? sec : secs);
|
||||
}
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
#ifndef MWGUI_WIDGETS_H
|
||||
#define MWGUI_WIDGETS_H
|
||||
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
#include "../mwmechanics/stat.hpp"
|
||||
#include "controllers.hpp"
|
||||
|
||||
#include <components/esm/effectlist.hpp>
|
||||
#include <components/esm/loadskil.hpp>
|
||||
|
||||
#include <MyGUI_Button.h>
|
||||
#include <MyGUI_EditBox.h>
|
||||
#include <MyGUI_ScrollBar.h>
|
||||
|
|
|
@ -1691,6 +1691,8 @@ namespace MWGui
|
|||
// Use black bars to correct aspect ratio
|
||||
mVideoBackground->setSize(screenWidth, screenHeight);
|
||||
|
||||
if (mVideoWidget->getVideoHeight() > 0)
|
||||
{
|
||||
double imageaspect = static_cast<double>(mVideoWidget->getVideoWidth())/mVideoWidget->getVideoHeight();
|
||||
|
||||
int leftPadding = std::max(0.0, (screenWidth - screenHeight * imageaspect) / 2);
|
||||
|
@ -1699,6 +1701,7 @@ namespace MWGui
|
|||
mVideoWidget->setCoord(leftPadding, topPadding,
|
||||
screenWidth - leftPadding*2, screenHeight - topPadding*2);
|
||||
}
|
||||
}
|
||||
|
||||
WindowModal* WindowManager::getCurrentModal() const
|
||||
{
|
||||
|
|
|
@ -195,7 +195,7 @@ namespace MWMechanics
|
|||
float magnitude = effectIt->mMagnitude;
|
||||
|
||||
if (magnitude)
|
||||
visitor.visit(MWMechanics::EffectKey(effectIt->mEffectId, effectIt->mArg), name, it->second.mCasterActorId, magnitude, remainingTime);
|
||||
visitor.visit(MWMechanics::EffectKey(effectIt->mEffectId, effectIt->mArg), name, it->first, it->second.mCasterActorId, magnitude, remainingTime, effectIt->mDuration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -229,6 +229,22 @@ namespace MWMechanics
|
|||
mSpellsChanged = true;
|
||||
}
|
||||
|
||||
void ActiveSpells::purgeEffect(short effectId, const std::string& sourceId)
|
||||
{
|
||||
for (TContainer::iterator it = mSpells.begin(); it != mSpells.end(); ++it)
|
||||
{
|
||||
for (std::vector<ActiveEffect>::iterator effectIt = it->second.mEffects.begin();
|
||||
effectIt != it->second.mEffects.end();)
|
||||
{
|
||||
if (effectIt->mEffectId == effectId && it->first == sourceId)
|
||||
effectIt = it->second.mEffects.erase(effectIt);
|
||||
else
|
||||
++effectIt;
|
||||
}
|
||||
}
|
||||
mSpellsChanged = true;
|
||||
}
|
||||
|
||||
void ActiveSpells::purge(int casterActorId)
|
||||
{
|
||||
for (TContainer::iterator it = mSpells.begin(); it != mSpells.end(); ++it)
|
||||
|
|
|
@ -82,6 +82,9 @@ namespace MWMechanics
|
|||
/// Remove all active effects with this effect id
|
||||
void purgeEffect (short effectId);
|
||||
|
||||
/// Remove all active effects with this effect id and source id
|
||||
void purgeEffect (short effectId, const std::string& sourceId);
|
||||
|
||||
/// Remove all active effects, if roll succeeds (for each effect)
|
||||
void purgeAll (float chance);
|
||||
|
||||
|
|
28
apps/openmw/mwmechanics/actor.cpp
Normal file
28
apps/openmw/mwmechanics/actor.cpp
Normal file
|
@ -0,0 +1,28 @@
|
|||
#include "actor.hpp"
|
||||
|
||||
#include "character.hpp"
|
||||
|
||||
namespace MWMechanics
|
||||
{
|
||||
|
||||
Actor::Actor(const MWWorld::Ptr &ptr, MWRender::Animation *animation)
|
||||
{
|
||||
mCharacterController.reset(new CharacterController(ptr, animation));
|
||||
}
|
||||
|
||||
void Actor::updatePtr(const MWWorld::Ptr &newPtr)
|
||||
{
|
||||
mCharacterController->updatePtr(newPtr);
|
||||
}
|
||||
|
||||
CharacterController* Actor::getCharacterController()
|
||||
{
|
||||
return mCharacterController.get();
|
||||
}
|
||||
|
||||
AiState& Actor::getAiState()
|
||||
{
|
||||
return mAiState;
|
||||
}
|
||||
|
||||
}
|
42
apps/openmw/mwmechanics/actor.hpp
Normal file
42
apps/openmw/mwmechanics/actor.hpp
Normal file
|
@ -0,0 +1,42 @@
|
|||
#ifndef OPENMW_MECHANICS_ACTOR_H
|
||||
#define OPENMW_MECHANICS_ACTOR_H
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "aistate.hpp"
|
||||
|
||||
namespace MWRender
|
||||
{
|
||||
class Animation;
|
||||
}
|
||||
namespace MWWorld
|
||||
{
|
||||
class Ptr;
|
||||
}
|
||||
|
||||
namespace MWMechanics
|
||||
{
|
||||
class CharacterController;
|
||||
|
||||
/// @brief Holds temporary state for an actor that will be discarded when the actor leaves the scene.
|
||||
class Actor
|
||||
{
|
||||
public:
|
||||
Actor(const MWWorld::Ptr& ptr, MWRender::Animation* animation);
|
||||
|
||||
/// Notify this actor of its new base object Ptr, use when the object changed cells
|
||||
void updatePtr(const MWWorld::Ptr& newPtr);
|
||||
|
||||
CharacterController* getCharacterController();
|
||||
|
||||
AiState& getAiState();
|
||||
|
||||
private:
|
||||
std::auto_ptr<CharacterController> mCharacterController;
|
||||
|
||||
AiState mAiState;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -35,6 +35,9 @@
|
|||
#include "aifollow.hpp"
|
||||
#include "aipursue.hpp"
|
||||
|
||||
#include "actor.hpp"
|
||||
#include "summoning.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
|
@ -71,6 +74,8 @@ bool disintegrateSlot (MWWorld::Ptr ptr, int slot, float disintegrate)
|
|||
if (charge == 0)
|
||||
return false;
|
||||
|
||||
// FIXME: charge should be a float, not int so that damage < 1 per frame can be applied.
|
||||
// This was also a bug in the original engine.
|
||||
charge -=
|
||||
std::min(disintegrate,
|
||||
static_cast<float>(charge));
|
||||
|
@ -101,8 +106,8 @@ public:
|
|||
, mCommanded(false){}
|
||||
|
||||
virtual void visit (MWMechanics::EffectKey key,
|
||||
const std::string& sourceName, int casterActorId,
|
||||
float magnitude, float remainingTime = -1)
|
||||
const std::string& sourceName, const std::string& sourceId, int casterActorId,
|
||||
float magnitude, float remainingTime = -1, float totalTime = -1)
|
||||
{
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
if ( ((key.mId == ESM::MagicEffect::CommandHumanoid && mActor.getClass().isNpc())
|
||||
|
@ -161,30 +166,6 @@ void getRestorationPerHourOfSleep (const MWWorld::Ptr& ptr, float& health, float
|
|||
}
|
||||
}
|
||||
|
||||
void cleanupSummonedCreature (MWMechanics::CreatureStats& casterStats, int creatureActorId)
|
||||
{
|
||||
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaActorId(creatureActorId);
|
||||
if (!ptr.isEmpty())
|
||||
{
|
||||
// TODO: Show death animation before deleting? We shouldn't allow looting the corpse while the animation
|
||||
// plays though, which is a rather lame exploit in vanilla.
|
||||
MWBase::Environment::get().getWorld()->deleteObject(ptr);
|
||||
|
||||
const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>()
|
||||
.search("VFX_Summon_End");
|
||||
if (fx)
|
||||
MWBase::Environment::get().getWorld()->spawnEffect("meshes\\" + fx->mModel,
|
||||
"", Ogre::Vector3(ptr.getRefData().getPosition().pos));
|
||||
}
|
||||
else
|
||||
{
|
||||
// We didn't find the creature. It's probably in an inactive cell.
|
||||
// Add to graveyard so we can delete it when the cell becomes active.
|
||||
std::vector<int>& graveyard = casterStats.getSummonedCreatureGraveyard();
|
||||
graveyard.push_back(creatureActorId);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace MWMechanics
|
||||
|
@ -199,8 +180,8 @@ namespace MWMechanics
|
|||
: mCreature(trappedCreature) {}
|
||||
|
||||
virtual void visit (MWMechanics::EffectKey key,
|
||||
const std::string& sourceName, int casterActorId,
|
||||
float magnitude, float remainingTime = -1)
|
||||
const std::string& sourceName, const std::string& sourceId, int casterActorId,
|
||||
float magnitude, float remainingTime = -1, float totalTime = -1)
|
||||
{
|
||||
if (key.mId != ESM::MagicEffect::Soultrap)
|
||||
return;
|
||||
|
@ -293,6 +274,9 @@ namespace MWMechanics
|
|||
if (sqrDist > maxDistance*maxDistance)
|
||||
return;
|
||||
|
||||
if (targetActor.getClass().getCreatureStats(targetActor).isDead())
|
||||
return;
|
||||
|
||||
// stop tracking when target is behind the actor
|
||||
Ogre::Vector3 actorDirection (actor.getRefData().getBaseNode()->getOrientation().yAxis());
|
||||
Ogre::Vector3 targetDirection (Ogre::Vector3(actor2Pos.pos) - Ogre::Vector3(actor1Pos.pos));
|
||||
|
@ -517,6 +501,9 @@ namespace MWMechanics
|
|||
|
||||
bool wasDead = creatureStats.isDead();
|
||||
|
||||
// FIXME: effect ticks should go into separate functions so they can be used with either
|
||||
// magnitude (instant effect) or magnitude*duration
|
||||
|
||||
// attributes
|
||||
for(int i = 0;i < ESM::Attribute::Length;++i)
|
||||
{
|
||||
|
@ -726,6 +713,8 @@ namespace MWMechanics
|
|||
}
|
||||
|
||||
// Update bound effects
|
||||
// Note: in vanilla MW multiple bound items of the same type can be created by different spells.
|
||||
// As these extra copies are kinda useless this may or may not be important.
|
||||
static std::map<int, std::string> boundItemsMap;
|
||||
if (boundItemsMap.empty())
|
||||
{
|
||||
|
@ -770,131 +759,11 @@ namespace MWMechanics
|
|||
}
|
||||
}
|
||||
|
||||
// Update summon effects
|
||||
static std::map<int, std::string> summonMap;
|
||||
if (summonMap.empty())
|
||||
{
|
||||
summonMap[ESM::MagicEffect::SummonAncestralGhost] = "sMagicAncestralGhostID";
|
||||
summonMap[ESM::MagicEffect::SummonBonelord] = "sMagicBonelordID";
|
||||
summonMap[ESM::MagicEffect::SummonBonewalker] = "sMagicLeastBonewalkerID";
|
||||
summonMap[ESM::MagicEffect::SummonCenturionSphere] = "sMagicCenturionSphereID";
|
||||
summonMap[ESM::MagicEffect::SummonClannfear] = "sMagicClannfearID";
|
||||
summonMap[ESM::MagicEffect::SummonDaedroth] = "sMagicDaedrothID";
|
||||
summonMap[ESM::MagicEffect::SummonDremora] = "sMagicDremoraID";
|
||||
summonMap[ESM::MagicEffect::SummonFabricant] = "sMagicFabricantID";
|
||||
summonMap[ESM::MagicEffect::SummonFlameAtronach] = "sMagicFlameAtronachID";
|
||||
summonMap[ESM::MagicEffect::SummonFrostAtronach] = "sMagicFrostAtronachID";
|
||||
summonMap[ESM::MagicEffect::SummonGoldenSaint] = "sMagicGoldenSaintID";
|
||||
summonMap[ESM::MagicEffect::SummonGreaterBonewalker] = "sMagicGreaterBonewalkerID";
|
||||
summonMap[ESM::MagicEffect::SummonHunger] = "sMagicHungerID";
|
||||
summonMap[ESM::MagicEffect::SummonScamp] = "sMagicScampID";
|
||||
summonMap[ESM::MagicEffect::SummonSkeletalMinion] = "sMagicSkeletalMinionID";
|
||||
summonMap[ESM::MagicEffect::SummonStormAtronach] = "sMagicStormAtronachID";
|
||||
summonMap[ESM::MagicEffect::SummonWingedTwilight] = "sMagicWingedTwilightID";
|
||||
summonMap[ESM::MagicEffect::SummonWolf] = "sMagicCreature01ID";
|
||||
summonMap[ESM::MagicEffect::SummonBear] = "sMagicCreature02ID";
|
||||
summonMap[ESM::MagicEffect::SummonBonewolf] = "sMagicCreature03ID";
|
||||
summonMap[ESM::MagicEffect::SummonCreature04] = "sMagicCreature04ID";
|
||||
summonMap[ESM::MagicEffect::SummonCreature05] = "sMagicCreature05ID";
|
||||
}
|
||||
|
||||
std::map<int, int>& creatureMap = creatureStats.getSummonedCreatureMap();
|
||||
for (std::map<int, std::string>::iterator it = summonMap.begin(); it != summonMap.end(); ++it)
|
||||
{
|
||||
bool found = creatureMap.find(it->first) != creatureMap.end();
|
||||
int magnitude = creatureStats.getMagicEffects().get(it->first).getMagnitude();
|
||||
if (found != (magnitude > 0))
|
||||
{
|
||||
if (magnitude > 0)
|
||||
{
|
||||
ESM::Position ipos = ptr.getRefData().getPosition();
|
||||
Ogre::Vector3 pos(ipos.pos);
|
||||
Ogre::Quaternion rot(Ogre::Radian(-ipos.rot[2]), Ogre::Vector3::UNIT_Z);
|
||||
const float distance = 50;
|
||||
pos = pos + distance*rot.yAxis();
|
||||
ipos.pos[0] = pos.x;
|
||||
ipos.pos[1] = pos.y;
|
||||
ipos.pos[2] = pos.z;
|
||||
ipos.rot[0] = 0;
|
||||
ipos.rot[1] = 0;
|
||||
ipos.rot[2] = 0;
|
||||
|
||||
std::string creatureID =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(it->second)->getString();
|
||||
|
||||
if (!creatureID.empty())
|
||||
{
|
||||
MWWorld::CellStore* store = ptr.getCell();
|
||||
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), creatureID, 1);
|
||||
ref.getPtr().getCellRef().setPosition(ipos);
|
||||
|
||||
MWMechanics::CreatureStats& summonedCreatureStats = ref.getPtr().getClass().getCreatureStats(ref.getPtr());
|
||||
|
||||
// Make the summoned creature follow its master and help in fights
|
||||
AiFollow package(ptr.getCellRef().getRefId());
|
||||
summonedCreatureStats.getAiSequence().stack(package, ref.getPtr());
|
||||
int creatureActorId = summonedCreatureStats.getActorId();
|
||||
|
||||
MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,ipos);
|
||||
|
||||
MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(placed);
|
||||
if (anim)
|
||||
{
|
||||
const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>()
|
||||
.search("VFX_Summon_Start");
|
||||
if (fx)
|
||||
anim->addEffect("meshes\\" + fx->mModel, -1, false);
|
||||
}
|
||||
|
||||
creatureMap.insert(std::make_pair(it->first, creatureActorId));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Effect has ended
|
||||
std::map<int, int>::iterator foundCreature = creatureMap.find(it->first);
|
||||
cleanupSummonedCreature(creatureStats, foundCreature->second);
|
||||
creatureMap.erase(foundCreature);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (std::map<int, int>::iterator it = creatureMap.begin(); it != creatureMap.end(); )
|
||||
{
|
||||
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaActorId(it->second);
|
||||
if (!ptr.isEmpty() && ptr.getClass().getCreatureStats(ptr).isDead())
|
||||
{
|
||||
// Purge the magic effect so a new creature can be summoned if desired
|
||||
creatureStats.getActiveSpells().purgeEffect(it->first);
|
||||
UpdateSummonedCreatures updateSummonedCreatures(ptr);
|
||||
creatureStats.getActiveSpells().visitEffectSources(updateSummonedCreatures);
|
||||
if (ptr.getClass().hasInventoryStore(ptr))
|
||||
ptr.getClass().getInventoryStore(ptr).purgeEffect(it->first);
|
||||
|
||||
cleanupSummonedCreature(creatureStats, it->second);
|
||||
creatureMap.erase(it++);
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
|
||||
std::vector<int>& graveyard = creatureStats.getSummonedCreatureGraveyard();
|
||||
for (std::vector<int>::iterator it = graveyard.begin(); it != graveyard.end(); )
|
||||
{
|
||||
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaActorId(*it);
|
||||
if (!ptr.isEmpty())
|
||||
{
|
||||
it = graveyard.erase(it);
|
||||
|
||||
const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>()
|
||||
.search("VFX_Summon_End");
|
||||
if (fx)
|
||||
MWBase::Environment::get().getWorld()->spawnEffect("meshes\\" + fx->mModel,
|
||||
"", Ogre::Vector3(ptr.getRefData().getPosition().pos));
|
||||
|
||||
MWBase::Environment::get().getWorld()->deleteObject(ptr);
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
ptr.getClass().getInventoryStore(ptr).visitEffectSources(updateSummonedCreatures);
|
||||
updateSummonedCreatures.finish();
|
||||
}
|
||||
|
||||
void Actors::calculateNpcStatModifiers (const MWWorld::Ptr& ptr, float duration)
|
||||
|
@ -917,10 +786,10 @@ namespace MWMechanics
|
|||
|
||||
void Actors::updateDrowning(const MWWorld::Ptr& ptr, float duration)
|
||||
{
|
||||
PtrControllerMap::iterator it = mActors.find(ptr);
|
||||
PtrActorMap::iterator it = mActors.find(ptr);
|
||||
if (it == mActors.end())
|
||||
return;
|
||||
CharacterController* ctrl = it->second;
|
||||
CharacterController* ctrl = it->second->getCharacterController();
|
||||
|
||||
NpcStats &stats = ptr.getClass().getNpcStats(ptr);
|
||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
|
@ -1125,14 +994,14 @@ namespace MWMechanics
|
|||
removeActor(ptr);
|
||||
|
||||
MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr);
|
||||
mActors.insert(std::make_pair(ptr, new CharacterController(ptr, anim)));
|
||||
mActors.insert(std::make_pair(ptr, new Actor(ptr, anim)));
|
||||
if (updateImmediately)
|
||||
mActors[ptr]->update(0);
|
||||
mActors[ptr]->getCharacterController()->update(0);
|
||||
}
|
||||
|
||||
void Actors::removeActor (const MWWorld::Ptr& ptr)
|
||||
{
|
||||
PtrControllerMap::iterator iter = mActors.find(ptr);
|
||||
PtrActorMap::iterator iter = mActors.find(ptr);
|
||||
if(iter != mActors.end())
|
||||
{
|
||||
delete iter->second;
|
||||
|
@ -1142,20 +1011,20 @@ namespace MWMechanics
|
|||
|
||||
void Actors::updateActor(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr)
|
||||
{
|
||||
PtrControllerMap::iterator iter = mActors.find(old);
|
||||
PtrActorMap::iterator iter = mActors.find(old);
|
||||
if(iter != mActors.end())
|
||||
{
|
||||
CharacterController *ctrl = iter->second;
|
||||
Actor *actor = iter->second;
|
||||
mActors.erase(iter);
|
||||
|
||||
ctrl->updatePtr(ptr);
|
||||
mActors.insert(std::make_pair(ptr, ctrl));
|
||||
actor->updatePtr(ptr);
|
||||
mActors.insert(std::make_pair(ptr, actor));
|
||||
}
|
||||
}
|
||||
|
||||
void Actors::dropActors (const MWWorld::CellStore *cellStore, const MWWorld::Ptr& ignore)
|
||||
{
|
||||
PtrControllerMap::iterator iter = mActors.begin();
|
||||
PtrActorMap::iterator iter = mActors.begin();
|
||||
while(iter != mActors.end())
|
||||
{
|
||||
if(iter->first.getCell()==cellStore && iter->first != ignore)
|
||||
|
@ -1189,8 +1058,10 @@ namespace MWMechanics
|
|||
// using higher values will make a quest in Bloodmoon harder or impossible to complete (bug #1876)
|
||||
const float sqrProcessingDistance = 7168*7168;
|
||||
|
||||
/// \todo move update logic to Actor class where appropriate
|
||||
|
||||
// AI and magic effects update
|
||||
for(PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
||||
for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
||||
{
|
||||
if (!iter->first.getClass().getCreatureStats(iter->first).isDead())
|
||||
{
|
||||
|
@ -1204,7 +1075,7 @@ namespace MWMechanics
|
|||
if (iter->first != player)
|
||||
adjustCommandedActor(iter->first);
|
||||
|
||||
for(PtrControllerMap::iterator it(mActors.begin()); it != mActors.end(); ++it)
|
||||
for(PtrActorMap::iterator it(mActors.begin()); it != mActors.end(); ++it)
|
||||
{
|
||||
if (it->first == iter->first || iter->first == player) // player is not AI-controlled
|
||||
continue;
|
||||
|
@ -1216,13 +1087,13 @@ namespace MWMechanics
|
|||
float sqrHeadTrackDistance = std::numeric_limits<float>::max();
|
||||
MWWorld::Ptr headTrackTarget;
|
||||
|
||||
for(PtrControllerMap::iterator it(mActors.begin()); it != mActors.end(); ++it)
|
||||
for(PtrActorMap::iterator it(mActors.begin()); it != mActors.end(); ++it)
|
||||
{
|
||||
if (it->first == iter->first)
|
||||
continue;
|
||||
updateHeadTracking(iter->first, it->first, headTrackTarget, sqrHeadTrackDistance);
|
||||
}
|
||||
iter->second->setHeadTrackTarget(headTrackTarget);
|
||||
iter->second->getCharacterController()->setHeadTrackTarget(headTrackTarget);
|
||||
}
|
||||
|
||||
if (iter->first.getClass().isNpc() && iter->first != player)
|
||||
|
@ -1251,12 +1122,12 @@ namespace MWMechanics
|
|||
// Reaching the text keys may trigger Hit / Spellcast (and as such, particles),
|
||||
// so updating VFX immediately after that would just remove the particle effects instantly.
|
||||
// There needs to be a magic effect update in between.
|
||||
for(PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
||||
iter->second->updateContinuousVfx();
|
||||
for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
||||
iter->second->getCharacterController()->updateContinuousVfx();
|
||||
|
||||
// Animation/movement update
|
||||
CharacterController* playerCharacter = NULL;
|
||||
for(PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
||||
for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
||||
{
|
||||
if (iter->first != player &&
|
||||
Ogre::Vector3(player.getRefData().getPosition().pos).squaredDistance(Ogre::Vector3(iter->first.getRefData().getPosition().pos))
|
||||
|
@ -1265,22 +1136,22 @@ namespace MWMechanics
|
|||
|
||||
if (iter->first.getClass().getCreatureStats(iter->first).getMagicEffects().get(
|
||||
ESM::MagicEffect::Paralyze).getMagnitude() > 0)
|
||||
iter->second->skipAnim();
|
||||
iter->second->getCharacterController()->skipAnim();
|
||||
|
||||
// Handle player last, in case a cell transition occurs by casting a teleportation spell
|
||||
// (would invalidate the iterator)
|
||||
if (iter->first.getCellRef().getRefId() == "player")
|
||||
{
|
||||
playerCharacter = iter->second;
|
||||
playerCharacter = iter->second->getCharacterController();
|
||||
continue;
|
||||
}
|
||||
iter->second->update(duration);
|
||||
iter->second->getCharacterController()->update(duration);
|
||||
}
|
||||
|
||||
if (playerCharacter)
|
||||
playerCharacter->update(duration);
|
||||
|
||||
for(PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
||||
for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
||||
{
|
||||
const MWWorld::Class &cls = iter->first.getClass();
|
||||
CreatureStats &stats = cls.getCreatureStats(iter->first);
|
||||
|
@ -1338,7 +1209,7 @@ namespace MWMechanics
|
|||
|
||||
bool detected = false;
|
||||
|
||||
for (PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
||||
for (PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
||||
{
|
||||
if (iter->first == player) // not the player
|
||||
continue;
|
||||
|
@ -1381,32 +1252,32 @@ namespace MWMechanics
|
|||
|
||||
void Actors::killDeadActors()
|
||||
{
|
||||
for(PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
||||
for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
||||
{
|
||||
const MWWorld::Class &cls = iter->first.getClass();
|
||||
CreatureStats &stats = cls.getCreatureStats(iter->first);
|
||||
|
||||
if(!stats.isDead())
|
||||
{
|
||||
if(iter->second->isDead())
|
||||
if(iter->second->getCharacterController()->isDead())
|
||||
{
|
||||
// Actor has been resurrected. Notify the CharacterController and re-enable collision.
|
||||
MWBase::Environment::get().getWorld()->enableActorCollision(iter->first, true);
|
||||
iter->second->resurrect();
|
||||
iter->second->getCharacterController()->resurrect();
|
||||
}
|
||||
|
||||
if(!stats.isDead())
|
||||
continue;
|
||||
}
|
||||
|
||||
if (iter->second->kill())
|
||||
if (iter->second->getCharacterController()->kill())
|
||||
{
|
||||
iter->first.getClass().getCreatureStats(iter->first).notifyDied();
|
||||
|
||||
++mDeathCount[Misc::StringUtils::lowerCase(iter->first.getCellRef().getRefId())];
|
||||
|
||||
// Make sure spell effects with CasterLinked flag are removed
|
||||
for (PtrControllerMap::iterator iter2(mActors.begin());iter2 != mActors.end();++iter2)
|
||||
for (PtrActorMap::iterator iter2(mActors.begin());iter2 != mActors.end();++iter2)
|
||||
{
|
||||
MWMechanics::ActiveSpells& spells = iter2->first.getClass().getCreatureStats(iter2->first).getActiveSpells();
|
||||
spells.purge(stats.getActorId());
|
||||
|
@ -1435,7 +1306,7 @@ namespace MWMechanics
|
|||
|
||||
void Actors::restoreDynamicStats(bool sleep)
|
||||
{
|
||||
for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
|
||||
for(PtrActorMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
|
||||
restoreDynamicStats(iter->first, sleep);
|
||||
}
|
||||
|
||||
|
@ -1467,35 +1338,35 @@ namespace MWMechanics
|
|||
|
||||
void Actors::forceStateUpdate(const MWWorld::Ptr & ptr)
|
||||
{
|
||||
PtrControllerMap::iterator iter = mActors.find(ptr);
|
||||
PtrActorMap::iterator iter = mActors.find(ptr);
|
||||
if(iter != mActors.end())
|
||||
iter->second->forceStateUpdate();
|
||||
iter->second->getCharacterController()->forceStateUpdate();
|
||||
}
|
||||
|
||||
void Actors::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number)
|
||||
{
|
||||
PtrControllerMap::iterator iter = mActors.find(ptr);
|
||||
PtrActorMap::iterator iter = mActors.find(ptr);
|
||||
if(iter != mActors.end())
|
||||
iter->second->playGroup(groupName, mode, number);
|
||||
iter->second->getCharacterController()->playGroup(groupName, mode, number);
|
||||
}
|
||||
void Actors::skipAnimation(const MWWorld::Ptr& ptr)
|
||||
{
|
||||
PtrControllerMap::iterator iter = mActors.find(ptr);
|
||||
PtrActorMap::iterator iter = mActors.find(ptr);
|
||||
if(iter != mActors.end())
|
||||
iter->second->skipAnim();
|
||||
iter->second->getCharacterController()->skipAnim();
|
||||
}
|
||||
|
||||
bool Actors::checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName)
|
||||
{
|
||||
PtrControllerMap::iterator iter = mActors.find(ptr);
|
||||
PtrActorMap::iterator iter = mActors.find(ptr);
|
||||
if(iter != mActors.end())
|
||||
return iter->second->isAnimPlaying(groupName);
|
||||
return iter->second->getCharacterController()->isAnimPlaying(groupName);
|
||||
return false;
|
||||
}
|
||||
|
||||
void Actors::getObjectsInRange(const Ogre::Vector3& position, float radius, std::vector<MWWorld::Ptr>& out)
|
||||
{
|
||||
for (PtrControllerMap::iterator iter = mActors.begin(); iter != mActors.end(); ++iter)
|
||||
for (PtrActorMap::iterator iter = mActors.begin(); iter != mActors.end(); ++iter)
|
||||
{
|
||||
if (Ogre::Vector3(iter->first.getRefData().getPosition().pos).squaredDistance(position) <= radius*radius)
|
||||
out.push_back(iter->first);
|
||||
|
@ -1505,7 +1376,7 @@ namespace MWMechanics
|
|||
std::list<MWWorld::Ptr> Actors::getActorsFollowing(const MWWorld::Ptr& actor)
|
||||
{
|
||||
std::list<MWWorld::Ptr> list;
|
||||
for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
|
||||
for(PtrActorMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
|
||||
{
|
||||
const MWWorld::Class &cls = iter->first.getClass();
|
||||
CreatureStats &stats = cls.getCreatureStats(iter->first);
|
||||
|
@ -1535,7 +1406,7 @@ namespace MWMechanics
|
|||
std::list<int> Actors::getActorsFollowingIndices(const MWWorld::Ptr &actor)
|
||||
{
|
||||
std::list<int> list;
|
||||
for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
|
||||
for(PtrActorMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
|
||||
{
|
||||
const MWWorld::Class &cls = iter->first.getClass();
|
||||
CreatureStats &stats = cls.getCreatureStats(iter->first);
|
||||
|
@ -1608,7 +1479,7 @@ namespace MWMechanics
|
|||
|
||||
void Actors::clear()
|
||||
{
|
||||
PtrControllerMap::iterator it(mActors.begin());
|
||||
PtrActorMap::iterator it(mActors.begin());
|
||||
for (; it != mActors.end(); ++it)
|
||||
{
|
||||
delete it->second;
|
||||
|
@ -1628,10 +1499,27 @@ namespace MWMechanics
|
|||
|
||||
bool Actors::isReadyToBlock(const MWWorld::Ptr &ptr) const
|
||||
{
|
||||
PtrControllerMap::const_iterator it = mActors.find(ptr);
|
||||
PtrActorMap::const_iterator it = mActors.find(ptr);
|
||||
if (it == mActors.end())
|
||||
return false;
|
||||
|
||||
return it->second->isReadyToBlock();
|
||||
return it->second->getCharacterController()->isReadyToBlock();
|
||||
}
|
||||
|
||||
void Actors::fastForwardAi()
|
||||
{
|
||||
if (!MWBase::Environment::get().getMechanicsManager()->isAIActive())
|
||||
return;
|
||||
|
||||
// making a copy since fast-forward could move actor to a different cell and invalidate the mActors iterator
|
||||
PtrActorMap map = mActors;
|
||||
for (PtrActorMap::iterator it = map.begin(); it != map.end(); ++it)
|
||||
{
|
||||
MWWorld::Ptr ptr = it->first;
|
||||
if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr())
|
||||
continue;
|
||||
MWMechanics::AiSequence& seq = ptr.getClass().getCreatureStats(ptr).getAiSequence();
|
||||
seq.fastForward(ptr, it->second->getAiState());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "character.hpp"
|
||||
#include "movement.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
||||
|
@ -23,6 +22,8 @@ namespace MWWorld
|
|||
|
||||
namespace MWMechanics
|
||||
{
|
||||
class Actor;
|
||||
|
||||
class Actors
|
||||
{
|
||||
std::map<std::string, int> mDeathCount;
|
||||
|
@ -51,10 +52,10 @@ namespace MWMechanics
|
|||
Actors();
|
||||
~Actors();
|
||||
|
||||
typedef std::map<MWWorld::Ptr,CharacterController*> PtrControllerMap;
|
||||
typedef std::map<MWWorld::Ptr,Actor*> PtrActorMap;
|
||||
|
||||
PtrControllerMap::const_iterator begin() { return mActors.begin(); }
|
||||
PtrControllerMap::const_iterator end() { return mActors.end(); }
|
||||
PtrActorMap::const_iterator begin() { return mActors.begin(); }
|
||||
PtrActorMap::const_iterator end() { return mActors.end(); }
|
||||
|
||||
/// Update magic effects for an actor. Usually done automatically once per frame, but if we're currently
|
||||
/// paused we may want to do it manually (after equipping permanent enchantment)
|
||||
|
@ -100,6 +101,9 @@ namespace MWMechanics
|
|||
int getHoursToRest(const MWWorld::Ptr& ptr) const;
|
||||
///< Calculate how many hours the given actor needs to rest in order to be fully healed
|
||||
|
||||
void fastForwardAi();
|
||||
///< Simulate the passing of time
|
||||
|
||||
int countDeaths (const std::string& id) const;
|
||||
///< Return the number of deaths for actors with the given ID.
|
||||
|
||||
|
@ -131,7 +135,7 @@ namespace MWMechanics
|
|||
bool isReadyToBlock(const MWWorld::Ptr& ptr) const;
|
||||
|
||||
private:
|
||||
PtrControllerMap mActors;
|
||||
PtrActorMap mActors;
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
@ -300,6 +300,14 @@ namespace MWMechanics
|
|||
|
||||
//Update with period = tReaction
|
||||
|
||||
// Stop attacking if target is not seen
|
||||
if (target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::Invisibility).getMagnitude() > 0
|
||||
|| target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::Chameleon).getMagnitude() > 75)
|
||||
{
|
||||
movement.mPosition[1] = movement.mPosition[0] = 0;
|
||||
return false; // TODO: run away instead of doing nothing
|
||||
}
|
||||
|
||||
timerReact = 0;
|
||||
const MWWorld::CellStore*& currentCell = storage.mCell;
|
||||
bool cellChange = currentCell && (actor.getCell() != currentCell);
|
||||
|
@ -326,10 +334,6 @@ namespace MWMechanics
|
|||
actionCooldown = currentAction->getActionCooldown();
|
||||
}
|
||||
|
||||
// Stop attacking if target is not seen
|
||||
if (!MWBase::Environment::get().getMechanicsManager()->awarenessCheck(target, actor))
|
||||
return true;
|
||||
|
||||
if (currentAction.get())
|
||||
currentAction->getCombatRange(rangeAttack, rangeFollow);
|
||||
|
||||
|
@ -576,7 +580,7 @@ namespace MWMechanics
|
|||
buildNewPath(actor, target); //may fail to build a path, check before use
|
||||
|
||||
//delete visited path node
|
||||
mPathFinder.checkWaypoint(pos.pos[0],pos.pos[1],pos.pos[2]);
|
||||
mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2]);
|
||||
|
||||
// This works on the borders between the path grid and areas with no waypoints.
|
||||
if(inLOS && mPathFinder.getPath().size() > 1)
|
||||
|
|
|
@ -294,7 +294,10 @@ namespace MWMechanics
|
|||
// Effect doesn't heal more than we need, *or* we are below 1/2 health
|
||||
if (current.getModified() - current.getCurrent() > toHeal
|
||||
|| current.getCurrent() < current.getModified()*0.5)
|
||||
return 10000.f * priority;
|
||||
{
|
||||
return 10000.f * priority
|
||||
- (toHeal - (current.getModified()-current.getCurrent())); // prefer the most fitting potion
|
||||
}
|
||||
else
|
||||
return -10000.f * priority; // Save for later
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
#include "pathfinding.hpp"
|
||||
#include <components/esm/defs.hpp>
|
||||
#include "../mwbase/world.hpp"
|
||||
|
||||
#include "obstacle.hpp"
|
||||
#include "aistate.hpp"
|
||||
|
@ -64,6 +63,9 @@ namespace MWMechanics
|
|||
|
||||
virtual void writeState (ESM::AiSequence::AiSequence& sequence) const {}
|
||||
|
||||
/// Simulates the passing of time
|
||||
virtual void fastForward(const MWWorld::Ptr& actor, AiState& state) {}
|
||||
|
||||
protected:
|
||||
/// Causes the actor to attempt to walk to the specified location
|
||||
/** \return If the actor has arrived at his destination **/
|
||||
|
|
|
@ -43,6 +43,10 @@ bool AiPursue::execute (const MWWorld::Ptr& actor, AiState& state, float duratio
|
|||
)
|
||||
return true; //Target doesn't exist
|
||||
|
||||
if (target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::Invisibility).getMagnitude() > 0
|
||||
|| target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::Chameleon).getMagnitude() > 75)
|
||||
return true;
|
||||
|
||||
if(target.getClass().getCreatureStats(target).isDead())
|
||||
return true;
|
||||
|
||||
|
|
|
@ -125,19 +125,23 @@ bool AiSequence::isInCombat(const MWWorld::Ptr &actor) const
|
|||
|
||||
void AiSequence::stopCombat()
|
||||
{
|
||||
while (getTypeId() == AiPackage::TypeIdCombat)
|
||||
for(std::list<AiPackage*>::iterator it = mPackages.begin(); it != mPackages.end(); )
|
||||
{
|
||||
delete *mPackages.begin();
|
||||
mPackages.erase (mPackages.begin());
|
||||
if ((*it)->getTypeId() == AiPackage::TypeIdCombat)
|
||||
it = mPackages.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
void AiSequence::stopPursuit()
|
||||
{
|
||||
while (getTypeId() == AiPackage::TypeIdPursue)
|
||||
for(std::list<AiPackage*>::iterator it = mPackages.begin(); it != mPackages.end(); )
|
||||
{
|
||||
delete *mPackages.begin();
|
||||
mPackages.erase (mPackages.begin());
|
||||
if ((*it)->getTypeId() == AiPackage::TypeIdPursue)
|
||||
it = mPackages.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -390,4 +394,13 @@ void AiSequence::readState(const ESM::AiSequence::AiSequence &sequence)
|
|||
}
|
||||
}
|
||||
|
||||
void AiSequence::fastForward(const MWWorld::Ptr& actor, AiState& state)
|
||||
{
|
||||
if (!mPackages.empty())
|
||||
{
|
||||
MWMechanics::AiPackage* package = mPackages.front();
|
||||
package->fastForward(actor, state);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace MWMechanics
|
||||
|
|
|
@ -97,6 +97,9 @@ namespace MWMechanics
|
|||
/// Execute current package, switching if needed.
|
||||
void execute (const MWWorld::Ptr& actor, MWMechanics::AiState& state, float duration);
|
||||
|
||||
/// Simulate the passing of time using the currently active AI package
|
||||
void fastForward(const MWWorld::Ptr &actor, AiState &state);
|
||||
|
||||
/// Remove all packages.
|
||||
void clear();
|
||||
|
||||
|
|
|
@ -76,24 +76,6 @@ namespace MWMechanics
|
|||
mStorage = p;
|
||||
}
|
||||
|
||||
/// \brief gives away ownership of object. Throws exception if storage does not contain Derived or is empty.
|
||||
template< class Derived >
|
||||
Derived* moveOut()
|
||||
{
|
||||
assert_derived<Derived>();
|
||||
|
||||
|
||||
if(!mStorage)
|
||||
throw std::runtime_error("Cant move out: empty storage.");
|
||||
|
||||
Derived* result = dynamic_cast<Derived*>(mStorage);
|
||||
|
||||
if(!mStorage)
|
||||
throw std::runtime_error("Cant move out: wrong type requested.");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return mStorage == NULL;
|
||||
|
@ -120,7 +102,7 @@ namespace MWMechanics
|
|||
/// \brief base class for the temporary storage of AiPackages.
|
||||
/**
|
||||
* Each AI package with temporary values needs a AiPackageStorage class
|
||||
* which is derived from AiTemporaryBase. The CharacterController holds a container
|
||||
* which is derived from AiTemporaryBase. The Actor holds a container
|
||||
* AiState where one of these storages can be stored at a time.
|
||||
* The execute(...) member function takes this container as an argument.
|
||||
* */
|
||||
|
|
|
@ -14,6 +14,19 @@
|
|||
#include "movement.hpp"
|
||||
#include "creaturestats.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
bool isWithinMaxRange(const Ogre::Vector3& pos1, const Ogre::Vector3& pos2)
|
||||
{
|
||||
// Maximum travel distance for vanilla compatibility.
|
||||
// Was likely meant to prevent NPCs walking into non-loaded exterior cells, but for some reason is used in interior cells as well.
|
||||
// We can make this configurable at some point, but the default *must* be the below value. Anything else will break shoddily-written content (*cough* MW *cough*) in bizarre ways.
|
||||
return (pos1.squaredDistance(pos2) <= 7168*7168);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace MWMechanics
|
||||
{
|
||||
AiTravel::AiTravel(float x, float y, float z)
|
||||
|
@ -71,10 +84,7 @@ namespace MWMechanics
|
|||
}
|
||||
}
|
||||
|
||||
// Maximum travel distance for vanilla compatibility.
|
||||
// Was likely meant to prevent NPCs walking into non-loaded exterior cells, but for some reason is used in interior cells as well.
|
||||
// We can make this configurable at some point, but the default *must* be the below value. Anything else will break shoddily-written content (*cough* MW *cough*) in bizarre ways.
|
||||
if (Ogre::Vector3(mX, mY, mZ).squaredDistance(Ogre::Vector3(pos.pos)) > 7168*7168)
|
||||
if (!isWithinMaxRange(Ogre::Vector3(mX, mY, mZ), Ogre::Vector3(pos.pos)))
|
||||
return false;
|
||||
|
||||
bool cellChange = cell->mData.mX != mCellX || cell->mData.mY != mCellY;
|
||||
|
@ -113,6 +123,16 @@ namespace MWMechanics
|
|||
return TypeIdTravel;
|
||||
}
|
||||
|
||||
void AiTravel::fastForward(const MWWorld::Ptr& actor, AiState& state)
|
||||
{
|
||||
if (!isWithinMaxRange(Ogre::Vector3(mX, mY, mZ), Ogre::Vector3(actor.getRefData().getPosition().pos)))
|
||||
return;
|
||||
// does not do any validation on the travel target (whether it's in air, inside collision geometry, etc),
|
||||
// that is the user's responsibility
|
||||
MWBase::Environment::get().getWorld()->moveObject(actor, mX, mY, mZ);
|
||||
actor.getClass().adjustPosition(actor, false);
|
||||
}
|
||||
|
||||
void AiTravel::writeState(ESM::AiSequence::AiSequence &sequence) const
|
||||
{
|
||||
std::auto_ptr<ESM::AiSequence::AiTravel> travel(new ESM::AiSequence::AiTravel());
|
||||
|
|
|
@ -23,6 +23,9 @@ namespace MWMechanics
|
|||
AiTravel(float x, float y, float z);
|
||||
AiTravel(const ESM::AiSequence::AiTravel* travel);
|
||||
|
||||
/// Simulates the passing of time
|
||||
virtual void fastForward(const MWWorld::Ptr& actor, AiState& state);
|
||||
|
||||
void writeState(ESM::AiSequence::AiSequence &sequence) const;
|
||||
|
||||
virtual AiTravel *clone() const;
|
||||
|
|
|
@ -41,13 +41,6 @@ namespace MWMechanics
|
|||
AiWander::GreetingState mSaidGreeting;
|
||||
int mGreetingTimer;
|
||||
|
||||
// Cached current cell location
|
||||
int mCellX;
|
||||
int mCellY;
|
||||
// Cell location multiplied by ESM::Land::REAL_SIZE
|
||||
float mXCell;
|
||||
float mYCell;
|
||||
|
||||
const MWWorld::CellStore* mCell; // for detecting cell change
|
||||
|
||||
// AiWander states
|
||||
|
@ -66,10 +59,6 @@ namespace MWMechanics
|
|||
mReaction(0),
|
||||
mSaidGreeting(AiWander::Greet_None),
|
||||
mGreetingTimer(0),
|
||||
mCellX(std::numeric_limits<int>::max()),
|
||||
mCellY(std::numeric_limits<int>::max()),
|
||||
mXCell(0),
|
||||
mYCell(0),
|
||||
mCell(NULL),
|
||||
mChooseAction(true),
|
||||
mIdleNow(false),
|
||||
|
@ -81,6 +70,7 @@ namespace MWMechanics
|
|||
|
||||
AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector<unsigned char>& idle, bool repeat):
|
||||
mDistance(distance), mDuration(duration), mTimeOfDay(timeOfDay), mIdle(idle), mRepeat(repeat)
|
||||
, mStoredInitialActorPosition(false)
|
||||
{
|
||||
mIdle.resize(8, 0);
|
||||
init();
|
||||
|
@ -183,7 +173,6 @@ namespace MWMechanics
|
|||
currentCell = actor.getCell();
|
||||
mStoredAvailableNodes = false; // prob. not needed since mDistance = 0
|
||||
}
|
||||
const ESM::Cell *cell = currentCell->getCell();
|
||||
|
||||
cStats.setDrawState(DrawState_Nothing);
|
||||
cStats.setMovementFlag(CreatureStats::Flag_Run, false);
|
||||
|
@ -213,7 +202,7 @@ namespace MWMechanics
|
|||
// Are we there yet?
|
||||
bool& chooseAction = storage.mChooseAction;
|
||||
if(walking &&
|
||||
storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2]))
|
||||
storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2], 64.f))
|
||||
{
|
||||
stopWalking(actor, storage);
|
||||
moveNow = false;
|
||||
|
@ -371,81 +360,10 @@ namespace MWMechanics
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int& cachedCellX = storage.mCellX;
|
||||
int& cachedCellY = storage.mCellY;
|
||||
float& cachedCellXposition = storage.mXCell;
|
||||
float& cachedCellYposition = storage.mYCell;
|
||||
// Initialization to discover & store allowed node points for this actor.
|
||||
if(!mStoredAvailableNodes)
|
||||
{
|
||||
// infrequently used, therefore no benefit in caching it as a member
|
||||
const ESM::Pathgrid *
|
||||
pathgrid = world->getStore().get<ESM::Pathgrid>().search(*cell);
|
||||
|
||||
// cache the current cell location
|
||||
cachedCellX = cell->mData.mX;
|
||||
cachedCellY = cell->mData.mY;
|
||||
|
||||
// If there is no path this actor doesn't go anywhere. See:
|
||||
// https://forum.openmw.org/viewtopic.php?t=1556
|
||||
// http://www.fliggerty.com/phpBB3/viewtopic.php?f=30&t=5833
|
||||
if(!pathgrid || pathgrid->mPoints.empty())
|
||||
mDistance = 0;
|
||||
|
||||
// A distance value passed into the constructor indicates how far the
|
||||
// actor can wander from the spawn position. AiWander assumes that
|
||||
// pathgrid points are available, and uses them to randomly select wander
|
||||
// destinations within the allowed set of pathgrid points (nodes).
|
||||
if(mDistance)
|
||||
{
|
||||
cachedCellXposition = 0;
|
||||
cachedCellYposition = 0;
|
||||
if(cell->isExterior())
|
||||
{
|
||||
cachedCellXposition = cachedCellX * ESM::Land::REAL_SIZE;
|
||||
cachedCellYposition = cachedCellY * ESM::Land::REAL_SIZE;
|
||||
}
|
||||
|
||||
// FIXME: There might be a bug here. The allowed node points are
|
||||
// based on the actor's current position rather than the actor's
|
||||
// spawn point. As a result the allowed nodes for wander can change
|
||||
// between saves, for example.
|
||||
//
|
||||
// convert npcPos to local (i.e. cell) co-ordinates
|
||||
Ogre::Vector3 npcPos(pos.pos);
|
||||
npcPos[0] = npcPos[0] - cachedCellXposition;
|
||||
npcPos[1] = npcPos[1] - cachedCellYposition;
|
||||
|
||||
// mAllowedNodes for this actor with pathgrid point indexes based on mDistance
|
||||
// NOTE: mPoints and mAllowedNodes are in local co-ordinates
|
||||
for(unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++)
|
||||
{
|
||||
Ogre::Vector3 nodePos(pathgrid->mPoints[counter].mX, pathgrid->mPoints[counter].mY,
|
||||
pathgrid->mPoints[counter].mZ);
|
||||
if(npcPos.squaredDistance(nodePos) <= mDistance * mDistance)
|
||||
mAllowedNodes.push_back(pathgrid->mPoints[counter]);
|
||||
}
|
||||
if(!mAllowedNodes.empty())
|
||||
{
|
||||
Ogre::Vector3 firstNodePos(mAllowedNodes[0].mX, mAllowedNodes[0].mY, mAllowedNodes[0].mZ);
|
||||
float closestNode = npcPos.squaredDistance(firstNodePos);
|
||||
unsigned int index = 0;
|
||||
for(unsigned int counterThree = 1; counterThree < mAllowedNodes.size(); counterThree++)
|
||||
{
|
||||
Ogre::Vector3 nodePos(mAllowedNodes[counterThree].mX, mAllowedNodes[counterThree].mY,
|
||||
mAllowedNodes[counterThree].mZ);
|
||||
float tempDist = npcPos.squaredDistance(nodePos);
|
||||
if(tempDist < closestNode)
|
||||
index = counterThree;
|
||||
}
|
||||
mCurrentNode = mAllowedNodes[index];
|
||||
mAllowedNodes.erase(mAllowedNodes.begin() + index);
|
||||
|
||||
mStoredAvailableNodes = true; // set only if successful in finding allowed nodes
|
||||
}
|
||||
}
|
||||
getAllowedNodes(actor, currentCell->getCell());
|
||||
}
|
||||
|
||||
// Actor becomes stationary - see above URL's for previous research
|
||||
|
@ -581,9 +499,14 @@ namespace MWMechanics
|
|||
|
||||
// convert dest to use world co-ordinates
|
||||
ESM::Pathgrid::Point dest;
|
||||
dest.mX = destNodePos[0] + cachedCellXposition;
|
||||
dest.mY = destNodePos[1] + cachedCellYposition;
|
||||
dest.mX = destNodePos[0];
|
||||
dest.mY = destNodePos[1];
|
||||
dest.mZ = destNodePos[2];
|
||||
if (currentCell->getCell()->isExterior())
|
||||
{
|
||||
dest.mX += currentCell->getCell()->mData.mX * ESM::Land::REAL_SIZE;
|
||||
dest.mY += currentCell->getCell()->mData.mY * ESM::Land::REAL_SIZE;
|
||||
}
|
||||
|
||||
// actor position is already in world co-ordinates
|
||||
ESM::Pathgrid::Point start;
|
||||
|
@ -732,6 +655,103 @@ namespace MWMechanics
|
|||
}
|
||||
}
|
||||
|
||||
void AiWander::fastForward(const MWWorld::Ptr& actor, AiState &state)
|
||||
{
|
||||
if (mDistance == 0)
|
||||
return;
|
||||
|
||||
if (!mStoredAvailableNodes)
|
||||
getAllowedNodes(actor, actor.getCell()->getCell());
|
||||
|
||||
if (mAllowedNodes.empty())
|
||||
return;
|
||||
|
||||
state.moveIn(new AiWanderStorage());
|
||||
|
||||
int index = std::rand() / (static_cast<double> (RAND_MAX) + 1) * mAllowedNodes.size();
|
||||
ESM::Pathgrid::Point dest = mAllowedNodes[index];
|
||||
|
||||
// apply a slight offset to prevent overcrowding
|
||||
dest.mX += Ogre::Math::RangeRandom(-64, 64);
|
||||
dest.mY += Ogre::Math::RangeRandom(-64, 64);
|
||||
|
||||
if (actor.getCell()->isExterior())
|
||||
{
|
||||
dest.mX += actor.getCell()->getCell()->mData.mX * ESM::Land::REAL_SIZE;
|
||||
dest.mY += actor.getCell()->getCell()->mData.mY * ESM::Land::REAL_SIZE;
|
||||
}
|
||||
|
||||
MWBase::Environment::get().getWorld()->moveObject(actor, dest.mX, dest.mY, dest.mZ);
|
||||
actor.getClass().adjustPosition(actor, false);
|
||||
}
|
||||
|
||||
void AiWander::getAllowedNodes(const MWWorld::Ptr& actor, const ESM::Cell* cell)
|
||||
{
|
||||
if (!mStoredInitialActorPosition)
|
||||
{
|
||||
mInitialActorPosition = Ogre::Vector3(actor.getRefData().getPosition().pos);
|
||||
mStoredInitialActorPosition = true;
|
||||
}
|
||||
|
||||
// infrequently used, therefore no benefit in caching it as a member
|
||||
const ESM::Pathgrid *
|
||||
pathgrid = MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*cell);
|
||||
|
||||
// If there is no path this actor doesn't go anywhere. See:
|
||||
// https://forum.openmw.org/viewtopic.php?t=1556
|
||||
// http://www.fliggerty.com/phpBB3/viewtopic.php?f=30&t=5833
|
||||
if(!pathgrid || pathgrid->mPoints.empty())
|
||||
mDistance = 0;
|
||||
|
||||
// A distance value passed into the constructor indicates how far the
|
||||
// actor can wander from the spawn position. AiWander assumes that
|
||||
// pathgrid points are available, and uses them to randomly select wander
|
||||
// destinations within the allowed set of pathgrid points (nodes).
|
||||
if(mDistance)
|
||||
{
|
||||
float cellXOffset = 0;
|
||||
float cellYOffset = 0;
|
||||
if(cell->isExterior())
|
||||
{
|
||||
cellXOffset = cell->mData.mX * ESM::Land::REAL_SIZE;
|
||||
cellYOffset = cell->mData.mY * ESM::Land::REAL_SIZE;
|
||||
}
|
||||
|
||||
// convert npcPos to local (i.e. cell) co-ordinates
|
||||
Ogre::Vector3 npcPos(mInitialActorPosition);
|
||||
npcPos[0] = npcPos[0] - cellXOffset;
|
||||
npcPos[1] = npcPos[1] - cellYOffset;
|
||||
|
||||
// mAllowedNodes for this actor with pathgrid point indexes based on mDistance
|
||||
// NOTE: mPoints and mAllowedNodes are in local co-ordinates
|
||||
for(unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++)
|
||||
{
|
||||
Ogre::Vector3 nodePos(pathgrid->mPoints[counter].mX, pathgrid->mPoints[counter].mY,
|
||||
pathgrid->mPoints[counter].mZ);
|
||||
if(npcPos.squaredDistance(nodePos) <= mDistance * mDistance)
|
||||
mAllowedNodes.push_back(pathgrid->mPoints[counter]);
|
||||
}
|
||||
if(!mAllowedNodes.empty())
|
||||
{
|
||||
Ogre::Vector3 firstNodePos(mAllowedNodes[0].mX, mAllowedNodes[0].mY, mAllowedNodes[0].mZ);
|
||||
float closestNode = npcPos.squaredDistance(firstNodePos);
|
||||
unsigned int index = 0;
|
||||
for(unsigned int counterThree = 1; counterThree < mAllowedNodes.size(); counterThree++)
|
||||
{
|
||||
Ogre::Vector3 nodePos(mAllowedNodes[counterThree].mX, mAllowedNodes[counterThree].mY,
|
||||
mAllowedNodes[counterThree].mZ);
|
||||
float tempDist = npcPos.squaredDistance(nodePos);
|
||||
if(tempDist < closestNode)
|
||||
index = counterThree;
|
||||
}
|
||||
mCurrentNode = mAllowedNodes[index];
|
||||
mAllowedNodes.erase(mAllowedNodes.begin() + index);
|
||||
|
||||
mStoredAvailableNodes = true; // set only if successful in finding allowed nodes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AiWander::writeState(ESM::AiSequence::AiSequence &sequence) const
|
||||
{
|
||||
std::auto_ptr<ESM::AiSequence::AiWander> wander(new ESM::AiSequence::AiWander());
|
||||
|
@ -743,6 +763,9 @@ namespace MWMechanics
|
|||
for (int i=0; i<8; ++i)
|
||||
wander->mData.mIdle[i] = mIdle[i];
|
||||
wander->mData.mShouldRepeat = mRepeat;
|
||||
wander->mStoredInitialActorPosition = mStoredInitialActorPosition;
|
||||
if (mStoredInitialActorPosition)
|
||||
wander->mInitialActorPosition = mInitialActorPosition;
|
||||
|
||||
ESM::AiSequence::AiPackageContainer package;
|
||||
package.mType = ESM::AiSequence::Ai_Wander;
|
||||
|
@ -756,7 +779,10 @@ namespace MWMechanics
|
|||
, mStartTime(MWWorld::TimeStamp(wander->mStartTime))
|
||||
, mTimeOfDay(wander->mData.mTimeOfDay)
|
||||
, mRepeat(wander->mData.mShouldRepeat)
|
||||
, mStoredInitialActorPosition(wander->mStoredInitialActorPosition)
|
||||
{
|
||||
if (mStoredInitialActorPosition)
|
||||
mInitialActorPosition = wander->mInitialActorPosition;
|
||||
for (int i=0; i<8; ++i)
|
||||
mIdle.push_back(wander->mData.mIdle[i]);
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue