mirror of
https://github.com/OpenMW/openmw.git
synced 2025-02-21 09:39:43 +00:00
Merge branch 'master' of github.com:OpenMW/openmw
This commit is contained in:
commit
584fcd4716
19 changed files with 945 additions and 744 deletions
|
@ -48,9 +48,11 @@
|
||||||
Feature #5445: Handle NiLines
|
Feature #5445: Handle NiLines
|
||||||
Feature #5457: Realistic diagonal movement
|
Feature #5457: Realistic diagonal movement
|
||||||
Feature #5486: Fixes trainers to choose their training skills based on their base skill points
|
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 #5524: Resume failed script execution after reload
|
||||||
Feature #5525: Search fields tweaks (utf-8)
|
Feature #5525: Search fields tweaks (utf-8)
|
||||||
Task #5480: Drop Qt4 support
|
Task #5480: Drop Qt4 support
|
||||||
|
Task #5520: Improve cell name autocompleter implementation
|
||||||
|
|
||||||
0.46.0
|
0.46.0
|
||||||
------
|
------
|
||||||
|
|
|
@ -4,9 +4,43 @@
|
||||||
#include <components/config/launchersettings.hpp>
|
#include <components/config/launchersettings.hpp>
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QCompleter>
|
#include <QCompleter>
|
||||||
|
#include <QProxyStyle>
|
||||||
#include <components/contentselector/view/contentselector.hpp>
|
#include <components/contentselector/view/contentselector.hpp>
|
||||||
#include <components/contentselector/model/esmfile.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,
|
Launcher::AdvancedPage::AdvancedPage(Files::ConfigurationManager &cfg,
|
||||||
Config::GameSettings &gameSettings,
|
Config::GameSettings &gameSettings,
|
||||||
Settings::Manager &engineSettings, QWidget *parent)
|
Settings::Manager &engineSettings, QWidget *parent)
|
||||||
|
@ -19,15 +53,16 @@ Launcher::AdvancedPage::AdvancedPage(Files::ConfigurationManager &cfg,
|
||||||
setupUi(this);
|
setupUi(this);
|
||||||
|
|
||||||
loadSettings();
|
loadSettings();
|
||||||
|
AdvancedTabWidget->tabBar()->setStyle(new HorizontalTextWestTabStyle);
|
||||||
|
mCellNameCompleter.setModel(&mCellNameCompleterModel);
|
||||||
|
startDefaultCharacterAtField->setCompleter(&mCellNameCompleter);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Launcher::AdvancedPage::loadCellsForAutocomplete(QStringList cellNames) {
|
void Launcher::AdvancedPage::loadCellsForAutocomplete(QStringList cellNames) {
|
||||||
// Set up an auto-completer for the "Start default character at" field
|
// Update the list of suggestions for the "Start default character at" field
|
||||||
auto *completer = new QCompleter(cellNames);
|
mCellNameCompleterModel.setStringList(cellNames);
|
||||||
completer->setCompletionMode(QCompleter::PopupCompletion);
|
mCellNameCompleter.setCompletionMode(QCompleter::PopupCompletion);
|
||||||
completer->setCaseSensitivity(Qt::CaseSensitivity::CaseInsensitive);
|
mCellNameCompleter.setCaseSensitivity(Qt::CaseSensitivity::CaseInsensitive);
|
||||||
startDefaultCharacterAtField->setCompleter(completer);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Launcher::AdvancedPage::on_skipMenuCheckBox_stateChanged(int state) {
|
void Launcher::AdvancedPage::on_skipMenuCheckBox_stateChanged(int state) {
|
||||||
|
@ -55,142 +90,220 @@ void Launcher::AdvancedPage::on_runScriptAfterStartupBrowseButton_clicked()
|
||||||
runScriptAfterStartupField->setText(path);
|
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()
|
bool Launcher::AdvancedPage::loadSettings()
|
||||||
{
|
{
|
||||||
// Testing
|
// Game mechanics
|
||||||
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
|
|
||||||
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");
|
|
||||||
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");
|
|
||||||
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())
|
|
||||||
{
|
{
|
||||||
loadSettingBool(weaponSheathingCheckBox, "weapon sheathing", "Game");
|
loadSettingBool(toggleSneakCheckBox, "toggle sneak", "Input");
|
||||||
loadSettingBool(shieldSheathingCheckBox, "shield sheathing", "Game");
|
loadSettingBool(canLootDuringDeathAnimationCheckBox, "can loot during death animation", "Game");
|
||||||
|
loadSettingBool(followersAttackOnSightCheckBox, "followers attack on sight", "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(uncappedDamageFatigueCheckBox, "uncapped damage fatigue", "Game");
|
|
||||||
loadSettingBool(trainersTrainingSkillsBasedOnBaseSkillCheckBox, "trainers training skills based on base skill", "Game");
|
|
||||||
|
|
||||||
// Input Settings
|
// Visuals
|
||||||
loadSettingBool(grabCursorCheckBox, "grab cursor", "Input");
|
{
|
||||||
loadSettingBool(toggleSneakCheckBox, "toggle sneak", "Input");
|
loadSettingBool(bumpMapLocalLightingCheckBox, "apply lighting to environment maps", "Shaders");
|
||||||
|
loadSettingBool(magicItemAnimationsCheckBox, "use magic item animations", "Game");
|
||||||
|
connect(animSourcesCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotAnimSourcesToggled(bool)));
|
||||||
|
loadSettingBool(animSourcesCheckBox, "use additional anim sources", "Game");
|
||||||
|
if (animSourcesCheckBox->checkState())
|
||||||
|
{
|
||||||
|
loadSettingBool(weaponSheathingCheckBox, "weapon sheathing", "Game");
|
||||||
|
loadSettingBool(shieldSheathingCheckBox, "shield sheathing", "Game");
|
||||||
|
}
|
||||||
|
loadSettingBool(viewOverShoulderCheckBox, "view over shoulder", "Camera");
|
||||||
|
loadSettingBool(turnToMovementDirectionCheckBox, "turn to movement direction", "Game");
|
||||||
|
|
||||||
// Saves Settings
|
const bool distantTerrain = mEngineSettings.getBool("distant terrain", "Terrain");
|
||||||
loadSettingBool(timePlayedCheckbox, "timeplayed", "Saves");
|
const bool objectPaging = mEngineSettings.getBool("object paging", "Terrain");
|
||||||
maximumQuicksavesComboBox->setValue(mEngineSettings.getInt("max quicksaves", "Saves"));
|
if (distantTerrain && objectPaging) {
|
||||||
|
distantLandCheckBox->setCheckState(Qt::Checked);
|
||||||
|
}
|
||||||
|
|
||||||
// User Interface Settings
|
loadSettingBool(activeGridObjectPagingCheckBox, "object paging active grid", "Terrain");
|
||||||
loadSettingBool(showEffectDurationCheckBox, "show effect duration", "Game");
|
viewingDistanceComboBox->setValue(convertToCells(mEngineSettings.getInt("viewing distance", "Camera")));
|
||||||
loadSettingBool(showEnchantChanceCheckBox, "show enchant chance", "Game");
|
}
|
||||||
loadSettingBool(showMeleeInfoCheckBox, "show melee info", "Game");
|
|
||||||
loadSettingBool(showProjectileDamageCheckBox, "show projectile damage", "Game");
|
|
||||||
loadSettingBool(changeDialogTopicsCheckBox, "color topic enable", "GUI");
|
|
||||||
int showOwnedIndex = mEngineSettings.getInt("show owned", "Game");
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
// Other Settings
|
// Interface Changes
|
||||||
QString screenshotFormatString = QString::fromStdString(mEngineSettings.getString("screenshot format", "General")).toUpper();
|
{
|
||||||
if (screenshotFormatComboBox->findText(screenshotFormatString) == -1)
|
loadSettingBool(showEffectDurationCheckBox, "show effect duration", "Game");
|
||||||
screenshotFormatComboBox->addItem(screenshotFormatString);
|
loadSettingBool(showEnchantChanceCheckBox, "show enchant chance", "Game");
|
||||||
screenshotFormatComboBox->setCurrentIndex(screenshotFormatComboBox->findText(screenshotFormatString));
|
loadSettingBool(showMeleeInfoCheckBox, "show melee info", "Game");
|
||||||
|
loadSettingBool(showProjectileDamageCheckBox, "show projectile damage", "Game");
|
||||||
|
loadSettingBool(changeDialogTopicsCheckBox, "color topic enable", "GUI");
|
||||||
|
int showOwnedIndex = mEngineSettings.getInt("show owned", "Game");
|
||||||
|
// 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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Launcher::AdvancedPage::saveSettings()
|
void Launcher::AdvancedPage::saveSettings()
|
||||||
{
|
{
|
||||||
// Ensure we only set the new settings if they changed. This is to avoid cluttering the
|
// Game mechanics
|
||||||
// user settings file (which by definition should only contain settings the user has touched)
|
{
|
||||||
|
saveSettingBool(toggleSneakCheckBox, "toggle sneak", "Input");
|
||||||
|
saveSettingBool(canLootDuringDeathAnimationCheckBox, "can loot during death animation", "Game");
|
||||||
|
saveSettingBool(followersAttackOnSightCheckBox, "followers attack on sight", "Game");
|
||||||
|
saveSettingBool(rebalanceSoulGemValuesCheckBox, "rebalance soul gem values", "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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Visuals
|
||||||
|
{
|
||||||
|
saveSettingBool(bumpMapLocalLightingCheckBox, "apply lighting to environment maps", "Shaders");
|
||||||
|
saveSettingBool(magicItemAnimationsCheckBox, "use magic item animations", "Game");
|
||||||
|
saveSettingBool(animSourcesCheckBox, "use additional anim sources", "Game");
|
||||||
|
saveSettingBool(weaponSheathingCheckBox, "weapon sheathing", "Game");
|
||||||
|
saveSettingBool(shieldSheathingCheckBox, "shield sheathing", "Game");
|
||||||
|
saveSettingBool(viewOverShoulderCheckBox, "view over shoulder", "Camera");
|
||||||
|
saveSettingBool(turnToMovementDirectionCheckBox, "turn to movement direction", "Game");
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
saveSettingBool(showProjectileDamageCheckBox, "show projectile damage", "Game");
|
||||||
|
saveSettingBool(changeDialogTopicsCheckBox, "color topic enable", "GUI");
|
||||||
|
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();
|
||||||
|
if (screenshotFormatString != mEngineSettings.getString("screenshot format", "General"))
|
||||||
|
mEngineSettings.setString("screenshot format", "General", screenshotFormatString);
|
||||||
|
}
|
||||||
|
|
||||||
// Testing
|
// Testing
|
||||||
int skipMenu = skipMenuCheckBox->checkState() == Qt::Checked;
|
{
|
||||||
if (skipMenu != mGameSettings.value("skip-menu").toInt())
|
saveSettingBool(grabCursorCheckBox, "grab cursor", "Input");
|
||||||
mGameSettings.setValue("skip-menu", QString::number(skipMenu));
|
|
||||||
|
|
||||||
QString startCell = startDefaultCharacterAtField->text();
|
int skipMenu = skipMenuCheckBox->checkState() == Qt::Checked;
|
||||||
if (startCell != mGameSettings.value("start")) {
|
if (skipMenu != mGameSettings.value("skip-menu").toInt())
|
||||||
mGameSettings.setValue("start", startCell);
|
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);
|
||||||
}
|
}
|
||||||
QString scriptRun = runScriptAfterStartupField->text();
|
|
||||||
if (scriptRun != mGameSettings.value("script-run"))
|
|
||||||
mGameSettings.setValue("script-run", scriptRun);
|
|
||||||
|
|
||||||
// Game Settings
|
|
||||||
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");
|
|
||||||
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");
|
|
||||||
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");
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// User Interface Settings
|
|
||||||
saveSettingBool(showEffectDurationCheckBox, "show effect duration", "Game");
|
|
||||||
saveSettingBool(showEnchantChanceCheckBox, "show enchant chance", "Game");
|
|
||||||
saveSettingBool(showMeleeInfoCheckBox, "show melee info", "Game");
|
|
||||||
saveSettingBool(showProjectileDamageCheckBox, "show projectile damage", "Game");
|
|
||||||
saveSettingBool(changeDialogTopicsCheckBox, "color topic enable", "GUI");
|
|
||||||
int showOwnedCurrentIndex = showOwnedComboBox->currentIndex();
|
|
||||||
if (showOwnedCurrentIndex != mEngineSettings.getInt("show owned", "Game"))
|
|
||||||
mEngineSettings.setInt("show owned", "Game", showOwnedCurrentIndex);
|
|
||||||
|
|
||||||
// Other Settings
|
|
||||||
std::string screenshotFormatString = screenshotFormatComboBox->currentText().toLower().toStdString();
|
|
||||||
if (screenshotFormatString != mEngineSettings.getString("screenshot format", "General"))
|
|
||||||
mEngineSettings.setString("screenshot format", "General", screenshotFormatString);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Launcher::AdvancedPage::loadSettingBool(QCheckBox *checkbox, const std::string &setting, const std::string &group) {
|
void Launcher::AdvancedPage::loadSettingBool(QCheckBox *checkbox, const std::string &setting, const std::string &group)
|
||||||
|
{
|
||||||
if (mEngineSettings.getBool(setting, group))
|
if (mEngineSettings.getBool(setting, group))
|
||||||
checkbox->setCheckState(Qt::Checked);
|
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();
|
bool cValue = checkbox->checkState();
|
||||||
if (cValue != mEngineSettings.getBool(setting, group))
|
if (cValue != mEngineSettings.getBool(setting, group))
|
||||||
mEngineSettings.setBool(setting, group, cValue);
|
mEngineSettings.setBool(setting, group, cValue);
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
#define ADVANCEDPAGE_H
|
#define ADVANCEDPAGE_H
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
#include <QCompleter>
|
||||||
|
#include <QStringListModel>
|
||||||
|
|
||||||
#include "ui_advancedpage.h"
|
#include "ui_advancedpage.h"
|
||||||
|
|
||||||
|
@ -35,6 +37,8 @@ namespace Launcher
|
||||||
Files::ConfigurationManager &mCfgMgr;
|
Files::ConfigurationManager &mCfgMgr;
|
||||||
Config::GameSettings &mGameSettings;
|
Config::GameSettings &mGameSettings;
|
||||||
Settings::Manager &mEngineSettings;
|
Settings::Manager &mEngineSettings;
|
||||||
|
QCompleter mCellNameCompleter;
|
||||||
|
QStringListModel mCellNameCompleterModel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load the cells associated with the given content files for use in autocomplete
|
* Load the cells associated with the given content files for use in autocomplete
|
||||||
|
|
|
@ -60,13 +60,14 @@ bool MWMechanics::AiAvoidDoor::execute (const MWWorld::Ptr& actor, CharacterCont
|
||||||
// Make all nearby actors also avoid the door
|
// Make all nearby actors also avoid the door
|
||||||
std::vector<MWWorld::Ptr> actors;
|
std::vector<MWWorld::Ptr> actors;
|
||||||
MWBase::Environment::get().getMechanicsManager()->getActorsInRange(pos.asVec3(),100,actors);
|
MWBase::Environment::get().getMechanicsManager()->getActorsInRange(pos.asVec3(),100,actors);
|
||||||
for(std::vector<MWWorld::Ptr>::iterator it = actors.begin(); it != actors.end(); ++it) {
|
for(auto& actor : actors)
|
||||||
if(*it != getPlayer()) { //Not the player
|
{
|
||||||
MWMechanics::AiSequence& seq = it->getClass().getCreatureStats(*it).getAiSequence();
|
if (actor == getPlayer())
|
||||||
if(seq.getTypeId() != MWMechanics::AiPackageTypeId::AvoidDoor) { //Only add it once
|
continue;
|
||||||
seq.stack(MWMechanics::AiAvoidDoor(mDoorPtr),*it);
|
|
||||||
}
|
MWMechanics::AiSequence& seq = actor.getClass().getCreatureStats(actor).getAiSequence();
|
||||||
}
|
if (seq.getTypeId() != MWMechanics::AiPackageTypeId::AvoidDoor)
|
||||||
|
seq.stack(MWMechanics::AiAvoidDoor(mDoorPtr), actor);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -124,9 +124,9 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characte
|
||||||
followDistance = 313;
|
followDistance = 313;
|
||||||
short i = 0;
|
short i = 0;
|
||||||
followers.sort();
|
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;
|
followDistance += 130 * i;
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
|
|
|
@ -406,36 +406,36 @@ void AiSequence::fill(const ESM::AIPackageList &list)
|
||||||
if (!list.mList.empty() && list.mList.begin() != (list.mList.end()-1))
|
if (!list.mList.empty() && list.mList.begin() != (list.mList.end()-1))
|
||||||
mRepeat = true;
|
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;
|
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;
|
std::vector<unsigned char> idles;
|
||||||
idles.reserve(8);
|
idles.reserve(8);
|
||||||
for (int i=0; i<8; ++i)
|
for (int i=0; i<8; ++i)
|
||||||
idles.push_back(data.mIdle[i]);
|
idles.push_back(data.mIdle[i]);
|
||||||
package = std::make_unique<MWMechanics::AiWander>(data.mDistance, data.mDuration, data.mTimeOfDay, idles, data.mShouldRepeat != 0);
|
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);
|
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);
|
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());
|
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);
|
package = std::make_unique<MWMechanics::AiFollow>(data.mId.toString(), data.mDuration, data.mX, data.mY, data.mZ);
|
||||||
}
|
}
|
||||||
mPackages.push_back(std::move(package));
|
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.
|
// If there is more than one non-combat, non-pursue package in the list, enable repeating.
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (std::vector<ESM::AiSequence::AiPackageContainer>::const_iterator it = sequence.mPackages.begin();
|
for (auto& container : sequence.mPackages)
|
||||||
it != sequence.mPackages.end(); ++it)
|
|
||||||
{
|
{
|
||||||
if (isActualAiPackage(static_cast<AiPackageTypeId>(it->mType)))
|
if (isActualAiPackage(static_cast<AiPackageTypeId>(container.mType)))
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -468,20 +467,19 @@ void AiSequence::readState(const ESM::AiSequence::AiSequence &sequence)
|
||||||
mRepeat = true;
|
mRepeat = true;
|
||||||
|
|
||||||
// Load packages
|
// Load packages
|
||||||
for (std::vector<ESM::AiSequence::AiPackageContainer>::const_iterator it = sequence.mPackages.begin();
|
for (auto& container : sequence.mPackages)
|
||||||
it != sequence.mPackages.end(); ++it)
|
|
||||||
{
|
{
|
||||||
std::unique_ptr<MWMechanics::AiPackage> package;
|
std::unique_ptr<MWMechanics::AiPackage> package;
|
||||||
switch (it->mType)
|
switch (container.mType)
|
||||||
{
|
{
|
||||||
case ESM::AiSequence::Ai_Wander:
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case ESM::AiSequence::Ai_Travel:
|
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)
|
if (source->mHidden)
|
||||||
package.reset(new AiInternalTravel(source));
|
package.reset(new AiInternalTravel(source));
|
||||||
else
|
else
|
||||||
|
@ -490,27 +488,27 @@ void AiSequence::readState(const ESM::AiSequence::AiSequence &sequence)
|
||||||
}
|
}
|
||||||
case ESM::AiSequence::Ai_Escort:
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case ESM::AiSequence::Ai_Follow:
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case ESM::AiSequence::Ai_Activate:
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case ESM::AiSequence::Ai_Combat:
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case ESM::AiSequence::Ai_Pursue:
|
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;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -809,11 +809,11 @@ namespace MWMechanics
|
||||||
void AiWander::AddNonPathGridAllowedPoints(osg::Vec3f npcPos, const ESM::Pathgrid * pathGrid, int pointIndex, AiWanderStorage& storage)
|
void AiWander::AddNonPathGridAllowedPoints(osg::Vec3f npcPos, const ESM::Pathgrid * pathGrid, int pointIndex, AiWanderStorage& storage)
|
||||||
{
|
{
|
||||||
storage.mAllowedNodes.push_back(PathFinder::makePathgridPoint(npcPos));
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,38 +61,36 @@ namespace MWMechanics
|
||||||
|
|
||||||
// Note: the algorithm heavily depends on the traversal order of the spells. For vanilla-compatible results the
|
// 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.
|
// 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;
|
continue;
|
||||||
if (!(spell->mData.mFlags & ESM::Spell::F_Autocalc))
|
if (!(spell.mData.mFlags & ESM::Spell::F_Autocalc))
|
||||||
continue;
|
continue;
|
||||||
static const int iAutoSpellTimesCanCast = gmst.find("iAutoSpellTimesCanCast")->mValue.getInteger();
|
static const int iAutoSpellTimesCanCast = gmst.find("iAutoSpellTimesCanCast")->mValue.getInteger();
|
||||||
if (baseMagicka < iAutoSpellTimesCanCast * spell->mData.mCost)
|
if (baseMagicka < iAutoSpellTimesCanCast * spell.mData.mCost)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (race && race->mPowers.exists(spell->mId))
|
if (race && race->mPowers.exists(spell.mId))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!attrSkillCheck(spell, actorSkills, actorAttributes))
|
if (!attrSkillCheck(&spell, actorSkills, actorAttributes))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
int school;
|
int school;
|
||||||
float skillTerm;
|
float skillTerm;
|
||||||
calcWeakestSchool(spell, actorSkills, school, skillTerm);
|
calcWeakestSchool(&spell, actorSkills, school, skillTerm);
|
||||||
assert(school >= 0 && school < 6);
|
assert(school >= 0 && school < 6);
|
||||||
SchoolCaps& cap = schoolCaps[school];
|
SchoolCaps& cap = schoolCaps[school];
|
||||||
|
|
||||||
if (cap.mReachedLimit && spell->mData.mCost <= cap.mMinCost)
|
if (cap.mReachedLimit && spell.mData.mCost <= cap.mMinCost)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
static const float fAutoSpellChance = gmst.find("fAutoSpellChance")->mValue.getFloat();
|
static const float fAutoSpellChance = gmst.find("fAutoSpellChance")->mValue.getFloat();
|
||||||
if (calcAutoCastChance(spell, actorSkills, actorAttributes, school) < fAutoSpellChance)
|
if (calcAutoCastChance(&spell, actorSkills, actorAttributes, school) < fAutoSpellChance)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
selectedSpells.push_back(spell->mId);
|
selectedSpells.push_back(spell.mId);
|
||||||
|
|
||||||
if (cap.mReachedLimit)
|
if (cap.mReachedLimit)
|
||||||
{
|
{
|
||||||
|
@ -101,9 +99,9 @@ namespace MWMechanics
|
||||||
selectedSpells.erase(found);
|
selectedSpells.erase(found);
|
||||||
|
|
||||||
cap.mMinCost = std::numeric_limits<int>::max();
|
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;
|
//int testSchool;
|
||||||
//float dummySkillTerm;
|
//float dummySkillTerm;
|
||||||
|
@ -130,10 +128,10 @@ namespace MWMechanics
|
||||||
if (cap.mCount == cap.mLimit)
|
if (cap.mCount == cap.mLimit)
|
||||||
cap.mReachedLimit = true;
|
cap.mReachedLimit = true;
|
||||||
|
|
||||||
if (spell->mData.mCost < cap.mMinCost)
|
if (spell.mData.mCost < cap.mMinCost)
|
||||||
{
|
{
|
||||||
cap.mWeakestSpell = spell->mId;
|
cap.mWeakestSpell = spell.mId;
|
||||||
cap.mMinCost = spell->mData.mCost;
|
cap.mMinCost = spell.mData.mCost;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -154,32 +152,28 @@ namespace MWMechanics
|
||||||
|
|
||||||
std::vector<std::string> selectedSpells;
|
std::vector<std::string> selectedSpells;
|
||||||
|
|
||||||
|
const MWWorld::Store<ESM::Spell> &spells = esmStore.get<ESM::Spell>();
|
||||||
const MWWorld::Store<ESM::Spell> &spells =
|
for (const ESM::Spell& spell : spells)
|
||||||
esmStore.get<ESM::Spell>();
|
|
||||||
for (MWWorld::Store<ESM::Spell>::iterator iter = spells.begin(); iter != spells.end(); ++iter)
|
|
||||||
{
|
{
|
||||||
const ESM::Spell* spell = &*iter;
|
if (spell.mData.mType != ESM::Spell::ST_Spell)
|
||||||
|
|
||||||
if (spell->mData.mType != ESM::Spell::ST_Spell)
|
|
||||||
continue;
|
continue;
|
||||||
if (!(spell->mData.mFlags & ESM::Spell::F_PCStart))
|
if (!(spell.mData.mFlags & ESM::Spell::F_PCStart))
|
||||||
continue;
|
continue;
|
||||||
if (reachedLimit && spell->mData.mCost <= minCost)
|
if (reachedLimit && spell.mData.mCost <= minCost)
|
||||||
continue;
|
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;
|
continue;
|
||||||
if (baseMagicka < spell->mData.mCost)
|
if (baseMagicka < spell.mData.mCost)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
static const float fAutoPCSpellChance = esmStore.get<ESM::GameSetting>().find("fAutoPCSpellChance")->mValue.getFloat();
|
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;
|
continue;
|
||||||
|
|
||||||
if (!attrSkillCheck(spell, actorSkills, actorAttributes))
|
if (!attrSkillCheck(&spell, actorSkills, actorAttributes))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
selectedSpells.push_back(spell->mId);
|
selectedSpells.push_back(spell.mId);
|
||||||
|
|
||||||
if (reachedLimit)
|
if (reachedLimit)
|
||||||
{
|
{
|
||||||
|
@ -188,9 +182,9 @@ namespace MWMechanics
|
||||||
selectedSpells.erase(it);
|
selectedSpells.erase(it);
|
||||||
|
|
||||||
minCost = std::numeric_limits<int>::max();
|
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)
|
if (testSpell->mData.mCost < minCost)
|
||||||
{
|
{
|
||||||
minCost = testSpell->mData.mCost;
|
minCost = testSpell->mData.mCost;
|
||||||
|
@ -200,9 +194,9 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (spell->mData.mCost < minCost)
|
if (spell.mData.mCost < minCost)
|
||||||
{
|
{
|
||||||
weakestSpell = spell;
|
weakestSpell = &spell;
|
||||||
minCost = weakestSpell->mData.mCost;
|
minCost = weakestSpell->mData.mCost;
|
||||||
}
|
}
|
||||||
static const unsigned int iAutoPCSpellMax = esmStore.get<ESM::GameSetting>().find("iAutoPCSpellMax")->mValue.getInteger();
|
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)
|
bool attrSkillCheck (const ESM::Spell* spell, const int* actorSkills, const int* actorAttributes)
|
||||||
{
|
{
|
||||||
const std::vector<ESM::ENAMstruct>& effects = spell->mEffects.mList;
|
for (const auto& spellEffect : spell->mEffects.mList)
|
||||||
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt = effects.begin(); effectIt != effects.end(); ++effectIt)
|
|
||||||
{
|
{
|
||||||
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();
|
static const int iAutoSpellAttSkillMin = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("iAutoSpellAttSkillMin")->mValue.getInteger();
|
||||||
|
|
||||||
if ((magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill))
|
if ((magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill))
|
||||||
{
|
{
|
||||||
assert (effectIt->mSkill >= 0 && effectIt->mSkill < ESM::Skill::Length);
|
assert (spellEffect.mSkill >= 0 && spellEffect.mSkill < ESM::Skill::Length);
|
||||||
if (actorSkills[effectIt->mSkill] < iAutoSpellAttSkillMin)
|
if (actorSkills[spellEffect.mSkill] < iAutoSpellAttSkillMin)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((magicEffect->mData.mFlags & ESM::MagicEffect::TargetAttribute))
|
if ((magicEffect->mData.mFlags & ESM::MagicEffect::TargetAttribute))
|
||||||
{
|
{
|
||||||
assert (effectIt->mAttribute >= 0 && effectIt->mAttribute < ESM::Attribute::Length);
|
assert (spellEffect.mAttribute >= 0 && spellEffect.mAttribute < ESM::Attribute::Length);
|
||||||
if (actorAttributes[effectIt->mAttribute] < iAutoSpellAttSkillMin)
|
if (actorAttributes[spellEffect.mAttribute] < iAutoSpellAttSkillMin)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -244,11 +237,8 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
// Morrowind for some reason uses a formula slightly different from magicka cost calculation
|
// Morrowind for some reason uses a formula slightly different from magicka cost calculation
|
||||||
float minChance = std::numeric_limits<float>::max();
|
float minChance = std::numeric_limits<float>::max();
|
||||||
|
for (const ESM::ENAMstruct& effect : spell->mEffects.mList)
|
||||||
const ESM::EffectList& effects = spell->mEffects;
|
|
||||||
for (std::vector<ESM::ENAMstruct>::const_iterator it = effects.mList.begin(); it != effects.mList.end(); ++it)
|
|
||||||
{
|
{
|
||||||
const ESM::ENAMstruct& effect = *it;
|
|
||||||
const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(effect.mEffectID);
|
const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(effect.mEffectID);
|
||||||
|
|
||||||
int minMagn = 1;
|
int minMagn = 1;
|
||||||
|
|
|
@ -2653,11 +2653,11 @@ void CharacterController::updateContinuousVfx()
|
||||||
std::vector<int> effects;
|
std::vector<int> effects;
|
||||||
mAnimation->getLoopingEffects(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()
|
if (mPtr.getClass().getCreatureStats(mPtr).isDeathAnimationFinished()
|
||||||
|| mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(MWMechanics::EffectKey(*it)).getMagnitude() <= 0)
|
|| mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(MWMechanics::EffectKey(effectId)).getMagnitude() <= 0)
|
||||||
mAnimation->removeEffect(*it);
|
mAnimation->removeEffect(effectId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,10 +31,10 @@ namespace MWMechanics
|
||||||
|
|
||||||
std::vector<std::string> candidates;
|
std::vector<std::string> candidates;
|
||||||
int highestLevel = 0;
|
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)
|
if (levelledItem.mLevel > highestLevel && levelledItem.mLevel <= playerLevel)
|
||||||
highestLevel = it->mLevel;
|
highestLevel = levelledItem.mLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For levelled creatures, the flags are swapped. This file format just makes so much sense.
|
// 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;
|
allLevels = levItem->mFlags & ESM::CreatureLevList::AllLevels;
|
||||||
|
|
||||||
std::pair<int, std::string> highest = std::make_pair(-1, "");
|
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
|
if (playerLevel >= levelledItem.mLevel
|
||||||
&& (allLevels || it->mLevel == highestLevel))
|
&& (allLevels || levelledItem.mLevel == highestLevel))
|
||||||
{
|
{
|
||||||
candidates.push_back(it->mId);
|
candidates.push_back(levelledItem.mId);
|
||||||
if (it->mLevel >= highest.first)
|
if (levelledItem.mLevel >= highest.first)
|
||||||
highest = std::make_pair(it->mLevel, it->mId);
|
highest = std::make_pair(levelledItem.mLevel, levelledItem.mId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (candidates.empty())
|
if (candidates.empty())
|
||||||
|
|
|
@ -19,11 +19,10 @@ Objects::Objects()
|
||||||
|
|
||||||
Objects::~Objects()
|
Objects::~Objects()
|
||||||
{
|
{
|
||||||
PtrControllerMap::iterator it(mObjects.begin());
|
for(auto& object : mObjects)
|
||||||
for (; it != mObjects.end();++it)
|
|
||||||
{
|
{
|
||||||
delete it->second;
|
delete object.second;
|
||||||
it->second = nullptr;
|
object.second = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,8 +76,8 @@ void Objects::update(float duration, bool paused)
|
||||||
{
|
{
|
||||||
if(!paused)
|
if(!paused)
|
||||||
{
|
{
|
||||||
for(PtrControllerMap::iterator iter(mObjects.begin());iter != mObjects.end();++iter)
|
for(auto& object : mObjects)
|
||||||
iter->second->update(duration);
|
object.second->update(duration);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -87,15 +86,15 @@ void Objects::update(float duration, bool paused)
|
||||||
if(mode != MWGui::GM_Container)
|
if(mode != MWGui::GM_Container)
|
||||||
return;
|
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;
|
continue;
|
||||||
|
|
||||||
if (iter->second->isAnimPlaying("containeropen"))
|
if (object.second->isAnimPlaying("containeropen"))
|
||||||
{
|
{
|
||||||
iter->second->update(duration);
|
object.second->update(duration);
|
||||||
MWBase::Environment::get().getWorld()->updateAnimatedCollisionShape(iter->first);
|
MWBase::Environment::get().getWorld()->updateAnimatedCollisionShape(object.first);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,17 +36,13 @@ namespace MWMechanics
|
||||||
|
|
||||||
// Check all the doors in this cell
|
// Check all the doors in this cell
|
||||||
const MWWorld::CellRefList<ESM::Door>& doors = cell->getReadOnlyDoors();
|
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());
|
osg::Vec3f pos(actor.getRefData().getPosition().asVec3());
|
||||||
pos.z() = 0;
|
pos.z() = 0;
|
||||||
|
|
||||||
osg::Vec3f actorDir = (actor.getRefData().getBaseNode()->getAttitude() * osg::Vec3f(0,1,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());
|
osg::Vec3f doorPos(ref.mData.getPosition().asVec3());
|
||||||
|
|
||||||
// FIXME: cast
|
// FIXME: cast
|
||||||
|
|
|
@ -21,14 +21,14 @@ namespace MWRender
|
||||||
mAutoSwitchShoulder(Settings::Manager::getBool("auto switch shoulder", "Camera")),
|
mAutoSwitchShoulder(Settings::Manager::getBool("auto switch shoulder", "Camera")),
|
||||||
mOverShoulderHorizontalOffset(30.f), mOverShoulderVerticalOffset(-10.f)
|
mOverShoulderHorizontalOffset(30.f), mOverShoulderVerticalOffset(-10.f)
|
||||||
{
|
{
|
||||||
std::stringstream offset(Settings::Manager::getString("view over shoulder offset", "Camera"));
|
osg::Vec2f offset = Settings::Manager::getVector2("view over shoulder offset", "Camera");
|
||||||
offset >> mOverShoulderHorizontalOffset >> mOverShoulderVerticalOffset;
|
mOverShoulderHorizontalOffset = std::abs(offset.x());
|
||||||
mDefaultShoulderIsRight = mOverShoulderHorizontalOffset >= 0;
|
mOverShoulderVerticalOffset = offset.y();
|
||||||
mOverShoulderHorizontalOffset = std::abs(mOverShoulderHorizontalOffset);
|
mDefaultShoulderIsRight = offset.x() >= 0;
|
||||||
|
|
||||||
mCamera->enableDynamicCameraDistance(true);
|
mCamera->enableDynamicCameraDistance(true);
|
||||||
mCamera->enableCrosshairInThirdPersonMode(true);
|
mCamera->enableCrosshairInThirdPersonMode(true);
|
||||||
mCamera->setFocalPointTargetOffset({mOverShoulderHorizontalOffset, mOverShoulderVerticalOffset});
|
mCamera->setFocalPointTargetOffset(offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewOverShoulderController::update()
|
void ViewOverShoulderController::update()
|
||||||
|
|
|
@ -8,6 +8,7 @@ ContentSelectorView::ComboBox::ComboBox(QWidget *parent) :
|
||||||
{
|
{
|
||||||
mValidator = new QRegExpValidator(QRegExp("^[a-zA-Z0-9_]*$"), this); // Alpha-numeric + underscore
|
mValidator = new QRegExpValidator(QRegExp("^[a-zA-Z0-9_]*$"), this); // Alpha-numeric + underscore
|
||||||
setValidator(mValidator);
|
setValidator(mValidator);
|
||||||
|
setEditable(true);
|
||||||
setCompleter(0);
|
setCompleter(0);
|
||||||
setEnabled (true);
|
setEnabled (true);
|
||||||
|
|
||||||
|
|
|
@ -76,6 +76,28 @@ bool Manager::getBool (const std::string& setting, const std::string& category)
|
||||||
return Misc::StringUtils::ciEqual(string, "true");
|
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)
|
void Manager::setString(const std::string &setting, const std::string &category, const std::string &value)
|
||||||
{
|
{
|
||||||
CategorySettingValueMap::key_type key = std::make_pair(category, setting);
|
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");
|
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)
|
void Manager::resetPendingChange(const std::string &setting, const std::string &category)
|
||||||
{
|
{
|
||||||
CategorySettingValueMap::key_type key = std::make_pair(category, setting);
|
CategorySettingValueMap::key_type key = std::make_pair(category, setting);
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <osg/Vec2f>
|
||||||
|
#include <osg/Vec3f>
|
||||||
|
|
||||||
namespace Settings
|
namespace Settings
|
||||||
{
|
{
|
||||||
|
@ -44,11 +46,15 @@ namespace Settings
|
||||||
static float getFloat (const std::string& setting, const std::string& category);
|
static float getFloat (const std::string& setting, const std::string& category);
|
||||||
static std::string getString (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 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 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 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 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 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);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -136,7 +136,7 @@ This setting controls third person view mode.
|
||||||
False: View is centered on the character's head. Crosshair is hidden.
|
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.
|
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 over shoulder offset
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
|
@ -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.
|
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
|
swim upward coef
|
||||||
----------------
|
----------------
|
||||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue