Add OpenMW commits up to 2 Aug 2019

# Conflicts:
#	apps/openmw/mwmechanics/combat.cpp
pull/541/head
David Cernat 5 years ago
commit ed05125f6a

@ -29,6 +29,7 @@ Programmers
Ardekantur
Armin Preiml
Artem Kotsynyak (greye)
Artem Nykolenko (anikm21)
artemutin
Arthur Moore (EmperorArthur)
Assumeru

@ -2,24 +2,30 @@
------
Bug #1515: Opening console masks dialogue, inventory menu
Bug #2395: Duplicated plugins in the launcher when multiple data directories provide the same plugin
Bug #2969: Scripted items can stack
Bug #2987: Editor: some chance and AI data fields can overflow
Bug #3006: 'else if' operator breaks script compilation
Bug #3109: SetPos/Position handles actors differently
Bug #3282: Unintended behaviour when assigning F3 and Windows keys
Bug #3550: Companion from mod attacks the air after combat has ended
Bug #3623: Display scaling breaks mouse recognition
Bug #3725: Using script function in a non-conditional expression breaks script compilation
Bug #3733: Normal maps are inverted on mirrored UVs
Bug #3765: DisableTeleporting makes Mark/Recall/Intervention effects undetectable
Bug #3778: [Mod] Improved Thrown Weapon Projectiles - weapons have wrong transformation during throw animation
Bug #3812: Wrong multiline tooltips width when word-wrapping is enabled
Bug #4202: Open .omwaddon files without needing toopen openmw-cs first
Bug #4240: Ash storm origin coordinates and hand shielding animation behavior are incorrect
Bug #4276: Resizing character window differs from vanilla
Bug #4329: Removed birthsign abilities are restored after reloading the save
Bug #4341: Error message about missing GDB is too vague
Bug #4383: Bow model obscures crosshair when arrow is drawn
Bug #4384: Resist Normal Weapons only checks ammunition for ranged weapons
Bug #4411: Reloading a saved game while falling prevents damage in some cases
Bug #4540: Rain delay when exiting water
Bug #4600: Crash when no sound output is available or --no-sound is used.
Bug #4639: Black screen after completing first mages guild mission + training
Bug #4701: PrisonMarker record is not hardcoded like other markers
Bug #4703: Editor: it's possible to preview levelled list records
Bug #4705: Editor: unable to open exterior cell views from Instances table
@ -99,6 +105,18 @@
Bug #5038: Enchanting success chance calculations are blatantly wrong
Bug #5047: # in cell names sets color
Bug #5050: Invalid spell effects are not handled gracefully
Bug #5056: Calling Cast function on player doesn't equip the spell but casts it
Bug #5060: Magic effect visuals stop when death animation begins instead of when it ends
Bug #5063: Shape named "Tri Shadow" in creature mesh is visible if it isn't hidden
Bug #5069: Blocking creatures' attacks doesn't degrade shields
Bug #5074: Paralyzed actors greet the player
Bug #5075: Enchanting cast style can be changed if there's no object
Bug #5082: Scrolling with controller in GUI mode is broken
Bug #5092: NPCs with enchanted weapons play sound when out of charges
Bug #5093: Hand to hand sound plays on knocked out enemies
Bug #5099: Non-swimming enemies will enter water if player is water walking
Bug #5105: NPCs start combat with werewolves from any distance
Bug #5110: ModRegion with a redundant numerical argument breaks script execution
Feature #1774: Handle AvoidNode
Feature #2229: Improve pathfinding AI
Feature #3025: Analogue gamepad movement controls
@ -126,14 +144,18 @@
Feature #4968: Scalable UI widget skins
Feature #4994: Persistent pinnable windows hiding
Feature #5000: Compressed BSA format support
Feature #5005: Editor: Instance window via Scene window
Feature #5010: Native graphics herbalism support
Feature #5031: Make GetWeaponType function return different values for tools
Feature #5033: Magic armor mitigation for creatures
Feature #5034: Make enchanting window stay open after a failed attempt
Feature #5036: Allow scripted faction leaving
Feature #5046: Gamepad thumbstick cursor speed
Feature #5051: Provide a separate textures for scrollbars
Feature #5094: Unix like console hotkeys
Task #4686: Upgrade media decoder to a more current FFmpeg API
Task #4695: Optimize Distant Terrain memory consumption
Task #4789: Optimize cell transitions
Task #4721: Add NMake support to the Windows prebuild script
0.45.0

@ -222,6 +222,9 @@ endif()
# Required for building the FFmpeg headers
add_definitions(-D__STDC_CONSTANT_MACROS)
# Reqiuired for unity build
add_definitions(-DMYGUI_DONT_REPLACE_NULLPTR)
# TinyXML
option(USE_SYSTEM_TINYXML "Use system TinyXML library instead of internal." OFF)
if (USE_SYSTEM_TINYXML)

@ -109,15 +109,14 @@ void Launcher::DataFilesPage::populateFileViews(const QString& contentModelName)
{
QStringList paths = mGameSettings.getDataDirs();
foreach(const QString &path, paths)
mSelector->addFiles(path);
mDataLocal = mGameSettings.getDataLocal();
if (!mDataLocal.isEmpty())
mSelector->addFiles(mDataLocal);
paths.insert(0, mDataLocal);
foreach(const QString &path, paths)
mSelector->addFiles(path);
paths.insert(0, mDataLocal);
PathIterator pathIterator(paths);
mSelector->setProfileContent(filesInProfile(contentModelName, pathIterator));

@ -44,6 +44,7 @@ Launcher::GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, Settings:
connect(fullScreenCheckBox, SIGNAL(stateChanged(int)), this, SLOT(slotFullScreenChanged(int)));
connect(standardRadioButton, SIGNAL(toggled(bool)), this, SLOT(slotStandardToggled(bool)));
connect(screenComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(screenChanged(int)));
connect(framerateLimitCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotFramerateLimitToggled(bool)));
}
@ -121,6 +122,13 @@ bool Launcher::GraphicsPage::loadSettings()
customHeightSpinBox->setValue(height);
}
float fpsLimit = mEngineSettings.getFloat("framerate limit", "Video");
if (fpsLimit != 0)
{
framerateLimitCheckBox->setCheckState(Qt::Checked);
framerateLimitSpinBox->setValue(fpsLimit);
}
return true;
}
@ -166,6 +174,17 @@ void Launcher::GraphicsPage::saveSettings()
int cScreen = screenComboBox->currentIndex();
if (cScreen != mEngineSettings.getInt("screen", "Video"))
mEngineSettings.setInt("screen", "Video", cScreen);
if (framerateLimitCheckBox->checkState())
{
float cFpsLimit = framerateLimitSpinBox->value();
if (cFpsLimit != mEngineSettings.getFloat("framerate limit", "Video"))
mEngineSettings.setFloat("framerate limit", "Video", cFpsLimit);
}
else if (mEngineSettings.getFloat("framerate limit", "Video") != 0)
{
mEngineSettings.setFloat("framerate limit", "Video", 0);
}
}
QStringList Launcher::GraphicsPage::getAvailableResolutions(int screen)
@ -266,3 +285,8 @@ void Launcher::GraphicsPage::slotStandardToggled(bool checked)
customHeightSpinBox->setEnabled(true);
}
}
void Launcher::GraphicsPage::slotFramerateLimitToggled(bool checked)
{
framerateLimitSpinBox->setEnabled(checked);
}

@ -31,6 +31,7 @@ namespace Launcher
private slots:
void slotFullScreenChanged(int state);
void slotStandardToggled(bool checked);
void slotFramerateLimitToggled(bool checked);
private:
Files::ConfigurationManager &mCfgMgr;

@ -27,8 +27,11 @@ CS::Editor::Editor (int argc, char **argv)
std::pair<Files::PathContainer, std::vector<std::string> > config = readConfig();
mViewManager = new CSVDoc::ViewManager(mDocumentManager);
setupDataFiles (config.first);
if (argc > 1)
{
mFileToLoad = argv[1];
mDataDirs = config.first;
}
NifOsg::Loader::setShowMarkers(true);
@ -79,15 +82,6 @@ CS::Editor::~Editor ()
remove(mPid.string().c_str())); // ignore any error
}
void CS::Editor::setupDataFiles (const Files::PathContainer& dataDirs)
{
for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter)
{
QString path = QString::fromUtf8 (iter->string().c_str());
mFileDialog.addFiles(path);
}
}
std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfig(bool quiet)
{
boost::program_options::variables_map variables;
@ -114,9 +108,9 @@ std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfi
Fallback::Map::init(variables["fallback"].as<FallbackMap>().mMap);
const std::string encoding = variables["encoding"].as<Files::EscapeHashString>().toStdString();
mDocumentManager.setEncoding (ToUTF8::calculateEncoding (encoding));
mFileDialog.setEncoding (QString::fromUtf8(encoding.c_str()));
mEncodingName = variables["encoding"].as<Files::EscapeHashString>().toStdString();
mDocumentManager.setEncoding(ToUTF8::calculateEncoding(mEncodingName));
mFileDialog.setEncoding (QString::fromUtf8(mEncodingName.c_str()));
mDocumentManager.setResourceDir (mResources = variables["resources"].as<Files::EscapeHashString>().toStdString());
@ -160,7 +154,7 @@ std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfi
dataDirs.insert (dataDirs.end(), dataLocal.begin(), dataLocal.end());
//iterate the data directories and add them to the file dialog for loading
for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter)
for (Files::PathContainer::const_reverse_iterator iter = dataDirs.rbegin(); iter != dataDirs.rend(); ++iter)
{
QString path = QString::fromUtf8 (iter->string().c_str());
mFileDialog.addFiles(path);
@ -199,8 +193,7 @@ void CS::Editor::createAddon()
mStartup.hide();
mFileDialog.clearFiles();
std::pair<Files::PathContainer, std::vector<std::string> > config = readConfig(/*quiet*/true);
setupDataFiles (config.first);
readConfig(/*quiet*/true);
mFileDialog.showDialog (CSVDoc::ContentAction_New);
}
@ -224,18 +217,24 @@ void CS::Editor::loadDocument()
mStartup.hide();
mFileDialog.clearFiles();
std::pair<Files::PathContainer, std::vector<std::string> > config = readConfig(/*quiet*/true);
setupDataFiles (config.first);
readConfig(/*quiet*/true);
mFileDialog.showDialog (CSVDoc::ContentAction_Edit);
}
void CS::Editor::openFiles (const boost::filesystem::path &savePath)
void CS::Editor::openFiles (const boost::filesystem::path &savePath, const std::vector<boost::filesystem::path> &discoveredFiles)
{
std::vector<boost::filesystem::path> files;
foreach (const QString &path, mFileDialog.selectedFilePaths())
files.push_back(path.toUtf8().constData());
if(discoveredFiles.empty())
{
foreach(const QString &path, mFileDialog.selectedFilePaths())
files.push_back(path.toUtf8().constData());
}
else
{
files = discoveredFiles;
}
mDocumentManager.addDocument (files, savePath, false);
@ -361,9 +360,53 @@ int CS::Editor::run()
Misc::Rng::init();
mStartup.show();
QApplication::setQuitOnLastWindowClosed(true);
QApplication::setQuitOnLastWindowClosed (true);
if (mFileToLoad.empty())
{
mStartup.show();
}
else
{
ESM::ESMReader fileReader;
ToUTF8::Utf8Encoder encoder = ToUTF8::calculateEncoding(mEncodingName);
fileReader.setEncoder(&encoder);
fileReader.open(mFileToLoad.string());
std::vector<boost::filesystem::path> discoveredFiles;
for (std::vector<ESM::Header::MasterData>::const_iterator itemIter = fileReader.getGameFiles().begin();
itemIter != fileReader.getGameFiles().end(); ++itemIter)
{
for (Files::PathContainer::const_iterator pathIter = mDataDirs.begin();
pathIter != mDataDirs.end(); ++pathIter)
{
const boost::filesystem::path masterPath = *pathIter / itemIter->name;
if (boost::filesystem::exists(masterPath))
{
discoveredFiles.push_back(masterPath);
break;
}
}
}
discoveredFiles.push_back(mFileToLoad);
QString extension = QString::fromStdString(mFileToLoad.extension().string()).toLower();
if (extension == ".esm")
{
mFileToLoad.replace_extension(".omwgame");
mDocumentManager.addDocument(discoveredFiles, mFileToLoad, false);
}
else if (extension == ".esp")
{
mFileToLoad.replace_extension(".omwaddon");
mDocumentManager.addDocument(discoveredFiles, mFileToLoad, false);
}
else
{
openFiles(mFileToLoad, discoveredFiles);
}
}
return QApplication::exec();
}

