diff --git a/CHANGELOG.md b/CHANGELOG.md index 83682c507..1923e5237 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ Bug #4327: Missing animations during spell/weapon stance switching Bug #4358: Running animation is interrupted when magic mode is toggled Bug #4368: Settings window ok button doesn't have key focus by default + Bug #4378: On-self absorb spells restore stats Bug #4393: NPCs walk back to where they were after using ResetActors Bug #4416: Handle exception if we try to play non-music file Bug #4419: MRK NiStringExtraData is handled incorrectly @@ -72,10 +73,12 @@ Bug #4503: Cast and ExplodeSpell commands increase alteration skill Bug #4510: Division by zero in MWMechanics::CreatureStats::setAttribute Bug #4519: Knockdown does not discard movement in the 1st-person mode + Bug #4539: Paper Doll is affected by GUI scaling Feature #2606: Editor: Implemented (optional) case sensitive global search Feature #3083: Play animation when NPC is casting spell via script Feature #3276: Editor: Search- Show number of (remaining) search results and indicate a search without any results Feature #3641: Editor: Limit FPS in 3d preview window + Feature #3703: Ranged sneak attack criticals Feature #4222: 360° screenshots Feature #4256: Implement ToggleBorders (TB) console command Feature #4324: Add CFBundleIdentifier in Info.plist to allow for macOS function key shortcuts diff --git a/apps/launcher/advancedpage.cpp b/apps/launcher/advancedpage.cpp index 3a4c50e9d..3e0314607 100644 --- a/apps/launcher/advancedpage.cpp +++ b/apps/launcher/advancedpage.cpp @@ -73,6 +73,8 @@ bool Launcher::AdvancedPage::loadSettings() loadSettingBool(followersAttackOnSightCheckBox, "followers attack on sight", "Game"); loadSettingBool(preventMerchantEquippingCheckBox, "prevent merchant equipping", "Game"); loadSettingBool(rebalanceSoulGemValuesCheckBox, "rebalance soul gem values", "Game"); + loadSettingBool(chargeForEveryFollowerCheckBox, "charge for every follower travelling", "Game"); + loadSettingBool(enchantedWeaponsMagicalCheckBox, "enchanted weapons are magical", "Game"); // Input Settings loadSettingBool(allowThirdPersonZoomCheckBox, "allow third person zoom", "Input"); @@ -125,6 +127,8 @@ void Launcher::AdvancedPage::saveSettings() saveSettingBool(followersAttackOnSightCheckBox, "followers attack on sight", "Game"); saveSettingBool(preventMerchantEquippingCheckBox, "prevent merchant equipping", "Game"); saveSettingBool(rebalanceSoulGemValuesCheckBox, "rebalance soul gem values", "Game"); + saveSettingBool(chargeForEveryFollowerCheckBox, "charge for every follower travelling", "Game"); + saveSettingBool(enchantedWeaponsMagicalCheckBox, "enchanted weapons are magical", "Game"); // Input Settings saveSettingBool(allowThirdPersonZoomCheckBox, "allow third person zoom", "Input"); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index e909ecbba..ce6d0d522 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -67,7 +67,12 @@ namespace MWGui , mLastYSize(0) , mPreview(new MWRender::InventoryPreview(parent, resourceSystem, MWMechanics::getPlayer())) , mTrading(false) + , mScaleFactor(1.0f) { + float uiScale = Settings::Manager::getFloat("scaling factor", "GUI"); + if (uiScale > 1.0) + mScaleFactor = uiScale; + mPreviewTexture.reset(new osgMyGUI::OSGTexture(mPreview->getTexture())); mPreview->rebuild(); @@ -431,10 +436,10 @@ namespace MWGui MyGUI::IntSize size = mAvatarImage->getSize(); int width = std::min(mPreview->getTextureWidth(), size.width); int height = std::min(mPreview->getTextureHeight(), size.height); - mPreview->setViewport(width, height); + mPreview->setViewport(int(width*mScaleFactor), int(height*mScaleFactor)); mAvatarImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, - width/float(mPreview->getTextureWidth()), height/float(mPreview->getTextureHeight()))); + width*mScaleFactor/float(mPreview->getTextureWidth()), height*mScaleFactor/float(mPreview->getTextureHeight()))); } void InventoryWindow::onFilterChanged(MyGUI::Widget* _sender) @@ -591,6 +596,11 @@ namespace MWGui { // convert to OpenGL lower-left origin y = (mAvatarImage->getHeight()-1) - y; + + // Scale coordinates + x = int(x*mScaleFactor); + y = int(y*mScaleFactor); + int slot = mPreview->getSlotSelected (x, y); if (slot == -1) diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 124fe7b0e..d9cf6870c 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -101,6 +101,7 @@ namespace MWGui std::unique_ptr mPreview; bool mTrading; + float mScaleFactor; void onItemSelected(int index); void onItemSelectedFromSourceModel(int index); diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index 6b45a513b..5910dbacd 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -209,8 +209,21 @@ namespace MWMechanics adjustWeaponDamage(damage, weapon, attacker); - if(attacker == getPlayer()) + if (attacker == getPlayer()) + { attacker.getClass().skillUsageSucceeded(attacker, weaponSkill, 0); + const MWMechanics::AiSequence& sequence = victim.getClass().getCreatureStats(victim).getAiSequence(); + + bool unaware = !sequence.isInCombat() + && !MWBase::Environment::get().getMechanicsManager()->awarenessCheck(attacker, victim); + + if (unaware) + { + damage *= gmst.find("fCombatCriticalStrikeMult")->getFloat(); + MWBase::Environment::get().getWindowManager()->messageBox("#{sTargetCriticalStrike}"); + MWBase::Environment::get().getSoundManager()->playSound3D(victim, "critical damage", 1.0f, 1.0f); + } + } if (victim.getClass().getCreatureStats(victim).getKnockedDown()) damage *= gmst.find("fCombatKODamageMult")->getFloat(); diff --git a/apps/openmw/mwmechanics/difficultyscaling.cpp b/apps/openmw/mwmechanics/difficultyscaling.cpp index 693587eda..53cf47dea 100644 --- a/apps/openmw/mwmechanics/difficultyscaling.cpp +++ b/apps/openmw/mwmechanics/difficultyscaling.cpp @@ -12,8 +12,10 @@ float scaleDamage(float damage, const MWWorld::Ptr& attacker, const MWWorld::Ptr { const MWWorld::Ptr& player = MWMechanics::getPlayer(); - // [-100, 100] + // [-500, 500] int difficultySetting = Settings::Manager::getInt("difficulty", "Game"); + difficultySetting = std::min(difficultySetting, 500); + difficultySetting = std::max(difficultySetting, -500); static const float fDifficultyMult = MWBase::Environment::get().getWorld()->getStore().get().find("fDifficultyMult")->getFloat(); diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 4557a52df..0741bedeb 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -420,9 +420,9 @@ namespace MWMechanics if (!checkEffectTarget(effectIt->mEffectID, target, caster, castByPlayer)) continue; - // caster needs to be an actor for linked effects (e.g. Absorb) + // caster needs to be an actor that's not the target for linked effects (e.g. Absorb) if (magicEffect->mData.mFlags & ESM::MagicEffect::CasterLinked - && (caster.isEmpty() || !caster.getClass().isActor())) + && (caster.isEmpty() || !caster.getClass().isActor() || caster == target)) continue; // If player is healing someone, show the target's HP bar @@ -554,7 +554,7 @@ namespace MWMechanics // For absorb effects, also apply the effect to the caster - but with a negative // magnitude, since we're transferring stats from the target to the caster - if (!caster.isEmpty() && caster.getClass().isActor()) + if (!caster.isEmpty() && caster != target && caster.getClass().isActor()) { for (int i=0; i<5; ++i) { diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 8353779a8..4e7f6d511 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -579,13 +579,11 @@ namespace NifOsg if (composite->getNumControllers() > 0) node->addUpdateCallback(composite); - // Note: NiTriShapes are not allowed to have KeyframeControllers (the vanilla engine just crashes when there is one). // We can take advantage of this constraint for optimizations later. - if (!nifNode->controller.empty() && node->getDataVariance() == osg::Object::DYNAMIC) + if (nifNode->recType != Nif::RC_NiTriShape && !nifNode->controller.empty() && node->getDataVariance() == osg::Object::DYNAMIC) handleNodeControllers(nifNode, static_cast(node.get()), animflags); - if (nifNode->recType == Nif::RC_NiLODNode) { const Nif::NiLODNode* niLodNode = static_cast(nifNode); diff --git a/files/ui/advancedpage.ui b/files/ui/advancedpage.ui index 0e43654f2..486d410df 100644 --- a/files/ui/advancedpage.ui +++ b/files/ui/advancedpage.ui @@ -21,8 +21,8 @@ 0 0 - 630 - 791 + 641 + 968 @@ -72,6 +72,26 @@ + + + + <html><head/><body><p>Account for the first follower in fast travel cost calculations.</p></body></html> + + + Charge for every follower travelling + + + + + + + <html><head/><body><p>Make enchanted weaponry without Magical flag bypass normal weapons resistance, like in Morrowind.</p></body></html> + + + Enchanted weapons are magical + + + @@ -137,7 +157,7 @@ - -1 + 6 0 @@ -312,7 +332,7 @@ - -1 + 6 0 @@ -379,7 +399,7 @@ - -1 + 6 0