1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-02-21 11:39:44 +00:00

Merge branch 'master' of github.com:OpenMW/openmw

This commit is contained in:
Bret Curtis 2020-07-26 11:54:51 +02:00
commit 584fcd4716
19 changed files with 945 additions and 744 deletions

View file

@ -48,9 +48,11 @@
Feature #5445: Handle NiLines
Feature #5457: Realistic diagonal movement
Feature #5486: Fixes trainers to choose their training skills based on their base skill points
Feature #5519: Code Patch tab in launcher
Feature #5524: Resume failed script execution after reload
Feature #5525: Search fields tweaks (utf-8)
Task #5480: Drop Qt4 support
Task #5520: Improve cell name autocompleter implementation
0.46.0
------

View file

@ -4,9 +4,43 @@
#include <components/config/launchersettings.hpp>
#include <QFileDialog>
#include <QCompleter>
#include <QProxyStyle>
#include <components/contentselector/view/contentselector.hpp>
#include <components/contentselector/model/esmfile.hpp>
#include <cmath>
class HorizontalTextWestTabStyle : public QProxyStyle
{
public:
QSize sizeFromContents(ContentsType type, const QStyleOption* option, const QSize& size, const QWidget* widget) const
{
QSize s = QProxyStyle::sizeFromContents(type, option, size, widget);
if (type == QStyle::CT_TabBarTab)
{
s.transpose();
s.setHeight(s.height() + 20);
}
return s;
}
void drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const
{
if (element == CE_TabBarTabLabel)
{
if (const QStyleOptionTab* tab = qstyleoption_cast<const QStyleOptionTab*>(option))
{
QStyleOptionTab opt(*tab);
opt.shape = QTabBar::RoundedNorth;
QProxyStyle::drawControl(element, &opt, painter, widget);
return;
}
}
QProxyStyle::drawControl(element, option, painter, widget);
}
};
Launcher::AdvancedPage::AdvancedPage(Files::ConfigurationManager &cfg,
Config::GameSettings &gameSettings,
Settings::Manager &engineSettings, QWidget *parent)
@ -19,15 +53,16 @@ Launcher::AdvancedPage::AdvancedPage(Files::ConfigurationManager &cfg,
setupUi(this);
loadSettings();
AdvancedTabWidget->tabBar()->setStyle(new HorizontalTextWestTabStyle);
mCellNameCompleter.setModel(&mCellNameCompleterModel);
startDefaultCharacterAtField->setCompleter(&mCellNameCompleter);
}
void Launcher::AdvancedPage::loadCellsForAutocomplete(QStringList cellNames) {
// Set up an auto-completer for the "Start default character at" field
auto *completer = new QCompleter(cellNames);
completer->setCompletionMode(QCompleter::PopupCompletion);
completer->setCaseSensitivity(Qt::CaseSensitivity::CaseInsensitive);
startDefaultCharacterAtField->setCompleter(completer);
// Update the list of suggestions for the "Start default character at" field
mCellNameCompleterModel.setStringList(cellNames);
mCellNameCompleter.setCompletionMode(QCompleter::PopupCompletion);
mCellNameCompleter.setCaseSensitivity(Qt::CaseSensitivity::CaseInsensitive);
}
void Launcher::AdvancedPage::on_skipMenuCheckBox_stateChanged(int state) {
@ -55,33 +90,44 @@ void Launcher::AdvancedPage::on_runScriptAfterStartupBrowseButton_clicked()
runScriptAfterStartupField->setText(path);
}
namespace
{
constexpr double CellSizeInUnits = 8192;
double convertToCells(double unitRadius)
{
return std::round((unitRadius / 0.93 + 1024) / CellSizeInUnits);
}
double convertToUnits(double CellGridRadius)
{
return (CellSizeInUnits * CellGridRadius - 1024) * 0.93;
}
}
bool Launcher::AdvancedPage::loadSettings()
{
// Testing
bool skipMenu = mGameSettings.value("skip-menu").toInt() == 1;
if (skipMenu) {
skipMenuCheckBox->setCheckState(Qt::Checked);
}
startDefaultCharacterAtLabel->setEnabled(skipMenu);
startDefaultCharacterAtField->setEnabled(skipMenu);
startDefaultCharacterAtField->setText(mGameSettings.value("start"));
runScriptAfterStartupField->setText(mGameSettings.value("script-run"));
// Game Settings
// Game mechanics
{
loadSettingBool(toggleSneakCheckBox, "toggle sneak", "Input");
loadSettingBool(canLootDuringDeathAnimationCheckBox, "can loot during death animation", "Game");
loadSettingBool(followersAttackOnSightCheckBox, "followers attack on sight", "Game");
loadSettingBool(preventMerchantEquippingCheckBox, "prevent merchant equipping", "Game");
loadSettingBool(classicReflectedAbsorbSpellsCheckBox, "classic reflected absorb spells behavior", "Game");
loadSettingBool(rebalanceSoulGemValuesCheckBox, "rebalance soul gem values", "Game");
loadSettingBool(enchantedWeaponsMagicalCheckBox, "enchanted weapons are magical", "Game");
loadSettingBool(permanentBarterDispositionChangeCheckBox, "barter disposition change is permanent", "Game");
loadSettingBool(classicReflectedAbsorbSpellsCheckBox, "classic reflected absorb spells behavior", "Game");
loadSettingBool(requireAppropriateAmmunitionCheckBox, "only appropriate ammunition bypasses resistance", "Game");
loadSettingBool(uncappedDamageFatigueCheckBox, "uncapped damage fatigue", "Game");
loadSettingBool(normaliseRaceSpeedCheckBox, "normalise race speed", "Game");
int unarmedFactorsStrengthIndex = mEngineSettings.getInt("strength influences hand to hand", "Game");
if (unarmedFactorsStrengthIndex >= 0 && unarmedFactorsStrengthIndex <= 2)
unarmedFactorsStrengthComboBox->setCurrentIndex(unarmedFactorsStrengthIndex);
loadSettingBool(requireAppropriateAmmunitionCheckBox, "only appropriate ammunition bypasses resistance", "Game");
}
// Visuals
{
loadSettingBool(bumpMapLocalLightingCheckBox, "apply lighting to environment maps", "Shaders");
loadSettingBool(magicItemAnimationsCheckBox, "use magic item animations", "Game");
loadSettingBool(normaliseRaceSpeedCheckBox, "normalise race speed", "Game");
connect(animSourcesCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotAnimSourcesToggled(bool)));
loadSettingBool(animSourcesCheckBox, "use additional anim sources", "Game");
if (animSourcesCheckBox->checkState())
@ -89,18 +135,21 @@ bool Launcher::AdvancedPage::loadSettings()
loadSettingBool(weaponSheathingCheckBox, "weapon sheathing", "Game");
loadSettingBool(shieldSheathingCheckBox, "shield sheathing", "Game");
}
loadSettingBool(uncappedDamageFatigueCheckBox, "uncapped damage fatigue", "Game");
loadSettingBool(trainersTrainingSkillsBasedOnBaseSkillCheckBox, "trainers training skills based on base skill", "Game");
loadSettingBool(viewOverShoulderCheckBox, "view over shoulder", "Camera");
loadSettingBool(turnToMovementDirectionCheckBox, "turn to movement direction", "Game");
// Input Settings
loadSettingBool(grabCursorCheckBox, "grab cursor", "Input");
loadSettingBool(toggleSneakCheckBox, "toggle sneak", "Input");
const bool distantTerrain = mEngineSettings.getBool("distant terrain", "Terrain");
const bool objectPaging = mEngineSettings.getBool("object paging", "Terrain");
if (distantTerrain && objectPaging) {
distantLandCheckBox->setCheckState(Qt::Checked);
}
// Saves Settings
loadSettingBool(timePlayedCheckbox, "timeplayed", "Saves");
maximumQuicksavesComboBox->setValue(mEngineSettings.getInt("max quicksaves", "Saves"));
loadSettingBool(activeGridObjectPagingCheckBox, "object paging active grid", "Terrain");
viewingDistanceComboBox->setValue(convertToCells(mEngineSettings.getInt("viewing distance", "Camera")));
}
// User Interface Settings
// Interface Changes
{
loadSettingBool(showEffectDurationCheckBox, "show effect duration", "Game");
loadSettingBool(showEnchantChanceCheckBox, "show enchant chance", "Game");
loadSettingBool(showMeleeInfoCheckBox, "show melee info", "Game");
@ -110,66 +159,92 @@ bool Launcher::AdvancedPage::loadSettings()
// Match the index with the option (only 0, 1, 2, or 3 are valid). Will default to 0 if invalid.
if (showOwnedIndex >= 0 && showOwnedIndex <= 3)
showOwnedComboBox->setCurrentIndex(showOwnedIndex);
}
// Bug fixes
{
loadSettingBool(preventMerchantEquippingCheckBox, "prevent merchant equipping", "Game");
loadSettingBool(trainersTrainingSkillsBasedOnBaseSkillCheckBox, "trainers training skills based on base skill", "Game");
}
// Miscellaneous
{
// Saves
loadSettingBool(timePlayedCheckbox, "timeplayed", "Saves");
maximumQuicksavesComboBox->setValue(mEngineSettings.getInt("max quicksaves", "Saves"));
// Other Settings
QString screenshotFormatString = QString::fromStdString(mEngineSettings.getString("screenshot format", "General")).toUpper();
if (screenshotFormatComboBox->findText(screenshotFormatString) == -1)
screenshotFormatComboBox->addItem(screenshotFormatString);
screenshotFormatComboBox->setCurrentIndex(screenshotFormatComboBox->findText(screenshotFormatString));
}
// Testing
{
loadSettingBool(grabCursorCheckBox, "grab cursor", "Input");
bool skipMenu = mGameSettings.value("skip-menu").toInt() == 1;
if (skipMenu)
{
skipMenuCheckBox->setCheckState(Qt::Checked);
}
startDefaultCharacterAtLabel->setEnabled(skipMenu);
startDefaultCharacterAtField->setEnabled(skipMenu);
startDefaultCharacterAtField->setText(mGameSettings.value("start"));
runScriptAfterStartupField->setText(mGameSettings.value("script-run"));
}
return true;
}
void Launcher::AdvancedPage::saveSettings()
{
// Ensure we only set the new settings if they changed. This is to avoid cluttering the
// user settings file (which by definition should only contain settings the user has touched)
// Testing
int skipMenu = skipMenuCheckBox->checkState() == Qt::Checked;
if (skipMenu != mGameSettings.value("skip-menu").toInt())
mGameSettings.setValue("skip-menu", QString::number(skipMenu));
QString startCell = startDefaultCharacterAtField->text();
if (startCell != mGameSettings.value("start")) {
mGameSettings.setValue("start", startCell);
}
QString scriptRun = runScriptAfterStartupField->text();
if (scriptRun != mGameSettings.value("script-run"))
mGameSettings.setValue("script-run", scriptRun);
// Game Settings
// Game mechanics
{
saveSettingBool(toggleSneakCheckBox, "toggle sneak", "Input");
saveSettingBool(canLootDuringDeathAnimationCheckBox, "can loot during death animation", "Game");
saveSettingBool(followersAttackOnSightCheckBox, "followers attack on sight", "Game");
saveSettingBool(preventMerchantEquippingCheckBox, "prevent merchant equipping", "Game");
saveSettingBool(rebalanceSoulGemValuesCheckBox, "rebalance soul gem values", "Game");
saveSettingBool(classicReflectedAbsorbSpellsCheckBox, "classic reflected absorb spells behavior", "Game");
saveSettingBool(enchantedWeaponsMagicalCheckBox, "enchanted weapons are magical", "Game");
saveSettingBool(permanentBarterDispositionChangeCheckBox, "barter disposition change is permanent", "Game");
saveSettingBool(classicReflectedAbsorbSpellsCheckBox, "classic reflected absorb spells behavior", "Game");
saveSettingBool(requireAppropriateAmmunitionCheckBox, "only appropriate ammunition bypasses resistance", "Game");
saveSettingBool(uncappedDamageFatigueCheckBox, "uncapped damage fatigue", "Game");
saveSettingBool(normaliseRaceSpeedCheckBox, "normalise race speed", "Game");
int unarmedFactorsStrengthIndex = unarmedFactorsStrengthComboBox->currentIndex();
if (unarmedFactorsStrengthIndex != mEngineSettings.getInt("strength influences hand to hand", "Game"))
mEngineSettings.setInt("strength influences hand to hand", "Game", unarmedFactorsStrengthIndex);
saveSettingBool(requireAppropriateAmmunitionCheckBox, "only appropriate ammunition bypasses resistance", "Game");
}
// Visuals
{
saveSettingBool(bumpMapLocalLightingCheckBox, "apply lighting to environment maps", "Shaders");
saveSettingBool(magicItemAnimationsCheckBox, "use magic item animations", "Game");
saveSettingBool(normaliseRaceSpeedCheckBox, "normalise race speed", "Game");
saveSettingBool(animSourcesCheckBox, "use additional anim sources", "Game");
saveSettingBool(weaponSheathingCheckBox, "weapon sheathing", "Game");
saveSettingBool(shieldSheathingCheckBox, "shield sheathing", "Game");
saveSettingBool(uncappedDamageFatigueCheckBox, "uncapped damage fatigue", "Game");
saveSettingBool(trainersTrainingSkillsBasedOnBaseSkillCheckBox, "trainers training skills based on base skill", "Game");
saveSettingBool(viewOverShoulderCheckBox, "view over shoulder", "Camera");
saveSettingBool(turnToMovementDirectionCheckBox, "turn to movement direction", "Game");
// Input Settings
saveSettingBool(grabCursorCheckBox, "grab cursor", "Input");
saveSettingBool(toggleSneakCheckBox, "toggle sneak", "Input");
// Saves Settings
saveSettingBool(timePlayedCheckbox, "timeplayed", "Saves");
int maximumQuicksaves = maximumQuicksavesComboBox->value();
if (maximumQuicksaves != mEngineSettings.getInt("max quicksaves", "Saves")) {
mEngineSettings.setInt("max quicksaves", "Saves", maximumQuicksaves);
const bool distantTerrain = mEngineSettings.getBool("distant terrain", "Terrain");
const bool objectPaging = mEngineSettings.getBool("object paging", "Terrain");
const bool wantDistantLand = distantLandCheckBox->checkState();
if (wantDistantLand != (distantTerrain && objectPaging)) {
mEngineSettings.setBool("distant terrain", "Terrain", wantDistantLand);
mEngineSettings.setBool("object paging", "Terrain", wantDistantLand);
}
// User Interface Settings
saveSettingBool(activeGridObjectPagingCheckBox, "object paging active grid", "Terrain");
double viewingDistance = viewingDistanceComboBox->value();
if (viewingDistance != convertToCells(mEngineSettings.getInt("viewing distance", "Camera")))
{
mEngineSettings.setInt("viewing distance", "Camera", convertToUnits(viewingDistance));
}
}
// Interface Changes
{
saveSettingBool(showEffectDurationCheckBox, "show effect duration", "Game");
saveSettingBool(showEnchantChanceCheckBox, "show enchant chance", "Game");
saveSettingBool(showMeleeInfoCheckBox, "show melee info", "Game");
@ -178,6 +253,23 @@ void Launcher::AdvancedPage::saveSettings()
int showOwnedCurrentIndex = showOwnedComboBox->currentIndex();
if (showOwnedCurrentIndex != mEngineSettings.getInt("show owned", "Game"))
mEngineSettings.setInt("show owned", "Game", showOwnedCurrentIndex);
}
// Bug fixes
{
saveSettingBool(preventMerchantEquippingCheckBox, "prevent merchant equipping", "Game");
saveSettingBool(trainersTrainingSkillsBasedOnBaseSkillCheckBox, "trainers training skills based on base skill", "Game");
}
// Miscellaneous
{
// Saves Settings
saveSettingBool(timePlayedCheckbox, "timeplayed", "Saves");
int maximumQuicksaves = maximumQuicksavesComboBox->value();
if (maximumQuicksaves != mEngineSettings.getInt("max quicksaves", "Saves"))
{
mEngineSettings.setInt("max quicksaves", "Saves", maximumQuicksaves);
}
// Other Settings
std::string screenshotFormatString = screenshotFormatComboBox->currentText().toLower().toStdString();
@ -185,12 +277,33 @@ void Launcher::AdvancedPage::saveSettings()
mEngineSettings.setString("screenshot format", "General", screenshotFormatString);
}
void Launcher::AdvancedPage::loadSettingBool(QCheckBox *checkbox, const std::string &setting, const std::string &group) {
// Testing
{
saveSettingBool(grabCursorCheckBox, "grab cursor", "Input");
int skipMenu = skipMenuCheckBox->checkState() == Qt::Checked;
if (skipMenu != mGameSettings.value("skip-menu").toInt())
mGameSettings.setValue("skip-menu", QString::number(skipMenu));
QString startCell = startDefaultCharacterAtField->text();
if (startCell != mGameSettings.value("start"))
{
mGameSettings.setValue("start", startCell);
}
QString scriptRun = runScriptAfterStartupField->text();
if (scriptRun != mGameSettings.value("script-run"))
mGameSettings.setValue("script-run", scriptRun);
}
}
void Launcher::AdvancedPage::loadSettingBool(QCheckBox *checkbox, const std::string &setting, const std::string &group)
{
if (mEngineSettings.getBool(setting, group))
checkbox->setCheckState(Qt::Checked);
}
void Launcher::AdvancedPage::saveSettingBool(QCheckBox *checkbox, const std::string &setting, const std::string &group) {
void Launcher::AdvancedPage::saveSettingBool(QCheckBox *checkbox, const std::string &setting, const std::string &group)
{
bool cValue = checkbox->checkState();
if (cValue != mEngineSettings.getBool(setting, group))
mEngineSettings.setBool(setting, group, cValue);

View file

@ -2,6 +2,8 @@
#define ADVANCEDPAGE_H
#include <QWidget>
#include <QCompleter>
#include <QStringListModel>
#include "ui_advancedpage.h"
@ -35,6 +37,8 @@ namespace Launcher
Files::ConfigurationManager &mCfgMgr;
Config::GameSettings &mGameSettings;
Settings::Manager &mEngineSettings;
QCompleter mCellNameCompleter;
QStringListModel mCellNameCompleterModel;
/**
* Load the cells associated with the given content files for use in autocomplete

View file

@ -60,13 +60,14 @@ bool MWMechanics::AiAvoidDoor::execute (const MWWorld::Ptr& actor, CharacterCont
// Make all nearby actors also avoid the door
std::vector<MWWorld::Ptr> actors;
MWBase::Environment::get().getMechanicsManager()->getActorsInRange(pos.asVec3(),100,actors);
for(std::vector<MWWorld::Ptr>::iterator it = actors.begin(); it != actors.end(); ++it) {
if(*it != getPlayer()) { //Not the player
MWMechanics::AiSequence& seq = it->getClass().getCreatureStats(*it).getAiSequence();
if(seq.getTypeId() != MWMechanics::AiPackageTypeId::AvoidDoor) { //Only add it once
seq.stack(MWMechanics::AiAvoidDoor(mDoorPtr),*it);
}
}
for(auto& actor : actors)
{
if (actor == getPlayer())
continue;
MWMechanics::AiSequence& seq = actor.getClass().getCreatureStats(actor).getAiSequence();
if (seq.getTypeId() != MWMechanics::AiPackageTypeId::AvoidDoor)
seq.stack(MWMechanics::AiAvoidDoor(mDoorPtr), actor);
}
return false;

View file

@ -124,9 +124,9 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characte
followDistance = 313;
short i = 0;
followers.sort();
for (std::list<int>::iterator it = followers.begin(); it != followers.end(); ++it)
for (int followIndex : followers)
{
if (*it == mFollowIndex)
if (followIndex == mFollowIndex)
followDistance += 130 * i;
++i;
}

View file

@ -406,36 +406,36 @@ void AiSequence::fill(const ESM::AIPackageList &list)
if (!list.mList.empty() && list.mList.begin() != (list.mList.end()-1))
mRepeat = true;
for (std::vector<ESM::AIPackage>::const_iterator it = list.mList.begin(); it != list.mList.end(); ++it)
for (const auto& esmPackage : list.mList)
{
std::unique_ptr<MWMechanics::AiPackage> package;
if (it->mType == ESM::AI_Wander)
if (esmPackage.mType == ESM::AI_Wander)
{
ESM::AIWander data = it->mWander;
ESM::AIWander data = esmPackage.mWander;
std::vector<unsigned char> idles;
idles.reserve(8);
for (int i=0; i<8; ++i)
idles.push_back(data.mIdle[i]);
package = std::make_unique<MWMechanics::AiWander>(data.mDistance, data.mDuration, data.mTimeOfDay, idles, data.mShouldRepeat != 0);
}
else if (it->mType == ESM::AI_Escort)
else if (esmPackage.mType == ESM::AI_Escort)
{
ESM::AITarget data = it->mTarget;
ESM::AITarget data = esmPackage.mTarget;
package = std::make_unique<MWMechanics::AiEscort>(data.mId.toString(), data.mDuration, data.mX, data.mY, data.mZ);
}
else if (it->mType == ESM::AI_Travel)
else if (esmPackage.mType == ESM::AI_Travel)
{
ESM::AITravel data = it->mTravel;
ESM::AITravel data = esmPackage.mTravel;
package = std::make_unique<MWMechanics::AiTravel>(data.mX, data.mY, data.mZ);
}
else if (it->mType == ESM::AI_Activate)
else if (esmPackage.mType == ESM::AI_Activate)
{
ESM::AIActivate data = it->mActivate;
ESM::AIActivate data = esmPackage.mActivate;
package = std::make_unique<MWMechanics::AiActivate>(data.mName.toString());
}
else //if (it->mType == ESM::AI_Follow)
else //if (esmPackage.mType == ESM::AI_Follow)
{
ESM::AITarget data = it->mTarget;
ESM::AITarget data = esmPackage.mTarget;
package = std::make_unique<MWMechanics::AiFollow>(data.mId.toString(), data.mDuration, data.mX, data.mY, data.mZ);
}
mPackages.push_back(std::move(package));
@ -457,10 +457,9 @@ void AiSequence::readState(const ESM::AiSequence::AiSequence &sequence)
// If there is more than one non-combat, non-pursue package in the list, enable repeating.
int count = 0;
for (std::vector<ESM::AiSequence::AiPackageContainer>::const_iterator it = sequence.mPackages.begin();
it != sequence.mPackages.end(); ++it)
for (auto& container : sequence.mPackages)
{
if (isActualAiPackage(static_cast<AiPackageTypeId>(it->mType)))
if (isActualAiPackage(static_cast<AiPackageTypeId>(container.mType)))
count++;
}
@ -468,20 +467,19 @@ void AiSequence::readState(const ESM::AiSequence::AiSequence &sequence)
mRepeat = true;
// Load packages
for (std::vector<ESM::AiSequence::AiPackageContainer>::const_iterator it = sequence.mPackages.begin();
it != sequence.mPackages.end(); ++it)
for (auto& container : sequence.mPackages)
{
std::unique_ptr<MWMechanics::AiPackage> package;
switch (it->mType)
switch (container.mType)
{
case ESM::AiSequence::Ai_Wander:
{
package.reset(new AiWander(static_cast<ESM::AiSequence::AiWander*>(it->mPackage)));
package.reset(new AiWander(static_cast<ESM::AiSequence::AiWander*>(container.mPackage)));
break;
}
case ESM::AiSequence::Ai_Travel:
{
const auto source = static_cast<const ESM::AiSequence::AiTravel*>(it->mPackage);
const auto source = static_cast<const ESM::AiSequence::AiTravel*>(container.mPackage);
if (source->mHidden)
package.reset(new AiInternalTravel(source));
else
@ -490,27 +488,27 @@ void AiSequence::readState(const ESM::AiSequence::AiSequence &sequence)
}
case ESM::AiSequence::Ai_Escort:
{
package.reset(new AiEscort(static_cast<ESM::AiSequence::AiEscort*>(it->mPackage)));
package.reset(new AiEscort(static_cast<ESM::AiSequence::AiEscort*>(container.mPackage)));
break;
}
case ESM::AiSequence::Ai_Follow:
{
package.reset(new AiFollow(static_cast<ESM::AiSequence::AiFollow*>(it->mPackage)));
package.reset(new AiFollow(static_cast<ESM::AiSequence::AiFollow*>(container.mPackage)));
break;
}
case ESM::AiSequence::Ai_Activate:
{
package.reset(new AiActivate(static_cast<ESM::AiSequence::AiActivate*>(it->mPackage)));
package.reset(new AiActivate(static_cast<ESM::AiSequence::AiActivate*>(container.mPackage)));
break;
}
case ESM::AiSequence::Ai_Combat:
{
package.reset(new AiCombat(static_cast<ESM::AiSequence::AiCombat*>(it->mPackage)));
package.reset(new AiCombat(static_cast<ESM::AiSequence::AiCombat*>(container.mPackage)));
break;
}
case ESM::AiSequence::Ai_Pursue:
{
package.reset(new AiPursue(static_cast<ESM::AiSequence::AiPursue*>(it->mPackage)));
package.reset(new AiPursue(static_cast<ESM::AiSequence::AiPursue*>(container.mPackage)));
break;
}
default:

View file

@ -809,11 +809,11 @@ namespace MWMechanics
void AiWander::AddNonPathGridAllowedPoints(osg::Vec3f npcPos, const ESM::Pathgrid * pathGrid, int pointIndex, AiWanderStorage& storage)
{
storage.mAllowedNodes.push_back(PathFinder::makePathgridPoint(npcPos));
for (std::vector<ESM::Pathgrid::Edge>::const_iterator it = pathGrid->mEdges.begin(); it != pathGrid->mEdges.end(); ++it)
for (auto& edge : pathGrid->mEdges)
{
if (it->mV0 == pointIndex)
if (edge.mV0 == pointIndex)
{
AddPointBetweenPathGridPoints(pathGrid->mPoints[it->mV0], pathGrid->mPoints[it->mV1], storage);
AddPointBetweenPathGridPoints(pathGrid->mPoints[edge.mV0], pathGrid->mPoints[edge.mV1], storage);
}
}
}

View file

@ -61,38 +61,36 @@ namespace MWMechanics
// Note: the algorithm heavily depends on the traversal order of the spells. For vanilla-compatible results the
// Store must preserve the record ordering as it was in the content files.
for (MWWorld::Store<ESM::Spell>::iterator iter = spells.begin(); iter != spells.end(); ++iter)
for (const ESM::Spell& spell : spells)
{
const ESM::Spell* spell = &*iter;
if (spell->mData.mType != ESM::Spell::ST_Spell)
if (spell.mData.mType != ESM::Spell::ST_Spell)
continue;
if (!(spell->mData.mFlags & ESM::Spell::F_Autocalc))
if (!(spell.mData.mFlags & ESM::Spell::F_Autocalc))
continue;
static const int iAutoSpellTimesCanCast = gmst.find("iAutoSpellTimesCanCast")->mValue.getInteger();
if (baseMagicka < iAutoSpellTimesCanCast * spell->mData.mCost)
if (baseMagicka < iAutoSpellTimesCanCast * spell.mData.mCost)
continue;
if (race && race->mPowers.exists(spell->mId))
if (race && race->mPowers.exists(spell.mId))
continue;
if (!attrSkillCheck(spell, actorSkills, actorAttributes))
if (!attrSkillCheck(&spell, actorSkills, actorAttributes))
continue;
int school;
float skillTerm;
calcWeakestSchool(spell, actorSkills, school, skillTerm);
calcWeakestSchool(&spell, actorSkills, school, skillTerm);
assert(school >= 0 && school < 6);
SchoolCaps& cap = schoolCaps[school];
if (cap.mReachedLimit && spell->mData.mCost <= cap.mMinCost)
if (cap.mReachedLimit && spell.mData.mCost <= cap.mMinCost)
continue;
static const float fAutoSpellChance = gmst.find("fAutoSpellChance")->mValue.getFloat();
if (calcAutoCastChance(spell, actorSkills, actorAttributes, school) < fAutoSpellChance)
if (calcAutoCastChance(&spell, actorSkills, actorAttributes, school) < fAutoSpellChance)
continue;
selectedSpells.push_back(spell->mId);
selectedSpells.push_back(spell.mId);
if (cap.mReachedLimit)
{
@ -101,9 +99,9 @@ namespace MWMechanics
selectedSpells.erase(found);
cap.mMinCost = std::numeric_limits<int>::max();
for (std::vector<std::string>::iterator weakIt = selectedSpells.begin(); weakIt != selectedSpells.end(); ++weakIt)
for (const std::string& testSpellName : selectedSpells)
{
const ESM::Spell* testSpell = spells.find(*weakIt);
const ESM::Spell* testSpell = spells.find(testSpellName);
//int testSchool;
//float dummySkillTerm;
@ -130,10 +128,10 @@ namespace MWMechanics
if (cap.mCount == cap.mLimit)
cap.mReachedLimit = true;
if (spell->mData.mCost < cap.mMinCost)
if (spell.mData.mCost < cap.mMinCost)
{
cap.mWeakestSpell = spell->mId;
cap.mMinCost = spell->mData.mCost;
cap.mWeakestSpell = spell.mId;
cap.mMinCost = spell.mData.mCost;
}
}
}
@ -154,32 +152,28 @@ namespace MWMechanics
std::vector<std::string> selectedSpells;
const MWWorld::Store<ESM::Spell> &spells =
esmStore.get<ESM::Spell>();
for (MWWorld::Store<ESM::Spell>::iterator iter = spells.begin(); iter != spells.end(); ++iter)
const MWWorld::Store<ESM::Spell> &spells = esmStore.get<ESM::Spell>();
for (const ESM::Spell& spell : spells)
{
const ESM::Spell* spell = &*iter;
if (spell->mData.mType != ESM::Spell::ST_Spell)
if (spell.mData.mType != ESM::Spell::ST_Spell)
continue;
if (!(spell->mData.mFlags & ESM::Spell::F_PCStart))
if (!(spell.mData.mFlags & ESM::Spell::F_PCStart))
continue;
if (reachedLimit && spell->mData.mCost <= minCost)
if (reachedLimit && spell.mData.mCost <= minCost)
continue;
if (race && std::find(race->mPowers.mList.begin(), race->mPowers.mList.end(), spell->mId) != race->mPowers.mList.end())
if (race && std::find(race->mPowers.mList.begin(), race->mPowers.mList.end(), spell.mId) != race->mPowers.mList.end())
continue;
if (baseMagicka < spell->mData.mCost)
if (baseMagicka < spell.mData.mCost)
continue;
static const float fAutoPCSpellChance = esmStore.get<ESM::GameSetting>().find("fAutoPCSpellChance")->mValue.getFloat();
if (calcAutoCastChance(spell, actorSkills, actorAttributes, -1) < fAutoPCSpellChance)
if (calcAutoCastChance(&spell, actorSkills, actorAttributes, -1) < fAutoPCSpellChance)
continue;
if (!attrSkillCheck(spell, actorSkills, actorAttributes))
if (!attrSkillCheck(&spell, actorSkills, actorAttributes))
continue;
selectedSpells.push_back(spell->mId);
selectedSpells.push_back(spell.mId);
if (reachedLimit)
{
@ -188,9 +182,9 @@ namespace MWMechanics
selectedSpells.erase(it);
minCost = std::numeric_limits<int>::max();
for (std::vector<std::string>::iterator weakIt = selectedSpells.begin(); weakIt != selectedSpells.end(); ++weakIt)
for (const std::string& testSpellName : selectedSpells)
{
const ESM::Spell* testSpell = esmStore.get<ESM::Spell>().find(*weakIt);
const ESM::Spell* testSpell = esmStore.get<ESM::Spell>().find(testSpellName);
if (testSpell->mData.mCost < minCost)
{
minCost = testSpell->mData.mCost;
@ -200,9 +194,9 @@ namespace MWMechanics
}
else
{
if (spell->mData.mCost < minCost)
if (spell.mData.mCost < minCost)
{
weakestSpell = spell;
weakestSpell = &spell;
minCost = weakestSpell->mData.mCost;
}
static const unsigned int iAutoPCSpellMax = esmStore.get<ESM::GameSetting>().find("iAutoPCSpellMax")->mValue.getInteger();
@ -216,23 +210,22 @@ namespace MWMechanics
bool attrSkillCheck (const ESM::Spell* spell, const int* actorSkills, const int* actorAttributes)
{
const std::vector<ESM::ENAMstruct>& effects = spell->mEffects.mList;
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt = effects.begin(); effectIt != effects.end(); ++effectIt)
for (const auto& spellEffect : spell->mEffects.mList)
{
const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(effectIt->mEffectID);
const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(spellEffect.mEffectID);
static const int iAutoSpellAttSkillMin = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("iAutoSpellAttSkillMin")->mValue.getInteger();
if ((magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill))
{
assert (effectIt->mSkill >= 0 && effectIt->mSkill < ESM::Skill::Length);
if (actorSkills[effectIt->mSkill] < iAutoSpellAttSkillMin)
assert (spellEffect.mSkill >= 0 && spellEffect.mSkill < ESM::Skill::Length);
if (actorSkills[spellEffect.mSkill] < iAutoSpellAttSkillMin)
return false;
}
if ((magicEffect->mData.mFlags & ESM::MagicEffect::TargetAttribute))
{
assert (effectIt->mAttribute >= 0 && effectIt->mAttribute < ESM::Attribute::Length);
if (actorAttributes[effectIt->mAttribute] < iAutoSpellAttSkillMin)
assert (spellEffect.mAttribute >= 0 && spellEffect.mAttribute < ESM::Attribute::Length);
if (actorAttributes[spellEffect.mAttribute] < iAutoSpellAttSkillMin)
return false;
}
}
@ -244,11 +237,8 @@ namespace MWMechanics
{
// Morrowind for some reason uses a formula slightly different from magicka cost calculation
float minChance = std::numeric_limits<float>::max();
const ESM::EffectList& effects = spell->mEffects;
for (std::vector<ESM::ENAMstruct>::const_iterator it = effects.mList.begin(); it != effects.mList.end(); ++it)
for (const ESM::ENAMstruct& effect : spell->mEffects.mList)
{
const ESM::ENAMstruct& effect = *it;
const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(effect.mEffectID);
int minMagn = 1;

View file

@ -2653,11 +2653,11 @@ void CharacterController::updateContinuousVfx()
std::vector<int> effects;
mAnimation->getLoopingEffects(effects);
for (std::vector<int>::iterator it = effects.begin(); it != effects.end(); ++it)
for (int effectId : effects)
{
if (mPtr.getClass().getCreatureStats(mPtr).isDeathAnimationFinished()
|| mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(MWMechanics::EffectKey(*it)).getMagnitude() <= 0)
mAnimation->removeEffect(*it);
|| mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(MWMechanics::EffectKey(effectId)).getMagnitude() <= 0)
mAnimation->removeEffect(effectId);
}
}

View file

@ -31,10 +31,10 @@ namespace MWMechanics
std::vector<std::string> candidates;
int highestLevel = 0;
for (std::vector<ESM::LevelledListBase::LevelItem>::const_iterator it = items.begin(); it != items.end(); ++it)
for (const auto& levelledItem : items)
{
if (it->mLevel > highestLevel && it->mLevel <= playerLevel)
highestLevel = it->mLevel;
if (levelledItem.mLevel > highestLevel && levelledItem.mLevel <= playerLevel)
highestLevel = levelledItem.mLevel;
}
// For levelled creatures, the flags are swapped. This file format just makes so much sense.
@ -43,14 +43,14 @@ namespace MWMechanics
allLevels = levItem->mFlags & ESM::CreatureLevList::AllLevels;
std::pair<int, std::string> highest = std::make_pair(-1, "");
for (std::vector<ESM::LevelledListBase::LevelItem>::const_iterator it = items.begin(); it != items.end(); ++it)
for (const auto& levelledItem : items)
{
if (playerLevel >= it->mLevel
&& (allLevels || it->mLevel == highestLevel))
if (playerLevel >= levelledItem.mLevel
&& (allLevels || levelledItem.mLevel == highestLevel))
{
candidates.push_back(it->mId);
if (it->mLevel >= highest.first)
highest = std::make_pair(it->mLevel, it->mId);
candidates.push_back(levelledItem.mId);
if (levelledItem.mLevel >= highest.first)
highest = std::make_pair(levelledItem.mLevel, levelledItem.mId);
}
}
if (candidates.empty())

View file

@ -19,11 +19,10 @@ Objects::Objects()
Objects::~Objects()
{
PtrControllerMap::iterator it(mObjects.begin());
for (; it != mObjects.end();++it)
for(auto& object : mObjects)
{
delete it->second;
it->second = nullptr;
delete object.second;
object.second = nullptr;
}
}
@ -77,8 +76,8 @@ void Objects::update(float duration, bool paused)
{
if(!paused)
{
for(PtrControllerMap::iterator iter(mObjects.begin());iter != mObjects.end();++iter)
iter->second->update(duration);
for(auto& object : mObjects)
object.second->update(duration);
}
else
{
@ -87,15 +86,15 @@ void Objects::update(float duration, bool paused)
if(mode != MWGui::GM_Container)
return;
for(PtrControllerMap::iterator iter(mObjects.begin());iter != mObjects.end();++iter)
for(auto& object : mObjects)
{
if (iter->first.getTypeName() != typeid(ESM::Container).name())
if (object.first.getTypeName() != typeid(ESM::Container).name())
continue;
if (iter->second->isAnimPlaying("containeropen"))
if (object.second->isAnimPlaying("containeropen"))
{
iter->second->update(duration);
MWBase::Environment::get().getWorld()->updateAnimatedCollisionShape(iter->first);
object.second->update(duration);
MWBase::Environment::get().getWorld()->updateAnimatedCollisionShape(object.first);
}
}
}

View file

@ -36,17 +36,13 @@ namespace MWMechanics
// Check all the doors in this cell
const MWWorld::CellRefList<ESM::Door>& doors = cell->getReadOnlyDoors();
const MWWorld::CellRefList<ESM::Door>::List& refList = doors.mList;
MWWorld::CellRefList<ESM::Door>::List::const_iterator it = refList.begin();
osg::Vec3f pos(actor.getRefData().getPosition().asVec3());
pos.z() = 0;
osg::Vec3f actorDir = (actor.getRefData().getBaseNode()->getAttitude() * osg::Vec3f(0,1,0));
for (; it != refList.end(); ++it)
for (const auto& ref : doors.mList)
{
const MWWorld::LiveCellRef<ESM::Door>& ref = *it;
osg::Vec3f doorPos(ref.mData.getPosition().asVec3());
// FIXME: cast

View file

@ -21,14 +21,14 @@ namespace MWRender
mAutoSwitchShoulder(Settings::Manager::getBool("auto switch shoulder", "Camera")),
mOverShoulderHorizontalOffset(30.f), mOverShoulderVerticalOffset(-10.f)
{
std::stringstream offset(Settings::Manager::getString("view over shoulder offset", "Camera"));
offset >> mOverShoulderHorizontalOffset >> mOverShoulderVerticalOffset;
mDefaultShoulderIsRight = mOverShoulderHorizontalOffset >= 0;
mOverShoulderHorizontalOffset = std::abs(mOverShoulderHorizontalOffset);
osg::Vec2f offset = Settings::Manager::getVector2("view over shoulder offset", "Camera");
mOverShoulderHorizontalOffset = std::abs(offset.x());
mOverShoulderVerticalOffset = offset.y();
mDefaultShoulderIsRight = offset.x() >= 0;
mCamera->enableDynamicCameraDistance(true);
mCamera->enableCrosshairInThirdPersonMode(true);
mCamera->setFocalPointTargetOffset({mOverShoulderHorizontalOffset, mOverShoulderVerticalOffset});
mCamera->setFocalPointTargetOffset(offset);
}
void ViewOverShoulderController::update()

View file

@ -8,6 +8,7 @@ ContentSelectorView::ComboBox::ComboBox(QWidget *parent) :
{
mValidator = new QRegExpValidator(QRegExp("^[a-zA-Z0-9_]*$"), this); // Alpha-numeric + underscore
setValidator(mValidator);
setEditable(true);
setCompleter(0);
setEnabled (true);

View file

@ -76,6 +76,28 @@ bool Manager::getBool (const std::string& setting, const std::string& category)
return Misc::StringUtils::ciEqual(string, "true");
}
osg::Vec2f Manager::getVector2 (const std::string& setting, const std::string& category)
{
const std::string& value = getString(setting, category);
std::stringstream stream(value);
float x, y;
stream >> x >> y;
if (stream.fail())
throw std::runtime_error(std::string("Can't parse 2d vector: " + value));
return osg::Vec2f(x, y);
}
osg::Vec3f Manager::getVector3 (const std::string& setting, const std::string& category)
{
const std::string& value = getString(setting, category);
std::stringstream stream(value);
float x, y, z;
stream >> x >> y >> z;
if (stream.fail())
throw std::runtime_error(std::string("Can't parse 3d vector: " + value));
return osg::Vec3f(x, y, z);
}
void Manager::setString(const std::string &setting, const std::string &category, const std::string &value)
{
CategorySettingValueMap::key_type key = std::make_pair(category, setting);
@ -111,6 +133,20 @@ void Manager::setBool(const std::string &setting, const std::string &category, c
setString(setting, category, value ? "true" : "false");
}
void Manager::setVector2 (const std::string &setting, const std::string &category, const osg::Vec2f value)
{
std::ostringstream stream;
stream << value.x() << " " << value.y();
setString(setting, category, stream.str());
}
void Manager::setVector3 (const std::string &setting, const std::string &category, const osg::Vec3f value)
{
std::ostringstream stream;
stream << value.x() << ' ' << value.y() << ' ' << value.z();
setString(setting, category, stream.str());
}
void Manager::resetPendingChange(const std::string &setting, const std::string &category)
{
CategorySettingValueMap::key_type key = std::make_pair(category, setting);

View file

@ -6,6 +6,8 @@
#include <set>
#include <map>
#include <string>
#include <osg/Vec2f>
#include <osg/Vec3f>
namespace Settings
{
@ -44,11 +46,15 @@ namespace Settings
static float getFloat (const std::string& setting, const std::string& category);
static std::string getString (const std::string& setting, const std::string& category);
static bool getBool (const std::string& setting, const std::string& category);
static osg::Vec2f getVector2 (const std::string& setting, const std::string& category);
static osg::Vec3f getVector3 (const std::string& setting, const std::string& category);
static void setInt (const std::string& setting, const std::string& category, const int value);
static void setFloat (const std::string& setting, const std::string& category, const float value);
static void setString (const std::string& setting, const std::string& category, const std::string& value);
static void setBool (const std::string& setting, const std::string& category, const bool value);
static void setVector2 (const std::string& setting, const std::string& category, const osg::Vec2f value);
static void setVector3 (const std::string& setting, const std::string& category, const osg::Vec3f value);
};
}

View file

@ -136,7 +136,7 @@ This setting controls third person view mode.
False: View is centered on the character's head. Crosshair is hidden.
True: In non-combat mode camera is positioned behind the character's shoulder. Crosshair is visible in third person mode as well.
This setting can only be configured by editing the settings configuration file.
This setting can be controlled in Advanced tab of the launcher.
view over shoulder offset
-------------------------

View file

@ -329,7 +329,7 @@ If disabled then the whole character's body is pointed to the direction of view.
If enabled then the character turns lower body to the direction of movement. Upper body is turned partially. Head is always pointed to the direction of view. In combat mode it works only for diagonal movement. In non-combat mode it also changes straight right and straight left movement.
This setting can only be configured by editing the settings configuration file.
This setting can be controlled in Advanced tab of the launcher.
swim upward coef
----------------

View file

@ -4,18 +4,28 @@
<widget class="QWidget" name="AdvancedPage">
<layout class="QVBoxLayout" name="pageVerticalLayout">
<item>
<widget class="QScrollArea" name="scrollArea">
<property name="widgetResizable">
<bool>true</bool>
<widget class="QTabWidget" name="AdvancedTabWidget">
<property name="tabPosition">
<enum>QTabWidget::West</enum>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<layout class="QVBoxLayout" name="scrollAreaVerticalLayout">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="GameMechanics">
<attribute name="title">
<string>Game mechanics</string>
</attribute>
<layout class="QVBoxLayout">
<item>
<widget class="QGroupBox" name="gameGroup">
<property name="title">
<string>Game Mechanics</string>
<widget class="QCheckBox" name="toggleSneakCheckBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;This setting causes the behavior of the sneak key (bound to Ctrl by default) to toggle sneaking on and off rather than requiring the key to be held down while sneaking. Players that spend significant time sneaking may find the character easier to control with this option enabled. &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<layout class="QVBoxLayout" name="gameGroupVerticalLayout">
<property name="text">
<string>Toggle sneak</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="canLootDuringDeathAnimationCheckBox">
<property name="toolTip">
@ -32,17 +42,7 @@
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Make player followers and escorters start combat with enemies who have started combat with them or the player. Otherwise they wait for the enemies or the player to do an attack first.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Followers attack on sight</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="preventMerchantEquippingCheckBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Prevents merchants from equipping items that are sold to them.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Prevent merchant equipping</string>
<string>Followers defend immediately</string>
</property>
</widget>
</item>
@ -52,7 +52,7 @@
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Make the value of filled soul gems dependent only on soul magnitude.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Rebalance soul gem values</string>
<string>Soulgem values rebalance</string>
</property>
</widget>
</item>
@ -72,7 +72,7 @@
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Make disposition change of merchants caused by trading permanent.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Barter disposition change is permanent</string>
<string>Permanent barter disposition changes</string>
</property>
</widget>
</item>
@ -96,27 +96,32 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="uncappedDamageFatigueCheckBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Make Damage Fatigue magic effect uncapped like Drain Fatigue effect.&lt;/p&gt;&lt;p&gt;This means that unlike Morrowind you will be able to knock down actors using this effect.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Uncapped Damage Fatigue</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="normaliseRaceSpeedCheckBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Don't use race weight in NPC movement speed calculations.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Racial variation in speed fix</string>
</property>
</widget>
</item>
<item alignment="Qt::AlignLeft">
<widget class="QWidget" name="unarmedFactorsStrengthGroup" native="true">
<widget class="QWidget" name="unarmedFactorsStrengthGroup">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Factor strength into hand-to-hand damage calculations, as the MCP formula: damage * (strength / 40).&lt;/p&gt;&lt;p&gt;The default value is Off.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<layout class="QHBoxLayout" name="horizontalUnarmedStrengthLayout">
<property name="spacing">
<number>-1</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item alignment="Qt::AlignRight">
<widget class="QLabel" name="unarmedFactorsStrengthLabel">
<property name="text">
@ -149,6 +154,33 @@
</layout>
</widget>
</item>
<item>
<spacer>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="Visuals">
<attribute name="title">
<string>Visuals</string>
</attribute>
<layout class="QVBoxLayout">
<item>
<widget class="QCheckBox" name="bumpMapLocalLightingCheckBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Normally environment map reflections aren't affected by lighting, which makes environment-mapped (and thus bump-mapped objects) glow in the dark.
Morrowind Code Patch includes an option to remedy that by doing environment-mapping before applying lighting, this is the equivalent of that option.
Affected objects will use shaders.
&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Bump/reflect map local lighting</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="magicItemAnimationsCheckBox">
<property name="toolTip">
@ -159,16 +191,6 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="normaliseRaceSpeedCheckBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Don't use race weight in NPC movement speed calculations.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Normalise race speed</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="animSourcesCheckBox">
<property name="toolTip">
@ -180,23 +202,11 @@
</widget>
</item>
<item>
<widget class="QWidget" name="sheathingGroup" native="true">
<widget class="QWidget" name="sheathingGroup">
<layout class="QVBoxLayout" name="sheathingLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>20</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QCheckBox" name="weaponSheathingCheckBox">
<property name="enabled">
@ -227,208 +237,92 @@
</widget>
</item>
<item>
<widget class="QCheckBox" name="uncappedDamageFatigueCheckBox">
<widget class="QCheckBox" name="viewOverShoulderCheckBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Make Damage Fatigue magic effect uncapped like Drain Fatigue effect.&lt;/p&gt;&lt;p&gt;This means that unlike Morrowind you will be able to knock down actors using this effect.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;This setting controls third person view mode.&lt;/p&gt;&lt;p&gt;False: View is centered on the character's head. Crosshair is hidden.
True: In non-combat mode camera is positioned behind the character's shoulder. Crosshair is visible in third person mode as well.
&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Uncapped Damage Fatigue</string>
<string>View over the shoulder</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="trainersTrainingSkillsBasedOnBaseSkillCheckBox">
<widget class="QCheckBox" name="turnToMovementDirectionCheckBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Trainers now only choose which skills to train using their base skill points, allowing mercantile improving effects to be used without making mercantile an offered skill.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Affects side and diagonal movement. Enabling this setting makes movement more realistic.&lt;/p&gt;&lt;p&gt;If disabled then the whole character's body is pointed to the direction of view. Diagonal movement has no special animation and causes sliding.&lt;/p&gt;&lt;p&gt;If enabled then the character turns lower body to the direction of movement. Upper body is turned partially. Head is always pointed to the direction of view. In combat mode it works only for diagonal movement. In non-combat mode it also changes straight right and straight left movement.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Trainers choose their training skills based on their base skill points</string>
<string>Turn to movement direction</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="inputGroup">
<property name="title">
<string>Input</string>
</property>
<layout class="QVBoxLayout" name="inputGroupVerticalLayout">
<item>
<widget class="QCheckBox" name="grabCursorCheckBox">
<widget class="QCheckBox" name="distantLandCheckBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;OpenMW will capture control of the cursor if this setting is true.&lt;/p&gt;&lt;p&gt;In “look mode”, OpenMW will center the cursor regardless of the value of this setting (since the cursor/crosshair is always centered in the OpenMW window). However, in GUI mode, this setting determines the behavior when the cursor is moved outside the OpenMW window. If true, the cursor movement stops at the edge of the window preventing access to other applications. If false, the cursor is allowed to move freely on the desktop.&lt;/p&gt;&lt;p&gt;This setting does not apply to the screen where escape has been pressed, where the cursor is never captured. Regardless of this setting “Alt-Tab” or some other operating system dependent key sequence can be used to allow the operating system to regain control of the mouse cursor. This setting interacts with the minimize on focus loss setting by affecting what counts as a focus loss. Specifically on a two-screen configuration it may be more convenient to access the second screen with setting disabled.&lt;/p&gt;&lt;p&gt;Note for developers: its desirable to have this setting disabled when running the game in a debugger, to prevent the mouse cursor from becoming unusable when the game pauses on a breakpoint.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;If true, use paging and LOD algorithms to display the entire terrain. If false, only display terrain of the loaded cells.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Grab cursor</string>
<string>Distant land</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="toggleSneakCheckBox">
<widget class="QCheckBox" name="activeGridObjectPagingCheckBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;This setting causes the behavior of the sneak key (bound to Ctrl by default) to toggle sneaking on and off rather than requiring the key to be held down while sneaking. Players that spend significant time sneaking may find the character easier to control with this option enabled. &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Use object paging for active cells grid.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Toggle sneak</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="savesGroup">
<property name="title">
<string>Saves</string>
</property>
<layout class="QVBoxLayout" name="savesGroupVerticalLayout">
<item>
<widget class="QCheckBox" name="timePlayedCheckbox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;This setting determines whether the amount of the time the player has spent playing will be displayed for each saved game in the Load menu.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Add &quot;Time Played&quot; to saves</string>
<string>Active grid object paging</string>
</property>
</widget>
</item>
<item alignment="Qt::AlignLeft">
<widget class="QWidget" name="maximumQuicksavesGroup" native="true">
<widget class="QWidget" name="viewingDistanceGroup">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;This setting determines how many quicksave and autosave slots you can have at a time. If greater than 1, quicksaves will be sequentially created each time you quicksave. Once the maximum number of quicksaves has been reached, the oldest quicksave will be recycled the next time you perform a quicksave.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<layout class="QHBoxLayout" name="maximumQuicksavesLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;This value controls the maximum visible distance (in cell units).
Larger values significantly improve rendering in exterior spaces,
but also increase the amount of rendered geometry and significantly reduce the frame rate.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<layout class="QHBoxLayout" name="viewingDistanceLayout">
<item>
<widget class="QLabel" name="maximumQuicksavesLabel">
<widget class="QLabel" name="viewingDistanceLabel">
<property name="text">
<string>Maximum Quicksaves</string>
<string>Viewing distance</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="maximumQuicksavesComboBox">
<widget class="QDoubleSpinBox" name="viewingDistanceComboBox">
<property name="minimum">
<number>1</number>
<double>0.0</double>
</property>
<property name="singleStep">
<double>0.5</double>
</property>
<property name="suffix">
<string> Cells</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="testingGroup">
<property name="title">
<string>Testing</string>
</property>
<layout class="QVBoxLayout" name="testingGroupVerticalLayout">
<item>
<widget class="QLabel" name="testingLabel">
<property name="text">
<string>These settings are intended for testing mods and will cause issues if used for normal gameplay.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="Line" name="testingLine">
<spacer>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="skipMenuCheckBox">
<property name="text">
<string>Skip menu and generate default character</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="startDefaultCharacterAtHorizontalLayout">
<item>
<spacer name="startDefaultCharacterAtHorizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
<enum>Qt::Vertical</enum>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="startDefaultCharacterAtLabel">
<property name="text">
<string>Start default character at</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="startDefaultCharacterAtField">
<property name="placeholderText">
<string>default cell</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Run script after startup:</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="runScriptAfterStartupHorizontalLayout">
<item>
<widget class="QLineEdit" name="runScriptAfterStartupField"/>
</item>
<item>
<widget class="QPushButton" name="runScriptAfterStartupBrowseButton">
<property name="text">
<string>Browse…</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="userInterfaceGroup">
<property name="title">
<string>User Interface</string>
</property>
<layout class="QVBoxLayout" name="userInterfaceVerticalLayout">
<widget class="QWidget" name="InterfaceChanges">
<attribute name="title">
<string>Interface changes</string>
</attribute>
<layout class="QVBoxLayout">
<item>
<widget class="QCheckBox" name="showEffectDurationCheckBox">
<property name="toolTip">
@ -480,26 +374,11 @@
</widget>
</item>
<item alignment="Qt::AlignLeft">
<widget class="QWidget" name="showOwnedGroup" native="true">
<widget class="QWidget" name="showOwnedGroup">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable visual clues for items owned by NPCs when the crosshair is on the object.&lt;/p&gt;&lt;p&gt;The default value is Off.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item alignment="Qt::AlignRight">
<widget class="QLabel" name="showOwnedLabel">
<property name="text">
@ -537,6 +416,93 @@
</layout>
</widget>
</item>
<item>
<spacer>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="BugFixes">
<attribute name="title">
<string>Bug fixes</string>
</attribute>
<layout class="QVBoxLayout">
<item>
<widget class="QCheckBox" name="preventMerchantEquippingCheckBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Prevents merchants from equipping items that are sold to them.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Merchant equipping fix</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="trainersTrainingSkillsBasedOnBaseSkillCheckBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Trainers now only choose which skills to train using their base skill points, allowing mercantile improving effects to be used without making mercantile an offered skill.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Trainers choose their training skills based on their base skill points</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="Miscellaneous">
<attribute name="title">
<string>Miscellaneous</string>
</attribute>
<layout class="QVBoxLayout" name="scrollAreaVerticalLayout">
<item>
<widget class="QGroupBox" name="savesGroup">
<property name="title">
<string>Saves</string>
</property>
<layout class="QVBoxLayout" name="savesGroupVerticalLayout">
<item>
<widget class="QCheckBox" name="timePlayedCheckbox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;This setting determines whether the amount of the time the player has spent playing will be displayed for each saved game in the Load menu.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Add &quot;Time Played&quot; to saves</string>
</property>
</widget>
</item>
<item alignment="Qt::AlignLeft">
<widget class="QWidget" name="maximumQuicksavesGroup">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;This setting determines how many quicksave and autosave slots you can have at a time. If greater than 1, quicksaves will be sequentially created each time you quicksave. Once the maximum number of quicksaves has been reached, the oldest quicksave will be recycled the next time you perform a quicksave.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<layout class="QHBoxLayout" name="maximumQuicksavesLayout">
<item>
<widget class="QLabel" name="maximumQuicksavesLabel">
<property name="text">
<string>Maximum Quicksaves</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="maximumQuicksavesComboBox">
<property name="minimum">
<number>1</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
@ -547,26 +513,11 @@
</property>
<layout class="QVBoxLayout" name="otherGroupVerticalLayout">
<item alignment="Qt::AlignLeft">
<widget class="QWidget" name="screenshotFormatGroup" native="true">
<widget class="QWidget" name="screenshotFormatGroup">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Specify the format for screen shots taken by pressing the screen shot key (bound to F12 by default). This setting should be the file extension commonly associated with the desired format. The formats supported will be determined at compilation, but “jpg”, “png”, and “tga” should be allowed.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<layout class="QHBoxLayout" name="screenshotFormatLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item alignment="Qt::AlignRight">
<widget class="QLabel" name="screenshotFormatLabel">
<property name="text">
@ -599,6 +550,110 @@
</layout>
</widget>
</item>
<item>
<spacer>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="Testing">
<attribute name="title">
<string>Testing</string>
</attribute>
<layout class="QVBoxLayout">
<item>
<widget class="QLabel" name="testingLabel">
<property name="text">
<string>These settings are intended for testing mods and will cause issues if used for normal gameplay.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="Line" name="testingLine">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="grabCursorCheckBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;OpenMW will capture control of the cursor if this setting is true.&lt;/p&gt;&lt;p&gt;In “look mode”, OpenMW will center the cursor regardless of the value of this setting (since the cursor/crosshair is always centered in the OpenMW window). However, in GUI mode, this setting determines the behavior when the cursor is moved outside the OpenMW window. If true, the cursor movement stops at the edge of the window preventing access to other applications. If false, the cursor is allowed to move freely on the desktop.&lt;/p&gt;&lt;p&gt;This setting does not apply to the screen where escape has been pressed, where the cursor is never captured. Regardless of this setting “Alt-Tab” or some other operating system dependent key sequence can be used to allow the operating system to regain control of the mouse cursor. This setting interacts with the minimize on focus loss setting by affecting what counts as a focus loss. Specifically on a two-screen configuration it may be more convenient to access the second screen with setting disabled.&lt;/p&gt;&lt;p&gt;Note for developers: its desirable to have this setting disabled when running the game in a debugger, to prevent the mouse cursor from becoming unusable when the game pauses on a breakpoint.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Grab cursor</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="skipMenuCheckBox">
<property name="text">
<string>Skip menu and generate default character</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="startDefaultCharacterAtHorizontalLayout">
<item>
<spacer name="startDefaultCharacterAtHorizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="startDefaultCharacterAtLabel">
<property name="text">
<string>Start default character at</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="startDefaultCharacterAtField">
<property name="placeholderText">
<string>default cell</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Run script after startup:</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="runScriptAfterStartupHorizontalLayout">
<item>
<widget class="QLineEdit" name="runScriptAfterStartupField"/>
</item>
<item>
<widget class="QPushButton" name="runScriptAfterStartupBrowseButton">
<property name="text">
<string>Browse…</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>