@ -54,8 +54,9 @@ namespace CS
bool mFsStrict;
CSVTools::Merge mMerge;
CSVDoc::ViewManager* mViewManager;
void setupDataFiles (const Files::PathContainer& dataDirs);
boost::filesystem::path mFileToLoad;
Files::PathContainer mDataDirs;
std::string mEncodingName;
std::pair<Files::PathContainer, std::vector<std::string> > readConfig(bool quiet=false);
///< \return data paths
@ -83,7 +84,7 @@ namespace CS
void cancelFileDialog();
void loadDocument();
void openFiles (const boost::filesystem::path &path);
void openFiles (const boost::filesystem::path &path, const std::vector<boost::filesystem::path> &discoveredFiles = std::vector<boost::filesystem::path>());
void createNewFile (const boost::filesystem::path& path);
void createNewGame (const boost::filesystem::path& file);

@ -3,6 +3,7 @@
#include <stdexcept>
#include <algorithm>
#include <sstream>
#include "intsetting.hpp"
#include "doublesetting.hpp"
@ -247,6 +248,9 @@ void CSMPrefs::State::declare()
addValues (landeditOutsideVisibleCell);
declareInt ("texturebrush-maximumsize", "Maximum texture brush size", 50).
setMin (1);
declareBool ("open-list-view", "Open displays list view", false).
setTooltip ("When opening a reference from the scene view, it will open the"
" instance list view instead of the individual instance record view.");
declareCategory ("Key Bindings");
@ -331,6 +335,7 @@ void CSMPrefs::State::declare()
declareShortcut ("scene-navi-primary", "Camera Rotation From Mouse Movement", QKeySequence(Qt::LeftButton));
declareShortcut ("scene-navi-secondary", "Camera Translation From Mouse Movement",
QKeySequence(Qt::ControlModifier | (int)Qt::LeftButton));
declareShortcut ("scene-open-primary", "Primary Open", QKeySequence(Qt::ShiftModifier | (int)Qt::LeftButton));
declareShortcut ("scene-edit-primary", "Primary Edit", QKeySequence(Qt::RightButton));
declareShortcut ("scene-edit-secondary", "Secondary Edit",
QKeySequence(Qt::ControlModifier | (int)Qt::RightButton));
@ -411,7 +416,9 @@ CSMPrefs::DoubleSetting& CSMPrefs::State::declareDouble (const std::string& key,
if (mCurrentCategory==mCategories.end())
throw std::logic_error ("no category for setting");
setDefault(key, std::to_string(default_));
std::ostringstream stream;
stream << default_;
setDefault(key, stream.str());
default_ = mSettings.getFloat (key, mCurrentCategory->second.getKey());

@ -422,7 +422,7 @@ namespace
static const char *sApparatusTypes[] =
{
"Mortar & Pestle", "Albemic", "Calcinator", "Retort", 0
"Mortar & Pestle", "Alembic", "Calcinator", "Retort", 0
};
static const char *sArmorTypes[] =

@ -22,6 +22,7 @@
#include "../../model/world/idtable.hpp"
#include "../world/subviews.hpp"
#include "../world/scenesubview.hpp"
#include "../world/tablesubview.hpp"
#include "../tools/subviews.hpp"
@ -626,6 +627,20 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin
connect (view, SIGNAL (updateSubViewIndices (SubView *)),
this, SLOT (updateSubViewIndices (SubView *)));
CSVWorld::TableSubView* tableView = dynamic_cast<CSVWorld::TableSubView*>(view);
if (tableView)
{
connect (this, SIGNAL (requestFocus (const std::string&)),
tableView, SLOT (requestFocus (const std::string&)));
}
CSVWorld::SceneSubView* sceneView = dynamic_cast<CSVWorld::SceneSubView*>(view);
if (sceneView)
{
connect(sceneView, SIGNAL(requestFocus(const std::string&)),
this, SLOT(onRequestFocus(const std::string&)));
}
view->show();
if (!hint.empty())
@ -1065,3 +1080,16 @@ void CSVDoc::View::createScrollArea()
mScroll->setWidget(&mSubViewWindow);
setCentralWidget(mScroll);
}
void CSVDoc::View::onRequestFocus (const std::string& id)
{
if(CSMPrefs::get()["3D Scene Editing"]["open-list-view"].isTrue())
{
addReferencesSubView();
emit requestFocus(id);
}
else
{
addSubView(CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Reference, id));
}
}

@ -140,6 +140,8 @@ namespace CSVDoc
void mergeDocument (CSMDoc::Document *document);
void requestFocus (const std::string& id);
public slots:
void addSubView (const CSMWorld::UniversalId& id, const std::string& hint = "");
@ -262,6 +264,8 @@ namespace CSVDoc
void moveScrollBarToEnd(int min, int max);
void merge();
void onRequestFocus (const std::string& id);
};
}

@ -29,6 +29,8 @@ void CSVRender::EditMode::setEditLock (bool locked)
}
void CSVRender::EditMode::primaryOpenPressed (const WorldspaceHitResult& hit) {}
void CSVRender::EditMode::primaryEditPressed (const WorldspaceHitResult& hit) {}
void CSVRender::EditMode::secondaryEditPressed (const WorldspaceHitResult& hit) {}

@ -39,6 +39,9 @@ namespace CSVRender
/// Default-implementation: Ignored.
virtual void setEditLock (bool locked);
/// Default-implementation: Ignored.
virtual void primaryOpenPressed (const WorldspaceHitResult& hit);
/// Default-implementation: Ignored.
virtual void primaryEditPressed (const WorldspaceHitResult& hit);

@ -94,6 +94,8 @@ CSVRender::InstanceMode::InstanceMode (WorldspaceWidget *worldspaceWidget, QWidg
parent), mSubMode (0), mSubModeId ("move"), mSelectionMode (0), mDragMode (DragMode_None),
mDragAxis (-1), mLocked (false), mUnitScaleDist(1)
{
connect(this, SIGNAL(requestFocus(const std::string&)),
worldspaceWidget, SIGNAL(requestFocus(const std::string&)));
}
void CSVRender::InstanceMode::activate (CSVWidget::SceneToolbar *toolbar)
@ -174,6 +176,18 @@ void CSVRender::InstanceMode::primaryEditPressed (const WorldspaceHitResult& hit
primarySelectPressed (hit);
}
void CSVRender::InstanceMode::primaryOpenPressed (const WorldspaceHitResult& hit)
{
if(hit.tag)
{
if (CSVRender::ObjectTag *objectTag = dynamic_cast<CSVRender::ObjectTag *> (hit.tag.get()))
{
const std::string refId = objectTag->mObject->getReferenceId();
emit requestFocus(refId);
}
}
}
void CSVRender::InstanceMode::secondaryEditPressed (const WorldspaceHitResult& hit)
{
if (CSMPrefs::get()["3D Scene Input"]["context-select"].isTrue())

@ -55,6 +55,8 @@ namespace CSVRender
virtual void setEditLock (bool locked);
virtual void primaryOpenPressed (const WorldspaceHitResult& hit);
virtual void primaryEditPressed (const WorldspaceHitResult& hit);
virtual void secondaryEditPressed (const WorldspaceHitResult& hit);
@ -83,6 +85,10 @@ namespace CSVRender
virtual int getSubMode() const;
signals:
void requestFocus (const std::string& id);
private slots:
void subModeChanged (const std::string& id);

@ -63,6 +63,10 @@ namespace CSVRender
}
}
void PathgridMode::primaryOpenPressed(const WorldspaceHitResult& hitResult)
{
}
void PathgridMode::primaryEditPressed(const WorldspaceHitResult& hitResult)
{
if (CSMPrefs::get()["3D Scene Input"]["context-select"].isTrue() &&

@ -21,6 +21,8 @@ namespace CSVRender
virtual void deactivate(CSVWidget::SceneToolbar* toolbar);
virtual void primaryOpenPressed(const WorldspaceHitResult& hit);
virtual void primaryEditPressed(const WorldspaceHitResult& hit);
virtual void secondaryEditPressed(const WorldspaceHitResult& hit);

@ -77,6 +77,10 @@ void CSVRender::TerrainTextureMode::deactivate(CSVWidget::SceneToolbar* toolbar)
EditMode::deactivate(toolbar);
}
void CSVRender::TerrainTextureMode::primaryOpenPressed(const WorldspaceHitResult& hit) // Apply changes here
{
}
void CSVRender::TerrainTextureMode::primaryEditPressed(const WorldspaceHitResult& hit) // Apply changes here
{
CSMDoc::Document& document = getWorldspaceWidget().getDocument();

@ -35,6 +35,8 @@ namespace CSVRender
/// \brief Editmode for terrain texture grid
TerrainTextureMode(WorldspaceWidget*, QWidget* parent = nullptr);
void primaryOpenPressed (const WorldspaceHitResult& hit);
/// \brief Create single command for one-click texture editing
void primaryEditPressed (const WorldspaceHitResult& hit);

@ -101,6 +101,9 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg
// Shortcuts
CSMPrefs::Shortcut* primaryEditShortcut = new CSMPrefs::Shortcut("scene-edit-primary", "scene-speed-modifier",
CSMPrefs::Shortcut::SM_Detach, this);
CSMPrefs::Shortcut* primaryOpenShortcut = new CSMPrefs::Shortcut("scene-open-primary", this);
connect(primaryOpenShortcut, SIGNAL(activated(bool)), this, SLOT(primaryOpen(bool)));
connect(primaryEditShortcut, SIGNAL(activated(bool)), this, SLOT(primaryEdit(bool)));
connect(primaryEditShortcut, SIGNAL(secondary(bool)), this, SLOT(speedMode(bool)));
@ -696,6 +699,8 @@ void CSVRender::WorldspaceWidget::handleInteractionPress (const WorldspaceHitRes
editMode.primarySelectPressed (hit);
else if (type == InteractionType_SecondarySelect)
editMode.secondarySelectPressed (hit);
else if (type == InteractionType_PrimaryOpen)
editMode.primaryOpenPressed (hit);
}
CSVRender::EditMode *CSVRender::WorldspaceWidget::getEditMode()
@ -703,6 +708,11 @@ CSVRender::EditMode *CSVRender::WorldspaceWidget::getEditMode()
return dynamic_cast<CSVRender::EditMode *> (mEditMode->getCurrent());
}
void CSVRender::WorldspaceWidget::primaryOpen(bool activate)
{
handleInteraction(InteractionType_PrimaryOpen, activate);
}
void CSVRender::WorldspaceWidget::primaryEdit(bool activate)
{
handleInteraction(InteractionType_PrimaryEdit, activate);

@ -91,6 +91,7 @@ namespace CSVRender
InteractionType_PrimarySelect,
InteractionType_SecondaryEdit,
InteractionType_SecondarySelect,
InteractionType_PrimaryOpen,
InteractionType_None
};
@ -263,6 +264,8 @@ namespace CSVRender
void showToolTip();
void primaryOpen(bool activate);
void primaryEdit(bool activate);
void secondaryEdit(bool activate);
@ -283,6 +286,8 @@ namespace CSVRender
void dataDropped(const std::vector<CSMWorld::UniversalId>& data);
void requestFocus (const std::string& id);
friend class MouseState;
};
}

@ -83,6 +83,9 @@ void CSVWorld::SceneSubView::makeConnections (CSVRender::UnpagedWorldspaceWidget
connect(widget, SIGNAL(cellChanged(const CSMWorld::UniversalId&)),
this, SLOT(cellSelectionChanged(const CSMWorld::UniversalId&)));
connect(widget, SIGNAL(requestFocus (const std::string&)),
this, SIGNAL(requestFocus (const std::string&)));
}
void CSVWorld::SceneSubView::makeConnections (CSVRender::PagedWorldspaceWidget* widget)
@ -94,6 +97,9 @@ void CSVWorld::SceneSubView::makeConnections (CSVRender::PagedWorldspaceWidget*
connect (widget, SIGNAL (cellSelectionChanged (const CSMWorld::CellSelection&)),
this, SLOT (cellSelectionChanged (const CSMWorld::CellSelection&)));
connect(widget, SIGNAL(requestFocus (const std::string&)),
this, SIGNAL(requestFocus (const std::string&)));
}
CSVWidget::SceneToolbar* CSVWorld::SceneSubView::makeToolbar (CSVRender::WorldspaceWidget* widget, widgetType type)

@ -82,6 +82,10 @@ namespace CSVWorld
void cellSelectionChanged (const CSMWorld::UniversalId& id);
void handleDrop(const std::vector<CSMWorld::UniversalId>& data);
signals:
void requestFocus (const std::string& id);
};
}

@ -737,7 +737,12 @@ void CSVWorld::Table::requestFocus (const std::string& id)
QModelIndex index = mProxyModel->getModelIndex (id, 0);
if (index.isValid())
scrollTo (index, QAbstractItemView::PositionAtTop);
{
// This will scroll to the row.
selectRow (index.row());
// This will actually select it.
selectionModel()->select (index, QItemSelectionModel::Select | QItemSelectionModel::Rows);
}
}
void CSVWorld::Table::recordFilterChanged (std::shared_ptr<CSMFilter::Node> filter)

@ -165,3 +165,8 @@ bool CSVWorld::TableSubView::eventFilter (QObject* object, QEvent* event)
}
return false;
}
void CSVWorld::TableSubView::requestFocus (const std::string& id)
{
mTable->requestFocus(id);
}

@ -60,6 +60,10 @@ namespace CSVWorld
void cloneRequest (const CSMWorld::UniversalId& toClone);
void createFilterRequest(std::vector< CSMWorld::UniversalId >& types,
Qt::DropAction action);
public slots:
void requestFocus (const std::string& id);
};
}

@ -375,6 +375,9 @@ namespace MWBase
virtual const Translation::Storage& getTranslationDataStorage() const = 0;
/// Warning: do not use MyGUI::InputManager::setKeyFocusWidget directly. Instead use this.
virtual void setKeyFocusWidget (MyGUI::Widget* widget) = 0;
virtual void loadUserFonts() = 0;
virtual Loading::Listener* getLoadingScreen() = 0;

@ -1365,7 +1365,7 @@ namespace MWClass
MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(ref->mBase->mRace);
// Race weight should not affect 1st-person meshes, otherwise it will change hand proportions and can break aiming.
if (ptr == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->isFirstPerson())
if (ptr == MWMechanics::getPlayer() && ptr.isInCell() && MWBase::Environment::get().getWorld()->isFirstPerson())
{
if (ref->mBase->isMale())
scale *= race->mData.mHeight.mMale;

@ -5,7 +5,6 @@
#include <MyGUI_EditBox.h>
#include <MyGUI_ControllerManager.h>
#include <MyGUI_ControllerRepeatClick.h>
#include <MyGUI_InputManager.h>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
@ -169,7 +168,7 @@ namespace MWGui
update();
MyGUI::InputManager::getInstance().setKeyFocusWidget(mNameEdit);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mNameEdit);
}
void AlchemyWindow::onIngredientSelected(MyGUI::Widget* _sender)

@ -4,7 +4,6 @@
#include <MyGUI_ImageBox.h>
#include <MyGUI_Gui.h>
#include <MyGUI_ScrollView.h>
#include <MyGUI_InputManager.h>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
@ -72,7 +71,7 @@ namespace MWGui
WindowModal::onOpen();
updateBirths();
updateSpells();
MyGUI::InputManager::getInstance().setKeyFocusWidget(mBirthList);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mBirthList);
// Show the current birthsign by default
const std::string &signId =

@ -101,7 +101,7 @@ namespace MWGui
setTakeButtonShow(showTakeButton);
MyGUI::InputManager::getInstance().setKeyFocusWidget(mCloseButton);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCloseButton);
}
void BookWindow::setTakeButtonShow(bool show)
@ -161,9 +161,9 @@ namespace MWGui
mPrevPageButton->setVisible(prevPageVisible);
if (focus == mNextPageButton && !nextPageVisible && prevPageVisible)
MyGUI::InputManager::getInstance().setKeyFocusWidget(mPrevPageButton);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mPrevPageButton);
else if (focus == mPrevPageButton && !prevPageVisible && nextPageVisible)
MyGUI::InputManager::getInstance().setKeyFocusWidget(mNextPageButton);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mNextPageButton);
if (mPages.empty())
return;

@ -3,7 +3,6 @@
#include <MyGUI_ImageBox.h>
#include <MyGUI_ListBox.h>
#include <MyGUI_Gui.h>
#include <MyGUI_InputManager.h>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
@ -136,7 +135,7 @@ namespace MWGui
WindowModal::onOpen ();
updateClasses();
updateStats();
MyGUI::InputManager::getInstance().setKeyFocusWidget(mClassList);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mClassList);
// Show the current class by default
MWWorld::Ptr player = MWMechanics::getPlayer();
@ -437,7 +436,7 @@ namespace MWGui
getWidget(mEditName, "EditName");
// Make sure the edit box has focus
MyGUI::InputManager::getInstance().setKeyFocusWidget(mEditName);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mEditName);
MyGUI::Button* descriptionButton;
getWidget(descriptionButton, "DescriptionButton");
@ -903,7 +902,7 @@ namespace MWGui
okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sInputMenu1", ""));
// Make sure the edit box has focus
MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mTextEdit);
}
DescriptionDialog::~DescriptionDialog()

@ -2,7 +2,6 @@
#include <MyGUI_Button.h>
#include <MyGUI_EditBox.h>
#include <MyGUI_InputManager.h>
#include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp"
@ -34,7 +33,7 @@ namespace MWGui
mMessage->setSize(mMessage->getWidth(), mMessage->getTextSize().height + 24);
MyGUI::InputManager::getInstance().setKeyFocusWidget(mOkButton);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mOkButton);
center();
}

@ -153,7 +153,7 @@ namespace MWGui
{
// Give keyboard focus to the combo box whenever the console is
// turned on and place it over other widgets
MyGUI::InputManager::getInstance().setKeyFocusWidget(mCommandLine);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCommandLine);
MyGUI::LayerManager::getInstance().upLayerItem(mMainWidget);
}
@ -238,11 +238,48 @@ namespace MWGui
resetReference();
}
bool isWhitespace(char c)
{
return c == ' ' || c == '\t';
}
void Console::keyPress(MyGUI::Widget* _sender,
MyGUI::KeyCode key,
MyGUI::Char _char)
{
if( key == MyGUI::KeyCode::Tab)
if(MyGUI::InputManager::getInstance().isControlPressed())
{
if(key == MyGUI::KeyCode::W)
{
const auto& caption = mCommandLine->getCaption();
if(caption.empty())
return;
size_t max = mCommandLine->getTextCursor();
while(max > 0 && (isWhitespace(caption[max - 1]) || caption[max - 1] == '>'))
max--;
while(max > 0 && !isWhitespace(caption[max - 1]) && caption[max - 1] != '>')
max--;
size_t length = mCommandLine->getTextCursor() - max;
if(length > 0)
{
std::string text = caption;
text.erase(max, length);
mCommandLine->setCaption(text);
mCommandLine->setTextCursor(max);
}
}
else if(key == MyGUI::KeyCode::U)
{
if(mCommandLine->getTextCursor() > 0)
{
std::string text = mCommandLine->getCaption();
text.erase(0, mCommandLine->getTextCursor());
mCommandLine->setCaption(text);
mCommandLine->setTextCursor(0);
}
}
}
else if(key == MyGUI::KeyCode::Tab)
{
std::vector<std::string> matches;
listNames();
@ -474,7 +511,7 @@ namespace MWGui
mPtr = object;
}
// User clicked on an object. Restore focus to the console command line.
MyGUI::InputManager::getInstance().setKeyFocusWidget(mCommandLine);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCommandLine);
}
else
{

@ -254,7 +254,7 @@ namespace MWGui
mItemView->setModel (mSortModel);
mItemView->resetScrollBars();
MyGUI::InputManager::getInstance().setKeyFocusWidget(mCloseButton);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCloseButton);
setTitle(container.getClass().getName(container));
}
@ -298,7 +298,7 @@ namespace MWGui
if(mDragAndDrop != nullptr && mDragAndDrop->mIsOnDragAndDrop)
return;
MyGUI::InputManager::getInstance().setKeyFocusWidget(mCloseButton);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCloseButton);
/*
Start of tes3mp addition
@ -378,7 +378,7 @@ namespace MWGui
{
if(mDragAndDrop == nullptr || !mDragAndDrop->mIsOnDragAndDrop)
{
MyGUI::InputManager::getInstance().setKeyFocusWidget(mCloseButton);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCloseButton);
onTakeAllButtonClicked(mTakeButton);

@ -3,7 +3,6 @@
#include <MyGUI_Button.h>
#include <MyGUI_ScrollBar.h>
#include <MyGUI_RenderManager.h>
#include <MyGUI_InputManager.h>
#include <components/widgets/numericeditbox.hpp>
@ -48,7 +47,7 @@ namespace MWGui
mMainWidget->getHeight());
// by default, the text edit field has the focus of the keyboard
MyGUI::InputManager::getInstance().setKeyFocusWidget(mItemEdit);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mItemEdit);
mSlider->setScrollPosition(maxCount-1);

@ -5,7 +5,6 @@
#include <MyGUI_ProgressBar.h>
#include <MyGUI_ScrollBar.h>
#include <MyGUI_Button.h>
#include <MyGUI_InputManager.h>
#include <components/debug/debuglog.hpp>
#include <components/widgets/list.hpp>
@ -381,7 +380,7 @@ namespace MWGui
{
onTopicActivated(topic);
if (mGoodbyeButton->getEnabled())
MyGUI::InputManager::getInstance().setKeyFocusWidget(mGoodbyeButton);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mGoodbyeButton);
}
else if (topic == sPersuasion)
mPersuasionDialog.setVisible(true);
@ -444,7 +443,7 @@ namespace MWGui
return;
}
MyGUI::InputManager::getInstance().setKeyFocusWidget(mGoodbyeButton);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mGoodbyeButton);
setTitle(mPtr.getClass().getName(mPtr));
@ -623,7 +622,7 @@ namespace MWGui
bool goodbyeWasEnabled = mGoodbyeButton->getEnabled();
mGoodbyeButton->setEnabled(goodbyeEnabled);
if (goodbyeEnabled && !goodbyeWasEnabled)
MyGUI::InputManager::getInstance().setKeyFocusWidget(mGoodbyeButton);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mGoodbyeButton);
bool topicsEnabled = !MWBase::Environment::get().getDialogueManager()->isInChoice() && !mGoodbye;
mTopicsList->setEnabled(topicsEnabled);

@ -5,7 +5,6 @@
#include <MyGUI_Button.h>
#include <MyGUI_ScrollView.h>
#include <MyGUI_EditBox.h>
#include <MyGUI_InputManager.h>
#include <components/widgets/list.hpp>
#include <components/settings/settings.hpp>
@ -68,7 +67,7 @@ namespace MWGui
void EnchantingDialog::onOpen()
{
center();
MyGUI::InputManager::getInstance().setKeyFocusWidget(mName);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mName);
}
void EnchantingDialog::setSoulGem(const MWWorld::Ptr &gem)

@ -254,7 +254,7 @@ namespace
}
updateShowingPages();
MyGUI::InputManager::getInstance().setKeyFocusWidget(getWidget<MyGUI::Widget>(CloseBTN));
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(getWidget<MyGUI::Widget>(CloseBTN));
}
void onClose()
@ -377,9 +377,9 @@ namespace
prevPageBtn->setVisible(prevPageVisible);
if (focus == nextPageBtn && !nextPageVisible && prevPageVisible)
MyGUI::InputManager::getInstance().setKeyFocusWidget(prevPageBtn);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(prevPageBtn);
else if (focus == prevPageBtn && !prevPageVisible && nextPageVisible)
MyGUI::InputManager::getInstance().setKeyFocusWidget(nextPageBtn);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(nextPageBtn);
setVisible (PageOneNum, relPages > 0);
setVisible (PageTwoNum, relPages > 1);

@ -83,7 +83,7 @@ void KeyboardNavigation::restoreFocus(int mode)
{
MyGUI::Widget* w = found->second;
if (w && w->getVisible() && w->getEnabled())
MyGUI::InputManager::getInstance().setKeyFocusWidget(found->second);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(found->second);
}
}
@ -130,7 +130,7 @@ void KeyboardNavigation::onFrame()
// workaround incorrect key focus resets (fix in MyGUI TBD)
if (!shouldAcceptKeyFocus(focus) && shouldAcceptKeyFocus(mCurrentFocus) && (!mModalWindow || isRootParent(mCurrentFocus, mModalWindow)))
{
MyGUI::InputManager::getInstance().setKeyFocusWidget(mCurrentFocus);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCurrentFocus);
focus = mCurrentFocus;
}
@ -154,12 +154,12 @@ void KeyboardNavigation::setDefaultFocus(MyGUI::Widget *window, MyGUI::Widget *d
MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget();
if (!focus || !shouldAcceptKeyFocus(focus))
{
MyGUI::InputManager::getInstance().setKeyFocusWidget(defaultFocus);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(defaultFocus);
}
else
{
if (!isRootParent(focus, window))
MyGUI::InputManager::getInstance().setKeyFocusWidget(defaultFocus);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(defaultFocus);
}
}
@ -276,7 +276,7 @@ bool KeyboardNavigation::switchFocus(int direction, bool wrap)
else if (direction == D_Up && (vertdiff >= 0 || !isVertical))
return false;
MyGUI::InputManager::getInstance().setKeyFocusWidget(keyFocusList[index]);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(keyFocusList[index]);
return true;
}
@ -291,7 +291,7 @@ bool KeyboardNavigation::selectFirstWidget()
if (!keyFocusList.empty())
{
MyGUI::InputManager::getInstance().setKeyFocusWidget(keyFocusList[0]);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(keyFocusList[0]);
return true;
}
return false;

@ -3,7 +3,6 @@
#include <MyGUI_TextBox.h>
#include <MyGUI_Gui.h>
#include <MyGUI_RenderManager.h>
#include <MyGUI_InputManager.h>
#include <components/widgets/imagebutton.hpp>
#include <components/settings/settings.hpp>
@ -68,12 +67,12 @@ namespace MWGui
if (isMainMenu)
{
if (mButtons["loadgame"]->getVisible())
MyGUI::InputManager::getInstance().setKeyFocusWidget(mButtons["loadgame"]);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mButtons["loadgame"]);
else
MyGUI::InputManager::getInstance().setKeyFocusWidget(mButtons["newgame"]);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mButtons["newgame"]);
}
else
MyGUI::InputManager::getInstance().setKeyFocusWidget(mButtons["return"]);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mButtons["return"]);
}
Layout::setVisible (visible);

@ -1196,7 +1196,7 @@ namespace MWGui
{
WindowModal::onOpen();
center();
MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mTextEdit);
}
void EditNoteDialog::onCancelButtonClicked(MyGUI::Widget *sender)

@ -3,7 +3,6 @@
#include <MyGUI_ListBox.h>
#include <MyGUI_ImageBox.h>
#include <MyGUI_Gui.h>
#include <MyGUI_InputManager.h>
#include <osg/Texture2D>
@ -177,7 +176,7 @@ namespace MWGui
mHeadRotate->setScrollPosition(initialPos);
onHeadRotate(mHeadRotate, initialPos);
MyGUI::InputManager::getInstance().setKeyFocusWidget(mRaceList);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mRaceList);
}
void RaceDialog::setRaceId(const std::string &raceId)

@ -94,7 +94,7 @@ namespace MWGui
MWBase::Environment::get().getStateManager()->deleteGame (mCurrentCharacter, mCurrentSlot);
mSaveList->removeItemAt(mSaveList->getIndexSelected());
onSlotSelected(mSaveList, mSaveList->getIndexSelected());
MyGUI::InputManager::getInstance().setKeyFocusWidget(mSaveList);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveList);
if (mSaveList->getItemCount() == 0)
{
@ -114,7 +114,7 @@ namespace MWGui
void SaveGameDialog::onDeleteSlotCancel()
{
MyGUI::InputManager::getInstance().setKeyFocusWidget(mSaveList);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveList);
}
void SaveGameDialog::onSaveNameChanged(MyGUI::EditBox *sender)
@ -138,9 +138,9 @@ namespace MWGui
mSaveNameEdit->setCaption ("");
if (mSaving)
MyGUI::InputManager::getInstance().setKeyFocusWidget(mSaveNameEdit);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveNameEdit);
else
MyGUI::InputManager::getInstance().setKeyFocusWidget(mSaveList);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveList);
center();
@ -244,7 +244,7 @@ namespace MWGui
void SaveGameDialog::onConfirmationCancel()
{
MyGUI::InputManager::getInstance().setKeyFocusWidget(mSaveList);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveList);
}
void SaveGameDialog::accept(bool reallySure)
@ -331,7 +331,7 @@ namespace MWGui
void SaveGameDialog::onCharacterAccept(MyGUI::ComboBox* sender, size_t pos)
{
// Give key focus to save list so we can confirm the selection with Enter
MyGUI::InputManager::getInstance().setKeyFocusWidget(mSaveList);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveList);
}
void SaveGameDialog::fillSaveList()

@ -38,12 +38,20 @@ namespace MWGui
if (!mRunning)
return;
if (mRemainingTime <= 0 || mStartAlpha == mTargetAlpha)
if (mStartAlpha == mTargetAlpha)
{
finish();
return;
}
if (mRemainingTime <= 0)
{
// Make sure the target alpha is applied
mFader->notifyAlphaChanged(mTargetAlpha);
finish();
return;
}
if (mRemainingTime > mTargetTime)
{
mRemainingTime -= dt;
@ -162,7 +170,7 @@ namespace MWGui
if (time < 0.f)
return;
if (time == 0.f)
if (time == 0.f && delay == 0.f)
{
mCurrentAlpha = targetAlpha;
applyAlpha();

@ -1,7 +1,6 @@
#include "scrollwindow.hpp"
#include <MyGUI_ScrollView.h>
#include <MyGUI_InputManager.h>
#include <components/esm/loadbook.hpp>
#include <components/widgets/imagebutton.hpp>
@ -67,7 +66,7 @@ namespace MWGui
setTakeButtonShow(showTakeButton);
MyGUI::InputManager::getInstance().setKeyFocusWidget(mCloseButton);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCloseButton);
}
void ScrollWindow::onKeyButtonPressed(MyGUI::Widget *sender, MyGUI::KeyCode key, MyGUI::Char character)

@ -6,7 +6,6 @@
#include <MyGUI_ScrollView.h>
#include <MyGUI_Gui.h>
#include <MyGUI_TabControl.h>
#include <MyGUI_InputManager.h>
#include <boost/algorithm/string.hpp>
@ -631,7 +630,7 @@ namespace MWGui
highlightCurrentResolution();
updateControlsBox();
resetScrollbars();
MyGUI::InputManager::getInstance().setKeyFocusWidget(mOkButton);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mOkButton);
}
void SettingsWindow::onWindowResize(MyGUI::Window *_sender)

@ -2,7 +2,6 @@
#include <MyGUI_ImageBox.h>
#include <MyGUI_Gui.h>
#include <MyGUI_InputManager.h>
#include <components/esm/records.hpp>
#include <components/widgets/list.hpp>
@ -458,7 +457,7 @@ namespace MWGui
void SpellCreationDialog::onOpen()
{
center();
MyGUI::InputManager::getInstance().setKeyFocusWidget(mNameEdit);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mNameEdit);
}
void SpellCreationDialog::onReferenceUnavailable ()

@ -94,7 +94,7 @@ namespace MWGui
// Reset the filter focus when opening the window
MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget();
if (focus == mFilterEdit)
MyGUI::InputManager::getInstance().resetKeyFocusWidget();
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(nullptr);
updateSpells();
}

@ -40,8 +40,8 @@ namespace MWGui
, mBounty(0)
, mSkillWidgets()
, mChanged(true)
, mMinFullWidth(mMainWidget->getSize().width)
{
setCoord(0,0,498, 342);
const char *names[][2] =
{
@ -88,8 +88,41 @@ namespace MWGui
void StatsWindow::onWindowResize(MyGUI::Window* window)
{
mLeftPane->setCoord( MyGUI::IntCoord(0, 0, static_cast<int>(0.44*window->getSize().width), window->getSize().height) );
mRightPane->setCoord( MyGUI::IntCoord(static_cast<int>(0.44*window->getSize().width), 0, static_cast<int>(0.56*window->getSize().width), window->getSize().height) );
int windowWidth = window->getSize().width;
int windowHeight = window->getSize().height;
//initial values defined in openmw_stats_window.layout, if custom options are not present in .layout, a default is loaded
float leftPaneRatio = 0.44;
if (mLeftPane->isUserString("LeftPaneRatio"))
leftPaneRatio = MyGUI::utility::parseFloat(mLeftPane->getUserString("LeftPaneRatio"));
int leftOffsetWidth = 24;
if (mLeftPane->isUserString("LeftOffsetWidth"))
leftOffsetWidth = MyGUI::utility::parseInt(mLeftPane->getUserString("LeftOffsetWidth"));
float rightPaneRatio = 1.f - leftPaneRatio;
int minLeftWidth = static_cast<int>(mMinFullWidth * leftPaneRatio);
int minLeftOffsetWidth = minLeftWidth + leftOffsetWidth;
//if there's no space for right pane
mRightPane->setVisible(windowWidth >= minLeftOffsetWidth);
if (!mRightPane->getVisible())
{
mLeftPane->setCoord(MyGUI::IntCoord(0, 0, windowWidth - leftOffsetWidth, windowHeight));
}
//if there's some space for right pane
else if (windowWidth < mMinFullWidth)
{
mLeftPane->setCoord(MyGUI::IntCoord(0, 0, minLeftWidth, windowHeight));
mRightPane->setCoord(MyGUI::IntCoord(minLeftWidth, 0, windowWidth - minLeftWidth, windowHeight));
}
//if there's enough space for both panes
else
{
mLeftPane->setCoord(MyGUI::IntCoord(0, 0, static_cast<int>(leftPaneRatio*windowWidth), windowHeight));
mRightPane->setCoord(MyGUI::IntCoord(static_cast<int>(leftPaneRatio*windowWidth), 0, static_cast<int>(rightPaneRatio*windowWidth), windowHeight));
}
// Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the scrollbar is hidden
mSkillView->setVisibleVScroll(false);
mSkillView->setCanvasSize (mSkillView->getWidth(), mSkillView->getCanvasSize().height);

@ -69,6 +69,7 @@ namespace MWGui
std::set<std::string> mExpelled;
bool mChanged;
const int mMinFullWidth;
protected:
virtual void onPinToggled();

@ -5,7 +5,6 @@
#include <MyGUI_EditBox.h>
#include <MyGUI_Button.h>
#include <MyGUI_InputManager.h>
namespace MWGui
{
@ -24,7 +23,7 @@ namespace MWGui
okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TextInputDialog::onOkClicked);
// Make sure the edit box has focus
MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mTextEdit);
}
void TextInputDialog::setNextButtonShow(bool shown)
@ -47,7 +46,7 @@ namespace MWGui
{
WindowModal::onOpen();
// Make sure the edit box has focus
MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mTextEdit);
}
// widget controls
@ -57,7 +56,7 @@ namespace MWGui
if (mTextEdit->getCaption() == "")
{
MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage37}");
MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget (mTextEdit);
}
else
eventDone(this);

@ -136,7 +136,7 @@ namespace MWGui
onFilterChanged(mFilterAll);
MyGUI::InputManager::getInstance().setKeyFocusWidget(mTotalBalance);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mTotalBalance);
}
void TradeWindow::onFrame(float dt)

@ -104,9 +104,9 @@ namespace MWGui
}
if (mUntilHealedButton->getVisible())
MyGUI::InputManager::getInstance().setKeyFocusWidget(mUntilHealedButton);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mUntilHealedButton);
else
MyGUI::InputManager::getInstance().setKeyFocusWidget(mWaitButton);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mWaitButton);
}
bool WaitDialog::exit()
@ -261,7 +261,7 @@ namespace MWGui
{
mHourText->setCaptionWithReplacing (MyGUI::utility::toString(position+1) + " #{sRestMenu2}");
mManualHours = position+1;
MyGUI::InputManager::getInstance().setKeyFocusWidget(mWaitButton);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mWaitButton);
}
void WaitDialog::onKeyButtonPressed(MyGUI::Widget *sender, MyGUI::KeyCode key, MyGUI::Char character)

@ -718,7 +718,7 @@ namespace MWGui
setCursorVisible(!gameMode);
if (gameMode)
MyGUI::InputManager::getInstance().resetKeyFocusWidget();
setKeyFocusWidget (nullptr);
// Icons of forced hidden windows are displayed
setMinimapVisibility((mAllowed & GW_Map) && (!mMap->pinned() || (mForceHidden & GW_Map)));
@ -1804,6 +1804,13 @@ namespace MWGui
}
}
// Remove this wrapper once onKeyFocusChanged call is rendered unnecessary
void WindowManager::setKeyFocusWidget(MyGUI::Widget *widget)
{
MyGUI::InputManager::getInstance().setKeyFocusWidget(widget);
onKeyFocusChanged(widget);
}
void WindowManager::onKeyFocusChanged(MyGUI::Widget *widget)
{
if (widget && widget->castType<MyGUI::EditBox>(false))
@ -1997,7 +2004,7 @@ namespace MWGui
sizeVideo(screenSize.width, screenSize.height);
MyGUI::Widget* oldKeyFocus = MyGUI::InputManager::getInstance().getKeyFocusWidget();
MyGUI::InputManager::getInstance().setKeyFocusWidget(mVideoWidget);
setKeyFocusWidget(mVideoWidget);
mVideoBackground->setVisible(true);
@ -2035,7 +2042,7 @@ namespace MWGui
MWBase::Environment::get().getSoundManager()->resumeSounds();
MyGUI::InputManager::getInstance().setKeyFocusWidget(oldKeyFocus);
setKeyFocusWidget(oldKeyFocus);
setCursorVisible(cursorWasVisible);

@ -147,6 +147,9 @@ namespace MWGui
/// (and will continually update the window while doing so)
virtual void playVideo(const std::string& name, bool allowSkipping);
/// Warning: do not use MyGUI::InputManager::setKeyFocusWidget directly. Instead use this.
virtual void setKeyFocusWidget (MyGUI::Widget* widget);
virtual void setNewGame(bool newgame);
virtual void pushGuiMode(GuiMode mode, const MWWorld::Ptr& arg);

@ -89,6 +89,7 @@ namespace MWInput
, mSneaking(false)
, mAttemptJump(false)
, mInvUiScalingFactor(1.f)
, mGamepadCursorSpeed(Settings::Manager::getFloat("gamepad cursor speed", "Input"))
, mFakeDeviceID(1)
{
mInputManager = new SDLUtil::InputWrapper(window, viewer, grab);
@ -570,9 +571,9 @@ namespace MWInput
// We keep track of our own mouse position, so that moving the mouse while in
// game mode does not move the position of the GUI cursor
float xmove = xAxis * dt * 1500.0f * mInvUiScalingFactor;
float ymove = yAxis * dt * 1500.0f * mInvUiScalingFactor;
if (xmove != 0|| ymove != 0)
float xmove = xAxis * dt * 1500.0f * mInvUiScalingFactor * mGamepadCursorSpeed;
float ymove = yAxis * dt * 1500.0f * mInvUiScalingFactor * mGamepadCursorSpeed;
if (xmove != 0|| ymove != 0 || zAxis != 0)
{
mGuiCursorX += xmove;
mGuiCursorY += ymove;
@ -635,11 +636,7 @@ namespace MWInput
mPlayer->setAutoMove (false);
mPlayer->setForwardBackward((yAxis - 0.5f) * 2 * -1);
}
else if(mPlayer->getAutoMove())
{
triedToMove = true;
mPlayer->setForwardBackward (1);
}
if (triedToMove)
mJoystickLastUsed = true;
@ -661,7 +658,8 @@ namespace MWInput
mPlayer->setAutoMove (false);
mPlayer->setForwardBackward (actionIsActive(A_MoveForward) ? 1 : -1);
}
else if(mPlayer->getAutoMove())
if (mPlayer->getAutoMove())
{
alwaysRunAllowed = true;
triedToMove = true;

@ -209,6 +209,7 @@ namespace MWInput
std::map<std::string, bool> mControlSwitch;
float mInvUiScalingFactor;
float mGamepadCursorSpeed;
private:
void convertMousePosForMyGUI(int& x, int& y);

@ -594,7 +594,7 @@ namespace MWMechanics
void Actors::adjustMagicEffects (const MWWorld::Ptr& creature)
{
CreatureStats& creatureStats = creature.getClass().getCreatureStats (creature);
if (creatureStats.isDead())
if (creatureStats.isDeathAnimationFinished())
return;
MagicEffects now = creatureStats.getSpells().getMagicEffects();
@ -1766,7 +1766,8 @@ namespace MWMechanics
else if (!isPlayer)
iter->first.getRefData().getBaseNode()->setNodeMask(MWRender::Mask_Actor);
if (iter->first.getClass().getCreatureStats(iter->first).isParalyzed())
const bool isDead = iter->first.getClass().getCreatureStats(iter->first).isDead();
if (!isDead && iter->first.getClass().getCreatureStats(iter->first).isParalyzed())
ctrl->skipAnim();
// Handle player last, in case a cell transition occurs by casting a teleportation spell
@ -1851,10 +1852,6 @@ namespace MWMechanics
stats.getActiveSpells().visitEffectSources(soulTrap);
}
// Reset magic effects and recalculate derived effects
// One case where we need this is to make sure bound items are removed upon death
stats.modifyMagicEffects(MWMechanics::MagicEffects());
stats.getActiveSpells().clear();
calculateCreatureStatModifiers(iter->first, 0);
if (cls.isEssential(iter->first))
@ -1896,6 +1893,10 @@ namespace MWMechanics
End of tes3mp addition
*/
// Reset magic effects and recalculate derived effects
// One case where we need this is to make sure bound items are removed upon death
stats.modifyMagicEffects(MWMechanics::MagicEffects());
stats.getActiveSpells().clear();
// Make sure spell effects are removed
purgeSpellEffects(stats.getActorId());

@ -129,6 +129,9 @@ namespace MWMechanics
|| target.getClass().getCreatureStats(target).isDead())
return true;
if (actor == target) // This should never happen.
return true;
if (!storage.isFleeing())
{
if (storage.mCurrentAction.get()) // need to wait to init action with its attack range

@ -422,6 +422,11 @@ namespace MWMechanics
return true;
}
if (actor.getClass().isPureLandCreature(actor) && MWBase::Environment::get().getWorld()->isWalkingOnWater(enemy))
{
return false;
}
if (actor.getClass().isPureFlyingCreature(actor) || actor.getClass().isPureLandCreature(actor))
{
if (MWBase::Environment::get().getWorld()->isSwimming(enemy))

@ -88,6 +88,7 @@ namespace MWMechanics
// that is the user's responsibility
MWBase::Environment::get().getWorld()->moveObject(actor, mX, mY, mZ);
actor.getClass().adjustPosition(actor, false);
reset();
}
void AiTravel::writeState(ESM::AiSequence::AiSequence &sequence) const

@ -527,7 +527,8 @@ namespace MWMechanics
if (greetingState == AiWanderStorage::Greet_None)
{
if ((playerPos - actorPos).length2() <= helloDistance*helloDistance &&
!player.getClass().getCreatureStats(player).isDead() && MWBase::Environment::get().getWorld()->getLOS(player, actor)
!player.getClass().getCreatureStats(player).isDead() && !actor.getClass().getCreatureStats(actor).isParalyzed()
&& MWBase::Environment::get().getWorld()->getLOS(player, actor)
&& MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, actor))
greetingTimer++;

@ -1013,7 +1013,6 @@ void CharacterController::handleTextKey(const std::string &groupname, const std:
if(evt.compare(0, 7, "sound: ") == 0)
{
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
sndMgr->stopSound3D(mPtr, evt.substr(7));
sndMgr->playSound3D(mPtr, evt.substr(7), 1.0f, 1.0f);
return;
}
@ -1054,7 +1053,6 @@ void CharacterController::handleTextKey(const std::string &groupname, const std:
}
else
{
sndMgr->stopSound3D(mPtr, sound);
sndMgr->playSound3D(mPtr, sound, volume, pitch);
}
}
@ -1165,8 +1163,8 @@ void CharacterController::updateIdleStormState(bool inwater)
{
if (!mAnimation->isPlaying("idlestorm"))
{
mAnimation->play("idlestorm", Priority_Storm, MWRender::Animation::BlendMask_RightArm, true,
1.0f, "start", "stop", 0.0f, ~0ul);
int mask = MWRender::Animation::BlendMask_Torso | MWRender::Animation::BlendMask_RightArm;
mAnimation->play("idlestorm", Priority_Storm, mask, true, 1.0f, "start", "stop", 0.0f, ~0ul);
}
else
{
@ -2791,7 +2789,7 @@ void CharacterController::updateContinuousVfx()
for (std::vector<int>::iterator it = effects.begin(); it != effects.end(); ++it)
{
if (mPtr.getClass().getCreatureStats(mPtr).isDead()
if (mPtr.getClass().getCreatureStats(mPtr).isDeathAnimationFinished()
|| mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(MWMechanics::EffectKey(*it)).getMagnitude() <= 0)
mAnimation->removeEffect(*it);
}
@ -2818,14 +2816,14 @@ void CharacterController::setVisibility(float visibility)
if (mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(ESM::MagicEffect::Invisibility).getModifier()) // Ignore base magnitude (see bug #3555).
{
if (mPtr == getPlayer())
alpha = 0.4f;
alpha = 0.25f;
else
alpha = 0.f;
alpha = 0.05f;
}
float chameleon = mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(ESM::MagicEffect::Chameleon).getMagnitude();
if (chameleon)
{
alpha *= std::max(0.2f, (100.f - chameleon)/100.f);
alpha *= std::min(0.75f, std::max(0.25f, (100.f - chameleon)/100.f));
}
visibility = std::min(visibility, alpha);

@ -154,16 +154,12 @@ namespace MWMechanics
End of tes3mp change (major)
*/
if (!(weapon.isEmpty() && !attacker.getClass().isNpc())) // Unarmed creature attacks don't affect armor condition
{
// Reduce shield durability by incoming damage
int shieldhealth = shield->getClass().getItemHealth(*shield);
shieldhealth -= std::min(shieldhealth, int(damage));
shield->getCellRef().setCharge(shieldhealth);
if (shieldhealth == 0)
inv.unequipItem(*shield, blocker);
}
// Reduce shield durability by incoming damage
int shieldhealth = shield->getClass().getItemHealth(*shield);
shieldhealth -= std::min(shieldhealth, int(damage));
shield->getCellRef().setCharge(shieldhealth);
if (shieldhealth == 0)
inv.unequipItem(*shield, blocker);
// Reduce blocker fatigue
const float fFatigueBlockBase = gmst.find("fFatigueBlockBase")->mValue.getFloat();
const float fFatigueBlockMult = gmst.find("fFatigueBlockMult")->mValue.getFloat();
@ -559,7 +555,7 @@ namespace MWMechanics
if(sound)
sndMgr->playSound3D(victim, sound->mId, 1.0f, 1.0f);
}
else
else if (!healthdmg)
sndMgr->playSound3D(victim, "Hand To Hand Hit", 1.0f, 1.0f);
}

@ -131,10 +131,7 @@ namespace MWMechanics
void Enchanting::nextCastStyle()
{
if (itemEmpty())
{
mCastStyle = ESM::Enchantment::WhenUsed;
return;
}
const bool powerfulSoul = getGemCharge() >= \
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find ("iSoulAmountForConstantEffect")->mValue.getInteger();
@ -296,6 +293,8 @@ namespace MWMechanics
void Enchanting::setEnchanter(const MWWorld::Ptr& enchanter)
{
mEnchanter = enchanter;
// Reset cast style
mCastStyle = ESM::Enchantment::CastOnce;
}
int Enchanting::getEnchantChance() const

@ -1740,18 +1740,28 @@ namespace MWMechanics
void MechanicsManager::startCombat(const MWWorld::Ptr &ptr, const MWWorld::Ptr &target)
{
MWMechanics::AiSequence& aiSequence = ptr.getClass().getCreatureStats(ptr).getAiSequence();
CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);
if (aiSequence.isInCombat(target))
// Don't add duplicate packages nor add packages to dead actors.
if (stats.isDead() || stats.getAiSequence().isInCombat(target))
return;
aiSequence.stack(MWMechanics::AiCombat(target), ptr);
// The target is somehow the same as the actor. Early-out.
if (ptr == target)
{
// We don't care about dialogue filters since the target is invalid.
// We still want to play the combat taunt.
MWBase::Environment::get().getDialogueManager()->say(ptr, "attack");
return;
}
stats.getAiSequence().stack(MWMechanics::AiCombat(target), ptr);
if (target == getPlayer())
{
// if guard starts combat with player, guards pursuing player should do the same
if (ptr.getClass().isClass(ptr, "Guard"))
{
ptr.getClass().getCreatureStats(ptr).setHitAttemptActorId(target.getClass().getCreatureStats(target).getActorId()); // Stops guard from ending combat if player is unreachable
stats.setHitAttemptActorId(target.getClass().getCreatureStats(target).getActorId()); // Stops guard from ending combat if player is unreachable
for (Actors::PtrActorMap::const_iterator iter = mActors.begin(); iter != mActors.end(); ++iter)
{
if (iter->first.getClass().isClass(iter->first, "Guard"))
@ -1769,8 +1779,7 @@ namespace MWMechanics
}
// Must be done after the target is set up, so that CreatureTargetted dialogue filter works properly
if (ptr.getClass().isNpc() && !ptr.getClass().getCreatureStats(ptr).isDead())
MWBase::Environment::get().getDialogueManager()->say(ptr, "attack");
MWBase::Environment::get().getDialogueManager()->say(ptr, "attack");
}
void MechanicsManager::getObjectsInRange(const osg::Vec3f &position, float radius, std::vector<MWWorld::Ptr> &objects)
@ -1869,8 +1878,8 @@ namespace MWMechanics
if (ptr.getClass().isNpc())
disposition = getDerivedDisposition(ptr, true);
int fight = std::max(0, ptr.getClass().getCreatureStats(ptr).getAiSetting(CreatureStats::AI_Fight).getModified()
+ static_cast<int>(getFightDistanceBias(ptr, target) + getFightDispositionBias(static_cast<float>(disposition))));
int fight = ptr.getClass().getCreatureStats(ptr).getAiSetting(CreatureStats::AI_Fight).getModified()
+ static_cast<int>(getFightDistanceBias(ptr, target) + getFightDispositionBias(static_cast<float>(disposition)));
if (ptr.getClass().isNpc() && target.getClass().isNpc())
{

@ -106,7 +106,7 @@ bool Objects::onOpen(const MWWorld::Ptr& ptr)
PtrControllerMap::iterator iter = mObjects.find(ptr);
if(iter != mObjects.end())
return iter->second->onOpen();
return false;
return true;
}
void Objects::onClose(const MWWorld::Ptr& ptr)

@ -951,21 +951,24 @@ namespace MWMechanics
if (item.getCellRef().getEnchantmentCharge() < castCost)
{
if (mCaster == getPlayer())
{
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicInsufficientCharge}");
// Failure sound
int school = 0;
if (!enchantment->mEffects.mList.empty())
{
short effectId = enchantment->mEffects.mList.front().mEffectID;
const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(effectId);
school = magicEffect->mData.mSchool;
// Failure sound
int school = 0;
if (!enchantment->mEffects.mList.empty())
{
short effectId = enchantment->mEffects.mList.front().mEffectID;
const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(effectId);
school = magicEffect->mData.mSchool;
}
static const std::string schools[] = {
"alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration"
};
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
sndMgr->playSound3D(mCaster, "Spell Failure " + schools[school], 1.0f, 1.0f);
}
static const std::string schools[] = {
"alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration"
};
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
sndMgr->playSound3D(mCaster, "Spell Failure " + schools[school], 1.0f, 1.0f);
return false;
}
// Reduce charge

@ -1215,21 +1215,29 @@ namespace MWScript
std::string targetId = ::Misc::StringUtils::lowerCase(runtime.getStringLiteral (runtime[0].mInteger));
runtime.pop();
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find (spellId);
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().search(spellId);
if (!spell)
{
runtime.getContext().report("spellcasting failed: can not find spell \""+spellId+"\"");
runtime.getContext().report("spellcasting failed: cannot find spell \""+spellId+"\"");
return;
}
if (spell->mData.mType != ESM::Spell::ST_Spell && spell->mData.mType != ESM::Spell::ST_Power)
{
runtime.getContext().report("spellcasting failed: you can cast only spells and powers.");
runtime.getContext().report("spellcasting failed: you can only cast spells and powers.");
return;
}
// Obviously we can not use casting animation for player here
if (ptr.getClass().isActor() && ptr != MWMechanics::getPlayer())
if (ptr == MWMechanics::getPlayer())
{
MWWorld::InventoryStore& store = ptr.getClass().getInventoryStore(ptr);
store.setSelectedEnchantItem(store.end());
MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, ptr)));
MWBase::Environment::get().getWindowManager()->updateSpellWindow();
return;
}
if (ptr.getClass().isActor())
{
MWMechanics::AiCast castPackage(targetId, spellId, true);
ptr.getClass().getCreatureStats (ptr).getAiSequence().stack(castPackage, ptr);

@ -747,6 +747,9 @@ namespace MWSound
void SoundManager::stopSound(const std::string& soundId)
{
if(!mOutput->isInitialized())
return;
Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId));
if (!sfx) return;
@ -755,6 +758,9 @@ namespace MWSound
void SoundManager::stopSound3D(const MWWorld::ConstPtr &ptr, const std::string& soundId)
{
if(!mOutput->isInitialized())
return;
Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId));
if (!sfx) return;

@ -169,8 +169,8 @@ void ESMStore::validate()
if (!fact)
{
Log(Debug::Verbose) << "NPC '" << npc.mId << "' (" << npc.mName << ") has nonexistent faction '" << npc.mFaction << "', ignoring it.";
npc.mFaction = "";
npc.mNpdt.mRank = -1;
npc.mFaction.clear();
npc.mNpdt.mRank = 0;
changed = true;
}
}

@ -3175,6 +3175,7 @@ namespace MWWorld
/// \note Using _any_ door pointed to the interior,
/// not the one pointed to current door.
pos = destDoor.mRef.getDoorDest();
pos.rot[0] = pos.rot[1] = pos.rot[2] = 0;
return true;
}
}
@ -3185,6 +3186,7 @@ namespace MWWorld
if (!statics.empty())
{
pos = statics.begin()->mRef.getPosition();
pos.rot[0] = pos.rot[1] = pos.rot[2] = 0;
return true;
}

@ -33,7 +33,7 @@ namespace Compiler
{
extensions.registerInstruction ("aiactivate", "c/l", opcodeAIActivate,
opcodeAIActivateExplicit);
extensions.registerInstruction ("aitravel", "fff/lx", opcodeAiTravel,
extensions.registerInstruction ("aitravel", "fff/zx", opcodeAiTravel,
opcodeAiTravelExplicit);
extensions.registerInstruction ("aiescort", "cffff/l", opcodeAiEscort,
opcodeAiEscortExplicit);
@ -340,7 +340,7 @@ namespace Compiler
extensions.registerFunction ("getmasserphase", 'l', "", opcodeGetMasserPhase);
extensions.registerFunction ("getsecundaphase", 'l', "", opcodeGetSecundaPhase);
extensions.registerFunction ("getcurrentweather", 'l', "", opcodeGetCurrentWeather);
extensions.registerInstruction ("modregion", "S/llllllllll", opcodeModRegion);
extensions.registerInstruction ("modregion", "S/llllllllllX", opcodeModRegion);
}
}

@ -428,7 +428,7 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path)
{
QFileInfo info(dir.absoluteFilePath(path2));
if (item(info.absoluteFilePath()) != 0)
if (item(info.fileName()))
continue;
try {

@ -16,7 +16,7 @@ struct CustomMarker
std::string mNote;
bool operator == (const CustomMarker& other)
bool operator == (const CustomMarker& other) const
{
return mNote == other.mNote && mCell == other.mCell && mWorldX == other.mWorldX && mWorldY == other.mWorldY;
}

@ -40,7 +40,7 @@ struct Clothing
int mType;
float mWeight;
unsigned short mValue;
short mEnchant;
unsigned short mEnchant;
};
CTDTstruct mData;

@ -59,7 +59,7 @@ struct Weapon
short mType;
unsigned short mHealth;
float mSpeed, mReach;
short mEnchant; // Enchantment points. The real value is mEnchant/10.f
unsigned short mEnchant; // Enchantment points. The real value is mEnchant/10.f
unsigned char mChop[2], mSlash[2], mThrust[2]; // Min and max
int mFlags;
}; // 32 bytes

@ -30,8 +30,8 @@ namespace Fallback
{
try
{
// We have to rely on Boost because std::stof from C++11
// uses the current locale for separators which we don't want and often silently ignores parsing errors.
// We have to rely on Boost because std::stof from C++11 uses the current locale
// for separators (which is undesired) and it often silently ignores parsing errors.
return boost::lexical_cast<float>(fallback);
}
catch (boost::bad_lexical_cast&)

@ -6,6 +6,7 @@
#include <unistd.h>
#include <boost/filesystem/fstream.hpp>
#include <components/debug/debuglog.hpp>
#include <components/misc/stringops.hpp>
@ -50,6 +51,9 @@ namespace Files
LinuxPath::LinuxPath(const std::string& application_name)
: mName(application_name)
{
boost::filesystem::path localPath = getLocalPath();
if (chdir(localPath.string().c_str()) != 0)
Log(Debug::Warning) << "Error " << errno << " when changing current directory";
}
boost::filesystem::path LinuxPath::getUserConfigPath() const
@ -75,7 +79,20 @@ boost::filesystem::path LinuxPath::getGlobalConfigPath() const
boost::filesystem::path LinuxPath::getLocalPath() const
{
return boost::filesystem::path("./");
boost::filesystem::path localPath("./");
std::string binPath(pathconf(".", _PC_PATH_MAX), '\0');
const char *statusPaths[] = {"/proc/self/exe", "/proc/self/file", "/proc/curproc/exe", "/proc/curproc/file"};
for(const char *path : statusPaths)
{
if (readlink(path, &binPath[0], binPath.size()) != -1)
{
localPath = boost::filesystem::path(binPath).parent_path();
break;
}
}
return localPath;
}
boost::filesystem::path LinuxPath::getGlobalDataPath() const

@ -9,11 +9,31 @@ namespace Files
struct MemBuf : std::streambuf
{
MemBuf(char const* buffer, size_t size)
{
// a streambuf isn't specific to istreams, so we need a non-const pointer :/
char* nonconstBuffer = (const_cast<char*>(buffer));
this->setg(nonconstBuffer, nonconstBuffer, nonconstBuffer + size);
: bufferStart(const_cast<char*>(buffer))
, bufferEnd(bufferStart + size)
{
this->setg(bufferStart, bufferStart, bufferEnd);
}
pos_type seekoff(off_type off, std::ios_base::seekdir dir, std::ios_base::openmode which) override
{
if (dir == std::ios_base::cur)
gbump(off);
else
setg(bufferStart, (dir == std::ios_base::beg ? bufferStart : bufferEnd) + off, bufferEnd);
return gptr() - bufferStart;
}
pos_type seekpos(pos_type pos, std::ios_base::openmode which) override
{
return seekoff(pos, std::ios_base::beg, which);
}
protected:
char* bufferStart;
char* bufferEnd;
};
/// @brief A variant of std::istream that reads from a constant in-memory buffer.

@ -11,6 +11,8 @@
#include <boost/locale.hpp>
namespace bconv = boost::locale::conv;
#include <components/debug/debuglog.hpp>
/**
* FIXME: Someone with Windows system should check this and correct if necessary
* FIXME: MAX_PATH is irrelevant for extended-length paths, i.e. \\?\...
@ -33,6 +35,10 @@ WindowsPath::WindowsPath(const std::string& application_name)
See boost::filesystem and boost::locale reference for details.
*/
boost::filesystem::path::imbue(boost::locale::generator().generate(""));
boost::filesystem::path localPath = getLocalPath();
if (!SetCurrentDirectoryA(localPath.string().c_str()))
Log(Debug::Warning) << "Error " << GetLastError() << " when changing current directory";
}
boost::filesystem::path WindowsPath::getUserConfigPath() const
@ -73,7 +79,17 @@ boost::filesystem::path WindowsPath::getGlobalConfigPath() const
boost::filesystem::path WindowsPath::getLocalPath() const
{
return boost::filesystem::path("./");
boost::filesystem::path localPath("./");
WCHAR path[MAX_PATH + 1];
memset(path, 0, sizeof(path));
if (GetModuleFileNameW(nullptr, path, MAX_PATH + 1) > 0)
{
localPath = boost::filesystem::path(bconv::utf_to_utf<char>(path)).parent_path();
}
// lookup exe path
return localPath;
}
boost::filesystem::path WindowsPath::getGlobalDataPath() const

@ -238,10 +238,12 @@ struct NiRotatingParticles : Node
// A node used as the base to switch between child nodes, such as for LOD levels.
struct NiSwitchNode : public NiNode
{
unsigned int initialIndex;
void read(NIFStream *nif)
{
NiNode::read(nif);
nif->getInt(); // unknown
initialIndex = nif->getUInt();
}
};

@ -400,7 +400,10 @@ namespace NifOsg
return;
}
osg::ref_ptr<osg::Texture2D> texture2d (new osg::Texture2D(handleSourceTexture(textureEffect->texture.getPtr(), imageManager)));
osg::ref_ptr<osg::Image> image (handleSourceTexture(textureEffect->texture.getPtr(), imageManager));
osg::ref_ptr<osg::Texture2D> texture2d (new osg::Texture2D(image));
if (image)
texture2d->setTextureSize(image->s(), image->t());
texture2d->setName("envMap");
unsigned int clamp = static_cast<unsigned int>(textureEffect->clamp);
int wrapT = (clamp) & 0x1;
@ -585,8 +588,11 @@ namespace NifOsg
{
const Nif::NiTriShape* triShape = static_cast<const Nif::NiTriShape*>(nifNode);
const std::string nodeName = Misc::StringUtils::lowerCase(triShape->name);
static const std::string pattern = "tri editormarker";
if (!hasMarkers || nodeName.compare(0, pattern.size(), pattern) != 0)
static const std::string markerName = "tri editormarker";
static const std::string shadowName = "shadow";
static const std::string shadowName2 = "tri shadow";
const bool isMarker = hasMarkers && !nodeName.compare(0, markerName.size(), markerName);
if (!isMarker && nodeName.compare(0, shadowName.size(), shadowName) && nodeName.compare(0, shadowName2.size(), shadowName2))
{
if (triShape->skin.empty())
handleTriShape(triShape, node, composite, boundTextures, animflags);
@ -629,10 +635,8 @@ namespace NifOsg
if (nifNode->recType == Nif::RC_NiSwitchNode)
{
// show only first child by default
node->asSwitch()->setSingleChildOn(0);
const Nif::NiSwitchNode* niSwitchNode = static_cast<const Nif::NiSwitchNode*>(nifNode);
node->asSwitch()->setSingleChildOn(niSwitchNode->initialIndex);
if (niSwitchNode->name == Constants::NightDayLabel && !SceneUtil::hasUserDescription(rootNode, Constants::NightDayLabel))
rootNode->getOrCreateUserDataContainer()->addDescription(Constants::NightDayLabel);
else if (niSwitchNode->name == Constants::HerbalismLabel && !SceneUtil::hasUserDescription(rootNode, Constants::HerbalismLabel))
@ -770,7 +774,10 @@ namespace NifOsg
wrapT = inherit->getWrap(osg::Texture2D::WRAP_T);
}
osg::ref_ptr<osg::Texture2D> texture (new osg::Texture2D(handleSourceTexture(st.getPtr(), imageManager)));
osg::ref_ptr<osg::Image> image (handleSourceTexture(st.getPtr(), imageManager));
osg::ref_ptr<osg::Texture2D> texture (new osg::Texture2D(image));
if (image)
texture->setTextureSize(image->s(), image->t());
texture->setWrap(osg::Texture::WRAP_S, wrapS);
texture->setWrap(osg::Texture::WRAP_T, wrapT);
textures.push_back(texture);
@ -1337,6 +1344,8 @@ namespace NifOsg
const Nif::NiSourceTexture *st = tex.texture.getPtr();
osg::ref_ptr<osg::Image> image = handleSourceTexture(st, imageManager);
texture2d = new osg::Texture2D(image);
if (image)
texture2d->setTextureSize(image->s(), image->t());
}
else
texture2d = new osg::Texture2D;

@ -1802,12 +1802,11 @@ bool Optimizer::MergeGeometryVisitor::mergePrimitive(osg::DrawElementsUInt& lhs,
bool Optimizer::MergeGroupsVisitor::isOperationPermissible(osg::Group& node)
{
return !node.asSwitch() &&
!node.asTransform() &&
!node.getCullCallback() &&
return !node.getCullCallback() &&
!node.getEventCallback() &&
!node.getUpdateCallback() &&
isOperationPermissibleForObject(&node);
isOperationPermissibleForObject(&node) &&
typeid(node)==typeid(osg::Group);
}
void Optimizer::MergeGroupsVisitor::apply(osg::LOD &lod)

@ -7,6 +7,7 @@
#include <boost/filesystem/fstream.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
namespace Settings
{
@ -354,12 +355,14 @@ float Manager::getFloat (const std::string& setting, const std::string& category
const std::string value = getString(setting, category);
try
{
return std::stof(value);
// We have to rely on Boost because std::stof from C++11 uses the current locale
// for separators (which is undesired) and it often silently ignores parsing errors.
return boost::lexical_cast<float>(value);
}
catch(const std::exception& e)
catch (boost::bad_lexical_cast&)
{
Log(Debug::Warning) << "Cannot parse setting '" << setting << "' (invalid setting value: " << value << ").";
return 0;
return 0.f;
}
}
@ -401,12 +404,16 @@ void Manager::setString(const std::string &setting, const std::string &category,
void Manager::setInt (const std::string& setting, const std::string& category, const int value)
{
setString(setting, category, std::to_string(value));
std::ostringstream stream;
stream << value;
setString(setting, category, stream.str());
}
void Manager::setFloat (const std::string &setting, const std::string &category, const float value)
{
setString(setting, category, std::to_string(value));
std::ostringstream stream;
stream << value;
setString(setting, category, stream.str());
}
void Manager::setBool(const std::string &setting, const std::string &category, const bool value)

@ -163,6 +163,7 @@ namespace Shader
if (image)
{
osg::ref_ptr<osg::Texture2D> normalMapTex (new osg::Texture2D(image));
normalMapTex->setTextureSize(image->s(), image->t());
normalMapTex->setWrap(osg::Texture::WRAP_S, diffuseMap->getWrap(osg::Texture::WRAP_S));
normalMapTex->setWrap(osg::Texture::WRAP_T, diffuseMap->getWrap(osg::Texture::WRAP_T));
normalMapTex->setFilter(osg::Texture::MIN_FILTER, diffuseMap->getFilter(osg::Texture::MIN_FILTER));
@ -186,7 +187,9 @@ namespace Shader
boost::replace_last(specularMapFileName, ".", mSpecularMapPattern + ".");
if (mImageManager.getVFS()->exists(specularMapFileName))
{
osg::ref_ptr<osg::Texture2D> specularMapTex (new osg::Texture2D(mImageManager.getImage(specularMapFileName)));
osg::ref_ptr<osg::Image> image (mImageManager.getImage(specularMapFileName));
osg::ref_ptr<osg::Texture2D> specularMapTex (new osg::Texture2D(image));
specularMapTex->setTextureSize(image->s(), image->t());
specularMapTex->setWrap(osg::Texture::WRAP_S, diffuseMap->getWrap(osg::Texture::WRAP_S));
specularMapTex->setWrap(osg::Texture::WRAP_T, diffuseMap->getWrap(osg::Texture::WRAP_T));
specularMapTex->setFilter(osg::Texture::MIN_FILTER, diffuseMap->getFilter(osg::Texture::MIN_FILTER));

@ -53,7 +53,7 @@ It is also possible to attach opening/closing sounds to container's animations:
::
1.0: ContainerClose: open
1.0: ContainerClose: start
1.01: Sound: AC_dw_drawer_close
2.0: ContainerClose: stop

@ -133,3 +133,16 @@ which are always sent if a controller is present and detected.
Disabling this setting can be useful for working around controller-related issues or for setting up split-screen gameplay configurations.
This setting can be toggled in game with the Enable Joystick button in the Controls panel of the Options menu.
gamepad cursor speed
--------------------
:Type: float
:Range: >0
:Default: 1.0
This setting controls the speed of the cursor within GUI mode when using the joystick.
This setting has no effect on the camera rotation speed, which is controlled by the
camera sensitivity setting.
This setting can only be configured by editing the settings configuration file.

@ -140,7 +140,7 @@ framerate limit
:Type: floating point
:Range: >= 0.0
:Default: 0.0
:Default: 300
This setting determines the maximum frame rate in frames per second.
If this setting is 0.0, the frame rate is unlimited.
@ -159,8 +159,6 @@ in the sense that enabling vertical sync limits the frame rate to the refresh ra
Choosing to limit the frame rate using this setting instead of vsync may reduce input lag
due to the game not having to wait for the vertical blanking interval.
This setting can only be configured by editing the settings configuration file.
contrast
--------

@ -19,6 +19,11 @@
<Child type="Button" skin="MW_Box" offset="18 0 54 14" align="Stretch" name="Background"/>
<!-- These are only provided to get mouse input, they should have no skin and be transparent -->
<Child type="Button" skin="MW_ScrollEmptyPart" offset="14 0 24 14" align="Top HStretch" name="FirstPart"/>
<Child type="Button" skin="MW_ScrollEmptyPart" offset="52 0 24 14" align="Top HStretch" name="SecondPart"/>
<!-- Arrows -->
<Child type="Widget" skin="MW_Box" offset="0 0 15 14" align="Left VStretch"/>
@ -27,11 +32,6 @@
<Child type="Widget" skin="MW_Box" offset="75 0 15 14" align="Right VStretch"/>
<Child type="Button" skin="MW_ArrowRight" offset="77 2 10 10" align="Right VStretch" name="End"/>
<!-- These are only provided to get mouse input, they should have no skin and be transparent -->
<Child type="Button" skin="MW_ScrollEmptyPart" offset="14 0 24 14" align="Top HStretch" name="FirstPart"/>
<Child type="Button" skin="MW_ScrollEmptyPart" offset="52 0 24 14" align="Top HStretch" name="SecondPart"/>
<Child type="Button" skin="MW_ScrollTrackH" offset="38 2 30 9" align="Left VStretch" name="Track"/>
</Resource>
@ -61,6 +61,11 @@
<Child type="Button" skin="MW_Box" offset="0 18 14 55" align="Stretch" name="Background"/>
<!-- These are only provided to get mouse input, they should have no skin and be transparent -->
<Child type="Button" skin="MW_ScrollEmptyPart" offset="0 14 24 14" align="Left VStretch" name="FirstPart"/>
<Child type="Button" skin="MW_ScrollEmptyPart" offset="0 52 24 14" align="Left VStretch" name="SecondPart"/>
<!-- Arrows -->
<Child type="Widget" skin="MW_Box" offset="0 0 14 15" align="Top HStretch"/>
@ -69,11 +74,6 @@
<Child type="Widget" skin="MW_Box" offset="0 76 14 15" align="Bottom HStretch"/>
<Child type="Button" skin="MW_ArrowDown" offset="2 78 10 10" align="Bottom HStretch" name="End"/>
<!-- These are only provided to get mouse input, they should have no skin and be transparent -->
<Child type="Button" skin="MW_ScrollEmptyPart" offset="0 14 24 14" align="Left VStretch" name="FirstPart"/>
<Child type="Button" skin="MW_ScrollEmptyPart" offset="0 52 24 14" align="Left VStretch" name="SecondPart"/>
<!-- Tracker must be last to be on top and receive mouse events -->
<Child type="Button" skin="MW_ScrollTrackV" offset="2 40 9 30" align="Top HStretch" name="Track"/>

@ -2,9 +2,10 @@
<MyGUI type="Layout">
<Widget type="Window" skin="MW_Window_Pinnable" layer="Windows" position="0 0 500 342" name="_Main">
<Property key="MinSize" value="40 40"/>
<Property key="MinSize" value="244 114"/>
<Widget type="Widget" skin="" name="LeftPane" position="0 0 220 342">
<UserString key="LeftOffsetWidth" value="24"/>
<UserString key="LeftPaneRatio" value="0.44"/>
<!-- Player health stats -->
<Widget type="Widget" skin="MW_Box" position="8 8 212 62" align="Left Top HStretch">

@ -364,6 +364,9 @@ invert y axis = false
# Enable controller support.
enable controller = true
# Emulated gamepad cursor sensitivity.
gamepad cursor speed = 1.0
[Saves]
# Name of last character played, and default for loading save files.
@ -442,7 +445,7 @@ antialiasing = 0
vsync = false
# Maximum frames per second. 0.0 is unlimited, or >0.0 to limit.
framerate limit = 0.0
framerate limit = 300
# Game video contrast. (>0.0). No effect in Linux.
contrast = 1.0

@ -34,7 +34,7 @@
<item row="2" column="0">
<widget class="QCheckBox" name="windowBorderCheckBox">
<property name="text">
<string>Window border</string>
<string>Window Border</string>
</property>
</widget>
</item>
@ -62,6 +62,13 @@
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QCheckBox" name="framerateLimitCheckBox">
<property name="text">
<string>Framerate Limit:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="antiAliasingComboBox">
<item>
@ -143,6 +150,31 @@
</item>
</layout>
</item>
<item row="6" column="1">
<widget class="QDoubleSpinBox" name="framerateLimitSpinBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="suffix">
<string> FPS</string>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="minimum">
<double>1</double>
</property>
<property name="maximum">
<double>1000</double>
</property>
<property name="singleStep">
<double>15</double>
</property>
<property name="value">
<double>300</double>
</property>
</widget>
</item>
</layout>
</widget>
</item>

Loading…
Cancel
Save