From 14240cf7a2803919fa685c5c538cbba0a33dc8aa Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sun, 16 Oct 2016 17:27:17 +0200 Subject: [PATCH 01/94] Fix autoEquip to better match vanilla (Fixes #3590) --- apps/openmw/mwworld/inventorystore.cpp | 90 ++++++++++++++------------ 1 file changed, 49 insertions(+), 41 deletions(-) diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index aa6880a49..25b9cbf08 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -216,22 +216,33 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::getSlot (int slot) void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) { + if (!actor.getClass().isNpc()) + // autoEquip is no-op for creatures + return; + + const MWBase::World *world = MWBase::Environment::get().getWorld(); + const MWWorld::Store &store = world->getStore().get(); + MWMechanics::NpcStats& stats = actor.getClass().getNpcStats(actor); + + static float fUnarmoredBase1 = store.find("fUnarmoredBase1")->getFloat(); + static float fUnarmoredBase2 = store.find("fUnarmoredBase2")->getFloat(); + int unarmoredSkill = stats.getSkill(ESM::Skill::Unarmored).getModified(); + + float unarmoredRating = static_cast((fUnarmoredBase1 * unarmoredSkill) * (fUnarmoredBase2 * unarmoredSkill)); + TSlots slots_; initSlots (slots_); // Disable model update during auto-equip mUpdatesEnabled = false; - for (ContainerStoreIterator iter (begin()); iter!=end(); ++iter) + // Relevant are only clothing and armor items: + // - Equipping lights is handled in Actors::updateEquippedLight based on environment light. + // - Equipping weapons is handled by AiCombat. + for (ContainerStoreIterator iter (begin(ContainerStore::Type_Clothing | ContainerStore::Type_Armor)); iter!=end(); ++iter) { Ptr test = *iter; - // Don't autoEquip lights. Handled in Actors::updateEquippedLight based on environment light. - if (test.getTypeName() == typeid(ESM::Light).name()) - { - continue; - } - // Only autoEquip if we are the original owner of the item. // This stops merchants from auto equipping anything you sell to them. // ...unless this is a companion, he should always equip items given to him. @@ -243,7 +254,20 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) { continue; } - int testSkill = test.getClass().getEquipmentSkill (test); + + switch(test.getClass().canBeEquipped (test, actor).first) + { + case 0: + continue; + default: + break; + } + + if (iter.getType() == ContainerStore::Type_Armor && + test.getClass().getEffectiveArmorRating(test, actor) <= std::max(unarmoredRating, 0.f)) + { + continue; + } std::pair, bool> itemsSlots = iter->getClass().getEquipmentSlots (*iter); @@ -251,51 +275,35 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) for (std::vector::const_iterator iter2 (itemsSlots.first.begin()); iter2!=itemsSlots.first.end(); ++iter2) { - if (*iter2 == Slot_CarriedRight) // Items in right hand are situational use, so don't equip them. - // Equipping weapons is handled by AiCombat. Anything else (lockpicks, probes) can't be used by NPCs anyway (yet) - continue; - - if (iter.getType() == MWWorld::ContainerStore::Type_Weapon) - continue; - if (slots_.at (*iter2)!=end()) { Ptr old = *slots_.at (*iter2); - // check skill - int oldSkill = old.getClass().getEquipmentSkill (old); - - bool use = false; - if (testSkill!=-1 && oldSkill==-1) - use = true; - else if (testSkill!=-1 && oldSkill!=-1 && testSkill!=oldSkill) + if (iter.getType() == ContainerStore::Type_Armor) { - if (actor.getClass().getSkill(actor, oldSkill) > actor.getClass().getSkill (actor, testSkill)) - continue; // rejected, because old item better matched the NPC's skills. - - if (actor.getClass().getSkill(actor, oldSkill) < actor.getClass().getSkill (actor, testSkill)) - use = true; + if (old.getTypeName() == typeid(ESM::Armor).name()) + { + if (old.getClass().getEffectiveArmorRating(old, actor) >= test.getClass().getEffectiveArmorRating(test, actor)) + // old armor had better armor rating + continue; + } + // suitable armor should replace already equipped clothing } - - if (!use) + else if (iter.getType() == ContainerStore::Type_Clothing) { - // check value - if (old.getClass().getValue (old)>= - test.getClass().getValue (test)) + if (old.getTypeName() == typeid(ESM::Clothing).name()) { - continue; + // check value + if (old.getClass().getValue (old) > test.getClass().getValue (test)) + // old clothing was more valuable + continue; } + else + // suitable clothing should NOT replace already equipped armor + continue; } } - switch(test.getClass().canBeEquipped (test, actor).first) - { - case 0: - continue; - default: - break; - } - if (!itemsSlots.second) // if itemsSlots.second is true, item can stay stacked when equipped { // unstack item pointed to by iterator if required From 77bc80730534d6a61838dc6c4880381b71b95038 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 17 Oct 2016 15:01:10 +0200 Subject: [PATCH 02/94] Attenuate the light ambient in lighting.glsl (Fixes #3597) --- files/shaders/lighting.glsl | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/files/shaders/lighting.glsl b/files/shaders/lighting.glsl index 08b369b5b..d62b61b52 100644 --- a/files/shaders/lighting.glsl +++ b/files/shaders/lighting.glsl @@ -20,9 +20,7 @@ vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor) d = length(lightDir); lightDir = normalize(lightDir); - lightResult.xyz += ambient * gl_LightSource[i].ambient.xyz; - lightResult.xyz += diffuse.xyz * gl_LightSource[i].diffuse.xyz * clamp(1.0 / (gl_LightSource[i].constantAttenuation + gl_LightSource[i].linearAttenuation * d + gl_LightSource[i].quadraticAttenuation * d * d), 0.0, 1.0) - * max(dot(viewNormal.xyz, lightDir), 0.0); + lightResult.xyz += (ambient * gl_LightSource[i].ambient.xyz + diffuse.xyz * gl_LightSource[i].diffuse.xyz * max(dot(viewNormal.xyz, lightDir), 0.0)) * clamp(1.0 / (gl_LightSource[i].constantAttenuation + gl_LightSource[i].linearAttenuation * d + gl_LightSource[i].quadraticAttenuation * d * d), 0.0, 1.0); } lightResult.xyz += gl_LightModel.ambient.xyz * ambient; From 1d3008594d934b1ce8dd42991ead94240574d8d1 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Tue, 18 Oct 2016 13:57:35 +0200 Subject: [PATCH 03/94] Autoequip weapons (Fixes #3562) --- apps/openmw/mwworld/inventorystore.cpp | 96 +++++++++++++++++++++++++- 1 file changed, 93 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 25b9cbf08..6620a991e 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -236,9 +236,9 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) // Disable model update during auto-equip mUpdatesEnabled = false; - // Relevant are only clothing and armor items: - // - Equipping lights is handled in Actors::updateEquippedLight based on environment light. - // - Equipping weapons is handled by AiCombat. + // Autoequip clothing, armor and weapons. + // Equipping lights is handled in Actors::updateEquippedLight based on environment light. + for (ContainerStoreIterator iter (begin(ContainerStore::Type_Clothing | ContainerStore::Type_Armor)); iter!=end(); ++iter) { Ptr test = *iter; @@ -318,6 +318,96 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) } } + static const ESM::Skill::SkillEnum weaponSkills[] = + { + ESM::Skill::LongBlade, + ESM::Skill::Axe, + ESM::Skill::Spear, + ESM::Skill::ShortBlade, + ESM::Skill::Marksman, + ESM::Skill::BluntWeapon + }; + const size_t weaponSkillsLength = sizeof(weaponSkills) / sizeof(weaponSkills[0]); + + bool weaponSkillVisited[weaponSkillsLength] = { false }; + + for (int i = 0; i < static_cast(weaponSkillsLength) - 1; ++i) + { + int max = 0; + int maxWeaponSkill = -1; + + for (int j = 0; j < static_cast(weaponSkillsLength) - 1; ++j) + { + int skillValue = stats.getSkill(static_cast(weaponSkills[j])).getModified(); + + if (skillValue > max && !weaponSkillVisited[j]) + { + max = skillValue; + maxWeaponSkill = j; + } + } + + if (maxWeaponSkill == -1) + break; + + max = 0; + ContainerStoreIterator weapon(end()); + + for (ContainerStoreIterator iter(begin(ContainerStore::Type_Weapon)); iter!=end(); ++iter) + { + const ESM::Weapon* esmWeapon = iter->get()->mBase; + + if (esmWeapon->mData.mType == ESM::Weapon::Arrow || esmWeapon->mData.mType == ESM::Weapon::Bolt) + continue; + + if (iter->getClass().getEquipmentSkill(*iter) == weaponSkills[maxWeaponSkill]) + { + if (esmWeapon->mData.mChop[1] >= max) + { + max = esmWeapon->mData.mChop[1]; + weapon = iter; + } + + if (esmWeapon->mData.mSlash[1] >= max) + { + max = esmWeapon->mData.mSlash[1]; + weapon = iter; + } + + if (esmWeapon->mData.mThrust[1] >= max) + { + max = esmWeapon->mData.mThrust[1]; + weapon = iter; + } + } + } + + if (weapon != end() && weapon->getClass().canBeEquipped(*weapon, actor).first) + { + std::pair, bool> itemsSlots = + weapon->getClass().getEquipmentSlots (*weapon); + + for (std::vector::const_iterator slot (itemsSlots.first.begin()); + slot!=itemsSlots.first.end(); ++slot) + { + if (!itemsSlots.second) + { + if (weapon->getRefData().getCount() > 1) + { + unstack(*weapon, actor); + } + } + + slots_[*slot] = weapon; + break; + } + + break; + } + + weaponSkillVisited[maxWeaponSkill] = true; + } + bool changed = false; for (std::size_t i=0; i Date: Tue, 18 Oct 2016 23:51:45 +0200 Subject: [PATCH 04/94] Properly handle moved references in respawning code (Fixes #3600) --- apps/openmw/mwworld/cellstore.cpp | 16 ++++++++++++---- apps/openmw/mwworld/cellstore.hpp | 3 +++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index db3707441..5e65bad7c 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -204,6 +204,14 @@ namespace MWWorld return (ref.mRef.mRefnum == pRefnum); } + Ptr CellStore::getCurrentPtr(LiveCellRefBase *ref) + { + MovedRefTracker::iterator found = mMovedToAnotherCell.find(ref); + if (found != mMovedToAnotherCell.end()) + return Ptr(ref, found->second); + return Ptr(ref, this); + } + void CellStore::moveFrom(const Ptr &object, CellStore *from) { if (mState != State_Loaded) @@ -964,26 +972,26 @@ namespace MWWorld mLastRespawn = MWBase::Environment::get().getWorld()->getTimeStamp(); for (CellRefList::List::iterator it (mContainers.mList.begin()); it!=mContainers.mList.end(); ++it) { - Ptr ptr (&*it, this); + Ptr ptr = getCurrentPtr(&*it); ptr.getClass().respawn(ptr); } } for (CellRefList::List::iterator it (mCreatures.mList.begin()); it!=mCreatures.mList.end(); ++it) { - Ptr ptr (&*it, this); + Ptr ptr = getCurrentPtr(&*it); clearCorpse(ptr); ptr.getClass().respawn(ptr); } for (CellRefList::List::iterator it (mNpcs.mList.begin()); it!=mNpcs.mList.end(); ++it) { - Ptr ptr (&*it, this); + Ptr ptr = getCurrentPtr(&*it); clearCorpse(ptr); ptr.getClass().respawn(ptr); } for (CellRefList::List::iterator it (mCreatureLists.mList.begin()); it!=mCreatureLists.mList.end(); ++it) { - Ptr ptr (&*it, this); + Ptr ptr = getCurrentPtr(&*it); // no need to clearCorpse, handled as part of mCreatures ptr.getClass().respawn(ptr); } diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 1aee13132..aa7d68d8c 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -111,6 +111,9 @@ namespace MWWorld // Merged list of ref's currently in this cell - i.e. with added refs from mMovedHere, removed refs from mMovedToAnotherCell std::vector mMergedRefs; + // Get the Ptr for the given ref which originated from this cell (possibly moved to another cell at this point). + Ptr getCurrentPtr(MWWorld::LiveCellRefBase* ref); + /// Moves object from the given cell to this cell. void moveFrom(const MWWorld::Ptr& object, MWWorld::CellStore* from); From 76ddd9bebb34da8421901739fe2fec67ef431b84 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Tue, 18 Oct 2016 14:03:11 +0200 Subject: [PATCH 05/94] Add a setting for merchant auto-equipping prevention --- apps/openmw/mwworld/inventorystore.cpp | 35 ++++++++++++++++++-------- apps/openmw/mwworld/inventorystore.hpp | 2 ++ files/settings-default.cfg | 3 +++ 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 6620a991e..cf2a88c1d 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -214,6 +215,26 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::getSlot (int slot) return mSlots[slot]; } +bool MWWorld::InventoryStore::canActorAutoEquip(const MWWorld::Ptr& actor, const MWWorld::Ptr& item) +{ + if (!Settings::Manager::getBool("prevent merchant equipping", "Game")) + return true; + + // Only autoEquip if we are the original owner of the item. + // This stops merchants from auto equipping anything you sell to them. + // ...unless this is a companion, he should always equip items given to him. + if (!Misc::StringUtils::ciEqual(item.getCellRef().getOwner(), actor.getCellRef().getRefId()) && + (actor.getClass().getScript(actor).empty() || + !actor.getRefData().getLocals().getIntVar(actor.getClass().getScript(actor), "companion")) + && !actor.getClass().getCreatureStats(actor).isDead() // Corpses can be dressed up by the player as desired + ) + { + return false; + } + + return true; +} + void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) { if (!actor.getClass().isNpc()) @@ -243,17 +264,8 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) { Ptr test = *iter; - // Only autoEquip if we are the original owner of the item. - // This stops merchants from auto equipping anything you sell to them. - // ...unless this is a companion, he should always equip items given to him. - if (!Misc::StringUtils::ciEqual(test.getCellRef().getOwner(), actor.getCellRef().getRefId()) && - (actor.getClass().getScript(actor).empty() || - !actor.getRefData().getLocals().getIntVar(actor.getClass().getScript(actor), "companion")) - && !actor.getClass().getCreatureStats(actor).isDead() // Corpses can be dressed up by the player as desired - ) - { + if (!canActorAutoEquip(actor, test)) continue; - } switch(test.getClass().canBeEquipped (test, actor).first) { @@ -355,6 +367,9 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) for (ContainerStoreIterator iter(begin(ContainerStore::Type_Weapon)); iter!=end(); ++iter) { + if (!canActorAutoEquip(actor, *iter)) + continue; + const ESM::Weapon* esmWeapon = iter->get()->mBase; if (esmWeapon->mData.mType == ESM::Weapon::Arrow || esmWeapon->mData.mType == ESM::Weapon::Bolt) diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 9e0a8d5b6..7e6a259c4 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -115,6 +115,8 @@ namespace MWWorld virtual void storeEquipmentState (const MWWorld::LiveCellRefBase& ref, int index, ESM::InventoryState& inventory) const; virtual void readEquipmentState (const MWWorld::ContainerStoreIterator& iter, int index, const ESM::InventoryState& inventory); + bool canActorAutoEquip(const MWWorld::Ptr& actor, const MWWorld::Ptr& item); + public: InventoryStore(); diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 3d2cd49bf..9813cb166 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -145,6 +145,9 @@ difficulty = 0 # Show duration of magic effect and lights in the spells window. show effect duration = false +# Prevents merchants from equipping items that are sold to them. +prevent merchant equipping = false + [General] # Anisotropy reduces distortion in textures at low angles (e.g. 0 to 16). From a5ca33ad0b2f87dac81e955d2527ca1af28d3f60 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 19 Oct 2016 21:59:49 +0200 Subject: [PATCH 06/94] Disable failing OSX build --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 574fe1ba8..4f811ee0f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ os: - linux - - osx +# - osx osx_image: xcode7.2 language: cpp sudo: required From 407abc605f17bb7b6e84fa33f8d4ba5c66149fe4 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Wed, 19 Oct 2016 22:37:45 +0200 Subject: [PATCH 07/94] Fix auto-equipping of blunt weapons --- apps/openmw/mwworld/inventorystore.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index cf2a88c1d..98cbad742 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -343,12 +343,12 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) bool weaponSkillVisited[weaponSkillsLength] = { false }; - for (int i = 0; i < static_cast(weaponSkillsLength) - 1; ++i) + for (int i = 0; i < static_cast(weaponSkillsLength); ++i) { int max = 0; int maxWeaponSkill = -1; - for (int j = 0; j < static_cast(weaponSkillsLength) - 1; ++j) + for (int j = 0; j < static_cast(weaponSkillsLength); ++j) { int skillValue = stats.getSkill(static_cast(weaponSkills[j])).getModified(); From 301dd77efb444da863aea35fdca93e5899e52471 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Thu, 20 Oct 2016 02:12:01 +0200 Subject: [PATCH 08/94] Save controls state (Fixes #3598) --- apps/openmw/mwbase/inputmanager.hpp | 17 ++++++++++ apps/openmw/mwinput/inputmanagerimp.cpp | 41 +++++++++++++++++++++++ apps/openmw/mwinput/inputmanagerimp.hpp | 4 +++ apps/openmw/mwstate/statemanagerimp.cpp | 8 ++++- components/CMakeLists.txt | 2 +- components/esm/controlsstate.cpp | 43 +++++++++++++++++++++++++ components/esm/controlsstate.hpp | 39 ++++++++++++++++++++++ components/esm/defs.hpp | 1 + 8 files changed, 153 insertions(+), 2 deletions(-) create mode 100644 components/esm/controlsstate.cpp create mode 100644 components/esm/controlsstate.hpp diff --git a/apps/openmw/mwbase/inputmanager.hpp b/apps/openmw/mwbase/inputmanager.hpp index 75c55e028..0eb06ee3d 100644 --- a/apps/openmw/mwbase/inputmanager.hpp +++ b/apps/openmw/mwbase/inputmanager.hpp @@ -5,6 +5,19 @@ #include #include +#include + +namespace Loading +{ + class Listener; +} + +namespace ESM +{ + class ESMReader; + class ESMWriter; +} + namespace MWBase { /// \brief Interface for input manager (implemented in MWInput) @@ -56,6 +69,10 @@ namespace MWBase /// Returns if the last used input device was a joystick or a keyboard /// @return true if joystick, false otherwise virtual bool joystickLastUsed() = 0; + + virtual int countSavedGameRecords() const = 0; + virtual void write(ESM::ESMWriter& writer, Loading::Listener& progress) = 0; + virtual void readRecord(ESM::ESMReader& reader, uint32_t type) = 0; }; } diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 6c2e695e6..2f49d3463 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -16,6 +16,9 @@ #include #include +#include +#include +#include #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" @@ -1574,6 +1577,44 @@ namespace MWInput mInputBinder->removeJoystickButtonBinding (mFakeDeviceID, mInputBinder->getJoystickButtonBinding (control, mFakeDeviceID, ICS::Control::INCREASE)); } + int InputManager::countSavedGameRecords() const + { + return 1; + } + + void InputManager::write(ESM::ESMWriter& writer, Loading::Listener& /*progress*/) + { + ESM::ControlsState controls; + controls.mViewSwitchDisabled = !getControlSwitch("playerviewswitch"); + controls.mControlsDisabled = !getControlSwitch("playercontrols"); + controls.mJumpingDisabled = !getControlSwitch("playerjumping"); + controls.mLookingDisabled = !getControlSwitch("playerlooking"); + controls.mVanityModeDisabled = !getControlSwitch("vanitymode"); + controls.mWeaponDrawingDisabled = !getControlSwitch("playerfighting"); + controls.mSpellDrawingDisabled = !getControlSwitch("playermagic"); + + writer.startRecord (ESM::REC_INPU); + controls.save(writer); + writer.endRecord (ESM::REC_INPU); + } + + void InputManager::readRecord(ESM::ESMReader& reader, uint32_t type) + { + if (type == ESM::REC_INPU) + { + ESM::ControlsState controls; + controls.load(reader); + + toggleControlSwitch("playerviewswitch", !controls.mViewSwitchDisabled); + toggleControlSwitch("playercontrols", !controls.mControlsDisabled); + toggleControlSwitch("playerjumping", !controls.mJumpingDisabled); + toggleControlSwitch("playerlooking", !controls.mLookingDisabled); + toggleControlSwitch("vanitymode", !controls.mVanityModeDisabled); + toggleControlSwitch("playerfighting", !controls.mWeaponDrawingDisabled); + toggleControlSwitch("playermagic", !controls.mSpellDrawingDisabled); + } + } + void InputManager::resetToDefaultKeyBindings() { loadKeyDefaults(true); diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 644391688..8809f44cd 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -149,6 +149,10 @@ namespace MWInput void clearAllKeyBindings (ICS::Control* control); void clearAllControllerBindings (ICS::Control* control); + virtual int countSavedGameRecords() const; + virtual void write(ESM::ESMWriter& writer, Loading::Listener& progress); + virtual void readRecord(ESM::ESMReader& reader, uint32_t type); + private: SDL_Window* mWindow; bool mWindowVisible; diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 48cc37935..58d85fe5b 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -249,7 +249,8 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot +MWBase::Environment::get().getScriptManager()->getGlobalScripts().countSavedGameRecords() +MWBase::Environment::get().getDialogueManager()->countSavedGameRecords() +MWBase::Environment::get().getWindowManager()->countSavedGameRecords() - +MWBase::Environment::get().getMechanicsManager()->countSavedGameRecords(); + +MWBase::Environment::get().getMechanicsManager()->countSavedGameRecords() + +MWBase::Environment::get().getInputManager()->countSavedGameRecords(); writer.setRecordCount (recordCount); writer.save (stream); @@ -271,6 +272,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot MWBase::Environment::get().getScriptManager()->getGlobalScripts().write (writer, listener); MWBase::Environment::get().getWindowManager()->write(writer, listener); MWBase::Environment::get().getMechanicsManager()->write(writer, listener); + MWBase::Environment::get().getInputManager()->write(writer, listener); // Ensure we have written the number of records that was estimated if (writer.getRecordCount() != recordCount+1) // 1 extra for TES3 record @@ -462,6 +464,10 @@ void MWState::StateManager::loadGame (const Character *character, const std::str MWBase::Environment::get().getMechanicsManager()->readRecord(reader, n.intval); break; + case ESM::REC_INPU: + MWBase::Environment::get().getInputManager()->readRecord(reader, n.intval); + break; + default: // ignore invalid records diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index d6063c230..51faaba1d 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -77,7 +77,7 @@ add_component_dir (esm loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap inventorystate containerstate npcstate creaturestate dialoguestate statstate npcstats creaturestats weatherstate quickkeys fogstate spellstate activespells creaturelevliststate doorstate projectilestate debugprofile - aisequence magiceffects util custommarkerstate stolenitems transport animationstate + aisequence magiceffects util custommarkerstate stolenitems transport animationstate controlsstate ) add_component_dir (esmterrain diff --git a/components/esm/controlsstate.cpp b/components/esm/controlsstate.cpp new file mode 100644 index 000000000..ae4e1dff1 --- /dev/null +++ b/components/esm/controlsstate.cpp @@ -0,0 +1,43 @@ +#include "controlsstate.hpp" + +#include "esmreader.hpp" +#include "esmwriter.hpp" + +ESM::ControlsState::ControlsState() + : mViewSwitchDisabled(false), + mControlsDisabled(false), + mJumpingDisabled(false), + mLookingDisabled(false), + mVanityModeDisabled(false), + mWeaponDrawingDisabled(false), + mSpellDrawingDisabled(false) +{ +} + +void ESM::ControlsState::load(ESM::ESMReader& esm) +{ + int flags; + esm.getHNT(flags, "CFLG"); + + mViewSwitchDisabled = flags & ViewSwitchDisabled; + mControlsDisabled = flags & ControlsDisabled; + mJumpingDisabled = flags & JumpingDisabled; + mLookingDisabled = flags & LookingDisabled; + mVanityModeDisabled = flags & VanityModeDisabled; + mWeaponDrawingDisabled = flags & WeaponDrawingDisabled; + mSpellDrawingDisabled = flags & SpellDrawingDisabled; +} + +void ESM::ControlsState::save(ESM::ESMWriter& esm) const +{ + int flags = 0; + if (mViewSwitchDisabled) flags |= ViewSwitchDisabled; + if (mControlsDisabled) flags |= ControlsDisabled; + if (mJumpingDisabled) flags |= JumpingDisabled; + if (mLookingDisabled) flags |= LookingDisabled; + if (mVanityModeDisabled) flags |= VanityModeDisabled; + if (mWeaponDrawingDisabled) flags |= WeaponDrawingDisabled; + if (mSpellDrawingDisabled) flags |= SpellDrawingDisabled; + + esm.writeHNT("CFLG", flags); +} diff --git a/components/esm/controlsstate.hpp b/components/esm/controlsstate.hpp new file mode 100644 index 000000000..b9654ea1a --- /dev/null +++ b/components/esm/controlsstate.hpp @@ -0,0 +1,39 @@ +#ifndef OPENMW_ESM_CONTROLSSTATE_H +#define OPENMW_ESM_CONTROLSSTATE_H + +namespace ESM +{ + class ESMReader; + class ESMWriter; + + // format 0, saved games only + + struct ControlsState + { + ControlsState(); + + enum Flags + { + ViewSwitchDisabled = 0x1, + ControlsDisabled = 0x4, + JumpingDisabled = 0x1000, + LookingDisabled = 0x2000, + VanityModeDisabled = 0x4000, + WeaponDrawingDisabled = 0x8000, + SpellDrawingDisabled = 0x10000 + }; + + bool mViewSwitchDisabled; + bool mControlsDisabled; + bool mJumpingDisabled; + bool mLookingDisabled; + bool mVanityModeDisabled; + bool mWeaponDrawingDisabled; + bool mSpellDrawingDisabled; + + void load (ESMReader &esm); + void save (ESMWriter &esm) const; + }; +} + +#endif diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index 8066b622a..0f0478faa 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -127,6 +127,7 @@ enum RecNameInts REC_ENAB = FourCC<'E','N','A','B'>::value, REC_CAM_ = FourCC<'C','A','M','_'>::value, REC_STLN = FourCC<'S','T','L','N'>::value, + REC_INPU = FourCC<'I','N','P','U'>::value, // format 1 REC_FILT = FourCC<'F','I','L','T'>::value, From f3ce0840be09f1efff55b7768a5a690c5eaeece6 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Thu, 20 Oct 2016 02:14:36 +0200 Subject: [PATCH 09/94] Import controls state from vanilla savegames --- apps/essimporter/converter.hpp | 2 +- apps/essimporter/convertplayer.cpp | 16 ++++++++++++---- apps/essimporter/convertplayer.hpp | 3 ++- apps/essimporter/importer.cpp | 4 ++++ apps/essimporter/importercontext.hpp | 3 +++ apps/essimporter/importplayer.hpp | 21 ++++++++++++--------- 6 files changed, 34 insertions(+), 15 deletions(-) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 11f966446..5e46e4309 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -278,7 +278,7 @@ public: PCDT pcdt; pcdt.load(esm); - convertPCDT(pcdt, mContext->mPlayer, mContext->mDialogueState.mKnownTopics, mFirstPersonCam); + convertPCDT(pcdt, mContext->mPlayer, mContext->mDialogueState.mKnownTopics, mFirstPersonCam, mContext->mControlsState); } virtual void write(ESM::ESMWriter &esm) { diff --git a/apps/essimporter/convertplayer.cpp b/apps/essimporter/convertplayer.cpp index 55aaad1c5..c7bd8526c 100644 --- a/apps/essimporter/convertplayer.cpp +++ b/apps/essimporter/convertplayer.cpp @@ -5,7 +5,7 @@ namespace ESSImport { - void convertPCDT(const PCDT& pcdt, ESM::Player& out, std::vector& outDialogueTopics, bool& firstPersonCam) + void convertPCDT(const PCDT& pcdt, ESM::Player& out, std::vector& outDialogueTopics, bool& firstPersonCam, ESM::ControlsState& controls) { out.mBirthsign = pcdt.mBirthsign; out.mObject.mNpcStats.mBounty = pcdt.mBounty; @@ -25,18 +25,26 @@ namespace ESSImport out.mObject.mNpcStats.mSkills[i].mProgress = pcdt.mPNAM.mSkillProgress[i]; out.mObject.mNpcStats.mLevelProgress = pcdt.mPNAM.mLevelProgress; - if (pcdt.mPNAM.mDrawState & PCDT::DrawState_Weapon) + if (pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_WeaponDrawn) out.mObject.mCreatureStats.mDrawState = 1; - if (pcdt.mPNAM.mDrawState & PCDT::DrawState_Spell) + if (pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_SpellDrawn) out.mObject.mCreatureStats.mDrawState = 2; - firstPersonCam = !(pcdt.mPNAM.mCameraFlags & PCDT::CameraFlag_ThirdPerson); + firstPersonCam = !(pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_ThirdPerson); for (std::vector::const_iterator it = pcdt.mKnownDialogueTopics.begin(); it != pcdt.mKnownDialogueTopics.end(); ++it) { outDialogueTopics.push_back(Misc::StringUtils::lowerCase(*it)); } + + controls.mViewSwitchDisabled = pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_ViewSwitchDisabled; + controls.mControlsDisabled = pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_ControlsDisabled; + controls.mJumpingDisabled = pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_JumpingDisabled; + controls.mLookingDisabled = pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_LookingDisabled; + controls.mVanityModeDisabled = pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_VanityModeDisabled; + controls.mWeaponDrawingDisabled = pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_WeaponDrawingDisabled; + controls.mSpellDrawingDisabled = pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_SpellDrawingDisabled; } } diff --git a/apps/essimporter/convertplayer.hpp b/apps/essimporter/convertplayer.hpp index f6731eed7..2e4565d8d 100644 --- a/apps/essimporter/convertplayer.hpp +++ b/apps/essimporter/convertplayer.hpp @@ -4,11 +4,12 @@ #include "importplayer.hpp" #include +#include namespace ESSImport { - void convertPCDT(const PCDT& pcdt, ESM::Player& out, std::vector& outDialogueTopics, bool& firstPersonCam); + void convertPCDT(const PCDT& pcdt, ESM::Player& out, std::vector& outDialogueTopics, bool& firstPersonCam, ESM::ControlsState& controls); } diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index f17db309f..1c255c56f 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -422,6 +422,10 @@ namespace ESSImport writer.startRecord (ESM::REC_DIAS); context.mDialogueState.save(writer); writer.endRecord(ESM::REC_DIAS); + + writer.startRecord(ESM::REC_INPU); + context.mControlsState.save(writer); + writer.endRecord(ESM::REC_INPU); } diff --git a/apps/essimporter/importercontext.hpp b/apps/essimporter/importercontext.hpp index c93dff269..fde247ebf 100644 --- a/apps/essimporter/importercontext.hpp +++ b/apps/essimporter/importercontext.hpp @@ -9,6 +9,7 @@ #include #include #include +#include #include "importnpcc.hpp" #include "importcrec.hpp" @@ -32,6 +33,8 @@ namespace ESSImport ESM::DialogueState mDialogueState; + ESM::ControlsState mControlsState; + // cells which should show an explored overlay on the global map std::set > mExploredCells; diff --git a/apps/essimporter/importplayer.hpp b/apps/essimporter/importplayer.hpp index 3baab1cd8..42881fcfd 100644 --- a/apps/essimporter/importplayer.hpp +++ b/apps/essimporter/importplayer.hpp @@ -38,14 +38,18 @@ struct PCDT std::vector mKnownDialogueTopics; - enum DrawState_ + enum PlayerFlags { - DrawState_Weapon = 0x80, - DrawState_Spell = 0x100 - }; - enum CameraFlags - { - CameraFlag_ThirdPerson = 0x2 + PlayerFlags_ViewSwitchDisabled = 0x1, + PlayerFlags_ControlsDisabled = 0x4, + PlayerFlags_WeaponDrawn = 0x80, + PlayerFlags_SpellDrawn = 0x100, + PlayerFlags_JumpingDisabled = 0x1000, + PlayerFlags_LookingDisabled = 0x2000, + PlayerFlags_VanityModeDisabled = 0x4000, + PlayerFlags_WeaponDrawingDisabled = 0x8000, + PlayerFlags_SpellDrawingDisabled = 0x10000, + PlayerFlags_ThirdPerson = 0x20000 }; #pragma pack(push) @@ -62,8 +66,7 @@ struct PCDT struct PNAM { - short mDrawState; // DrawState - short mCameraFlags; // CameraFlags + int mPlayerFlags; // controls, camera and draw state unsigned int mLevelProgress; float mSkillProgress[27]; // skill progress, non-uniform scaled unsigned char mSkillIncreases[8]; // number of skill increases for each attribute From cd9de94c0cfc6576c4a18121204f70f204d0f81d Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Thu, 20 Oct 2016 14:38:18 +0200 Subject: [PATCH 10/94] Import teleporting and levitation disabled state from vanilla savegames (Fixes #3420) --- apps/essimporter/converter.hpp | 15 +++++++++++++-- apps/essimporter/convertplayer.cpp | 4 +++- apps/essimporter/convertplayer.hpp | 2 +- apps/essimporter/importplayer.hpp | 4 +++- 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 5e46e4309..b05337aea 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -271,23 +271,34 @@ private: class ConvertPCDT : public Converter { public: - ConvertPCDT() : mFirstPersonCam(true) {} + ConvertPCDT() + : mFirstPersonCam(true), + mTeleportingEnabled(true), + mLevitationEnabled(true) + {} virtual void read(ESM::ESMReader &esm) { PCDT pcdt; pcdt.load(esm); - convertPCDT(pcdt, mContext->mPlayer, mContext->mDialogueState.mKnownTopics, mFirstPersonCam, mContext->mControlsState); + convertPCDT(pcdt, mContext->mPlayer, mContext->mDialogueState.mKnownTopics, mFirstPersonCam, mTeleportingEnabled, mLevitationEnabled, mContext->mControlsState); } virtual void write(ESM::ESMWriter &esm) { + esm.startRecord(ESM::REC_ENAB); + esm.writeHNT("TELE", mTeleportingEnabled); + esm.writeHNT("LEVT", mLevitationEnabled); + esm.endRecord(ESM::REC_ENAB); + esm.startRecord(ESM::REC_CAM_); esm.writeHNT("FIRS", mFirstPersonCam); esm.endRecord(ESM::REC_CAM_); } private: bool mFirstPersonCam; + bool mTeleportingEnabled; + bool mLevitationEnabled; }; class ConvertCNTC : public Converter diff --git a/apps/essimporter/convertplayer.cpp b/apps/essimporter/convertplayer.cpp index c7bd8526c..9d82af022 100644 --- a/apps/essimporter/convertplayer.cpp +++ b/apps/essimporter/convertplayer.cpp @@ -5,7 +5,7 @@ namespace ESSImport { - void convertPCDT(const PCDT& pcdt, ESM::Player& out, std::vector& outDialogueTopics, bool& firstPersonCam, ESM::ControlsState& controls) + void convertPCDT(const PCDT& pcdt, ESM::Player& out, std::vector& outDialogueTopics, bool& firstPersonCam, bool& teleportingEnabled, bool& levitationEnabled, ESM::ControlsState& controls) { out.mBirthsign = pcdt.mBirthsign; out.mObject.mNpcStats.mBounty = pcdt.mBounty; @@ -31,6 +31,8 @@ namespace ESSImport out.mObject.mCreatureStats.mDrawState = 2; firstPersonCam = !(pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_ThirdPerson); + teleportingEnabled = !(pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_TeleportingDisabled); + levitationEnabled = !(pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_LevitationDisabled); for (std::vector::const_iterator it = pcdt.mKnownDialogueTopics.begin(); it != pcdt.mKnownDialogueTopics.end(); ++it) diff --git a/apps/essimporter/convertplayer.hpp b/apps/essimporter/convertplayer.hpp index 2e4565d8d..1d2fdc87a 100644 --- a/apps/essimporter/convertplayer.hpp +++ b/apps/essimporter/convertplayer.hpp @@ -9,7 +9,7 @@ namespace ESSImport { - void convertPCDT(const PCDT& pcdt, ESM::Player& out, std::vector& outDialogueTopics, bool& firstPersonCam, ESM::ControlsState& controls); + void convertPCDT(const PCDT& pcdt, ESM::Player& out, std::vector& outDialogueTopics, bool& firstPersonCam, bool& teleportingEnabled, bool& levitationEnabled, ESM::ControlsState& controls); } diff --git a/apps/essimporter/importplayer.hpp b/apps/essimporter/importplayer.hpp index 42881fcfd..9f6b055c0 100644 --- a/apps/essimporter/importplayer.hpp +++ b/apps/essimporter/importplayer.hpp @@ -49,7 +49,9 @@ struct PCDT PlayerFlags_VanityModeDisabled = 0x4000, PlayerFlags_WeaponDrawingDisabled = 0x8000, PlayerFlags_SpellDrawingDisabled = 0x10000, - PlayerFlags_ThirdPerson = 0x20000 + PlayerFlags_ThirdPerson = 0x20000, + PlayerFlags_TeleportingDisabled = 0x40000, + PlayerFlags_LevitationDisabled = 0x80000 }; #pragma pack(push) From f6ef1ce27689e3f5671bca7a2df01b9e6f6211be Mon Sep 17 00:00:00 2001 From: Assumeru Date: Tue, 25 Oct 2016 15:42:37 +0200 Subject: [PATCH 11/94] Fix Calm/Frenzy/Demoralize/Rally Creature weakness and resistance --- components/esm/loadmgef.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/components/esm/loadmgef.cpp b/components/esm/loadmgef.cpp index 7568ebe7e..dc8266132 100644 --- a/components/esm/loadmgef.cpp +++ b/components/esm/loadmgef.cpp @@ -298,10 +298,10 @@ short MagicEffect::getResistanceEffect(short effect) for (int i=0; i<2; ++i) { - effects[CalmHumanoid] = ResistMagicka; - effects[FrenzyHumanoid] = ResistMagicka; - effects[DemoralizeHumanoid] = ResistMagicka; - effects[RallyHumanoid] = ResistMagicka; + effects[CalmHumanoid+i] = ResistMagicka; + effects[FrenzyHumanoid+i] = ResistMagicka; + effects[DemoralizeHumanoid+i] = ResistMagicka; + effects[RallyHumanoid+i] = ResistMagicka; } effects[TurnUndead] = ResistMagicka; @@ -341,10 +341,10 @@ short MagicEffect::getWeaknessEffect(short effect) for (int i=0; i<2; ++i) { - effects[CalmHumanoid] = WeaknessToMagicka; - effects[FrenzyHumanoid] = WeaknessToMagicka; - effects[DemoralizeHumanoid] = WeaknessToMagicka; - effects[RallyHumanoid] = WeaknessToMagicka; + effects[CalmHumanoid+i] = WeaknessToMagicka; + effects[FrenzyHumanoid+i] = WeaknessToMagicka; + effects[DemoralizeHumanoid+i] = WeaknessToMagicka; + effects[RallyHumanoid+i] = WeaknessToMagicka; } effects[TurnUndead] = WeaknessToMagicka; From 8a8aa664e3f3b958c2126b9dd1a0ee5eda5aaa7e Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 25 Oct 2016 16:44:54 +0200 Subject: [PATCH 12/94] Update AUTHORS.md --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 2a43168e6..a876bcbfd 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -27,6 +27,7 @@ Programmers Artem Kotsynyak (greye) artemutin Arthur Moore (EmperorArthur) + Assumeru athile Ben Shealy (bentsherman) Bret Curtis (psi29a) From a72cd896caf7ef09c52ff2e9c9b338acc0ee2d7c Mon Sep 17 00:00:00 2001 From: Assumeru Date: Tue, 25 Oct 2016 19:26:17 +0200 Subject: [PATCH 13/94] Move actors out of the water if there's room for them. Fixes #1138 --- apps/openmw/mwphysics/physicssystem.cpp | 33 +++++++++++++++++++++---- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index e442fbda1..cf75cbf10 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -1318,11 +1318,34 @@ namespace MWPhysics const MWMechanics::MagicEffects& effects = iter->first.getClass().getCreatureStats(iter->first).getMagicEffects(); bool waterCollision = false; - if (effects.get(ESM::MagicEffect::WaterWalking).getMagnitude() - && cell->getCell()->hasWater() - && !world->isUnderwater(iter->first.getCell(), - osg::Vec3f(iter->first.getRefData().getPosition().asVec3()))) - waterCollision = true; + if (cell->getCell()->hasWater() && effects.get(ESM::MagicEffect::WaterWalking).getMagnitude()) + { + if (!world->isUnderwater(iter->first.getCell(), osg::Vec3f(iter->first.getRefData().getPosition().asVec3()))) + waterCollision = true; + else + { + Actor *actor = getActor(iter->first); + // Actor can collide + if (actor->getCollisionMode()) + { + const osg::Vec3f actorPosition = actor->getPosition(); + const osg::Vec3f destinationPosition(actorPosition.x(), actorPosition.y(), waterlevel); + ActorTracer tracer; + tracer.doTrace(actor->getCollisionObject(), actorPosition, destinationPosition, mCollisionWorld); + if (tracer.mFraction >= 1.0f) + { + waterCollision = true; + actor->setPosition(destinationPosition); + } + else + { + //Remove the effect to remove the performance hit of casting in a weird spot + //probably makes that Tribunal quest where the water rises a bit safer + iter->first.getClass().getCreatureStats(iter->first).getActiveSpells().purgeEffect(ESM::MagicEffect::WaterWalking); + } + } + } + } ActorMap::iterator foundActor = mActors.find(iter->first); if (foundActor == mActors.end()) // actor was already removed from the scene From 25d64989b3ea5c31360991730e035fa2840584d6 Mon Sep 17 00:00:00 2001 From: Assumeru Date: Wed, 26 Oct 2016 11:04:54 +0200 Subject: [PATCH 14/94] Check if the actor still exists /first/ --- apps/openmw/mwphysics/physicssystem.cpp | 44 +++++++++++-------------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index cf75cbf10..cd4484aa1 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -1309,12 +1309,16 @@ namespace MWPhysics PtrVelocityList::iterator iter = mMovementQueue.begin(); for(;iter != mMovementQueue.end();++iter) { + ActorMap::iterator foundActor = mActors.find(iter->first); + if (foundActor == mActors.end()) // actor was already removed from the scene + continue; + Actor* physicActor = foundActor->second; + float waterlevel = -std::numeric_limits::max(); const MWWorld::CellStore *cell = iter->first.getCell(); if(cell->getCell()->hasWater()) waterlevel = cell->getWaterLevel(); - const MWMechanics::MagicEffects& effects = iter->first.getClass().getCreatureStats(iter->first).getMagicEffects(); bool waterCollision = false; @@ -1322,35 +1326,25 @@ namespace MWPhysics { if (!world->isUnderwater(iter->first.getCell(), osg::Vec3f(iter->first.getRefData().getPosition().asVec3()))) waterCollision = true; - else + else if (physicActor->getCollisionMode()) { - Actor *actor = getActor(iter->first); - // Actor can collide - if (actor->getCollisionMode()) + const osg::Vec3f actorPosition = physicActor->getPosition(); + const osg::Vec3f destinationPosition(actorPosition.x(), actorPosition.y(), waterlevel); + ActorTracer tracer; + tracer.doTrace(physicActor->getCollisionObject(), actorPosition, destinationPosition, mCollisionWorld); + if (tracer.mFraction >= 1.0f) { - const osg::Vec3f actorPosition = actor->getPosition(); - const osg::Vec3f destinationPosition(actorPosition.x(), actorPosition.y(), waterlevel); - ActorTracer tracer; - tracer.doTrace(actor->getCollisionObject(), actorPosition, destinationPosition, mCollisionWorld); - if (tracer.mFraction >= 1.0f) - { - waterCollision = true; - actor->setPosition(destinationPosition); - } - else - { - //Remove the effect to remove the performance hit of casting in a weird spot - //probably makes that Tribunal quest where the water rises a bit safer - iter->first.getClass().getCreatureStats(iter->first).getActiveSpells().purgeEffect(ESM::MagicEffect::WaterWalking); - } + waterCollision = true; + physicActor->setPosition(destinationPosition); + } + else + { + //Remove the effect to remove the performance hit of casting in a weird spot + //probably makes that Tribunal quest where the water rises a bit safer + iter->first.getClass().getCreatureStats(iter->first).getActiveSpells().purgeEffect(ESM::MagicEffect::WaterWalking); } } } - - ActorMap::iterator foundActor = mActors.find(iter->first); - if (foundActor == mActors.end()) // actor was already removed from the scene - continue; - Actor* physicActor = foundActor->second; physicActor->setCanWaterWalk(waterCollision); // Slow fall reduces fall speed by a factor of (effect magnitude / 200) From 125e94ef0e0d3ab18024aa77cd0dda5f31f9bb83 Mon Sep 17 00:00:00 2001 From: Allofich Date: Mon, 31 Oct 2016 00:23:51 +0900 Subject: [PATCH 15/94] Fix shadowing warnings --- apps/launcher/maindialog.cpp | 2 +- apps/opencs/model/tools/mergestages.cpp | 2 +- apps/opencs/model/world/idtable.cpp | 2 +- apps/opencs/model/world/refcollection.cpp | 2 +- apps/openmw/mwclass/creaturelevlist.cpp | 6 +++--- apps/openmw/mwgui/alchemywindow.cpp | 10 +++++----- apps/openmw/mwgui/birth.cpp | 2 +- apps/openmw/mwgui/inventoryitemmodel.cpp | 4 ++-- apps/openmw/mwgui/tooltips.cpp | 2 +- apps/openmw/mwmechanics/aiactivate.cpp | 2 -- apps/openmw/mwrender/animation.cpp | 6 +++--- apps/openmw/mwrender/characterpreview.cpp | 6 +++--- apps/openmw/mwrender/ripplesimulation.cpp | 10 +++++----- apps/openmw/mwscript/locals.cpp | 8 ++++---- apps/wizard/existinginstallationpage.cpp | 4 ++-- apps/wizard/mainwizard.cpp | 2 +- components/contentselector/view/contentselector.cpp | 4 ++-- 17 files changed, 36 insertions(+), 38 deletions(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 60ae5b3a0..f2ec62939 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -326,7 +326,7 @@ bool Launcher::MainDialog::setupGameSettings() foreach (const QString &path, paths) { qDebug() << "Loading config file:" << path.toUtf8().constData(); - QFile file(path); + file.setFileName(path); if (file.exists()) { if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { cfgError(tr("Error opening OpenMW configuration file"), diff --git a/apps/opencs/model/tools/mergestages.cpp b/apps/opencs/model/tools/mergestages.cpp index 4d4835ece..02fc551ab 100644 --- a/apps/opencs/model/tools/mergestages.cpp +++ b/apps/opencs/model/tools/mergestages.cpp @@ -184,7 +184,7 @@ void CSMTools::MergeLandTexturesStage::perform (int stage, CSMDoc::Messages& mes CSMWorld::LandTexture texture = mState.mSource.getData().getLandTextures().getRecord (index).get(); - std::ostringstream stream; + stream.clear(); stream << mNext->second-1 << "_0"; texture.mIndex = mNext->second-1; diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 9dbe38998..7975e05ea 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -191,7 +191,7 @@ void CSMWorld::IdTable::setRecord (const std::string& id, const RecordBase& reco if (index==-1) { - int index = mIdCollection->getAppendIndex (id, type); + index = mIdCollection->getAppendIndex (id, type); beginInsertRows (QModelIndex(), index, index); diff --git a/apps/opencs/model/world/refcollection.cpp b/apps/opencs/model/world/refcollection.cpp index 506f9027e..6b586dcec 100644 --- a/apps/opencs/model/world/refcollection.cpp +++ b/apps/opencs/model/world/refcollection.cpp @@ -63,7 +63,7 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool std::cerr << "Position: #" << index.first << " " << index.second <<", Target #"<< mref.mTarget[0] << " " << mref.mTarget[1] << std::endl; - std::ostringstream stream; + stream.clear(); stream << "#" << mref.mTarget[0] << " " << mref.mTarget[1]; ref.mCell = stream.str(); // overwrite } diff --git a/apps/openmw/mwclass/creaturelevlist.cpp b/apps/openmw/mwclass/creaturelevlist.cpp index e0e890b60..5941a09f5 100644 --- a/apps/openmw/mwclass/creaturelevlist.cpp +++ b/apps/openmw/mwclass/creaturelevlist.cpp @@ -118,9 +118,9 @@ namespace MWClass } const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); - MWWorld::ManualRef ref(store, id); - ref.getPtr().getCellRef().setPosition(ptr.getCellRef().getPosition()); - MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->placeObject(ref.getPtr(), ptr.getCell() , ptr.getCellRef().getPosition()); + MWWorld::ManualRef manualRef(store, id); + manualRef.getPtr().getCellRef().setPosition(ptr.getCellRef().getPosition()); + MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->placeObject(manualRef.getPtr(), ptr.getCell() , ptr.getCellRef().getPosition()); customData.mSpawnActorId = placed.getClass().getCreatureStats(placed).getActorId(); customData.mSpawn = false; } diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 61a0efc46..385010ac5 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -200,15 +200,15 @@ namespace MWGui std::set effectIds = mAlchemy->listEffects(); Widgets::SpellEffectList list; unsigned int effectIndex=0; - for (std::set::iterator it = effectIds.begin(); it != effectIds.end(); ++it) + for (std::set::iterator it2 = effectIds.begin(); it2 != effectIds.end(); ++it2) { Widgets::SpellEffectParams params; - params.mEffectID = it->mId; - const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find(it->mId); + params.mEffectID = it2->mId; + const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find(it2->mId); if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill) - params.mSkill = it->mArg; + params.mSkill = it2->mArg; else if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetAttribute) - params.mAttribute = it->mArg; + params.mAttribute = it2->mArg; params.mIsConstant = true; params.mNoTarget = true; diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index 327d5e5cf..69fb2c462 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -226,7 +226,7 @@ namespace MWGui coord.top += lineHeight; end = categories[category].spells.end(); - for (std::vector::const_iterator it = categories[category].spells.begin(); it != end; ++it) + for (it = categories[category].spells.begin(); it != end; ++it) { const std::string &spellId = *it; spellWidget = mSpellArea->createWidget("MW_StatName", coord, MyGUI::Align::Default, std::string("Spell") + MyGUI::utility::toString(i)); diff --git a/apps/openmw/mwgui/inventoryitemmodel.cpp b/apps/openmw/mwgui/inventoryitemmodel.cpp index 061c8c4c4..2fe540f22 100644 --- a/apps/openmw/mwgui/inventoryitemmodel.cpp +++ b/apps/openmw/mwgui/inventoryitemmodel.cpp @@ -85,8 +85,8 @@ void InventoryItemModel::update() if (mActor.getClass().hasInventoryStore(mActor)) { - MWWorld::InventoryStore& store = mActor.getClass().getInventoryStore(mActor); - if (store.isEquipped(newItem.mBase)) + MWWorld::InventoryStore& invStore = mActor.getClass().getInventoryStore(mActor); + if (invStore.isEquipped(newItem.mBase)) newItem.mType = ItemStack::Type_Equipped; } diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index b0838b336..b3cc19a64 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -256,7 +256,7 @@ namespace MWGui std::string key = it->first.substr(0, underscorePos); std::string widgetName = it->first.substr(underscorePos+1, it->first.size()-(underscorePos+1)); - std::string type = "Property"; + type = "Property"; size_t caretPos = key.find("^"); if (caretPos != std::string::npos) { diff --git a/apps/openmw/mwmechanics/aiactivate.cpp b/apps/openmw/mwmechanics/aiactivate.cpp index 745a01c8b..b1426a4c1 100644 --- a/apps/openmw/mwmechanics/aiactivate.cpp +++ b/apps/openmw/mwmechanics/aiactivate.cpp @@ -41,9 +41,7 @@ namespace MWMechanics if (pathTo(actor, dest, duration, MWBase::Environment::get().getWorld()->getMaxActivationDistance())) //Stop when you get in activation range { // activate when reached - MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr(mObjectId,false); MWBase::Environment::get().getWorld()->activate(target, actor); - return true; } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index c2761e25d..e7227178f 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -686,9 +686,9 @@ namespace MWRender state.mAutoDisable = autodisable; mStates[groupname] = state; - NifOsg::TextKeyMap::const_iterator textkey(textkeys.lower_bound(state.getTime())); if (state.mPlaying) { + NifOsg::TextKeyMap::const_iterator textkey(textkeys.lower_bound(state.getTime())); while(textkey != textkeys.end() && textkey->first <= state.getTime()) { handleTextKey(state, groupname, textkey, textkeys); @@ -976,14 +976,14 @@ namespace MWRender while(!(velocity > 1.0f) && ++animiter != mAnimSources.rend()) { - const NifOsg::TextKeyMap &keys = (*animiter)->getTextKeys(); + const NifOsg::TextKeyMap &keys2 = (*animiter)->getTextKeys(); const AnimSource::ControllerMap& ctrls2 = (*animiter)->mControllerMap[0]; for (AnimSource::ControllerMap::const_iterator it = ctrls2.begin(); it != ctrls2.end(); ++it) { if (Misc::StringUtils::ciEqual(it->first, mAccumRoot->getName())) { - velocity = calcAnimVelocity(keys, it->second, mAccumulate, groupname); + velocity = calcAnimVelocity(keys2, it->second, mAccumulate, groupname); break; } } diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index ed61334bb..b26744920 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -221,10 +221,10 @@ namespace MWRender groupname = "inventoryhandtohand"; else { - const std::string &type = iter->getTypeName(); - if(type == typeid(ESM::Lockpick).name() || type == typeid(ESM::Probe).name()) + const std::string &typeName = iter->getTypeName(); + if(typeName == typeid(ESM::Lockpick).name() || typeName == typeid(ESM::Probe).name()) groupname = "inventoryweapononehand"; - else if(type == typeid(ESM::Weapon).name()) + else if(typeName == typeid(ESM::Weapon).name()) { MWWorld::LiveCellRef *ref = iter->get(); diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index 85319a632..56302077e 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -39,11 +39,11 @@ namespace { std::ostringstream texname; texname << "textures/water/" << tex << std::setw(2) << std::setfill('0') << i << ".dds"; - osg::ref_ptr tex (new osg::Texture2D(resourceSystem->getImageManager()->getImage(texname.str()))); - tex->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); - tex->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); - resourceSystem->getSceneManager()->applyFilterSettings(tex); - textures.push_back(tex); + osg::ref_ptr tex2 (new osg::Texture2D(resourceSystem->getImageManager()->getImage(texname.str()))); + tex2->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); + tex2->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); + resourceSystem->getSceneManager()->applyFilterSettings(tex2); + textures.push_back(tex2); } osg::ref_ptr controller (new NifOsg::FlipController(0, 0.3f/rippleFrameCount, textures)); diff --git a/apps/openmw/mwscript/locals.cpp b/apps/openmw/mwscript/locals.cpp index 5c9ffa07a..a535910da 100644 --- a/apps/openmw/mwscript/locals.cpp +++ b/apps/openmw/mwscript/locals.cpp @@ -238,15 +238,15 @@ namespace MWScript else { char type = declarations.getType (iter->first); - char index = declarations.getIndex (iter->first); + char index2 = declarations.getIndex (iter->first); try { switch (type) { - case 's': mShorts.at (index) = iter->second.getInteger(); break; - case 'l': mLongs.at (index) = iter->second.getInteger(); break; - case 'f': mFloats.at (index) = iter->second.getFloat(); break; + case 's': mShorts.at (index2) = iter->second.getInteger(); break; + case 'l': mLongs.at (index2) = iter->second.getInteger(); break; + case 'f': mFloats.at (index2) = iter->second.getFloat(); break; // silently ignore locals that don't exist anymore } diff --git a/apps/wizard/existinginstallationpage.cpp b/apps/wizard/existinginstallationpage.cpp index f821b38ba..a04e721d8 100644 --- a/apps/wizard/existinginstallationpage.cpp +++ b/apps/wizard/existinginstallationpage.cpp @@ -63,13 +63,13 @@ bool Wizard::ExistingInstallationPage::validatePage() The Wizard needs to update settings in this file.

\ Press \"Browse...\" to specify the location manually.
")); - QAbstractButton *browseButton = + QAbstractButton *browseButton2 = msgBox.addButton(QObject::tr("B&rowse..."), QMessageBox::ActionRole); msgBox.exec(); QString iniFile; - if (msgBox.clickedButton() == browseButton) { + if (msgBox.clickedButton() == browseButton2) { iniFile = QFileDialog::getOpenFileName( this, QObject::tr("Select configuration file"), diff --git a/apps/wizard/mainwizard.cpp b/apps/wizard/mainwizard.cpp index 19cdf9535..fa934868b 100644 --- a/apps/wizard/mainwizard.cpp +++ b/apps/wizard/mainwizard.cpp @@ -165,7 +165,7 @@ void Wizard::MainWizard::setupGameSettings() foreach (const QString &path, paths) { qDebug() << "Loading config file:" << path.toUtf8().constData(); - QFile file(path); + file.setFileName(path); if (file.exists()) { if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { QMessageBox msgBox; diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp index 87c9cea08..514a0444a 100644 --- a/components/contentselector/view/contentselector.cpp +++ b/components/contentselector/view/contentselector.cpp @@ -192,8 +192,8 @@ void ContentSelectorView::ContentSelector::setGameFileSelected(int index, bool s const ContentSelectorModel::EsmFile* file = mContentModel->item(fileName); if (file != NULL) { - QModelIndex index(mContentModel->indexFromItem(file)); - mContentModel->setData(index, selected, Qt::UserRole + 1); + QModelIndex index2(mContentModel->indexFromItem(file)); + mContentModel->setData(index2, selected, Qt::UserRole + 1); } } From 68ed264f40dffd85cc87cab03f4a05592bce3f3f Mon Sep 17 00:00:00 2001 From: Allofich Date: Mon, 31 Oct 2016 00:53:17 +0900 Subject: [PATCH 16/94] Fix narrowing conversion warning --- apps/opencs/model/world/defaultgmsts.cpp | 516 +++++++++++------------ 1 file changed, 258 insertions(+), 258 deletions(-) diff --git a/apps/opencs/model/world/defaultgmsts.cpp b/apps/opencs/model/world/defaultgmsts.cpp index f44e98411..da83a86be 100644 --- a/apps/opencs/model/world/defaultgmsts.cpp +++ b/apps/opencs/model/world/defaultgmsts.cpp @@ -1627,264 +1627,264 @@ const char * CSMWorld::DefaultGmsts::OptionalStrings[CSMWorld::DefaultGmsts::Opt const float CSMWorld::DefaultGmsts::FloatsDefaultValues[CSMWorld::DefaultGmsts::FloatCount] = { - 0.3, // fAIFleeFleeMult - 7.0, // fAIFleeHealthMult - 3.0, // fAIMagicSpellMult - 1.0, // fAIMeleeArmorMult - 1.0, // fAIMeleeSummWeaponMult - 2.0, // fAIMeleeWeaponMult - 5.0, // fAIRangeMagicSpellMult - 5.0, // fAIRangeMeleeWeaponMult - 2000.0, // fAlarmRadius - 1.0, // fAthleticsRunBonus - 40.0, // fAudioDefaultMaxDistance - 5.0, // fAudioDefaultMinDistance - 50.0, // fAudioMaxDistanceMult - 20.0, // fAudioMinDistanceMult - 60.0, // fAudioVoiceDefaultMaxDistance - 10.0, // fAudioVoiceDefaultMinDistance - 50.0, // fAutoPCSpellChance - 80.0, // fAutoSpellChance - 50.0, // fBargainOfferBase - -4.0, // fBargainOfferMulti - 24.0, // fBarterGoldResetDelay - 1.75, // fBaseRunMultiplier - 1.25, // fBlockStillBonus - 150.0, // fBribe1000Mod - 75.0, // fBribe100Mod - 35.0, // fBribe10Mod - 60.0, // fCombatAngleXY - 60.0, // fCombatAngleZ - 0.25, // fCombatArmorMinMult - -90.0, // fCombatBlockLeftAngle - 30.0, // fCombatBlockRightAngle - 4.0, // fCombatCriticalStrikeMult - 0.1, // fCombatDelayCreature - 0.1, // fCombatDelayNPC - 128.0, // fCombatDistance - 0.3, // fCombatDistanceWerewolfMod - 30.0, // fCombatForceSideAngle - 0.2, // fCombatInvisoMult - 1.5, // fCombatKODamageMult - 45.0, // fCombatTorsoSideAngle - 0.3, // fCombatTorsoStartPercent - 0.8, // fCombatTorsoStopPercent - 15.0, // fConstantEffectMult - 72.0, // fCorpseClearDelay - 72.0, // fCorpseRespawnDelay - 0.5, // fCrimeGoldDiscountMult - 0.9, // fCrimeGoldTurnInMult - 1.0, // fCrimeStealing - 0.5, // fDamageStrengthBase - 0.1, // fDamageStrengthMult - 5.0, // fDifficultyMult - 2.5, // fDiseaseXferChance - -10.0, // fDispAttacking - -1.0, // fDispBargainFailMod - 1.0, // fDispBargainSuccessMod - 0.0, // fDispCrimeMod - -10.0, // fDispDiseaseMod - 3.0, // fDispFactionMod - 1.0, // fDispFactionRankBase - 0.5, // fDispFactionRankMult - 1.0, // fDispositionMod - 50.0, // fDispPersonalityBase - 0.5, // fDispPersonalityMult - -25.0, // fDispPickPocketMod - 5.0, // fDispRaceMod - -0.5, // fDispStealing - -5.0, // fDispWeaponDrawn - 0.5, // fEffectCostMult - 0.1, // fElementalShieldMult - 3.0, // fEnchantmentChanceMult - 0.5, // fEnchantmentConstantChanceMult - 100.0, // fEnchantmentConstantDurationMult - 0.1, // fEnchantmentMult - 1000.0, // fEnchantmentValueMult - 0.3, // fEncumberedMoveEffect - 5.0, // fEncumbranceStrMult - 0.04, // fEndFatigueMult - 0.25, // fFallAcroBase - 0.01, // fFallAcroMult - 400.0, // fFallDamageDistanceMin - 0.0, // fFallDistanceBase - 0.07, // fFallDistanceMult - 2.0, // fFatigueAttackBase - 0.0, // fFatigueAttackMult - 1.25, // fFatigueBase - 4.0, // fFatigueBlockBase - 0.0, // fFatigueBlockMult - 5.0, // fFatigueJumpBase - 0.0, // fFatigueJumpMult - 0.5, // fFatigueMult - 2.5, // fFatigueReturnBase - 0.02, // fFatigueReturnMult - 5.0, // fFatigueRunBase - 2.0, // fFatigueRunMult - 1.5, // fFatigueSneakBase - 1.5, // fFatigueSneakMult - 0.0, // fFatigueSpellBase - 0.0, // fFatigueSpellCostMult - 0.0, // fFatigueSpellMult - 7.0, // fFatigueSwimRunBase - 0.0, // fFatigueSwimRunMult - 2.5, // fFatigueSwimWalkBase - 0.0, // fFatigueSwimWalkMult - 0.2, // fFightDispMult - 0.005, // fFightDistanceMultiplier - 50.0, // fFightStealing - 3000.0, // fFleeDistance - 512.0, // fGreetDistanceReset - 0.1, // fHandtoHandHealthPer - 1.0, // fHandToHandReach - 0.5, // fHoldBreathEndMult - 20.0, // fHoldBreathTime - 0.75, // fIdleChanceMultiplier - 1.0, // fIngredientMult - 0.5, // fInteriorHeadTrackMult - 128.0, // fJumpAcrobaticsBase - 4.0, // fJumpAcroMultiplier - 0.5, // fJumpEncumbranceBase - 1.0, // fJumpEncumbranceMultiplier - 0.5, // fJumpMoveBase - 0.5, // fJumpMoveMult - 1.0, // fJumpRunMultiplier - 0.5, // fKnockDownMult - 5.0, // fLevelMod - 0.1, // fLevelUpHealthEndMult - 0.6, // fLightMaxMod - 10.0, // fLuckMod - 10.0, // fMagesGuildTravel - 1.5, // fMagicCreatureCastDelay - 0.0167, // fMagicDetectRefreshRate - 1.0, // fMagicItemConstantMult - 1.0, // fMagicItemCostMult - 1.0, // fMagicItemOnceMult - 1.0, // fMagicItemPriceMult - 0.05, // fMagicItemRechargePerSecond - 1.0, // fMagicItemStrikeMult - 1.0, // fMagicItemUsedMult - 3.0, // fMagicStartIconBlink - 0.5, // fMagicSunBlockedMult - 0.75, // fMajorSkillBonus - 300.0, // fMaxFlySpeed - 0.5, // fMaxHandToHandMult - 400.0, // fMaxHeadTrackDistance - 200.0, // fMaxWalkSpeed - 300.0, // fMaxWalkSpeedCreature - 0.9, // fMedMaxMod - 0.1, // fMessageTimePerChar - 5.0, // fMinFlySpeed - 0.1, // fMinHandToHandMult - 1.0, // fMinorSkillBonus - 100.0, // fMinWalkSpeed - 5.0, // fMinWalkSpeedCreature - 1.25, // fMiscSkillBonus - 2.0, // fNPCbaseMagickaMult - 0.5, // fNPCHealthBarFade - 3.0, // fNPCHealthBarTime - 1.0, // fPCbaseMagickaMult - 0.3, // fPerDieRollMult - 5.0, // fPersonalityMod - 1.0, // fPerTempMult - -1.0, // fPickLockMult - 0.3, // fPickPocketMod - 20.0, // fPotionMinUsefulDuration - 0.5, // fPotionStrengthMult - 0.5, // fPotionT1DurMult - 1.5, // fPotionT1MagMult - 20.0, // fPotionT4BaseStrengthMult - 12.0, // fPotionT4EquipStrengthMult - 3000.0, // fProjectileMaxSpeed - 400.0, // fProjectileMinSpeed - 25.0, // fProjectileThrownStoreChance - 3.0, // fRepairAmountMult - 1.0, // fRepairMult - 1.0, // fReputationMod - 0.15, // fRestMagicMult - 0.0, // fSeriousWoundMult - 0.25, // fSleepRandMod - 0.3, // fSleepRestMod - -1.0, // fSneakBootMult - 0.5, // fSneakDistanceBase - 0.002, // fSneakDistanceMultiplier - 0.5, // fSneakNoViewMult - 1.0, // fSneakSkillMult - 0.75, // fSneakSpeedMultiplier - 1.0, // fSneakUseDelay - 500.0, // fSneakUseDist - 1.5, // fSneakViewMult - 3.0, // fSoulGemMult - 0.8, // fSpecialSkillBonus - 7.0, // fSpellMakingValueMult - 2.0, // fSpellPriceMult - 10.0, // fSpellValueMult - 0.25, // fStromWalkMult - 0.7, // fStromWindSpeed - 3.0, // fSuffocationDamage - 0.9, // fSwimHeightScale - 0.1, // fSwimRunAthleticsMult - 0.5, // fSwimRunBase - 0.02, // fSwimWalkAthleticsMult - 0.5, // fSwimWalkBase - 1.0, // fSwingBlockBase - 1.0, // fSwingBlockMult - 1000.0, // fTargetSpellMaxSpeed - 1000.0, // fThrownWeaponMaxSpeed - 300.0, // fThrownWeaponMinSpeed - 0.0, // fTrapCostMult - 4000.0, // fTravelMult - 16000.0,// fTravelTimeMult - 0.1, // fUnarmoredBase1 - 0.065, // fUnarmoredBase2 - 30.0, // fVanityDelay - 10.0, // fVoiceIdleOdds - 0.0, // fWaterReflectUpdateAlways - 10.0, // fWaterReflectUpdateSeldom - 0.1, // fWeaponDamageMult - 1.0, // fWeaponFatigueBlockMult - 0.25, // fWeaponFatigueMult - 150.0, // fWereWolfAcrobatics - 150.0, // fWereWolfAgility - 1.0, // fWereWolfAlchemy - 1.0, // fWereWolfAlteration - 1.0, // fWereWolfArmorer - 150.0, // fWereWolfAthletics - 1.0, // fWereWolfAxe - 1.0, // fWereWolfBlock - 1.0, // fWereWolfBluntWeapon - 1.0, // fWereWolfConjuration - 1.0, // fWereWolfDestruction - 1.0, // fWereWolfEnchant - 150.0, // fWereWolfEndurance - 400.0, // fWereWolfFatigue - 100.0, // fWereWolfHandtoHand - 2.0, // fWereWolfHealth - 1.0, // fWereWolfHeavyArmor - 1.0, // fWereWolfIllusion - 1.0, // fWereWolfIntellegence - 1.0, // fWereWolfLightArmor - 1.0, // fWereWolfLongBlade - 1.0, // fWereWolfLuck - 100.0, // fWereWolfMagicka - 1.0, // fWereWolfMarksman - 1.0, // fWereWolfMediumArmor - 1.0, // fWereWolfMerchantile - 1.0, // fWereWolfMysticism - 1.0, // fWereWolfPersonality - 1.0, // fWereWolfRestoration - 1.5, // fWereWolfRunMult - 1.0, // fWereWolfSecurity - 1.0, // fWereWolfShortBlade - 1.5, // fWereWolfSilverWeaponDamageMult - 1.0, // fWereWolfSneak - 1.0, // fWereWolfSpear - 1.0, // fWereWolfSpeechcraft - 150.0, // fWereWolfSpeed - 150.0, // fWereWolfStrength - 100.0, // fWereWolfUnarmored - 1.0, // fWereWolfWillPower - 15.0 // fWortChanceValue + 0.3f, // fAIFleeFleeMult + 7.0f, // fAIFleeHealthMult + 3.0f, // fAIMagicSpellMult + 1.0f, // fAIMeleeArmorMult + 1.0f, // fAIMeleeSummWeaponMult + 2.0f, // fAIMeleeWeaponMult + 5.0f, // fAIRangeMagicSpellMult + 5.0f, // fAIRangeMeleeWeaponMult + 2000.0f, // fAlarmRadius + 1.0f, // fAthleticsRunBonus + 40.0f, // fAudioDefaultMaxDistance + 5.0f, // fAudioDefaultMinDistance + 50.0f, // fAudioMaxDistanceMult + 20.0f, // fAudioMinDistanceMult + 60.0f, // fAudioVoiceDefaultMaxDistance + 10.0f, // fAudioVoiceDefaultMinDistance + 50.0f, // fAutoPCSpellChance + 80.0f, // fAutoSpellChance + 50.0f, // fBargainOfferBase + -4.0f, // fBargainOfferMulti + 24.0f, // fBarterGoldResetDelay + 1.75f, // fBaseRunMultiplier + 1.25f, // fBlockStillBonus + 150.0f, // fBribe1000Mod + 75.0f, // fBribe100Mod + 35.0f, // fBribe10Mod + 60.0f, // fCombatAngleXY + 60.0f, // fCombatAngleZ + 0.25f, // fCombatArmorMinMult + -90.0f, // fCombatBlockLeftAngle + 30.0f, // fCombatBlockRightAngle + 4.0f, // fCombatCriticalStrikeMult + 0.1f, // fCombatDelayCreature + 0.1f, // fCombatDelayNPC + 128.0f, // fCombatDistance + 0.3f, // fCombatDistanceWerewolfMod + 30.0f, // fCombatForceSideAngle + 0.2f, // fCombatInvisoMult + 1.5f, // fCombatKODamageMult + 45.0f, // fCombatTorsoSideAngle + 0.3f, // fCombatTorsoStartPercent + 0.8f, // fCombatTorsoStopPercent + 15.0f, // fConstantEffectMult + 72.0f, // fCorpseClearDelay + 72.0f, // fCorpseRespawnDelay + 0.5f, // fCrimeGoldDiscountMult + 0.9f, // fCrimeGoldTurnInMult + 1.0f, // fCrimeStealing + 0.5f, // fDamageStrengthBase + 0.1f, // fDamageStrengthMult + 5.0f, // fDifficultyMult + 2.5f, // fDiseaseXferChance + -10.0f, // fDispAttacking + -1.0f, // fDispBargainFailMod + 1.0f, // fDispBargainSuccessMod + 0.0f, // fDispCrimeMod + -10.0f, // fDispDiseaseMod + 3.0f, // fDispFactionMod + 1.0f, // fDispFactionRankBase + 0.5f, // fDispFactionRankMult + 1.0f, // fDispositionMod + 50.0f, // fDispPersonalityBase + 0.5f, // fDispPersonalityMult + -25.0f, // fDispPickPocketMod + 5.0f, // fDispRaceMod + -0.5f, // fDispStealing + -5.0f, // fDispWeaponDrawn + 0.5f, // fEffectCostMult + 0.1f, // fElementalShieldMult + 3.0f, // fEnchantmentChanceMult + 0.5f, // fEnchantmentConstantChanceMult + 100.0f, // fEnchantmentConstantDurationMult + 0.1f, // fEnchantmentMult + 1000.0f, // fEnchantmentValueMult + 0.3f, // fEncumberedMoveEffect + 5.0f, // fEncumbranceStrMult + 0.04f, // fEndFatigueMult + 0.25f, // fFallAcroBase + 0.01f, // fFallAcroMult + 400.0f, // fFallDamageDistanceMin + 0.0f, // fFallDistanceBase + 0.07f, // fFallDistanceMult + 2.0f, // fFatigueAttackBase + 0.0f, // fFatigueAttackMult + 1.25f, // fFatigueBase + 4.0f, // fFatigueBlockBase + 0.0f, // fFatigueBlockMult + 5.0f, // fFatigueJumpBase + 0.0f, // fFatigueJumpMult + 0.5f, // fFatigueMult + 2.5f, // fFatigueReturnBase + 0.02f, // fFatigueReturnMult + 5.0f, // fFatigueRunBase + 2.0f, // fFatigueRunMult + 1.5f, // fFatigueSneakBase + 1.5f, // fFatigueSneakMult + 0.0f, // fFatigueSpellBase + 0.0f, // fFatigueSpellCostMult + 0.0f, // fFatigueSpellMult + 7.0f, // fFatigueSwimRunBase + 0.0f, // fFatigueSwimRunMult + 2.5f, // fFatigueSwimWalkBase + 0.0f, // fFatigueSwimWalkMult + 0.2f, // fFightDispMult + 0.005f, // fFightDistanceMultiplier + 50.0f, // fFightStealing + 3000.0f, // fFleeDistance + 512.0f, // fGreetDistanceReset + 0.1f, // fHandtoHandHealthPer + 1.0f, // fHandToHandReach + 0.5f, // fHoldBreathEndMult + 20.0f, // fHoldBreathTime + 0.75f, // fIdleChanceMultiplier + 1.0f, // fIngredientMult + 0.5f, // fInteriorHeadTrackMult + 128.0f, // fJumpAcrobaticsBase + 4.0f, // fJumpAcroMultiplier + 0.5f, // fJumpEncumbranceBase + 1.0f, // fJumpEncumbranceMultiplier + 0.5f, // fJumpMoveBase + 0.5f, // fJumpMoveMult + 1.0f, // fJumpRunMultiplier + 0.5f, // fKnockDownMult + 5.0f, // fLevelMod + 0.1f, // fLevelUpHealthEndMult + 0.6f, // fLightMaxMod + 10.0f, // fLuckMod + 10.0f, // fMagesGuildTravel + 1.5f, // fMagicCreatureCastDelay + 0.0167f, // fMagicDetectRefreshRate + 1.0f, // fMagicItemConstantMult + 1.0f, // fMagicItemCostMult + 1.0f, // fMagicItemOnceMult + 1.0f, // fMagicItemPriceMult + 0.05f, // fMagicItemRechargePerSecond + 1.0f, // fMagicItemStrikeMult + 1.0f, // fMagicItemUsedMult + 3.0f, // fMagicStartIconBlink + 0.5f, // fMagicSunBlockedMult + 0.75f, // fMajorSkillBonus + 300.0f, // fMaxFlySpeed + 0.5f, // fMaxHandToHandMult + 400.0f, // fMaxHeadTrackDistance + 200.0f, // fMaxWalkSpeed + 300.0f, // fMaxWalkSpeedCreature + 0.9f, // fMedMaxMod + 0.1f, // fMessageTimePerChar + 5.0f, // fMinFlySpeed + 0.1f, // fMinHandToHandMult + 1.0f, // fMinorSkillBonus + 100.0f, // fMinWalkSpeed + 5.0f, // fMinWalkSpeedCreature + 1.25f, // fMiscSkillBonus + 2.0f, // fNPCbaseMagickaMult + 0.5f, // fNPCHealthBarFade + 3.0f, // fNPCHealthBarTime + 1.0f, // fPCbaseMagickaMult + 0.3f, // fPerDieRollMult + 5.0f, // fPersonalityMod + 1.0f, // fPerTempMult + -1.0f, // fPickLockMult + 0.3f, // fPickPocketMod + 20.0f, // fPotionMinUsefulDuration + 0.5f, // fPotionStrengthMult + 0.5f, // fPotionT1DurMult + 1.5f, // fPotionT1MagMult + 20.0f, // fPotionT4BaseStrengthMult + 12.0f, // fPotionT4EquipStrengthMult + 3000.0f, // fProjectileMaxSpeed + 400.0f, // fProjectileMinSpeed + 25.0f, // fProjectileThrownStoreChance + 3.0f, // fRepairAmountMult + 1.0f, // fRepairMult + 1.0f, // fReputationMod + 0.15f, // fRestMagicMult + 0.0f, // fSeriousWoundMult + 0.25f, // fSleepRandMod + 0.3f, // fSleepRestMod + -1.0f, // fSneakBootMult + 0.5f, // fSneakDistanceBase + 0.002f, // fSneakDistanceMultiplier + 0.5f, // fSneakNoViewMult + 1.0f, // fSneakSkillMult + 0.75f, // fSneakSpeedMultiplier + 1.0f, // fSneakUseDelay + 500.0f, // fSneakUseDist + 1.5f, // fSneakViewMult + 3.0f, // fSoulGemMult + 0.8f, // fSpecialSkillBonus + 7.0f, // fSpellMakingValueMult + 2.0f, // fSpellPriceMult + 10.0f, // fSpellValueMult + 0.25f, // fStromWalkMult + 0.7f, // fStromWindSpeed + 3.0f, // fSuffocationDamage + 0.9f, // fSwimHeightScale + 0.1f, // fSwimRunAthleticsMult + 0.5f, // fSwimRunBase + 0.02f, // fSwimWalkAthleticsMult + 0.5f, // fSwimWalkBase + 1.0f, // fSwingBlockBase + 1.0f, // fSwingBlockMult + 1000.0f, // fTargetSpellMaxSpeed + 1000.0f, // fThrownWeaponMaxSpeed + 300.0f, // fThrownWeaponMinSpeed + 0.0f, // fTrapCostMult + 4000.0f, // fTravelMult + 16000.0f,// fTravelTimeMult + 0.1f, // fUnarmoredBase1 + 0.065f, // fUnarmoredBase2 + 30.0f, // fVanityDelay + 10.0f, // fVoiceIdleOdds + 0.0f, // fWaterReflectUpdateAlways + 10.0f, // fWaterReflectUpdateSeldom + 0.1f, // fWeaponDamageMult + 1.0f, // fWeaponFatigueBlockMult + 0.25f, // fWeaponFatigueMult + 150.0f, // fWereWolfAcrobatics + 150.0f, // fWereWolfAgility + 1.0f, // fWereWolfAlchemy + 1.0f, // fWereWolfAlteration + 1.0f, // fWereWolfArmorer + 150.0f, // fWereWolfAthletics + 1.0f, // fWereWolfAxe + 1.0f, // fWereWolfBlock + 1.0f, // fWereWolfBluntWeapon + 1.0f, // fWereWolfConjuration + 1.0f, // fWereWolfDestruction + 1.0f, // fWereWolfEnchant + 150.0f, // fWereWolfEndurance + 400.0f, // fWereWolfFatigue + 100.0f, // fWereWolfHandtoHand + 2.0f, // fWereWolfHealth + 1.0f, // fWereWolfHeavyArmor + 1.0f, // fWereWolfIllusion + 1.0f, // fWereWolfIntellegence + 1.0f, // fWereWolfLightArmor + 1.0f, // fWereWolfLongBlade + 1.0f, // fWereWolfLuck + 100.0f, // fWereWolfMagicka + 1.0f, // fWereWolfMarksman + 1.0f, // fWereWolfMediumArmor + 1.0f, // fWereWolfMerchantile + 1.0f, // fWereWolfMysticism + 1.0f, // fWereWolfPersonality + 1.0f, // fWereWolfRestoration + 1.5f, // fWereWolfRunMult + 1.0f, // fWereWolfSecurity + 1.0f, // fWereWolfShortBlade + 1.5f, // fWereWolfSilverWeaponDamageMult + 1.0f, // fWereWolfSneak + 1.0f, // fWereWolfSpear + 1.0f, // fWereWolfSpeechcraft + 150.0f, // fWereWolfSpeed + 150.0f, // fWereWolfStrength + 100.0f, // fWereWolfUnarmored + 1.0f, // fWereWolfWillPower + 15.0f // fWortChanceValue }; const int CSMWorld::DefaultGmsts::IntsDefaultValues[CSMWorld::DefaultGmsts::IntCount] = From 19db070fca743c197d0e2613c14d864b51c2084a Mon Sep 17 00:00:00 2001 From: Allofich Date: Mon, 31 Oct 2016 01:19:38 +0900 Subject: [PATCH 17/94] Don't update ripple simulation when paused --- apps/openmw/mwrender/renderingmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index c237f2320..c1261fd2b 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -458,9 +458,9 @@ namespace MWRender { mEffectManager->update(dt); mSky->update(dt); + mWater->update(dt); } - mWater->update(dt); mCamera->update(dt, paused); osg::Vec3f focal, cameraPos; From e0f613661e485d01d5a32ae50e2314efa7908f20 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 30 Oct 2016 20:05:51 +0100 Subject: [PATCH 18/94] Fix char -> int, fix shadowing warning --- apps/openmw/mwscript/locals.cpp | 2 +- apps/wizard/componentselectionpage.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwscript/locals.cpp b/apps/openmw/mwscript/locals.cpp index a535910da..9dd9d338e 100644 --- a/apps/openmw/mwscript/locals.cpp +++ b/apps/openmw/mwscript/locals.cpp @@ -238,7 +238,7 @@ namespace MWScript else { char type = declarations.getType (iter->first); - char index2 = declarations.getIndex (iter->first); + int index2 = declarations.getIndex (iter->first); try { diff --git a/apps/wizard/componentselectionpage.cpp b/apps/wizard/componentselectionpage.cpp index 21a5c58d9..161e51515 100644 --- a/apps/wizard/componentselectionpage.cpp +++ b/apps/wizard/componentselectionpage.cpp @@ -24,7 +24,7 @@ Wizard::ComponentSelectionPage::ComponentSelectionPage(QWidget *parent) : } -void Wizard::ComponentSelectionPage::updateButton(QListWidgetItem *item) +void Wizard::ComponentSelectionPage::updateButton(QListWidgetItem*) { if (field(QLatin1String("installation.new")).toBool() == true) return; // Morrowind is always checked here From c99d9a47e8725f907e589a9b1a6cfbda6a8ede87 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Sun, 30 Oct 2016 19:30:54 +0100 Subject: [PATCH 19/94] [OS X] Reenable CI --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4f811ee0f..574fe1ba8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ os: - linux -# - osx + - osx osx_image: xcode7.2 language: cpp sudo: required From cf2e59c98318caaccfb20b2d472635888e5e9ad0 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Sun, 30 Oct 2016 19:32:44 +0100 Subject: [PATCH 20/94] [OS X] Use Qt 5.5 on CI Newer Qt versions require C++11. --- CI/before_install.osx.sh | 3 ++- CI/before_script.osx.sh | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CI/before_install.osx.sh b/CI/before_install.osx.sh index b9da52193..8a306186e 100755 --- a/CI/before_install.osx.sh +++ b/CI/before_install.osx.sh @@ -1,10 +1,11 @@ #!/bin/sh brew update + brew rm cmake || true brew rm pkgconfig || true brew rm qt5 || true -brew install cmake pkgconfig qt5 +brew install cmake pkgconfig qt55 curl http://downloads.openmw.org/osx/dependencies/openmw-deps-263d4a8.zip -o ~/openmw-deps.zip unzip ~/openmw-deps.zip -d /private/tmp/openmw-deps > /dev/null diff --git a/CI/before_script.osx.sh b/CI/before_script.osx.sh index c3822291d..32bdd41ae 100755 --- a/CI/before_script.osx.sh +++ b/CI/before_script.osx.sh @@ -4,7 +4,7 @@ export CXX=clang++ export CC=clang DEPENDENCIES_ROOT="/private/tmp/openmw-deps/openmw-deps" -QT_PATH="/usr/local/opt/qt5" +QT_PATH="/usr/local/opt/qt55" mkdir build cd build From 5cd04af3fa5239c2c548a43a465ec905438bde0a Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Tue, 1 Nov 2016 16:37:00 +0100 Subject: [PATCH 21/94] Fix horrible performance when resizing/moving the settings window Resize widgets instead of reconstructing them. --- apps/openmw/mwgui/settingswindow.cpp | 28 ++++++++++++++++++++-------- apps/openmw/mwgui/settingswindow.hpp | 2 ++ 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index a0833194b..3211473e2 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -466,9 +466,6 @@ namespace MWGui else actions = MWBase::Environment::get().getInputManager()->getActionControllerSorting(); - const int h = 18; - const int w = mControlsBox->getWidth() - 28; - int curH = 0; for (std::vector::const_iterator it = actions.begin(); it != actions.end(); ++it) { std::string desc = MWBase::Environment::get().getInputManager()->getActionDescription (*it); @@ -481,16 +478,15 @@ namespace MWGui else binding = MWBase::Environment::get().getInputManager()->getActionControllerBindingName(*it); - Gui::SharedStateButton* leftText = mControlsBox->createWidget("SandTextButton", MyGUI::IntCoord(0,curH,w,h), MyGUI::Align::Default); + Gui::SharedStateButton* leftText = mControlsBox->createWidget("SandTextButton", MyGUI::IntCoord(), MyGUI::Align::Default); leftText->setCaptionWithReplacing(desc); - Gui::SharedStateButton* rightText = mControlsBox->createWidget("SandTextButton", MyGUI::IntCoord(0,curH,w,h), MyGUI::Align::Default); + Gui::SharedStateButton* rightText = mControlsBox->createWidget("SandTextButton", MyGUI::IntCoord(), MyGUI::Align::Default); rightText->setCaptionWithReplacing(binding); rightText->setTextAlign (MyGUI::Align::Right); rightText->setUserData(*it); // save the action id for callbacks rightText->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onRebindAction); rightText->eventMouseWheel += MyGUI::newDelegate(this, &SettingsWindow::onInputTabMouseWheel); - curH += h; Gui::ButtonGroup group; group.push_back(leftText); @@ -498,9 +494,25 @@ namespace MWGui Gui::SharedStateButton::createButtonGroup(group); } + layoutControlsBox(); + } + + void SettingsWindow::layoutControlsBox() + { + const int h = 18; + const int w = mControlsBox->getWidth() - 28; + const int noWidgetsInRow = 2; + const int totalH = mControlsBox->getChildCount() / noWidgetsInRow * h; + + for (size_t i = 0; i < mControlsBox->getChildCount(); i++) + { + MyGUI::Widget * widget = mControlsBox->getChildAt(i); + widget->setCoord(0, i / noWidgetsInRow * h, w, h); + } + // Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the scrollbar is hidden mControlsBox->setVisibleVScroll(false); - mControlsBox->setCanvasSize (mControlsBox->getWidth(), std::max(curH, mControlsBox->getHeight())); + mControlsBox->setCanvasSize (mControlsBox->getWidth(), std::max(totalH, mControlsBox->getHeight())); mControlsBox->setVisibleVScroll(true); } @@ -556,7 +568,7 @@ namespace MWGui void SettingsWindow::onWindowResize(MyGUI::Window *_sender) { - updateControlsBox(); + layoutControlsBox(); } void SettingsWindow::resetScrollbars() diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 5b12cc557..2ac06dcaa 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -66,6 +66,8 @@ namespace MWGui void configureWidgets(MyGUI::Widget* widget); void updateSliderLabel(MyGUI::ScrollBar* scroller, const std::string& value); + + void layoutControlsBox(); private: void resetScrollbars(); From 89e85a6acf459d2a33b2bc551369d50f7258ed9f Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Tue, 1 Nov 2016 21:14:24 +0100 Subject: [PATCH 22/94] Use local path from configuration manager to load openmw.cfg in launcher --- apps/launcher/maindialog.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index f2ec62939..15a1a5c2a 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -293,6 +293,7 @@ bool Launcher::MainDialog::setupGameSettings() { mGameSettings.clear(); + QString localPath = QString::fromUtf8(mCfgMgr.getLocalPath().string().c_str()); QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()); QString globalPath = QString::fromUtf8(mCfgMgr.getGlobalPath().string().c_str()); @@ -320,7 +321,7 @@ bool Launcher::MainDialog::setupGameSettings() // Now the rest - priority: user > local > global QStringList paths; paths.append(globalPath + QString("openmw.cfg")); - paths.append(QString("openmw.cfg")); + paths.append(localPath + QString("openmw.cfg")); paths.append(userPath + QString("openmw.cfg")); foreach (const QString &path, paths) { From 224d7f27b098b6e84871ba2b69f45a72c9d62ae5 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Tue, 1 Nov 2016 21:19:27 +0100 Subject: [PATCH 23/94] Revert "Use local path from configuration manager to load openmw.cfg in launcher" 89e85a6acf459d2a33b2bc551369d50f7258ed9f --- apps/launcher/maindialog.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 15a1a5c2a..f2ec62939 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -293,7 +293,6 @@ bool Launcher::MainDialog::setupGameSettings() { mGameSettings.clear(); - QString localPath = QString::fromUtf8(mCfgMgr.getLocalPath().string().c_str()); QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()); QString globalPath = QString::fromUtf8(mCfgMgr.getGlobalPath().string().c_str()); @@ -321,7 +320,7 @@ bool Launcher::MainDialog::setupGameSettings() // Now the rest - priority: user > local > global QStringList paths; paths.append(globalPath + QString("openmw.cfg")); - paths.append(localPath + QString("openmw.cfg")); + paths.append(QString("openmw.cfg")); paths.append(userPath + QString("openmw.cfg")); foreach (const QString &path, paths) { From 5d4734c02e0b9b17203d3c9d255ba03de58adbec Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Tue, 1 Nov 2016 21:14:24 +0100 Subject: [PATCH 24/94] Use local path from configuration manager to load openmw.cfg in launcher --- apps/launcher/maindialog.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index f2ec62939..15a1a5c2a 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -293,6 +293,7 @@ bool Launcher::MainDialog::setupGameSettings() { mGameSettings.clear(); + QString localPath = QString::fromUtf8(mCfgMgr.getLocalPath().string().c_str()); QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()); QString globalPath = QString::fromUtf8(mCfgMgr.getGlobalPath().string().c_str()); @@ -320,7 +321,7 @@ bool Launcher::MainDialog::setupGameSettings() // Now the rest - priority: user > local > global QStringList paths; paths.append(globalPath + QString("openmw.cfg")); - paths.append(QString("openmw.cfg")); + paths.append(localPath + QString("openmw.cfg")); paths.append(userPath + QString("openmw.cfg")); foreach (const QString &path, paths) { From 0c4dd05118527bbc51e690edf8497c8690e6e86d Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Sat, 5 Nov 2016 12:09:47 +0100 Subject: [PATCH 25/94] Link OpenMW with libz on macOS --- CI/before_script.osx.sh | 1 - apps/openmw/CMakeLists.txt | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/CI/before_script.osx.sh b/CI/before_script.osx.sh index 32bdd41ae..00a948c65 100755 --- a/CI/before_script.osx.sh +++ b/CI/before_script.osx.sh @@ -10,7 +10,6 @@ mkdir build cd build cmake \ --D CMAKE_EXE_LINKER_FLAGS="-lz" \ -D CMAKE_PREFIX_PATH="$DEPENDENCIES_ROOT;$QT_PATH" \ -D CMAKE_OSX_DEPLOYMENT_TARGET="10.8" \ -D CMAKE_OSX_SYSROOT="macosx10.11" \ diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 58dc2e8e5..c349e3fef 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -181,7 +181,7 @@ endif() if(APPLE) find_library(COCOA_FRAMEWORK Cocoa) find_library(IOKIT_FRAMEWORK IOKit) - target_link_libraries(openmw ${COCOA_FRAMEWORK} ${IOKIT_FRAMEWORK}) + target_link_libraries(openmw z ${COCOA_FRAMEWORK} ${IOKIT_FRAMEWORK}) if (FFmpeg_FOUND) find_library(COREVIDEO_FRAMEWORK CoreVideo) From 0115a3a87437d4da33b8162776e6149cbe5de236 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Sat, 5 Nov 2016 12:11:04 +0100 Subject: [PATCH 26/94] Revert "Link OpenMW with libz on macOS" This reverts commit 0c4dd05118527bbc51e690edf8497c8690e6e86d. --- CI/before_script.osx.sh | 1 + apps/openmw/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CI/before_script.osx.sh b/CI/before_script.osx.sh index 00a948c65..32bdd41ae 100755 --- a/CI/before_script.osx.sh +++ b/CI/before_script.osx.sh @@ -10,6 +10,7 @@ mkdir build cd build cmake \ +-D CMAKE_EXE_LINKER_FLAGS="-lz" \ -D CMAKE_PREFIX_PATH="$DEPENDENCIES_ROOT;$QT_PATH" \ -D CMAKE_OSX_DEPLOYMENT_TARGET="10.8" \ -D CMAKE_OSX_SYSROOT="macosx10.11" \ diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index c349e3fef..58dc2e8e5 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -181,7 +181,7 @@ endif() if(APPLE) find_library(COCOA_FRAMEWORK Cocoa) find_library(IOKIT_FRAMEWORK IOKit) - target_link_libraries(openmw z ${COCOA_FRAMEWORK} ${IOKIT_FRAMEWORK}) + target_link_libraries(openmw ${COCOA_FRAMEWORK} ${IOKIT_FRAMEWORK}) if (FFmpeg_FOUND) find_library(COREVIDEO_FRAMEWORK CoreVideo) From 3adf4cb97f0f986c3a19fafc42b53555ed8c80b2 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Sat, 5 Nov 2016 12:09:47 +0100 Subject: [PATCH 27/94] Link OpenMW with libz on macOS --- CI/before_script.osx.sh | 1 - apps/openmw/CMakeLists.txt | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/CI/before_script.osx.sh b/CI/before_script.osx.sh index 32bdd41ae..00a948c65 100755 --- a/CI/before_script.osx.sh +++ b/CI/before_script.osx.sh @@ -10,7 +10,6 @@ mkdir build cd build cmake \ --D CMAKE_EXE_LINKER_FLAGS="-lz" \ -D CMAKE_PREFIX_PATH="$DEPENDENCIES_ROOT;$QT_PATH" \ -D CMAKE_OSX_DEPLOYMENT_TARGET="10.8" \ -D CMAKE_OSX_SYSROOT="macosx10.11" \ diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 58dc2e8e5..332a6f0ac 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -186,7 +186,7 @@ if(APPLE) if (FFmpeg_FOUND) find_library(COREVIDEO_FRAMEWORK CoreVideo) find_library(VDA_FRAMEWORK VideoDecodeAcceleration) - target_link_libraries(openmw ${COREVIDEO_FRAMEWORK} ${VDA_FRAMEWORK}) + target_link_libraries(openmw z ${COREVIDEO_FRAMEWORK} ${VDA_FRAMEWORK}) endif() endif(APPLE) From e80636f0cafa090b05015f249eb770b5c901722f Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sun, 6 Nov 2016 11:01:46 +0100 Subject: [PATCH 28/94] Improve performance of repairing/recharging (Fixes #2493) --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwgui/itemchargeview.cpp | 212 ++++++++++++++++++++++ apps/openmw/mwgui/itemchargeview.hpp | 78 ++++++++ apps/openmw/mwgui/recharge.cpp | 92 +++------- apps/openmw/mwgui/recharge.hpp | 6 +- apps/openmw/mwgui/repair.cpp | 99 +++------- apps/openmw/mwgui/repair.hpp | 9 +- apps/openmw/mwgui/sortfilteritemmodel.cpp | 32 ++++ apps/openmw/mwgui/sortfilteritemmodel.hpp | 2 + apps/openmw/mwgui/windowmanagerimp.cpp | 2 + files/mygui/openmw_list.skin.xml | 9 + files/mygui/openmw_recharge_dialog.layout | 32 ++-- files/mygui/openmw_repair.layout | 37 ++-- 13 files changed, 436 insertions(+), 176 deletions(-) create mode 100644 apps/openmw/mwgui/itemchargeview.cpp create mode 100644 apps/openmw/mwgui/itemchargeview.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 332a6f0ac..277acea2d 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -42,7 +42,7 @@ add_openmw_dir (mwgui itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview tradeitemmodel companionitemmodel pickpocketitemmodel controllers savegamedialog recharge mode videowidget backgroundimage itemwidget screenfader debugwindow spellmodel spellview - draganddrop timeadvancer jailscreen + draganddrop timeadvancer jailscreen itemchargeview ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwgui/itemchargeview.cpp b/apps/openmw/mwgui/itemchargeview.cpp new file mode 100644 index 000000000..83517e353 --- /dev/null +++ b/apps/openmw/mwgui/itemchargeview.cpp @@ -0,0 +1,212 @@ +#include "itemchargeview.hpp" + +#include + +#include +#include +#include +#include + +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + +#include "../mwworld/class.hpp" +#include "../mwworld/esmstore.hpp" + +#include "itemmodel.hpp" +#include "itemwidget.hpp" + +namespace MWGui +{ + ItemChargeView::ItemChargeView() + : mScrollView(NULL), + mDisplayMode(DisplayMode_Health) + { + } + + void ItemChargeView::registerComponents() + { + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + } + + void ItemChargeView::initialiseOverride() + { + Base::initialiseOverride(); + + assignWidget(mScrollView, "ScrollView"); + if (mScrollView == NULL) + throw std::runtime_error("Item charge view needs a scroll view"); + + mScrollView->setCanvasAlign(MyGUI::Align::Left | MyGUI::Align::Top); + } + + void ItemChargeView::setModel(ItemModel* model) + { + mModel.reset(model); + } + + void ItemChargeView::setDisplayMode(ItemChargeView::DisplayMode type) + { + mDisplayMode = type; + update(); + } + + void ItemChargeView::update() + { + if (!mModel.get()) + { + layoutWidgets(); + return; + } + + mModel->update(); + + Lines lines; + std::set visitedLines; + + for (size_t i = 0; i < mModel->getItemCount(); ++i) + { + ItemStack stack = mModel->getItem(static_cast(i)); + + bool found = false; + for (Lines::const_iterator iter = mLines.begin(); iter != mLines.end(); ++iter) + { + if (iter->mItemPtr == stack.mBase) + { + found = true; + visitedLines.insert(iter); + + // update line widgets + updateLine(*iter); + lines.push_back(*iter); + break; + } + } + + if (!found) + { + // add line widgets + Line line; + line.mItemPtr = stack.mBase; + + line.mText = mScrollView->createWidget("SandText", MyGUI::IntCoord(), MyGUI::Align::Default); + line.mText->setNeedMouseFocus(false); + + line.mIcon = mScrollView->createWidget("MW_ItemIconSmall", MyGUI::IntCoord(), MyGUI::Align::Default); + line.mIcon->setItem(line.mItemPtr); + line.mIcon->setUserString("ToolTipType", "ItemPtr"); + line.mIcon->setUserData(line.mItemPtr); + line.mIcon->eventMouseButtonClick += MyGUI::newDelegate(this, &ItemChargeView::onIconClicked); + line.mIcon->eventMouseWheel += MyGUI::newDelegate(this, &ItemChargeView::onMouseWheel); + + line.mCharge = mScrollView->createWidget("MW_ChargeBar", MyGUI::IntCoord(), MyGUI::Align::Default); + line.mCharge->setNeedMouseFocus(false); + + updateLine(line); + + lines.push_back(line); + } + } + + for (Lines::iterator iter = mLines.begin(); iter != mLines.end(); ++iter) + { + if (visitedLines.count(iter)) + continue; + + // remove line widgets + MyGUI::Gui::getInstance().destroyWidget(iter->mText); + MyGUI::Gui::getInstance().destroyWidget(iter->mIcon); + MyGUI::Gui::getInstance().destroyWidget(iter->mCharge); + } + + mLines.swap(lines); + + layoutWidgets(); + } + + void ItemChargeView::layoutWidgets() + { + int currentY = 0; + + for (Lines::const_iterator iter = mLines.begin(); iter != mLines.end(); ++iter) + { + iter->mText->setCoord(8, currentY, mScrollView->getWidth()-8, 18); + currentY += 19; + + iter->mIcon->setCoord(16, currentY, 32, 32); + iter->mCharge->setCoord(72, currentY+2, std::max(199, mScrollView->getWidth()-72-38), 20); + currentY += 32 + 4; + } + + // Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the scrollbar is hidden + mScrollView->setVisibleVScroll(false); + mScrollView->setCanvasSize(MyGUI::IntSize(mScrollView->getWidth(), std::max(mScrollView->getHeight(), currentY))); + mScrollView->setVisibleVScroll(true); + } + + void ItemChargeView::resetScrollbars() + { + mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); + } + + void ItemChargeView::setSize(const MyGUI::IntSize& value) + { + bool changed = (value.width != getWidth() || value.height != getHeight()); + Base::setSize(value); + if (changed) + layoutWidgets(); + } + + void ItemChargeView::setCoord(const MyGUI::IntCoord& value) + { + bool changed = (value.width != getWidth() || value.height != getHeight()); + Base::setCoord(value); + if (changed) + layoutWidgets(); + } + + void ItemChargeView::updateLine(const ItemChargeView::Line& line) + { + line.mText->setCaption(line.mItemPtr.getClass().getName(line.mItemPtr)); + + line.mCharge->setVisible(false); + switch (mDisplayMode) + { + case DisplayMode_Health: + if (!line.mItemPtr.getClass().hasItemHealth(line.mItemPtr)) + break; + + line.mCharge->setVisible(true); + line.mCharge->setValue(line.mItemPtr.getClass().getItemHealth(line.mItemPtr), + line.mItemPtr.getClass().getItemMaxHealth(line.mItemPtr)); + break; + case DisplayMode_EnchantmentCharge: + std::string enchId = line.mItemPtr.getClass().getEnchantment(line.mItemPtr); + if (enchId.empty()) + break; + const ESM::Enchantment* ench = MWBase::Environment::get().getWorld()->getStore().get().search(enchId); + if (!ench) + break; + + line.mCharge->setVisible(true); + line.mCharge->setValue(static_cast(line.mItemPtr.getCellRef().getEnchantmentCharge()), + ench->mData.mCharge); + break; + } + } + + void ItemChargeView::onIconClicked(MyGUI::Widget* sender) + { + eventItemClicked(this, *sender->getUserData()); + } + + void ItemChargeView::onMouseWheel(MyGUI::Widget* /*sender*/, int rel) + { + if (mScrollView->getViewOffset().top + rel*0.3f > 0) + mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); + else + mScrollView->setViewOffset(MyGUI::IntPoint(0, static_cast(mScrollView->getViewOffset().top + rel*0.3f))); + } +} diff --git a/apps/openmw/mwgui/itemchargeview.hpp b/apps/openmw/mwgui/itemchargeview.hpp new file mode 100644 index 000000000..1ff077ef2 --- /dev/null +++ b/apps/openmw/mwgui/itemchargeview.hpp @@ -0,0 +1,78 @@ +#ifndef MWGUI_ITEMCHARGEVIEW_H +#define MWGUI_ITEMCHARGEVIEW_H + +#include +#include + +#include + +#include "../mwworld/ptr.hpp" + +#include "widgets.hpp" + +namespace MyGUI +{ + class TextBox; + class ScrollView; +} + +namespace MWGui +{ + class ItemModel; + class ItemWidget; + + class ItemChargeView : public MyGUI::Widget + { + MYGUI_RTTI_DERIVED(ItemChargeView) + public: + enum DisplayMode + { + DisplayMode_Health, + DisplayMode_EnchantmentCharge + }; + + ItemChargeView(); + + /// Register needed components with MyGUI's factory manager + static void registerComponents(); + + virtual void initialiseOverride(); + + /// Takes ownership of \a model + void setModel(ItemModel* model); + + void setDisplayMode(DisplayMode type); + + void update(); + void layoutWidgets(); + void resetScrollbars(); + + virtual void setSize(const MyGUI::IntSize& value); + virtual void setCoord(const MyGUI::IntCoord& value); + + MyGUI::delegates::CMultiDelegate2 eventItemClicked; + + private: + struct Line + { + MWWorld::Ptr mItemPtr; + MyGUI::TextBox* mText; + ItemWidget* mIcon; + Widgets::MWDynamicStatPtr mCharge; + }; + + void updateLine(const Line& line); + + void onIconClicked(MyGUI::Widget* sender); + void onMouseWheel(MyGUI::Widget* sender, int rel); + + typedef std::vector Lines; + Lines mLines; + + std::auto_ptr mModel; + MyGUI::ScrollView* mScrollView; + DisplayMode mDisplayMode; + }; +} + +#endif diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 1dac7138f..66d29bd59 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -5,6 +5,8 @@ #include #include +#include + #include #include "../mwbase/world.hpp" @@ -21,6 +23,9 @@ #include "widgets.hpp" #include "itemwidget.hpp" +#include "itemchargeview.hpp" +#include "sortfilteritemmodel.hpp" +#include "inventoryitemmodel.hpp" namespace MWGui { @@ -29,13 +34,15 @@ Recharge::Recharge() : WindowBase("openmw_recharge_dialog.layout") { getWidget(mBox, "Box"); - getWidget(mView, "View"); getWidget(mGemBox, "GemBox"); getWidget(mGemIcon, "GemIcon"); getWidget(mChargeLabel, "ChargeLabel"); getWidget(mCancelButton, "CancelButton"); mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &Recharge::onCancel); + mBox->eventItemClicked += MyGUI::newDelegate(this, &Recharge::onItemClicked); + + mBox->setDisplayMode(ItemChargeView::DisplayMode_EnchantmentCharge); setVisible(false); } @@ -43,8 +50,13 @@ Recharge::Recharge() void Recharge::open() { center(); + + SortFilterItemModel * model = new SortFilterItemModel(new InventoryItemModel(MWMechanics::getPlayer())); + model->setFilter(SortFilterItemModel::Filter_OnlyRechargable); + mBox->setModel(model); + // Reset scrollbars - mView->setViewOffset(MyGUI::IntPoint(0, 0)); + mBox->resetScrollbars(); } void Recharge::exit() @@ -72,66 +84,16 @@ void Recharge::updateView() bool toolBoxVisible = (gem.getRefData().getCount() != 0); mGemBox->setVisible(toolBoxVisible); + mGemBox->setUserString("Hidden", toolBoxVisible ? "false" : "true"); - bool toolBoxWasVisible = (mBox->getPosition().top != mGemBox->getPosition().top); - - if (toolBoxVisible && !toolBoxWasVisible) - { - // shrink - mBox->setPosition(mBox->getPosition() + MyGUI::IntPoint(0, mGemBox->getSize().height)); - mBox->setSize(mBox->getSize() - MyGUI::IntSize(0,mGemBox->getSize().height)); - } - else if (!toolBoxVisible && toolBoxWasVisible) - { - // expand - mBox->setPosition(MyGUI::IntPoint (mBox->getPosition().left, mGemBox->getPosition().top)); - mBox->setSize(mBox->getSize() + MyGUI::IntSize(0,mGemBox->getSize().height)); - } - - while (mView->getChildCount()) - MyGUI::Gui::getInstance().destroyWidget(mView->getChildAt(0)); + mBox->update(); - int currentY = 0; + Gui::Box* box = dynamic_cast(mMainWidget); + if (box == NULL) + throw std::runtime_error("main widget must be a box"); - MWWorld::Ptr player = MWMechanics::getPlayer(); - MWWorld::ContainerStore& store = player.getClass().getContainerStore(player); - for (MWWorld::ContainerStoreIterator iter (store.begin()); - iter!=store.end(); ++iter) - { - std::string enchantmentName = iter->getClass().getEnchantment(*iter); - if (enchantmentName.empty()) - continue; - const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get().find(enchantmentName); - if (iter->getCellRef().getEnchantmentCharge() >= enchantment->mData.mCharge - || iter->getCellRef().getEnchantmentCharge() == -1) - continue; - - MyGUI::TextBox* text = mView->createWidget ( - "SandText", MyGUI::IntCoord(8, currentY, mView->getWidth()-8, 18), MyGUI::Align::Default); - text->setCaption(iter->getClass().getName(*iter)); - text->setNeedMouseFocus(false); - currentY += 19; - - ItemWidget* icon = mView->createWidget ( - "MW_ItemIconSmall", MyGUI::IntCoord(16, currentY, 32, 32), MyGUI::Align::Default); - icon->setItem(*iter); - icon->setUserString("ToolTipType", "ItemPtr"); - icon->setUserData(*iter); - icon->eventMouseButtonClick += MyGUI::newDelegate(this, &Recharge::onItemClicked); - icon->eventMouseWheel += MyGUI::newDelegate(this, &Recharge::onMouseWheel); - - Widgets::MWDynamicStatPtr chargeWidget = mView->createWidget - ("MW_ChargeBar", MyGUI::IntCoord(72, currentY+2, 199, 20), MyGUI::Align::Default); - chargeWidget->setValue(static_cast(iter->getCellRef().getEnchantmentCharge()), enchantment->mData.mCharge); - chargeWidget->setNeedMouseFocus(false); - - currentY += 32 + 4; - } - - // Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the scrollbar is hidden - mView->setVisibleVScroll(false); - mView->setCanvasSize (MyGUI::IntSize(mView->getWidth(), std::max(mView->getHeight(), currentY))); - mView->setVisibleVScroll(true); + box->notifyChildrenSizeChanged(); + center(); } void Recharge::onCancel(MyGUI::Widget *sender) @@ -139,15 +101,13 @@ void Recharge::onCancel(MyGUI::Widget *sender) exit(); } -void Recharge::onItemClicked(MyGUI::Widget *sender) +void Recharge::onItemClicked(MyGUI::Widget *sender, const MWWorld::Ptr& item) { MWWorld::Ptr gem = *mGemIcon->getUserData(); if (!gem.getRefData().getCount()) return; - MWWorld::Ptr item = *sender->getUserData(); - MWWorld::Ptr player = MWMechanics::getPlayer(); MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); MWMechanics::NpcStats& npcStats = player.getClass().getNpcStats(player); @@ -198,12 +158,4 @@ void Recharge::onItemClicked(MyGUI::Widget *sender) updateView(); } -void Recharge::onMouseWheel(MyGUI::Widget* _sender, int _rel) -{ - if (mView->getViewOffset().top + _rel*0.3f > 0) - mView->setViewOffset(MyGUI::IntPoint(0, 0)); - else - mView->setViewOffset(MyGUI::IntPoint(0, static_cast(mView->getViewOffset().top + _rel*0.3f))); -} - } diff --git a/apps/openmw/mwgui/recharge.hpp b/apps/openmw/mwgui/recharge.hpp index 3e8e1269e..bbcf994dd 100644 --- a/apps/openmw/mwgui/recharge.hpp +++ b/apps/openmw/mwgui/recharge.hpp @@ -12,6 +12,7 @@ namespace MWGui { class ItemWidget; +class ItemChargeView; class Recharge : public WindowBase { @@ -25,8 +26,7 @@ public: void start (const MWWorld::Ptr& gem); protected: - MyGUI::Widget* mBox; - MyGUI::ScrollView* mView; + ItemChargeView* mBox; MyGUI::Widget* mGemBox; @@ -38,7 +38,7 @@ protected: void updateView(); - void onItemClicked (MyGUI::Widget* sender); + void onItemClicked (MyGUI::Widget* sender, const MWWorld::Ptr& item); void onCancel (MyGUI::Widget* sender); void onMouseWheel(MyGUI::Widget* _sender, int _rel); diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index 49d5735a4..07fd6520c 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -4,6 +4,9 @@ #include #include +#include + +#include #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" @@ -17,6 +20,9 @@ #include "widgets.hpp" #include "itemwidget.hpp" +#include "itemchargeview.hpp" +#include "sortfilteritemmodel.hpp" +#include "inventoryitemmodel.hpp" namespace MWGui { @@ -25,7 +31,6 @@ Repair::Repair() : WindowBase("openmw_repair.layout") { getWidget(mRepairBox, "RepairBox"); - getWidget(mRepairView, "RepairView"); getWidget(mToolBox, "ToolBox"); getWidget(mToolIcon, "ToolIcon"); getWidget(mUsesLabel, "UsesLabel"); @@ -33,13 +38,21 @@ Repair::Repair() getWidget(mCancelButton, "CancelButton"); mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &Repair::onCancel); + mRepairBox->eventItemClicked += MyGUI::newDelegate(this, &Repair::onRepairItem); + + mRepairBox->setDisplayMode(ItemChargeView::DisplayMode_Health); } void Repair::open() { center(); + + SortFilterItemModel * model = new SortFilterItemModel(new InventoryItemModel(MWMechanics::getPlayer())); + model->setFilter(SortFilterItemModel::Filter_OnlyRepairable); + mRepairBox->setModel(model); + // Reset scrollbars - mRepairView->setViewOffset(MyGUI::IntPoint(0, 0)); + mRepairBox->resetScrollbars(); } void Repair::exit() @@ -75,89 +88,31 @@ void Repair::updateRepairView() bool toolBoxVisible = (mRepair.getTool().getRefData().getCount() != 0); mToolBox->setVisible(toolBoxVisible); + mToolBox->setUserString("Hidden", toolBoxVisible ? "false" : "true"); + + mRepairBox->update(); - bool toolBoxWasVisible = (mRepairBox->getPosition().top != mToolBox->getPosition().top); - - if (toolBoxVisible && !toolBoxWasVisible) - { - // shrink - mRepairBox->setPosition(mRepairBox->getPosition() + MyGUI::IntPoint(0,mToolBox->getSize().height)); - mRepairBox->setSize(mRepairBox->getSize() - MyGUI::IntSize(0,mToolBox->getSize().height)); - } - else if (!toolBoxVisible && toolBoxWasVisible) - { - // expand - mRepairBox->setPosition(MyGUI::IntPoint (mRepairBox->getPosition().left, mToolBox->getPosition().top)); - mRepairBox->setSize(mRepairBox->getSize() + MyGUI::IntSize(0,mToolBox->getSize().height)); - } - - while (mRepairView->getChildCount()) - MyGUI::Gui::getInstance().destroyWidget(mRepairView->getChildAt(0)); - - int currentY = 0; - - MWWorld::Ptr player = MWMechanics::getPlayer(); - MWWorld::ContainerStore& store = player.getClass().getContainerStore(player); - int categories = MWWorld::ContainerStore::Type_Weapon | MWWorld::ContainerStore::Type_Armor; - for (MWWorld::ContainerStoreIterator iter (store.begin(categories)); - iter!=store.end(); ++iter) - { - if (iter->getClass().hasItemHealth(*iter)) - { - int maxDurability = iter->getClass().getItemMaxHealth(*iter); - int durability = iter->getClass().getItemHealth(*iter); - if (maxDurability == durability) - continue; - - MyGUI::TextBox* text = mRepairView->createWidget ( - "SandText", MyGUI::IntCoord(8, currentY, mRepairView->getWidth()-8, 18), MyGUI::Align::Default); - text->setCaption(iter->getClass().getName(*iter)); - text->setNeedMouseFocus(false); - currentY += 19; - - ItemWidget* icon = mRepairView->createWidget ( - "MW_ItemIconSmall", MyGUI::IntCoord(16, currentY, 32, 32), MyGUI::Align::Default); - icon->setItem(*iter); - icon->setUserString("ToolTipType", "ItemPtr"); - icon->setUserData(*iter); - icon->eventMouseButtonClick += MyGUI::newDelegate(this, &Repair::onRepairItem); - icon->eventMouseWheel += MyGUI::newDelegate(this, &Repair::onMouseWheel); - - Widgets::MWDynamicStatPtr chargeWidget = mRepairView->createWidget - ("MW_ChargeBar", MyGUI::IntCoord(72, currentY+2, 199, 20), MyGUI::Align::Default); - chargeWidget->setValue(durability, maxDurability); - chargeWidget->setNeedMouseFocus(false); - - currentY += 32 + 4; - } - } - // Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the scrollbar is hidden - mRepairView->setVisibleVScroll(false); - mRepairView->setCanvasSize (MyGUI::IntSize(mRepairView->getWidth(), std::max(mRepairView->getHeight(), currentY))); - mRepairView->setVisibleVScroll(true); + Gui::Box* box = dynamic_cast(mMainWidget); + if (box == NULL) + throw std::runtime_error("main widget must be a box"); + + box->notifyChildrenSizeChanged(); + center(); } -void Repair::onCancel(MyGUI::Widget *sender) +void Repair::onCancel(MyGUI::Widget* /*sender*/) { exit(); } -void Repair::onRepairItem(MyGUI::Widget *sender) +void Repair::onRepairItem(MyGUI::Widget* /*sender*/, const MWWorld::Ptr& ptr) { if (!mRepair.getTool().getRefData().getCount()) return; - mRepair.repair(*sender->getUserData()); + mRepair.repair(ptr); updateRepairView(); } -void Repair::onMouseWheel(MyGUI::Widget* _sender, int _rel) -{ - if (mRepairView->getViewOffset().top + _rel*0.3f > 0) - mRepairView->setViewOffset(MyGUI::IntPoint(0, 0)); - else - mRepairView->setViewOffset(MyGUI::IntPoint(0, static_cast(mRepairView->getViewOffset().top + _rel*0.3f))); -} - } diff --git a/apps/openmw/mwgui/repair.hpp b/apps/openmw/mwgui/repair.hpp index 439ee1169..8746f7dc4 100644 --- a/apps/openmw/mwgui/repair.hpp +++ b/apps/openmw/mwgui/repair.hpp @@ -9,6 +9,7 @@ namespace MWGui { class ItemWidget; +class ItemChargeView; class Repair : public WindowBase { @@ -22,8 +23,7 @@ public: void startRepairItem (const MWWorld::Ptr& item); protected: - MyGUI::Widget* mRepairBox; - MyGUI::ScrollView* mRepairView; + ItemChargeView* mRepairBox; MyGUI::Widget* mToolBox; @@ -38,9 +38,8 @@ protected: void updateRepairView(); - void onRepairItem (MyGUI::Widget* sender); - void onCancel (MyGUI::Widget* sender); - void onMouseWheel(MyGUI::Widget* _sender, int _rel); + void onRepairItem(MyGUI::Widget* sender, const MWWorld::Ptr& ptr); + void onCancel(MyGUI::Widget* sender); }; diff --git a/apps/openmw/mwgui/sortfilteritemmodel.cpp b/apps/openmw/mwgui/sortfilteritemmodel.cpp index 9c73db340..0d7053404 100644 --- a/apps/openmw/mwgui/sortfilteritemmodel.cpp +++ b/apps/openmw/mwgui/sortfilteritemmodel.cpp @@ -1,5 +1,7 @@ #include "sortfilteritemmodel.hpp" +#include + #include #include @@ -14,9 +16,14 @@ #include #include #include +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" #include "../mwworld/class.hpp" #include "../mwworld/nullaction.hpp" +#include "../mwworld/esmstore.hpp" namespace { @@ -139,6 +146,31 @@ namespace MWGui return false; } + if ((mFilter & Filter_OnlyRepairable) && ( + !base.getClass().hasItemHealth(base) + || (base.getClass().getItemHealth(base) == base.getClass().getItemMaxHealth(base)) + || (base.getTypeName() != typeid(ESM::Weapon).name() + && base.getTypeName() != typeid(ESM::Armor).name()))) + return false; + + if (mFilter & Filter_OnlyRechargable) + { + if (!(item.mFlags & ItemStack::Flag_Enchanted)) + return false; + + std::string enchId = base.getClass().getEnchantment(base); + const ESM::Enchantment* ench = MWBase::Environment::get().getWorld()->getStore().get().search(enchId); + if (!ench) + { + std::cerr << "Can't find enchantment '" << enchId << "' on item " << base.getCellRef().getRefId() << std::endl; + return false; + } + + if (base.getCellRef().getEnchantmentCharge() >= ench->mData.mCharge + || base.getCellRef().getEnchantmentCharge() == -1) + return false; + } + return true; } diff --git a/apps/openmw/mwgui/sortfilteritemmodel.hpp b/apps/openmw/mwgui/sortfilteritemmodel.hpp index 064f62e77..3d5396e2a 100644 --- a/apps/openmw/mwgui/sortfilteritemmodel.hpp +++ b/apps/openmw/mwgui/sortfilteritemmodel.hpp @@ -39,6 +39,8 @@ namespace MWGui static const int Filter_OnlyEnchantable = (1<<2); static const int Filter_OnlyChargedSoulstones = (1<<3); static const int Filter_OnlyUsableItems = (1<<4); // Only items with a Use action + static const int Filter_OnlyRepairable = (1<<5); + static const int Filter_OnlyRechargable = (1<<6); private: diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 09b72ad3d..5c41fd55b 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -109,6 +109,7 @@ #include "container.hpp" #include "controllers.hpp" #include "jailscreen.hpp" +#include "itemchargeview.hpp" namespace MWGui { @@ -223,6 +224,7 @@ namespace MWGui MyGUI::FactoryManager::getInstance().registerFactory("Layer"); BookPage::registerMyGUIComponents (); ItemView::registerComponents(); + ItemChargeView::registerComponents(); ItemWidget::registerComponents(); SpellView::registerComponents(); Gui::registerAllWidgets(); diff --git a/files/mygui/openmw_list.skin.xml b/files/mygui/openmw_list.skin.xml index ce8209e3d..c1e8114e9 100644 --- a/files/mygui/openmw_list.skin.xml +++ b/files/mygui/openmw_list.skin.xml @@ -157,6 +157,15 @@ + + + + + + + + + diff --git a/files/mygui/openmw_recharge_dialog.layout b/files/mygui/openmw_recharge_dialog.layout index 1b2ad947b..1bf7d9038 100644 --- a/files/mygui/openmw_recharge_dialog.layout +++ b/files/mygui/openmw_recharge_dialog.layout @@ -1,27 +1,37 @@ - + + + - - + + - + + + + + - - - - + + + - - - + + + + + + + + diff --git a/files/mygui/openmw_repair.layout b/files/mygui/openmw_repair.layout index 09a372440..9706a2b92 100644 --- a/files/mygui/openmw_repair.layout +++ b/files/mygui/openmw_repair.layout @@ -1,31 +1,40 @@ - + + + - - + + - + + + - - + + + + - - - - - + + + - - - + + + + + + + + From c7313606f5e4059091a4e2419edaada6348f8b26 Mon Sep 17 00:00:00 2001 From: Allofich Date: Mon, 7 Nov 2016 00:28:22 +0900 Subject: [PATCH 29/94] Fix dereference of null pointer warning --- apps/essimporter/importer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 1c255c56f..a420d08da 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -51,6 +51,7 @@ namespace { for (int x=0; x<128; ++x) { + assert(image->data(x,y)); *(image->data(x,y)+2) = *it++; *(image->data(x,y)+1) = *it++; *image->data(x,y) = *it++; From 2d48c38d0df40e7af24dbc3a291c676689d67948 Mon Sep 17 00:00:00 2001 From: lysol90 Date: Wed, 9 Nov 2016 13:14:50 +0100 Subject: [PATCH 30/94] Create convert_bump_mapped_mods.rst A tutorial to how normal mapping works with different mods in Morrowind and how they work in OpenMW. It also covers how to convert the mods made for Morrowind to be used with OpenMW. --- .../openmw-mods/convert_bump_mapped_mods.rst | 213 ++++++++++++++++++ 1 file changed, 213 insertions(+) create mode 100644 docs/source/openmw-mods/convert_bump_mapped_mods.rst diff --git a/docs/source/openmw-mods/convert_bump_mapped_mods.rst b/docs/source/openmw-mods/convert_bump_mapped_mods.rst new file mode 100644 index 000000000..aef15835e --- /dev/null +++ b/docs/source/openmw-mods/convert_bump_mapped_mods.rst @@ -0,0 +1,213 @@ +Normal maps from Morrowind to OpenMW +==================================== + +Index: +------ + +- `1. General introduction to normal map conversion`_ + - `Normal Mapping in OpenMW`_ + - `Activating normal mapping shaders in OpenMW`_ + - `Normal mapping in Morrowind with Morrowind Code Patch`_ + - `Normal mapping in Morrowind with MGE XE (PBR version)`_ +- `2. Converting PeterBitt's Scamp Replacer`_ (Mod made for the MGE XE PBR prototype) + - `Tutorial - MGE`_ +- `3. Converting Lougian's Hlaalu Bump mapped`_ (MCP's fake bump map function, part 1: *without* custom models) + - `Tutorial - MCP, Part 1`_ +- `4. Converting Apel's Various Things – Sacks`_ (MCP's fake bump map function, part 2: *with* custom models) + - `Tutorial - MCP, Part 2`_ + +1. General introduction to normal map conversion +================================================ + +:Author(s): Joakim (Lysol) Berg +:Latest update: 2016-11-09 + +Hi. + +This page has general information and tutorials on how normal mapping works in OpenMW and how you can make mods using the old fake normal mapping technique (such as `Netch Bump mapped`_ and `Hlaalu Bump mapped`_ work in OpenMW. + +*Note:* The conversion made in part four of this tutorial require the use of the application NifSkope, which is a Windows-only application. Read part one of this tutorial to learn more. + +*Another note:* I will use the terms bump mapping and normal mapping simultaneously. Normal mapping is one form of bump mapping. In other words, normal mapping is bump mapping, but bump mapping isn't necessarily normal mapping. There are several techniques for bump mapping, and normal mapping is the most common one today. + +So let's get on with it. + +Normal Mapping in OpenMW +------------------------ + +Normal mapping in OpenMW works in a very simple way: The engine just looks for a texture with a "_n.dds" suffix, and you're done. + +So to expand on this a bit, let's take a look at how a model seeks for textures. + +Let us assume we have the model "example.nif". In this model file, there should be a tag (NiSourceTexture) that states what texture it should use and where to find it. Typically, it will point to something like "exampletexture_01.dds". This texture is supposed to be located directly in the Textures folder since it does not state anything else. If the model is a custom made one, modders tend to group their textures in separate folders, just to easily keep track of them. It might be something like "Textures\moddername\exampletexture_02.dds". + +When OpenMW finally adds normal mapping, it simply takes the NiSourceTexture file path, e.g., "exampletexture_01.dds", and looks for a "exampletexture_01_n.dds". If it can't find this file, no normal mapping is added. If it *does* find this file, the model will use this texture as a normal map. Simple. + +Activating normal mapping shaders in OpenMW +******************************************* + +Before normal (and specular and parallax) maps will show up in OpenMW, you'll need to activate them in the settings.cfg_-file. Add these rows where it would make sense: + +:: + + [Shaders] + auto use object normal maps = true + auto use terrain normal maps = true + [/code] + +And while we're at it, why not activate specular maps too just for the sake of it? + +:: + + [code] + auto use object specular maps = true + auto use terrain specular maps = true + [/code] + +Lastly, if you want really nice lights in OpenMW, add these rows: + +:: + + [code] + force shaders = true + clamp lighting = false + [/code] + +See OpenMW's wiki page about `texture modding`_ to read more about this. + +Normal mapping in Morrowind with Morrowind Code Patch +----------------------------------------------------- + +**Conversion difficulty:** +*Varies. Sometimes quick and easy, sometimes time-consuming and hard.* + +You might have bumped (pun intended) on a few bump-mapped texture packs for Morrowind that require the Morrowind Code Patch (MCP). You might even be thinking: Why doesn't OpenMW just support these instead of reinventing the wheel? I know it sounds strange, but it will make sense. Here's how MCP handles normal maps: + +Morrowind does not recognize normal maps (they weren't really a "thing" yet in 2002), so even if you have a normal map, Morrowind will not load and display it. MCP has a clever way to solve this issue, by using something Morrowind *does* support, namely environment maps. You could add a tag for an environment map and then add a normal map as the environment map, but you'd end up with a shiny ugly model in the game. MCP solves this by turning down the brightness of the environment maps, making the model look *kind of* as if it had a normal map applied to it. I say kind of because it does not really look as good as normal mapping usually does. It was a hacky way to do it, but it was the only way at the time, and therefore the best way. + +The biggest problem with this is not that it doesn't look as good as it could – no, the biggest problem in my opinion is that it requires you to state the file paths for your normal map textures *in the models*! For buildings, which often use several textures for one single model file, it could take *ages* to do this, and you had to do it for dozens of model files too. You also had to ship your texture pack with model files, making your mod bigger in file size. + +These are basically the reasons why OpenMW does not support fake bump maps like MCP does. It is just a really bad way to enhance your models, all the more when you have the possibility to do it in a better way. + +Normal mapping in Morrowind with MGE XE (PBR version) +----------------------------------------------------- + +**Conversion difficulty:** +*Easy* + +The most recent feature on this topic is that the Morrowind Graphics Extender (MGE) finally started to support real normal mapping in an experimental version available here: `MGE XE`_ (you can't use MGE with OpenMW!). Not only this but it also adds full support for physically based rendering (PBR), making it one step ahead of OpenMW in terms of texturing techniques. However, OpenMW will probably have this feature in the future too – and let's hope that OpenMW and MGE will handle PBR in a similar fashion in the future so that mods can be used for both MGE and OpenMW without any hassle. + +I haven't researched that much on the MGE variant yet but it does support real implementation of normal mapping, making it really easy to convert mods made for MGE into OpenMW (I'm only talking about the normal map textures though). There's some kind of text file if I understood it correctly that MGE uses to find the normal map. OpenMW does not need this, you just have to make sure the normal map has the same name as the diffuse texture but with the correct suffix after. + +Now, on to the tutorials. + +2. Converting PeterBitt's Scamp Replacer +======================================== +Mod made for the MGE XE PBR prototype +------------------------------------- + +:Author: Joakim (Lysol) Berg +:Latest update: 2016-11-09 + +So, let's say you've found out that PeterBitt_ makes awesome models and textures featuring physically based rendering (PBR) and normal maps. Let's say that you tried to run his `PBR Scamp Replacer`_ in OpenMW and that you were greatly disappointed when the normal map didn't seem to work. Lastly, let's say you came here, looking for some answers. Am I right? Great. Because you've come to the right place! + +*A quick note before we begin*: Please note that you can only use the normal map texture and not the rest of the materials, since PBR isn't implemented in OpenMW yet. Sometimes PBR textures can look dull without all of the texture files, so have that in mind. + +Tutorial - MGE +-------------- + +In this tutorial, I will use PeterBitt's `PBR Scamp Replacer`_ as an example, but any mod featuring PBR that requires the PBR version of MGE will do, provided it also includes a normal map (which it probably does). + +So, follow these steps: + +#. Go to the Nexus page for PeterBitt's `PBR Scamp Replacer`_ +#. Go to the *files* tab and download the main file and the "PBR materials" file. +#. Extract the main file as if you'd install a normal mod (**Pro tip**: Install using OpenMW's `Multi-data`_ folder function!) +#. Now, open the PBR materials file: + - Go to "Materials/PB/". + - Select the "**tx_Scamp_normals.dds**" file, which is, obviously, the normal map texture. + - Extract this file to the place you extracted the main file to, but in the subdirectory "Textures/PB/". +#. Rename your newly extracted file ("**tx_Scamp_normals.dds**") to "**tx_Scamp_n.dds**" (which is exactly the same name as the diffuse texture file, except for the added "**_n**" suffix before the filename extention). +#. You're actually done! + +So as you might notice, converting these mods is very simple and takes just a couple of minutes. It's more or less just a matter of renaming and moving a few files. + +I totally recommend you to also try this on PeterBitt's Nix Hound replacer and Flash3113's various replacers. It should be the same principle to get those to work. + +And let's hope that some one implements PBR shaders to OpenMW too, so that we can use all the material files of these mods in the future. + +3. Converting Lougian's Hlaalu Bump mapped +========================================== +Mod made for MCP's fake bump function, without custom models +------------------------------------------------------------ + +:Author: Joakim (Lysol) Berg +:Latest update: 2016-11-09 + +Converting textures made for the Morrowind Code Patch (MCP) fake bump mapping can be really easy or a real pain, depending on a few circumstances. In this tutorial, we will look at a very easy, although in some cases a bit time-consuming, example. + +Tutorial - MCP, Part 1 +---------------------- + +We will be converting a quite popular texture replacer of the Hlaalu architecture, namely Lougian's `Hlaalu Bump mapped`_. Since this is just a texture pack and not a model replacer, we can convert the mod in a few minutes by just renaming a few dozen files and by *not* extracting the included model (.nif) files when installing the mod. + +#. Download Lougian's `Hlaalu Bump mapped`_. +#. Install the mod by extracting the Textures folder to a data folder the way you usually install mods (**Pro tip**: Install using OpenMW's `Multi-data`_ folder function!). + - Again, yes, *only* the Textures folder. Do *not* extract the Meshes folder. They are only there to make the MCP hack work, which is not of any interest to us. +#. Go to your new texture folder. If you installed the mod like I recommended, you won't have any trouble finding the files. If you instead placed all your files in Morrowinds main Data Files folder (sigh), you need to check with the mod's .rar file to see what files you should look for. Because you'll be scrolling through a lot of files. +#. Find all the textures related to the texture pack in the Textures folder and take note of all the ones that ends with a "**_nm.dds**". +#. The "**_nm.dds**" files are normal map files. OpenMW's standard format is to have the normal maps with a "**_n.dds**" instead. Rename all the normal map textures to only have a "**_n.dds**" instead of the "**_nm.dds**". + - As a nice bonus to this tutorial, this pack actually included one specularity texture too. We should use it of course. It's the one called "**tx_glass_amber_02_reflection.dds**". For OpenMW to recognize this file and use it as a specular map, you need to change the "**_reflection.dds**" part to "**_spec.dds**". +#. That should be it. Really simple, but I do know that it takes a few minutes to rename all those files. + +Now – if the mod you want to change includes custom made models it gets a bit more complicated I'm afraid. But that is for the next tutorial. + +4. Converting Apel's Various Things – Sacks +=========================================== +Mod made for MCP's fake bump function, with custom models +--------------------------------------------------------- + +:Author: Joakim (Lysol) Berg +:Latest update: 2016-11-09 + +In part one of this tutorial, we converted a mod that only included modified Morrowind model (.nif) files so that the normal maps could be loaded in Morrowind with MCP. We ignored those model files since they are not needed with OpenMW. In this tutorial however, we will convert a mod that includes new, custom made models. In other words, we cannot just ignore those files this time. + +Before we begin, you need to know that we will be needing a Windows OS for this, unless you can get the application we will be using to work in Wine or something similar. + +Tutorial - MCP, Part 2 +---------------------- + +The sacks included in Apel's `Various Things - Sacks`_ come in two versions – Without bump mapping, and with bump mapping. Since we want the glory of normal mapping in our OpenMW setup, we will go with the bump-mapped version. + +#. Start by downloading Apel's `Various Things - Sacks`_ from Nexus. +#. Once downloaded, install it the way you'd normally install your mods (**Pro tip**: Install using OpenMW's `Multi-data`_ folder function!). +#. Now, if you ran the mod right away, your sacks will be made out of lead_. This is because the normal map is loaded as an environment map which MCP fixes so that it looks less shiny. We don't use MCP, so therefore, it looks kind of like the shack was made out of lead. +#. We need to fix this by removing some tags in the model files. You need to download NifSkope_ for this, which, again, is a Windows-only application. +#. Go the place where you installed the mod and go to "Meshes/o/" to find the model files. + - If you installed the mod like I suggested, finding the files will be easy as a pie, but if you installed it by dropping everything into your main Morrowind Data Files folder, then you'll have to scroll a lot to find them. Check the mod's zip file for the file names of the models if this is the case. The same thing applies to when fixing the textures. +#. Open up each of the models in NifSkope and look for these certain blocks_: + - NiTextureEffect + - NiSourceTexture with the value that appears to be a normal map file, in this mod, they have the suffix "**_nm.dds**". +#. Remove all these tags by selecting them one at a time and press right click>Block>Remove. +#. Repeat this on all the affected models. +#. If you launch OpenMW now, you'll `no longer have shiny models`_. But one thing is missing. Can you see it? It's actually hard to spot on still pictures, but we have no normal maps here. +#. Now, go back to the root of where you installed the mod. Now go to "Textures/" and you'll find the texture files in question. +#. OpenMW detects normal maps if they have the same name as the base diffuse texture, but with a "**_n.dds**" suffix. In this mod, the normal maps has a suffix of "**_nm.dds**". Change all the files that ends with "**_nm.dds**" to instead end with "**_n.dds**". +#. Finally, `we are done`_! + +Since these models have one or two textures applied to them, the fix was not that time-consuming. It gets worse when you have to fix a model that uses loads of textures. The principle is the same, it just requires more manual work which is annoying and takes time. + +.. _`Netch Bump mapped`: http://www.nexusmods.com/morrowind/mods/42851/? +.. _`Hlaalu Bump mapped`: http://www.nexusmods.com/morrowind/mods/42396/? +.. _`texture modding`: https://wiki.openmw.org/index.php?title=TextureModding +.. _`MGE XE`: http://www.nexusmods.com/morrowind/mods/26348/? +.. _PeterBitt: http://www.nexusmods.com/morrowind/users/4381248/? +.. _`PBR Scamp Replacer`: http://www.nexusmods.com/morrowind/mods/44314/? +.. _settings.cfg: https://wiki.openmw.org/index.php?title=Settings +.. _`Multi-data`: https://wiki.openmw.org/index.php?title=Mod_installation +.. _`Various Things - Sacks`: http://www.nexusmods.com/morrowind/mods/42558/? +.. _Lead: http://imgur.com/bwpcYlc +.. _NifSkope: http://niftools.sourceforge.net/wiki/NifSkope +.. _Blocks: http://imgur.com/VmQC0WG +.. _`no longer have shiny models`: http://imgur.com/vu1k7n1 +.. _`we are done`: http://imgur.com/yyZxlTw From 1b8cfee5eba9808b82c238d5f691f86e2d5cf951 Mon Sep 17 00:00:00 2001 From: Joakim Berg Date: Wed, 9 Nov 2016 15:38:49 +0100 Subject: [PATCH 31/94] Update convert_bump_mapped_mods.rst --- .../openmw-mods/convert_bump_mapped_mods.rst | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/docs/source/openmw-mods/convert_bump_mapped_mods.rst b/docs/source/openmw-mods/convert_bump_mapped_mods.rst index aef15835e..3566ebf46 100644 --- a/docs/source/openmw-mods/convert_bump_mapped_mods.rst +++ b/docs/source/openmw-mods/convert_bump_mapped_mods.rst @@ -35,13 +35,13 @@ So let's get on with it. Normal Mapping in OpenMW ------------------------ -Normal mapping in OpenMW works in a very simple way: The engine just looks for a texture with a "_n.dds" suffix, and you're done. +Normal mapping in OpenMW works in a very simple way: The engine just looks for a texture with a *_n.dds* suffix, and you're done. So to expand on this a bit, let's take a look at how a model seeks for textures. -Let us assume we have the model "example.nif". In this model file, there should be a tag (NiSourceTexture) that states what texture it should use and where to find it. Typically, it will point to something like "exampletexture_01.dds". This texture is supposed to be located directly in the Textures folder since it does not state anything else. If the model is a custom made one, modders tend to group their textures in separate folders, just to easily keep track of them. It might be something like "Textures\moddername\exampletexture_02.dds". +Let us assume we have the model *example.nif*. In this model file, there should be a tag (NiSourceTexture) that states what texture it should use and where to find it. Typically, it will point to something like *exampletexture_01.dds*. This texture is supposed to be located directly in the Textures folder since it does not state anything else. If the model is a custom made one, modders tend to group their textures in separate folders, just to easily keep track of them. It might be something like *Textures\moddername\exampletexture_02.dds*. -When OpenMW finally adds normal mapping, it simply takes the NiSourceTexture file path, e.g., "exampletexture_01.dds", and looks for a "exampletexture_01_n.dds". If it can't find this file, no normal mapping is added. If it *does* find this file, the model will use this texture as a normal map. Simple. +When OpenMW finally adds normal mapping, it simply takes the NiSourceTexture file path, e.g., *exampletexture_01.dds*, and looks for a *exampletexture_01_n.dds*. If it can't find this file, no normal mapping is added. If it *does* find this file, the model will use this texture as a normal map. Simple. Activating normal mapping shaders in OpenMW ******************************************* @@ -106,7 +106,7 @@ Now, on to the tutorials. Mod made for the MGE XE PBR prototype ------------------------------------- -:Author: Joakim (Lysol) Berg +:Author(s): Joakim (Lysol) Berg :Latest update: 2016-11-09 So, let's say you've found out that PeterBitt_ makes awesome models and textures featuring physically based rendering (PBR) and normal maps. Let's say that you tried to run his `PBR Scamp Replacer`_ in OpenMW and that you were greatly disappointed when the normal map didn't seem to work. Lastly, let's say you came here, looking for some answers. Am I right? Great. Because you've come to the right place! @@ -124,10 +124,10 @@ So, follow these steps: #. Go to the *files* tab and download the main file and the "PBR materials" file. #. Extract the main file as if you'd install a normal mod (**Pro tip**: Install using OpenMW's `Multi-data`_ folder function!) #. Now, open the PBR materials file: - - Go to "Materials/PB/". - - Select the "**tx_Scamp_normals.dds**" file, which is, obviously, the normal map texture. - - Extract this file to the place you extracted the main file to, but in the subdirectory "Textures/PB/". -#. Rename your newly extracted file ("**tx_Scamp_normals.dds**") to "**tx_Scamp_n.dds**" (which is exactly the same name as the diffuse texture file, except for the added "**_n**" suffix before the filename extention). + - Go to ``Materials/PB/``. + - Select the ``tx_Scamp_normals.dds`` file, which is, obviously, the normal map texture. + - Extract this file to the place you extracted the main file to, but in the subdirectory ``Textures/PB/``. +#. Rename your newly extracted file (``tx_Scamp_normals.dds``) to ``tx_Scamp_n.dds`` (which is exactly the same name as the diffuse texture file, except for the added *_n* suffix before the filename extention). #. You're actually done! So as you might notice, converting these mods is very simple and takes just a couple of minutes. It's more or less just a matter of renaming and moving a few files. @@ -149,15 +149,15 @@ Converting textures made for the Morrowind Code Patch (MCP) fake bump mapping ca Tutorial - MCP, Part 1 ---------------------- -We will be converting a quite popular texture replacer of the Hlaalu architecture, namely Lougian's `Hlaalu Bump mapped`_. Since this is just a texture pack and not a model replacer, we can convert the mod in a few minutes by just renaming a few dozen files and by *not* extracting the included model (.nif) files when installing the mod. +We will be converting a quite popular texture replacer of the Hlaalu architecture, namely Lougian's `Hlaalu Bump mapped`_. Since this is just a texture pack and not a model replacer, we can convert the mod in a few minutes by just renaming a few dozen files and by *not* extracting the included model (``.nif``) files when installing the mod. #. Download Lougian's `Hlaalu Bump mapped`_. -#. Install the mod by extracting the Textures folder to a data folder the way you usually install mods (**Pro tip**: Install using OpenMW's `Multi-data`_ folder function!). - - Again, yes, *only* the Textures folder. Do *not* extract the Meshes folder. They are only there to make the MCP hack work, which is not of any interest to us. +#. Install the mod by extracting the ``Textures`` folder to a data folder the way you usually install mods (**Pro tip**: Install using OpenMW's `Multi-data`_ folder function!). + - Again, yes, *only* the ``Textures`` folder. Do *not* extract the Meshes folder. They are only there to make the MCP hack work, which is not of any interest to us. #. Go to your new texture folder. If you installed the mod like I recommended, you won't have any trouble finding the files. If you instead placed all your files in Morrowinds main Data Files folder (sigh), you need to check with the mod's .rar file to see what files you should look for. Because you'll be scrolling through a lot of files. -#. Find all the textures related to the texture pack in the Textures folder and take note of all the ones that ends with a "**_nm.dds**". -#. The "**_nm.dds**" files are normal map files. OpenMW's standard format is to have the normal maps with a "**_n.dds**" instead. Rename all the normal map textures to only have a "**_n.dds**" instead of the "**_nm.dds**". - - As a nice bonus to this tutorial, this pack actually included one specularity texture too. We should use it of course. It's the one called "**tx_glass_amber_02_reflection.dds**". For OpenMW to recognize this file and use it as a specular map, you need to change the "**_reflection.dds**" part to "**_spec.dds**". +#. Find all the textures related to the texture pack in the Textures folder and take note of all the ones that ends with a *_nm.dds*. +#. The *_nm.dds* files are normal map files. OpenMW's standard format is to have the normal maps with a *_n.dds* instead. Rename all the normal map textures to only have a *_n.dds* instead of the *_nm.dds*. + - As a nice bonus to this tutorial, this pack actually included one specularity texture too. We should use it of course. It's the one called "``tx_glass_amber_02_reflection.dds``". For OpenMW to recognize this file and use it as a specular map, you need to change the *_reflection.dds* part to *_spec.dds*, resulting in the name ``tx_glass_amber_01_spec.dds``. #. That should be it. Really simple, but I do know that it takes a few minutes to rename all those files. Now – if the mod you want to change includes custom made models it gets a bit more complicated I'm afraid. But that is for the next tutorial. @@ -170,7 +170,7 @@ Mod made for MCP's fake bump function, with custom models :Author: Joakim (Lysol) Berg :Latest update: 2016-11-09 -In part one of this tutorial, we converted a mod that only included modified Morrowind model (.nif) files so that the normal maps could be loaded in Morrowind with MCP. We ignored those model files since they are not needed with OpenMW. In this tutorial however, we will convert a mod that includes new, custom made models. In other words, we cannot just ignore those files this time. +In part one of this tutorial, we converted a mod that only included modified Morrowind model (``.nif``) files so that the normal maps could be loaded in Morrowind with MCP. We ignored those model files since they are not needed with OpenMW. In this tutorial however, we will convert a mod that includes new, custom made models. In other words, we cannot just ignore those files this time. Before we begin, you need to know that we will be needing a Windows OS for this, unless you can get the application we will be using to work in Wine or something similar. @@ -183,16 +183,16 @@ The sacks included in Apel's `Various Things - Sacks`_ come in two versions – #. Once downloaded, install it the way you'd normally install your mods (**Pro tip**: Install using OpenMW's `Multi-data`_ folder function!). #. Now, if you ran the mod right away, your sacks will be made out of lead_. This is because the normal map is loaded as an environment map which MCP fixes so that it looks less shiny. We don't use MCP, so therefore, it looks kind of like the shack was made out of lead. #. We need to fix this by removing some tags in the model files. You need to download NifSkope_ for this, which, again, is a Windows-only application. -#. Go the place where you installed the mod and go to "Meshes/o/" to find the model files. +#. Go the place where you installed the mod and go to ``Meshes/o/`` to find the model files. - If you installed the mod like I suggested, finding the files will be easy as a pie, but if you installed it by dropping everything into your main Morrowind Data Files folder, then you'll have to scroll a lot to find them. Check the mod's zip file for the file names of the models if this is the case. The same thing applies to when fixing the textures. #. Open up each of the models in NifSkope and look for these certain blocks_: - NiTextureEffect - - NiSourceTexture with the value that appears to be a normal map file, in this mod, they have the suffix "**_nm.dds**". + - NiSourceTexture with the value that appears to be a normal map file, in this mod, they have the suffix *_nm.dds*. #. Remove all these tags by selecting them one at a time and press right click>Block>Remove. #. Repeat this on all the affected models. #. If you launch OpenMW now, you'll `no longer have shiny models`_. But one thing is missing. Can you see it? It's actually hard to spot on still pictures, but we have no normal maps here. -#. Now, go back to the root of where you installed the mod. Now go to "Textures/" and you'll find the texture files in question. -#. OpenMW detects normal maps if they have the same name as the base diffuse texture, but with a "**_n.dds**" suffix. In this mod, the normal maps has a suffix of "**_nm.dds**". Change all the files that ends with "**_nm.dds**" to instead end with "**_n.dds**". +#. Now, go back to the root of where you installed the mod. Now go to ``Textures/`` and you'll find the texture files in question. +#. OpenMW detects normal maps if they have the same name as the base diffuse texture, but with a *_n.dds* suffix. In this mod, the normal maps has a suffix of *_nm.dds*. Change all the files that ends with *_nm.dds* to instead end with *_n.dds*. #. Finally, `we are done`_! Since these models have one or two textures applied to them, the fix was not that time-consuming. It gets worse when you have to fix a model that uses loads of textures. The principle is the same, it just requires more manual work which is annoying and takes time. From 3ee28bfeac6a8a8fa86fb6b278501f1a87633623 Mon Sep 17 00:00:00 2001 From: Joakim Berg Date: Wed, 9 Nov 2016 15:47:50 +0100 Subject: [PATCH 32/94] Update convert_bump_mapped_mods.rst This should be correct according to the style-guide. Well, except for the British/American spelling. I need a Brit and/or an American to confirm that. --- .../openmw-mods/convert_bump_mapped_mods.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/source/openmw-mods/convert_bump_mapped_mods.rst b/docs/source/openmw-mods/convert_bump_mapped_mods.rst index 3566ebf46..600aca475 100644 --- a/docs/source/openmw-mods/convert_bump_mapped_mods.rst +++ b/docs/source/openmw-mods/convert_bump_mapped_mods.rst @@ -19,8 +19,8 @@ Index: 1. General introduction to normal map conversion ================================================ -:Author(s): Joakim (Lysol) Berg -:Latest update: 2016-11-09 +:Authors: Joakim (Lysol) Berg +:Updated: 2016-11-09 Hi. @@ -106,8 +106,8 @@ Now, on to the tutorials. Mod made for the MGE XE PBR prototype ------------------------------------- -:Author(s): Joakim (Lysol) Berg -:Latest update: 2016-11-09 +:Authors: Joakim (Lysol) Berg +:Updated: 2016-11-09 So, let's say you've found out that PeterBitt_ makes awesome models and textures featuring physically based rendering (PBR) and normal maps. Let's say that you tried to run his `PBR Scamp Replacer`_ in OpenMW and that you were greatly disappointed when the normal map didn't seem to work. Lastly, let's say you came here, looking for some answers. Am I right? Great. Because you've come to the right place! @@ -141,8 +141,8 @@ And let's hope that some one implements PBR shaders to OpenMW too, so that we ca Mod made for MCP's fake bump function, without custom models ------------------------------------------------------------ -:Author: Joakim (Lysol) Berg -:Latest update: 2016-11-09 +:Authors: Joakim (Lysol) Berg +:Updated: 2016-11-09 Converting textures made for the Morrowind Code Patch (MCP) fake bump mapping can be really easy or a real pain, depending on a few circumstances. In this tutorial, we will look at a very easy, although in some cases a bit time-consuming, example. @@ -167,8 +167,8 @@ Now – if the mod you want to change includes custom made models it gets a bit Mod made for MCP's fake bump function, with custom models --------------------------------------------------------- -:Author: Joakim (Lysol) Berg -:Latest update: 2016-11-09 +:Authors: Joakim (Lysol) Berg +:Updated: 2016-11-09 In part one of this tutorial, we converted a mod that only included modified Morrowind model (``.nif``) files so that the normal maps could be loaded in Morrowind with MCP. We ignored those model files since they are not needed with OpenMW. In this tutorial however, we will convert a mod that includes new, custom made models. In other words, we cannot just ignore those files this time. From d7bf2b9e85889dde6908d6959d21531f2a74a1c9 Mon Sep 17 00:00:00 2001 From: Joakim Berg Date: Wed, 9 Nov 2016 15:56:07 +0100 Subject: [PATCH 33/94] Update index.rst Added convert_bump_mapped_mods to the table of contents. --- docs/source/openmw-mods/index.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/source/openmw-mods/index.rst b/docs/source/openmw-mods/index.rst index 49113426c..34d04abb0 100644 --- a/docs/source/openmw-mods/index.rst +++ b/docs/source/openmw-mods/index.rst @@ -13,4 +13,5 @@ The following document is the complete reference guide to modifying, or modding, foreword differences - mod-install \ No newline at end of file + mod-install + convert_bump_mapped_mods From 99bc4f733fac5cda55c1832e17e12627f9a88cea Mon Sep 17 00:00:00 2001 From: Assumeru Date: Wed, 9 Nov 2016 18:03:10 +0100 Subject: [PATCH 34/94] Trace up to waterlevel + halfextent --- apps/openmw/mwphysics/physicssystem.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index cd4484aa1..d854e0aca 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -1329,13 +1329,13 @@ namespace MWPhysics else if (physicActor->getCollisionMode()) { const osg::Vec3f actorPosition = physicActor->getPosition(); - const osg::Vec3f destinationPosition(actorPosition.x(), actorPosition.y(), waterlevel); + const osg::Vec3f destinationPosition(actorPosition.x(), actorPosition.y(), waterlevel + physicActor->getHalfExtents().z()); ActorTracer tracer; tracer.doTrace(physicActor->getCollisionObject(), actorPosition, destinationPosition, mCollisionWorld); if (tracer.mFraction >= 1.0f) { waterCollision = true; - physicActor->setPosition(destinationPosition); + physicActor->setPosition(osg::Vec3f(actorPosition.x(), actorPosition.y(), waterlevel)); } else { From e957e2b3cce919285b85995d6618b4a7ea29191e Mon Sep 17 00:00:00 2001 From: Joakim Berg Date: Wed, 9 Nov 2016 22:47:39 +0100 Subject: [PATCH 35/94] Update convert_bump_mapped_mods.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ok, so another update then. Sorry for another one so soon after the first PR, but I think (or hope) that this will be the last edit for some time. It looks good to me now. ´ Mainly, I changed changed some "=" headers to "-", and while at it, I fixed some typing errors and just edited some text to read better. --- .../openmw-mods/convert_bump_mapped_mods.rst | 54 ++++++++----------- 1 file changed, 22 insertions(+), 32 deletions(-) diff --git a/docs/source/openmw-mods/convert_bump_mapped_mods.rst b/docs/source/openmw-mods/convert_bump_mapped_mods.rst index 600aca475..75115ae1c 100644 --- a/docs/source/openmw-mods/convert_bump_mapped_mods.rst +++ b/docs/source/openmw-mods/convert_bump_mapped_mods.rst @@ -1,29 +1,27 @@ +==================================== Normal maps from Morrowind to OpenMW ==================================== - Index: ------ -- `1. General introduction to normal map conversion`_ +- `General introduction to normal map conversion`_ - `Normal Mapping in OpenMW`_ - `Activating normal mapping shaders in OpenMW`_ - `Normal mapping in Morrowind with Morrowind Code Patch`_ - `Normal mapping in Morrowind with MGE XE (PBR version)`_ -- `2. Converting PeterBitt's Scamp Replacer`_ (Mod made for the MGE XE PBR prototype) +- `Converting PeterBitt's Scamp Replacer`_ (Mod made for the MGE XE PBR prototype) - `Tutorial - MGE`_ -- `3. Converting Lougian's Hlaalu Bump mapped`_ (MCP's fake bump map function, part 1: *without* custom models) +- `Converting Lougian's Hlaalu Bump mapped`_ (MCP's fake bump map function, part 1: *without* custom models) - `Tutorial - MCP, Part 1`_ -- `4. Converting Apel's Various Things – Sacks`_ (MCP's fake bump map function, part 2: *with* custom models) +- `Converting Apel's Various Things – Sacks`_ (MCP's fake bump map function, part 2: *with* custom models) - `Tutorial - MCP, Part 2`_ -1. General introduction to normal map conversion -================================================ +General introduction to normal map conversion +------------------------------------------------ :Authors: Joakim (Lysol) Berg :Updated: 2016-11-09 -Hi. - This page has general information and tutorials on how normal mapping works in OpenMW and how you can make mods using the old fake normal mapping technique (such as `Netch Bump mapped`_ and `Hlaalu Bump mapped`_ work in OpenMW. *Note:* The conversion made in part four of this tutorial require the use of the application NifSkope, which is a Windows-only application. Read part one of this tutorial to learn more. @@ -33,7 +31,7 @@ This page has general information and tutorials on how normal mapping works in O So let's get on with it. Normal Mapping in OpenMW ------------------------- +************************ Normal mapping in OpenMW works in a very simple way: The engine just looks for a texture with a *_n.dds* suffix, and you're done. @@ -53,30 +51,25 @@ Before normal (and specular and parallax) maps will show up in OpenMW, you'll ne [Shaders] auto use object normal maps = true auto use terrain normal maps = true - [/code] And while we're at it, why not activate specular maps too just for the sake of it? :: - [code] auto use object specular maps = true auto use terrain specular maps = true - [/code] Lastly, if you want really nice lights in OpenMW, add these rows: :: - [code] force shaders = true clamp lighting = false - [/code] -See OpenMW's wiki page about `texture modding`_ to read more about this. +See OpenMW's wiki page about `texture modding`_ to read further about this. Normal mapping in Morrowind with Morrowind Code Patch ------------------------------------------------------ +***************************************************** **Conversion difficulty:** *Varies. Sometimes quick and easy, sometimes time-consuming and hard.* @@ -90,7 +83,7 @@ The biggest problem with this is not that it doesn't look as good as it could These are basically the reasons why OpenMW does not support fake bump maps like MCP does. It is just a really bad way to enhance your models, all the more when you have the possibility to do it in a better way. Normal mapping in Morrowind with MGE XE (PBR version) ------------------------------------------------------ +***************************************************** **Conversion difficulty:** *Easy* @@ -101,10 +94,9 @@ I haven't researched that much on the MGE variant yet but it does support real i Now, on to the tutorials. -2. Converting PeterBitt's Scamp Replacer -======================================== -Mod made for the MGE XE PBR prototype +Converting PeterBitt's Scamp Replacer ------------------------------------- +**Mod made for the MGE XE PBR prototype** :Authors: Joakim (Lysol) Berg :Updated: 2016-11-09 @@ -114,7 +106,7 @@ So, let's say you've found out that PeterBitt_ makes awesome models and textures *A quick note before we begin*: Please note that you can only use the normal map texture and not the rest of the materials, since PBR isn't implemented in OpenMW yet. Sometimes PBR textures can look dull without all of the texture files, so have that in mind. Tutorial - MGE --------------- +************** In this tutorial, I will use PeterBitt's `PBR Scamp Replacer`_ as an example, but any mod featuring PBR that requires the PBR version of MGE will do, provided it also includes a normal map (which it probably does). @@ -136,10 +128,9 @@ I totally recommend you to also try this on PeterBitt's Nix Hound replacer and F And let's hope that some one implements PBR shaders to OpenMW too, so that we can use all the material files of these mods in the future. -3. Converting Lougian's Hlaalu Bump mapped -========================================== -Mod made for MCP's fake bump function, without custom models ------------------------------------------------------------- +Converting Lougian's Hlaalu Bump mapped +--------------------------------------- +**Mod made for MCP's fake bump function, without custom models** :Authors: Joakim (Lysol) Berg :Updated: 2016-11-09 @@ -147,7 +138,7 @@ Mod made for MCP's fake bump function, without custom models Converting textures made for the Morrowind Code Patch (MCP) fake bump mapping can be really easy or a real pain, depending on a few circumstances. In this tutorial, we will look at a very easy, although in some cases a bit time-consuming, example. Tutorial - MCP, Part 1 ----------------------- +********************** We will be converting a quite popular texture replacer of the Hlaalu architecture, namely Lougian's `Hlaalu Bump mapped`_. Since this is just a texture pack and not a model replacer, we can convert the mod in a few minutes by just renaming a few dozen files and by *not* extracting the included model (``.nif``) files when installing the mod. @@ -162,10 +153,9 @@ We will be converting a quite popular texture replacer of the Hlaalu architectur Now – if the mod you want to change includes custom made models it gets a bit more complicated I'm afraid. But that is for the next tutorial. -4. Converting Apel's Various Things – Sacks -=========================================== -Mod made for MCP's fake bump function, with custom models ---------------------------------------------------------- +Converting Apel's Various Things – Sacks +---------------------------------------- +**Mod made for MCP's fake bump function, with custom models** :Authors: Joakim (Lysol) Berg :Updated: 2016-11-09 @@ -175,7 +165,7 @@ In part one of this tutorial, we converted a mod that only included modified Mor Before we begin, you need to know that we will be needing a Windows OS for this, unless you can get the application we will be using to work in Wine or something similar. Tutorial - MCP, Part 2 ----------------------- +********************** The sacks included in Apel's `Various Things - Sacks`_ come in two versions – Without bump mapping, and with bump mapping. Since we want the glory of normal mapping in our OpenMW setup, we will go with the bump-mapped version. From 303fe013ea1293f72ccfe0fddc6d4edaadbc2d9f Mon Sep 17 00:00:00 2001 From: Joakim Berg Date: Wed, 9 Nov 2016 22:51:27 +0100 Subject: [PATCH 36/94] Update convert_bump_mapped_mods.rst --- docs/source/openmw-mods/convert_bump_mapped_mods.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/openmw-mods/convert_bump_mapped_mods.rst b/docs/source/openmw-mods/convert_bump_mapped_mods.rst index 75115ae1c..520b4403e 100644 --- a/docs/source/openmw-mods/convert_bump_mapped_mods.rst +++ b/docs/source/openmw-mods/convert_bump_mapped_mods.rst @@ -6,7 +6,7 @@ Index: - `General introduction to normal map conversion`_ - `Normal Mapping in OpenMW`_ - - `Activating normal mapping shaders in OpenMW`_ + - `Activating normal mapping shaders in OpenMW`_ - `Normal mapping in Morrowind with Morrowind Code Patch`_ - `Normal mapping in Morrowind with MGE XE (PBR version)`_ - `Converting PeterBitt's Scamp Replacer`_ (Mod made for the MGE XE PBR prototype) From 02d859e2983a61fd9602a223ade21bc460faf3ac Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Thu, 10 Nov 2016 10:50:43 +0100 Subject: [PATCH 37/94] minor fix to remove Index:, it isn't necessary --- docs/source/openmw-mods/convert_bump_mapped_mods.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/source/openmw-mods/convert_bump_mapped_mods.rst b/docs/source/openmw-mods/convert_bump_mapped_mods.rst index 520b4403e..7d695d1d3 100644 --- a/docs/source/openmw-mods/convert_bump_mapped_mods.rst +++ b/docs/source/openmw-mods/convert_bump_mapped_mods.rst @@ -1,8 +1,6 @@ ==================================== Normal maps from Morrowind to OpenMW ==================================== -Index: ------- - `General introduction to normal map conversion`_ - `Normal Mapping in OpenMW`_ From 05cc258ed3fcd598ee90c608239b8f753262317d Mon Sep 17 00:00:00 2001 From: Assumeru Date: Thu, 10 Nov 2016 15:38:14 +0100 Subject: [PATCH 38/94] Start trace from collision object origin --- apps/openmw/mwphysics/physicssystem.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index d854e0aca..21867591c 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -1328,10 +1328,12 @@ namespace MWPhysics waterCollision = true; else if (physicActor->getCollisionMode()) { + const float halfZ = physicActor->getHalfExtents().z(); const osg::Vec3f actorPosition = physicActor->getPosition(); - const osg::Vec3f destinationPosition(actorPosition.x(), actorPosition.y(), waterlevel + physicActor->getHalfExtents().z()); + const osg::Vec3f startingPosition(actorPosition.x(), actorPosition.y(), actorPosition.z() + halfZ); + const osg::Vec3f destinationPosition(actorPosition.x(), actorPosition.y(), waterlevel + halfZ); ActorTracer tracer; - tracer.doTrace(physicActor->getCollisionObject(), actorPosition, destinationPosition, mCollisionWorld); + tracer.doTrace(physicActor->getCollisionObject(), startingPosition, destinationPosition, mCollisionWorld); if (tracer.mFraction >= 1.0f) { waterCollision = true; From 2feddcbcc5b5296a5f32cff6639b71d9b206729c Mon Sep 17 00:00:00 2001 From: Joakim Berg Date: Fri, 11 Nov 2016 22:52:14 +0100 Subject: [PATCH 39/94] Updated the bump mapping tutorial Fixed some linking errors, edited a few backslashes to become forwardslashes (the backslashes couldn't even be viewed), made all the paths a bit more correctly formatted by writing them with a ./ first (please tell me if that is a bad idea) and added a link to the On The Rocks! mod, since it is a very common mod with this problem (it is featured in MGSO and Morrowind Rebirth). --- .../openmw-mods/convert_bump_mapped_mods.rst | 39 ++++++++++--------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/docs/source/openmw-mods/convert_bump_mapped_mods.rst b/docs/source/openmw-mods/convert_bump_mapped_mods.rst index 7d695d1d3..d9d689148 100644 --- a/docs/source/openmw-mods/convert_bump_mapped_mods.rst +++ b/docs/source/openmw-mods/convert_bump_mapped_mods.rst @@ -6,23 +6,23 @@ Normal maps from Morrowind to OpenMW - `Normal Mapping in OpenMW`_ - `Activating normal mapping shaders in OpenMW`_ - `Normal mapping in Morrowind with Morrowind Code Patch`_ - - `Normal mapping in Morrowind with MGE XE (PBR version)`_ + - `Normal mapping in Morrowind with MGE XE`_ - `Converting PeterBitt's Scamp Replacer`_ (Mod made for the MGE XE PBR prototype) - `Tutorial - MGE`_ - `Converting Lougian's Hlaalu Bump mapped`_ (MCP's fake bump map function, part 1: *without* custom models) - `Tutorial - MCP, Part 1`_ -- `Converting Apel's Various Things – Sacks`_ (MCP's fake bump map function, part 2: *with* custom models) +- `Converting Apel's Various Things - Sacks`_ (MCP's fake bump map function, part 2: *with* custom models) - `Tutorial - MCP, Part 2`_ General introduction to normal map conversion ------------------------------------------------ :Authors: Joakim (Lysol) Berg -:Updated: 2016-11-09 +:Updated: 2016-11-11 -This page has general information and tutorials on how normal mapping works in OpenMW and how you can make mods using the old fake normal mapping technique (such as `Netch Bump mapped`_ and `Hlaalu Bump mapped`_ work in OpenMW. +This page has general information and tutorials on how normal mapping works in OpenMW and how you can make mods using the old fake normal mapping technique (such as `Netch Bump mapped`_ and `Hlaalu Bump mapped`_, and maybe the most (in)famous one to give shiny rocks in OpenMW, the mod `On the Rocks`_!, featured in MGSO and Morrowind Rebirth) work in OpenMW. -*Note:* The conversion made in part four of this tutorial require the use of the application NifSkope, which is a Windows-only application. Read part one of this tutorial to learn more. +*Note:* The conversion made in the `Converting Apel's Various Things - Sacks`_-part of this tutorial require the use of the application NifSkope, which is a Windows-only application. Please inform us if you get that application to work on other OS:es via Wine or similar. *Another note:* I will use the terms bump mapping and normal mapping simultaneously. Normal mapping is one form of bump mapping. In other words, normal mapping is bump mapping, but bump mapping isn't necessarily normal mapping. There are several techniques for bump mapping, and normal mapping is the most common one today. @@ -35,7 +35,7 @@ Normal mapping in OpenMW works in a very simple way: The engine just looks for a So to expand on this a bit, let's take a look at how a model seeks for textures. -Let us assume we have the model *example.nif*. In this model file, there should be a tag (NiSourceTexture) that states what texture it should use and where to find it. Typically, it will point to something like *exampletexture_01.dds*. This texture is supposed to be located directly in the Textures folder since it does not state anything else. If the model is a custom made one, modders tend to group their textures in separate folders, just to easily keep track of them. It might be something like *Textures\moddername\exampletexture_02.dds*. +Let us assume we have the model *example.nif*. In this model file, there should be a tag (NiSourceTexture) that states what texture it should use and where to find it. Typically, it will point to something like *exampletexture_01.dds*. This texture is supposed to be located directly in the Textures folder since it does not state anything else. If the model is a custom made one, modders tend to group their textures in separate folders, just to easily keep track of them. It might be something like *./Textures/moddername/exampletexture_02.dds*. When OpenMW finally adds normal mapping, it simply takes the NiSourceTexture file path, e.g., *exampletexture_01.dds*, and looks for a *exampletexture_01_n.dds*. If it can't find this file, no normal mapping is added. If it *does* find this file, the model will use this texture as a normal map. Simple. @@ -80,8 +80,8 @@ The biggest problem with this is not that it doesn't look as good as it could These are basically the reasons why OpenMW does not support fake bump maps like MCP does. It is just a really bad way to enhance your models, all the more when you have the possibility to do it in a better way. -Normal mapping in Morrowind with MGE XE (PBR version) -***************************************************** +Normal mapping in Morrowind with MGE XE +*************************************** **Conversion difficulty:** *Easy* @@ -97,7 +97,7 @@ Converting PeterBitt's Scamp Replacer **Mod made for the MGE XE PBR prototype** :Authors: Joakim (Lysol) Berg -:Updated: 2016-11-09 +:Updated: 2016-11-11 So, let's say you've found out that PeterBitt_ makes awesome models and textures featuring physically based rendering (PBR) and normal maps. Let's say that you tried to run his `PBR Scamp Replacer`_ in OpenMW and that you were greatly disappointed when the normal map didn't seem to work. Lastly, let's say you came here, looking for some answers. Am I right? Great. Because you've come to the right place! @@ -112,11 +112,11 @@ So, follow these steps: #. Go to the Nexus page for PeterBitt's `PBR Scamp Replacer`_ #. Go to the *files* tab and download the main file and the "PBR materials" file. -#. Extract the main file as if you'd install a normal mod (**Pro tip**: Install using OpenMW's `Multi-data`_ folder function!) +#. Extract the main file as if you'd install a normal mod (**Pro tip**: Install using OpenMW's `Multiple data folders`_ function!) #. Now, open the PBR materials file: - - Go to ``Materials/PB/``. + - Go to ``./Materials/PB/``. - Select the ``tx_Scamp_normals.dds`` file, which is, obviously, the normal map texture. - - Extract this file to the place you extracted the main file to, but in the subdirectory ``Textures/PB/``. + - Extract this file to the place you extracted the main file to, but in the subdirectory ``./Textures/PB/``. #. Rename your newly extracted file (``tx_Scamp_normals.dds``) to ``tx_Scamp_n.dds`` (which is exactly the same name as the diffuse texture file, except for the added *_n* suffix before the filename extention). #. You're actually done! @@ -131,7 +131,7 @@ Converting Lougian's Hlaalu Bump mapped **Mod made for MCP's fake bump function, without custom models** :Authors: Joakim (Lysol) Berg -:Updated: 2016-11-09 +:Updated: 2016-11-11 Converting textures made for the Morrowind Code Patch (MCP) fake bump mapping can be really easy or a real pain, depending on a few circumstances. In this tutorial, we will look at a very easy, although in some cases a bit time-consuming, example. @@ -141,8 +141,8 @@ Tutorial - MCP, Part 1 We will be converting a quite popular texture replacer of the Hlaalu architecture, namely Lougian's `Hlaalu Bump mapped`_. Since this is just a texture pack and not a model replacer, we can convert the mod in a few minutes by just renaming a few dozen files and by *not* extracting the included model (``.nif``) files when installing the mod. #. Download Lougian's `Hlaalu Bump mapped`_. -#. Install the mod by extracting the ``Textures`` folder to a data folder the way you usually install mods (**Pro tip**: Install using OpenMW's `Multi-data`_ folder function!). - - Again, yes, *only* the ``Textures`` folder. Do *not* extract the Meshes folder. They are only there to make the MCP hack work, which is not of any interest to us. +#. Install the mod by extracting the ``./Textures`` folder to a data folder the way you usually install mods (**Pro tip**: Install using OpenMW's `Multiple data folders`_ function!). + - Again, yes, *only* the ``./Textures`` folder. Do *not* extract the Meshes folder. They are only there to make the MCP hack work, which is not of any interest to us. #. Go to your new texture folder. If you installed the mod like I recommended, you won't have any trouble finding the files. If you instead placed all your files in Morrowinds main Data Files folder (sigh), you need to check with the mod's .rar file to see what files you should look for. Because you'll be scrolling through a lot of files. #. Find all the textures related to the texture pack in the Textures folder and take note of all the ones that ends with a *_nm.dds*. #. The *_nm.dds* files are normal map files. OpenMW's standard format is to have the normal maps with a *_n.dds* instead. Rename all the normal map textures to only have a *_n.dds* instead of the *_nm.dds*. @@ -168,10 +168,10 @@ Tutorial - MCP, Part 2 The sacks included in Apel's `Various Things - Sacks`_ come in two versions – Without bump mapping, and with bump mapping. Since we want the glory of normal mapping in our OpenMW setup, we will go with the bump-mapped version. #. Start by downloading Apel's `Various Things - Sacks`_ from Nexus. -#. Once downloaded, install it the way you'd normally install your mods (**Pro tip**: Install using OpenMW's `Multi-data`_ folder function!). +#. Once downloaded, install it the way you'd normally install your mods (**Pro tip**: Install using OpenMW's `Multiple data folders`_ function!). #. Now, if you ran the mod right away, your sacks will be made out of lead_. This is because the normal map is loaded as an environment map which MCP fixes so that it looks less shiny. We don't use MCP, so therefore, it looks kind of like the shack was made out of lead. #. We need to fix this by removing some tags in the model files. You need to download NifSkope_ for this, which, again, is a Windows-only application. -#. Go the place where you installed the mod and go to ``Meshes/o/`` to find the model files. +#. Go the place where you installed the mod and go to ``./Meshes/o/`` to find the model files. - If you installed the mod like I suggested, finding the files will be easy as a pie, but if you installed it by dropping everything into your main Morrowind Data Files folder, then you'll have to scroll a lot to find them. Check the mod's zip file for the file names of the models if this is the case. The same thing applies to when fixing the textures. #. Open up each of the models in NifSkope and look for these certain blocks_: - NiTextureEffect @@ -179,7 +179,7 @@ The sacks included in Apel's `Various Things - Sacks`_ come in two versions – #. Remove all these tags by selecting them one at a time and press right click>Block>Remove. #. Repeat this on all the affected models. #. If you launch OpenMW now, you'll `no longer have shiny models`_. But one thing is missing. Can you see it? It's actually hard to spot on still pictures, but we have no normal maps here. -#. Now, go back to the root of where you installed the mod. Now go to ``Textures/`` and you'll find the texture files in question. +#. Now, go back to the root of where you installed the mod. Now go to ``./Textures/`` and you'll find the texture files in question. #. OpenMW detects normal maps if they have the same name as the base diffuse texture, but with a *_n.dds* suffix. In this mod, the normal maps has a suffix of *_nm.dds*. Change all the files that ends with *_nm.dds* to instead end with *_n.dds*. #. Finally, `we are done`_! @@ -187,12 +187,13 @@ Since these models have one or two textures applied to them, the fix was not tha .. _`Netch Bump mapped`: http://www.nexusmods.com/morrowind/mods/42851/? .. _`Hlaalu Bump mapped`: http://www.nexusmods.com/morrowind/mods/42396/? +.. _`On the Rocks`: http://mw.modhistory.com/download-44-14107 .. _`texture modding`: https://wiki.openmw.org/index.php?title=TextureModding .. _`MGE XE`: http://www.nexusmods.com/morrowind/mods/26348/? .. _PeterBitt: http://www.nexusmods.com/morrowind/users/4381248/? .. _`PBR Scamp Replacer`: http://www.nexusmods.com/morrowind/mods/44314/? .. _settings.cfg: https://wiki.openmw.org/index.php?title=Settings -.. _`Multi-data`: https://wiki.openmw.org/index.php?title=Mod_installation +.. _`Multiple data folders`: https://wiki.openmw.org/index.php?title=Mod_installation .. _`Various Things - Sacks`: http://www.nexusmods.com/morrowind/mods/42558/? .. _Lead: http://imgur.com/bwpcYlc .. _NifSkope: http://niftools.sourceforge.net/wiki/NifSkope From 12dd60fe2076770c2391857e9b3fee2b961415f6 Mon Sep 17 00:00:00 2001 From: Joakim Berg Date: Fri, 11 Nov 2016 22:53:25 +0100 Subject: [PATCH 40/94] Update convert_bump_mapped_mods.rst Forgot to fix one link. --- docs/source/openmw-mods/convert_bump_mapped_mods.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/openmw-mods/convert_bump_mapped_mods.rst b/docs/source/openmw-mods/convert_bump_mapped_mods.rst index d9d689148..37a772f13 100644 --- a/docs/source/openmw-mods/convert_bump_mapped_mods.rst +++ b/docs/source/openmw-mods/convert_bump_mapped_mods.rst @@ -151,7 +151,7 @@ We will be converting a quite popular texture replacer of the Hlaalu architectur Now – if the mod you want to change includes custom made models it gets a bit more complicated I'm afraid. But that is for the next tutorial. -Converting Apel's Various Things – Sacks +Converting Apel's Various Things - Sacks ---------------------------------------- **Mod made for MCP's fake bump function, with custom models** From fee39afe38e990ff78659748fc56f5c42cb46cb8 Mon Sep 17 00:00:00 2001 From: Allofich Date: Sun, 13 Nov 2016 18:27:02 +0900 Subject: [PATCH 41/94] Don't allow resting on water with water walking --- apps/openmw/mwworld/worldimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 625ef93a9..fce3d69db 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2183,7 +2183,7 @@ namespace MWWorld if (!actor) throw std::runtime_error("can't find player"); - if ((actor->getCollisionMode() && !mPhysics->isOnSolidGround(player)) || isUnderwater(currentCell, playerPos)) + if ((actor->getCollisionMode() && !mPhysics->isOnSolidGround(player)) || isUnderwater(currentCell, playerPos) || isWalkingOnWater(player)) return 2; if((currentCell->getCell()->mData.mFlags&ESM::Cell::NoSleep) || player.getClass().getNpcStats(player).isWerewolf()) From 3420121c3fbbd3f18110b603d270a01ed44774fc Mon Sep 17 00:00:00 2001 From: Allofich Date: Sun, 13 Nov 2016 22:48:33 +0900 Subject: [PATCH 42/94] Fix shadowing warnings --- apps/launcher/maindialog.cpp | 12 +++---- apps/wizard/mainwizard.cpp | 6 ++-- .../contentselector/model/contentmodel.cpp | 32 +++++++++---------- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 15a1a5c2a..94e186db8 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -324,10 +324,10 @@ bool Launcher::MainDialog::setupGameSettings() paths.append(localPath + QString("openmw.cfg")); paths.append(userPath + QString("openmw.cfg")); - foreach (const QString &path, paths) { - qDebug() << "Loading config file:" << path.toUtf8().constData(); + foreach (const QString &path2, paths) { + qDebug() << "Loading config file:" << path2.toUtf8().constData(); - file.setFileName(path); + file.setFileName(path2); if (file.exists()) { if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { cfgError(tr("Error opening OpenMW configuration file"), @@ -347,13 +347,13 @@ bool Launcher::MainDialog::setupGameSettings() QStringList dataDirs; // Check if the paths actually contain data files - foreach (const QString path, mGameSettings.getDataDirs()) { - QDir dir(path); + foreach (const QString path3, mGameSettings.getDataDirs()) { + QDir dir(path3); QStringList filters; filters << "*.esp" << "*.esm" << "*.omwgame" << "*.omwaddon"; if (!dir.entryList(filters).isEmpty()) - dataDirs.append(path); + dataDirs.append(path3); } if (dataDirs.isEmpty()) diff --git a/apps/wizard/mainwizard.cpp b/apps/wizard/mainwizard.cpp index fa934868b..7ef8761dd 100644 --- a/apps/wizard/mainwizard.cpp +++ b/apps/wizard/mainwizard.cpp @@ -162,10 +162,10 @@ void Wizard::MainWizard::setupGameSettings() paths.append(QLatin1String("openmw.cfg")); paths.append(globalPath + QLatin1String("openmw.cfg")); - foreach (const QString &path, paths) { - qDebug() << "Loading config file:" << path.toUtf8().constData(); + foreach (const QString &path2, paths) { + qDebug() << "Loading config file:" << path2.toUtf8().constData(); - file.setFileName(path); + file.setFileName(path2); if (file.exists()) { if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { QMessageBox msgBox; diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 26f0a4806..a7ac29b46 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -110,26 +110,26 @@ Qt::ItemFlags ContentSelectorModel::ContentModel::flags(const QModelIndex &index bool gamefileChecked = (file->gameFiles().count() == 0); foreach (const QString &fileName, file->gameFiles()) { - foreach (EsmFile *dependency, mFiles) + for (QListIterator dependencyIter(mFiles); dependencyIter.hasNext(); dependencyIter.next()) { //compare filenames only. Multiple instances //of the filename (with different paths) is not relevant here. - bool depFound = (dependency->fileName().compare(fileName, Qt::CaseInsensitive) == 0); + bool depFound = (dependencyIter.peekNext()->fileName().compare(fileName, Qt::CaseInsensitive) == 0); if (!depFound) continue; if (!gamefileChecked) { - if (isChecked (dependency->filePath())) - gamefileChecked = (dependency->isGameFile()); + if (isChecked (dependencyIter.peekNext()->filePath())) + gamefileChecked = (dependencyIter.peekNext()->isGameFile()); } // force it to iterate all files in cases where the current // dependency is a game file to ensure that a later duplicate // game file is / is not checked. // (i.e., break only if it's not a gamefile or the game file has been checked previously) - if (gamefileChecked || !(dependency->isGameFile())) + if (gamefileChecked || !(dependencyIter.peekNext()->isGameFile())) break; } } @@ -283,12 +283,11 @@ bool ContentSelectorModel::ContentModel::setData(const QModelIndex &index, const else return success; - - foreach (EsmFile *file, mFiles) + foreach (EsmFile *file2, mFiles) { - if (file->gameFiles().contains(fileName, Qt::CaseInsensitive)) + if (file2->gameFiles().contains(fileName, Qt::CaseInsensitive)) { - QModelIndex idx = indexFromItem(file); + QModelIndex idx = indexFromItem(file2); emit dataChanged(idx, idx); } } @@ -425,9 +424,9 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path) filters << "*.esp" << "*.esm" << "*.omwgame" << "*.omwaddon"; dir.setNameFilters(filters); - foreach (const QString &path, dir.entryList()) + foreach (const QString &path2, dir.entryList()) { - QFileInfo info(dir.absoluteFilePath(path)); + QFileInfo info(dir.absoluteFilePath(path2)); if (item(info.absoluteFilePath()) != 0) continue; @@ -437,12 +436,13 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path) ToUTF8::Utf8Encoder encoder = ToUTF8::calculateEncoding(mEncoding.toStdString()); fileReader.setEncoder(&encoder); - fileReader.open(std::string(dir.absoluteFilePath(path).toUtf8().constData())); - - EsmFile *file = new EsmFile(path); + fileReader.open(std::string(dir.absoluteFilePath(path2).toUtf8().constData())); - foreach (const ESM::Header::MasterData &item, fileReader.getGameFiles()) - file->addGameFile(QString::fromUtf8(item.name.c_str())); + EsmFile *file = new EsmFile(path2); + + for (std::vector::const_iterator itemIter = fileReader.getGameFiles().begin(); + itemIter != fileReader.getGameFiles().end(); ++itemIter) + file->addGameFile(QString::fromUtf8(itemIter->name.c_str())); file->setAuthor (QString::fromUtf8(fileReader.getAuthor().c_str())); file->setDate (info.lastModified()); From 175cfd4dff2067405ac748f5e9f297f1bad28509 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sun, 13 Nov 2016 17:22:50 +0100 Subject: [PATCH 43/94] Fix overloaded virtual function warning --- apps/openmw/mwgui/itemchargeview.cpp | 4 ++-- apps/openmw/mwgui/itemchargeview.hpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/itemchargeview.cpp b/apps/openmw/mwgui/itemchargeview.cpp index 83517e353..522acca26 100644 --- a/apps/openmw/mwgui/itemchargeview.cpp +++ b/apps/openmw/mwgui/itemchargeview.cpp @@ -99,7 +99,7 @@ namespace MWGui line.mIcon->setUserString("ToolTipType", "ItemPtr"); line.mIcon->setUserData(line.mItemPtr); line.mIcon->eventMouseButtonClick += MyGUI::newDelegate(this, &ItemChargeView::onIconClicked); - line.mIcon->eventMouseWheel += MyGUI::newDelegate(this, &ItemChargeView::onMouseWheel); + line.mIcon->eventMouseWheel += MyGUI::newDelegate(this, &ItemChargeView::onMouseWheelMoved); line.mCharge = mScrollView->createWidget("MW_ChargeBar", MyGUI::IntCoord(), MyGUI::Align::Default); line.mCharge->setNeedMouseFocus(false); @@ -202,7 +202,7 @@ namespace MWGui eventItemClicked(this, *sender->getUserData()); } - void ItemChargeView::onMouseWheel(MyGUI::Widget* /*sender*/, int rel) + void ItemChargeView::onMouseWheelMoved(MyGUI::Widget* /*sender*/, int rel) { if (mScrollView->getViewOffset().top + rel*0.3f > 0) mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); diff --git a/apps/openmw/mwgui/itemchargeview.hpp b/apps/openmw/mwgui/itemchargeview.hpp index 1ff077ef2..0988f655b 100644 --- a/apps/openmw/mwgui/itemchargeview.hpp +++ b/apps/openmw/mwgui/itemchargeview.hpp @@ -64,7 +64,7 @@ namespace MWGui void updateLine(const Line& line); void onIconClicked(MyGUI::Widget* sender); - void onMouseWheel(MyGUI::Widget* sender, int rel); + void onMouseWheelMoved(MyGUI::Widget* sender, int rel); typedef std::vector Lines; Lines mLines; From 2efd38b1ab3f9d349284eb478caaf4918eeac030 Mon Sep 17 00:00:00 2001 From: Phillip Andrews Date: Sun, 13 Nov 2016 13:32:42 -0600 Subject: [PATCH 44/94] Fix install procedure so it works with all MSVC build configurations, not just Release --- CMakeLists.txt | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 939c27310..7d206baab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,7 +46,7 @@ if(EXISTS ${PROJECT_SOURCE_DIR}/.git) else(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/shallow) message(STATUS "Shallow Git clone detected, not attempting to retrieve version info") endif(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/shallow) -endif(EXISTS ${PROJECT_SOURCE_DIR}/.git) +endif(EXISTS ${PROJECT_SOURCE_DIR}/.git) # Macros include(OpenMWMacros) @@ -419,8 +419,10 @@ IF(NOT WIN32 AND NOT APPLE) ENDIF(NOT WIN32 AND NOT APPLE) if(WIN32) - FILE(GLOB dll_files "${OpenMW_BINARY_DIR}/Release/*.dll") - INSTALL(FILES ${dll_files} DESTINATION ".") + FILE(GLOB dll_files_debug "${OpenMW_BINARY_DIR}/Debug/*.dll") + FILE(GLOB dll_files_release "${OpenMW_BINARY_DIR}/Release/*.dll") + INSTALL(FILES ${dll_files_debug} DESTINATION "." CONFIGURATIONS Debug) + INSTALL(FILES ${dll_files_release} DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel) INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg") INSTALL(FILES "${OpenMW_SOURCE_DIR}/CHANGELOG.md" DESTINATION "." RENAME "CHANGELOG.txt") INSTALL(FILES "${OpenMW_SOURCE_DIR}/README.md" DESTINATION "." RENAME "README.txt") @@ -429,27 +431,34 @@ if(WIN32) "${OpenMW_SOURCE_DIR}/Docs/license/DejaVu Font License.txt" "${OpenMW_BINARY_DIR}/settings-default.cfg" "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" - "${OpenMW_BINARY_DIR}/Release/openmw.exe" DESTINATION ".") + INSTALL(FILES "${OpenMW_BINARY_DIR}/Debug/openmw.exe" DESTINATION "." CONFIGURATIONS Debug) + INSTALL(FILES "${OpenMW_BINARY_DIR}/Release/openmw.exe" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel) IF(BUILD_LAUNCHER) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-launcher.exe" DESTINATION ".") + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Debug/openmw-launcher.exe" DESTINATION "." CONFIGURATIONS Debug) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-launcher.exe" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel) ENDIF(BUILD_LAUNCHER) IF(BUILD_MWINIIMPORTER) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-iniimporter.exe" DESTINATION ".") + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Debug/openmw-iniimporter.exe" DESTINATION "." CONFIGURATIONS Debug) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-iniimporter.exe" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel) ENDIF(BUILD_MWINIIMPORTER) IF(BUILD_ESSIMPORTER) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-essimporter.exe" DESTINATION ".") + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Debug/openmw-essimporter.exe" DESTINATION "." CONFIGURATIONS Debug) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-essimporter.exe" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel) ENDIF(BUILD_ESSIMPORTER) IF(BUILD_OPENCS) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-cs.exe" DESTINATION ".") + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Debug/openmw-cs.exe" DESTINATION "." CONFIGURATIONS Debug) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-cs.exe" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel) INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.cfg" DESTINATION ".") ENDIF(BUILD_OPENCS) IF(BUILD_WIZARD) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-wizard.exe" DESTINATION ".") + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Debug/openmw-wizard.exe" DESTINATION "." CONFIGURATIONS Debug) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-wizard.exe" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel) ENDIF(BUILD_WIZARD) if(BUILD_MYGUI_PLUGIN) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/Plugin_MyGUI_OpenMW_Resources.dll" DESTINATION ".") + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Debug/Plugin_MyGUI_OpenMW_Resources.dll" DESTINATION "." CONFIGURATIONS Debug) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/Plugin_MyGUI_OpenMW_Resources.dll" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel) ENDIF(BUILD_MYGUI_PLUGIN) IF(DESIRED_QT_VERSION MATCHES 5) @@ -828,3 +837,4 @@ if (DOXYGEN_FOUND) WORKING_DIRECTORY ${OpenMW_BINARY_DIR} COMMENT "Generating documentation for the github-pages at ${DOXYGEN_PAGES_OUTPUT_DIR}" VERBATIM) endif () + From 1861302dbd82ff674da0beacad76c44b21760c7b Mon Sep 17 00:00:00 2001 From: Phillip Andrews Date: Sun, 13 Nov 2016 14:27:59 -0600 Subject: [PATCH 45/94] Include various libraries for Visual Studio environment --- apps/essimporter/CMakeLists.txt | 4 ++++ apps/launcher/CMakeLists.txt | 4 ++++ apps/mwiniimporter/CMakeLists.txt | 4 ++++ apps/opencs/CMakeLists.txt | 9 +++++++++ apps/openmw/CMakeLists.txt | 2 ++ 5 files changed, 23 insertions(+) diff --git a/apps/essimporter/CMakeLists.txt b/apps/essimporter/CMakeLists.txt index 84e31dad9..5fe93bd3e 100644 --- a/apps/essimporter/CMakeLists.txt +++ b/apps/essimporter/CMakeLists.txt @@ -42,3 +42,7 @@ if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(openmw-essimporter gcov) endif() + +if (MSVC) + target_link_libraries(openmw-essimporter imm32.lib winmm.lib version.lib) +endif(MSVC) diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 207f6a84b..8bb55158e 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -92,6 +92,10 @@ target_link_libraries(openmw-launcher components ) +if(MSVC) + target_link_libraries(openmw-launcher imm32.lib winmm.lib version.lib) +endif(MSVC) + if (DESIRED_QT_VERSION MATCHES 4) target_link_libraries(openmw-launcher ${QT_QTGUI_LIBRARY} ${QT_QTCORE_LIBRARY}) if(WIN32) diff --git a/apps/mwiniimporter/CMakeLists.txt b/apps/mwiniimporter/CMakeLists.txt index 4024c0b42..4c73a4c35 100644 --- a/apps/mwiniimporter/CMakeLists.txt +++ b/apps/mwiniimporter/CMakeLists.txt @@ -24,6 +24,10 @@ if (WIN32) ${Boost_LOCALE_LIBRARY}) endif() +if(MSVC) + target_link_libraries(openmw-iniimporter imm32.lib winmm.lib version.lib) +endif(MSVC) + if (MINGW) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -municode") endif() diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 1f572c3f8..c5f18656c 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -225,6 +225,15 @@ if (WIN32) target_link_libraries(openmw-cs ${Boost_LOCALE_LIBRARY}) endif() +if (MSVC) + # Debug version needs increased number of sections beyond 2^16 + if (CMAKE_CL_64) + set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj") + endif (CMAKE_CL_64) + add_definitions("-D_USE_MATH_DEFINES") + target_link_libraries(openmw-cs imm32.lib winmm.lib version.lib) +endif (MSVC) + if(APPLE) INSTALL(TARGETS openmw-cs BUNDLE DESTINATION OpenMW COMPONENT BUNDLE) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 277acea2d..e24c8ad94 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -201,4 +201,6 @@ if (MSVC) set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj") endif (CMAKE_CL_64) add_definitions("-D_USE_MATH_DEFINES") + target_link_libraries(openmw imm32.lib winmm.lib version.lib) endif (MSVC) + From a1225ff4ecd915a481848104252d737263249761 Mon Sep 17 00:00:00 2001 From: Phillip Andrews Date: Sun, 13 Nov 2016 14:34:12 -0600 Subject: [PATCH 46/94] Additional MSVC library dependencies --- apps/bsatool/CMakeLists.txt | 4 ++++ apps/esmtool/CMakeLists.txt | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/apps/bsatool/CMakeLists.txt b/apps/bsatool/CMakeLists.txt index 27baff815..0c18e6bc1 100644 --- a/apps/bsatool/CMakeLists.txt +++ b/apps/bsatool/CMakeLists.txt @@ -18,3 +18,7 @@ if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(bsatool gcov) endif() + +if(MSVC) + target_link_libraries(bsatool imm32.lib winmm.lib version.lib) +endif(MSVC) diff --git a/apps/esmtool/CMakeLists.txt b/apps/esmtool/CMakeLists.txt index 1d5e662d8..6704e45f4 100644 --- a/apps/esmtool/CMakeLists.txt +++ b/apps/esmtool/CMakeLists.txt @@ -21,3 +21,7 @@ if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(esmtool gcov) endif() + +if(MSVC) + target_link_libraries(esmtool imm32.lib winmm.lib version.lib) +endif(MSVC) From 86b46735396e9fcc871e0f02327415cb4bfcc40a Mon Sep 17 00:00:00 2001 From: Phillip Andrews Date: Sun, 13 Nov 2016 16:43:07 -0600 Subject: [PATCH 47/94] Removed math constants in openmw-cs, which are apparently not going to be used --- apps/opencs/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index c5f18656c..6e5b7b7c9 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -230,7 +230,6 @@ if (MSVC) if (CMAKE_CL_64) set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj") endif (CMAKE_CL_64) - add_definitions("-D_USE_MATH_DEFINES") target_link_libraries(openmw-cs imm32.lib winmm.lib version.lib) endif (MSVC) From 59eba1dedecee642c9c0b68d5c7829b9f0688631 Mon Sep 17 00:00:00 2001 From: Phillip Andrews Date: Sun, 13 Nov 2016 16:59:36 -0600 Subject: [PATCH 48/94] Changed tabs to spaces, oops --- CMakeLists.txt | 21 +++++++++++---------- apps/essimporter/CMakeLists.txt | 2 +- apps/launcher/CMakeLists.txt | 2 +- apps/mwiniimporter/CMakeLists.txt | 2 +- apps/opencs/CMakeLists.txt | 2 +- apps/openmw/CMakeLists.txt | 2 +- 6 files changed, 16 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d206baab..b4d4b37cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -419,10 +419,11 @@ IF(NOT WIN32 AND NOT APPLE) ENDIF(NOT WIN32 AND NOT APPLE) if(WIN32) - FILE(GLOB dll_files_debug "${OpenMW_BINARY_DIR}/Debug/*.dll") + MESSAGE(${RUNTIME_OUTPUT_DIR}) + FILE(GLOB dll_files_debug "${OpenMW_BINARY_DIR}/Debug/*.dll") FILE(GLOB dll_files_release "${OpenMW_BINARY_DIR}/Release/*.dll") INSTALL(FILES ${dll_files_debug} DESTINATION "." CONFIGURATIONS Debug) - INSTALL(FILES ${dll_files_release} DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel) + INSTALL(FILES ${dll_files_release} DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel) INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg") INSTALL(FILES "${OpenMW_SOURCE_DIR}/CHANGELOG.md" DESTINATION "." RENAME "CHANGELOG.txt") INSTALL(FILES "${OpenMW_SOURCE_DIR}/README.md" DESTINATION "." RENAME "README.txt") @@ -432,32 +433,32 @@ if(WIN32) "${OpenMW_BINARY_DIR}/settings-default.cfg" "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION ".") - INSTALL(FILES "${OpenMW_BINARY_DIR}/Debug/openmw.exe" DESTINATION "." CONFIGURATIONS Debug) - INSTALL(FILES "${OpenMW_BINARY_DIR}/Release/openmw.exe" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel) + INSTALL(FILES "${OpenMW_BINARY_DIR}/Debug/openmw.exe" DESTINATION "." CONFIGURATIONS Debug) + INSTALL(FILES "${OpenMW_BINARY_DIR}/Release/openmw.exe" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel) IF(BUILD_LAUNCHER) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Debug/openmw-launcher.exe" DESTINATION "." CONFIGURATIONS Debug) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Debug/openmw-launcher.exe" DESTINATION "." CONFIGURATIONS Debug) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-launcher.exe" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel) ENDIF(BUILD_LAUNCHER) IF(BUILD_MWINIIMPORTER) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Debug/openmw-iniimporter.exe" DESTINATION "." CONFIGURATIONS Debug) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Debug/openmw-iniimporter.exe" DESTINATION "." CONFIGURATIONS Debug) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-iniimporter.exe" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel) ENDIF(BUILD_MWINIIMPORTER) IF(BUILD_ESSIMPORTER) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Debug/openmw-essimporter.exe" DESTINATION "." CONFIGURATIONS Debug) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Debug/openmw-essimporter.exe" DESTINATION "." CONFIGURATIONS Debug) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-essimporter.exe" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel) ENDIF(BUILD_ESSIMPORTER) IF(BUILD_OPENCS) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Debug/openmw-cs.exe" DESTINATION "." CONFIGURATIONS Debug) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Debug/openmw-cs.exe" DESTINATION "." CONFIGURATIONS Debug) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-cs.exe" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel) INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.cfg" DESTINATION ".") ENDIF(BUILD_OPENCS) IF(BUILD_WIZARD) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Debug/openmw-wizard.exe" DESTINATION "." CONFIGURATIONS Debug) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Debug/openmw-wizard.exe" DESTINATION "." CONFIGURATIONS Debug) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-wizard.exe" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel) ENDIF(BUILD_WIZARD) if(BUILD_MYGUI_PLUGIN) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Debug/Plugin_MyGUI_OpenMW_Resources.dll" DESTINATION "." CONFIGURATIONS Debug) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Debug/Plugin_MyGUI_OpenMW_Resources.dll" DESTINATION "." CONFIGURATIONS Debug) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/Plugin_MyGUI_OpenMW_Resources.dll" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel) ENDIF(BUILD_MYGUI_PLUGIN) diff --git a/apps/essimporter/CMakeLists.txt b/apps/essimporter/CMakeLists.txt index 5fe93bd3e..5a0a3e6b8 100644 --- a/apps/essimporter/CMakeLists.txt +++ b/apps/essimporter/CMakeLists.txt @@ -44,5 +44,5 @@ if (BUILD_WITH_CODE_COVERAGE) endif() if (MSVC) - target_link_libraries(openmw-essimporter imm32.lib winmm.lib version.lib) + target_link_libraries(openmw-essimporter imm32.lib winmm.lib version.lib) endif(MSVC) diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 8bb55158e..6d5655836 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -93,7 +93,7 @@ target_link_libraries(openmw-launcher ) if(MSVC) - target_link_libraries(openmw-launcher imm32.lib winmm.lib version.lib) + target_link_libraries(openmw-launcher imm32.lib winmm.lib version.lib) endif(MSVC) if (DESIRED_QT_VERSION MATCHES 4) diff --git a/apps/mwiniimporter/CMakeLists.txt b/apps/mwiniimporter/CMakeLists.txt index 4c73a4c35..3e0f4da61 100644 --- a/apps/mwiniimporter/CMakeLists.txt +++ b/apps/mwiniimporter/CMakeLists.txt @@ -25,7 +25,7 @@ if (WIN32) endif() if(MSVC) - target_link_libraries(openmw-iniimporter imm32.lib winmm.lib version.lib) + target_link_libraries(openmw-iniimporter imm32.lib winmm.lib version.lib) endif(MSVC) if (MINGW) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 6e5b7b7c9..00c2853a6 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -230,7 +230,7 @@ if (MSVC) if (CMAKE_CL_64) set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj") endif (CMAKE_CL_64) - target_link_libraries(openmw-cs imm32.lib winmm.lib version.lib) + target_link_libraries(openmw-cs imm32.lib winmm.lib version.lib) endif (MSVC) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index e24c8ad94..21b69f36e 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -201,6 +201,6 @@ if (MSVC) set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj") endif (CMAKE_CL_64) add_definitions("-D_USE_MATH_DEFINES") - target_link_libraries(openmw imm32.lib winmm.lib version.lib) + target_link_libraries(openmw imm32.lib winmm.lib version.lib) endif (MSVC) From 7383cc9de4dd03c5402a4366b47942cc82e9914e Mon Sep 17 00:00:00 2001 From: Phillip Andrews Date: Sun, 13 Nov 2016 17:06:00 -0600 Subject: [PATCH 49/94] Forgot to undo my test edits because I am a big dum-dum --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b4d4b37cf..025e602f8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -419,7 +419,6 @@ IF(NOT WIN32 AND NOT APPLE) ENDIF(NOT WIN32 AND NOT APPLE) if(WIN32) - MESSAGE(${RUNTIME_OUTPUT_DIR}) FILE(GLOB dll_files_debug "${OpenMW_BINARY_DIR}/Debug/*.dll") FILE(GLOB dll_files_release "${OpenMW_BINARY_DIR}/Release/*.dll") INSTALL(FILES ${dll_files_debug} DESTINATION "." CONFIGURATIONS Debug) From aeaedbc57a682cc50dc645654f8a3039e7d842b8 Mon Sep 17 00:00:00 2001 From: Phillip Andrews Date: Sun, 13 Nov 2016 22:49:01 -0600 Subject: [PATCH 50/94] Moved install commands to target-specific cmakelists so that all configurations work. --- CMakeLists.txt | 32 ++++++------------------------- apps/essimporter/CMakeLists.txt | 4 ++++ apps/launcher/CMakeLists.txt | 4 ++++ apps/mwiniimporter/CMakeLists.txt | 3 ++- apps/opencs/CMakeLists.txt | 2 ++ apps/openmw/CMakeLists.txt | 4 ++++ apps/wizard/CMakeLists.txt | 3 +++ 7 files changed, 25 insertions(+), 27 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 025e602f8..0d74e8cbc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -432,42 +432,22 @@ if(WIN32) "${OpenMW_BINARY_DIR}/settings-default.cfg" "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION ".") - INSTALL(FILES "${OpenMW_BINARY_DIR}/Debug/openmw.exe" DESTINATION "." CONFIGURATIONS Debug) - INSTALL(FILES "${OpenMW_BINARY_DIR}/Release/openmw.exe" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel) - IF(BUILD_LAUNCHER) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Debug/openmw-launcher.exe" DESTINATION "." CONFIGURATIONS Debug) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-launcher.exe" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel) - ENDIF(BUILD_LAUNCHER) - IF(BUILD_MWINIIMPORTER) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Debug/openmw-iniimporter.exe" DESTINATION "." CONFIGURATIONS Debug) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-iniimporter.exe" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel) - ENDIF(BUILD_MWINIIMPORTER) - IF(BUILD_ESSIMPORTER) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Debug/openmw-essimporter.exe" DESTINATION "." CONFIGURATIONS Debug) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-essimporter.exe" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel) - ENDIF(BUILD_ESSIMPORTER) - IF(BUILD_OPENCS) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Debug/openmw-cs.exe" DESTINATION "." CONFIGURATIONS Debug) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-cs.exe" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel) - INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.cfg" DESTINATION ".") - ENDIF(BUILD_OPENCS) - IF(BUILD_WIZARD) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Debug/openmw-wizard.exe" DESTINATION "." CONFIGURATIONS Debug) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-wizard.exe" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel) - ENDIF(BUILD_WIZARD) if(BUILD_MYGUI_PLUGIN) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Debug/Plugin_MyGUI_OpenMW_Resources.dll" DESTINATION "." CONFIGURATIONS Debug) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/Plugin_MyGUI_OpenMW_Resources.dll" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel) ENDIF(BUILD_MYGUI_PLUGIN) IF(DESIRED_QT_VERSION MATCHES 5) - INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/Release/platforms" DESTINATION ".") + INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/Debug/platforms" DESTINATION "." CONFIGURATIONS Debug) + INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/Release/platforms" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel) ENDIF() INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ".") - FILE(GLOB plugin_dir "${OpenMW_BINARY_DIR}/Release/osgPlugins-*") - INSTALL(DIRECTORY ${plugin_dir} DESTINATION ".") + FILE(GLOB plugin_dir_debug "${OpenMW_BINARY_DIR}/Debug/osgPlugins-*") + FILE(GLOB plugin_dir_release "${OpenMW_BINARY_DIR}/Release/osgPlugins-*") + INSTALL(DIRECTORY ${plugin_dir_debug} DESTINATION "." CONFIGURATIONS Debug) + INSTALL(DIRECTORY ${plugin_dir_release} DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel) SET(CPACK_GENERATOR "NSIS") SET(CPACK_PACKAGE_NAME "OpenMW") diff --git a/apps/essimporter/CMakeLists.txt b/apps/essimporter/CMakeLists.txt index 5a0a3e6b8..5683a6a86 100644 --- a/apps/essimporter/CMakeLists.txt +++ b/apps/essimporter/CMakeLists.txt @@ -43,6 +43,10 @@ if (BUILD_WITH_CODE_COVERAGE) target_link_libraries(openmw-essimporter gcov) endif() +if (WIN32) + INSTALL(TARGETS openmw-essimporter RUNTIME DESTINATION ".") +endif(WIN32) + if (MSVC) target_link_libraries(openmw-essimporter imm32.lib winmm.lib version.lib) endif(MSVC) diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 6d5655836..476451d2a 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -87,6 +87,10 @@ add_executable(openmw-launcher ${UI_HDRS} ) +if (WIN32) + INSTALL(TARGETS openmw-launcher RUNTIME DESTINATION ".") +endif (WIN32) + target_link_libraries(openmw-launcher ${SDL2_LIBRARY_ONLY} components diff --git a/apps/mwiniimporter/CMakeLists.txt b/apps/mwiniimporter/CMakeLists.txt index 3e0f4da61..b0351eb3f 100644 --- a/apps/mwiniimporter/CMakeLists.txt +++ b/apps/mwiniimporter/CMakeLists.txt @@ -22,7 +22,8 @@ target_link_libraries(openmw-iniimporter if (WIN32) target_link_libraries(openmw-iniimporter ${Boost_LOCALE_LIBRARY}) -endif() + INSTALL(TARGETS openmw-iniimporter RUNTIME DESTINATION ".") +endif(WIN32) if(MSVC) target_link_libraries(openmw-iniimporter imm32.lib winmm.lib version.lib) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 00c2853a6..1511a0bc4 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -223,6 +223,8 @@ endif() if (WIN32) target_link_libraries(openmw-cs ${Boost_LOCALE_LIBRARY}) + INSTALL(TARGETS openmw-cs RUNTIME DESTINATION ".") + INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.cfg" DESTINATION ".") endif() if (MSVC) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 21b69f36e..fa2fed3c6 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -204,3 +204,7 @@ if (MSVC) target_link_libraries(openmw imm32.lib winmm.lib version.lib) endif (MSVC) +if (WIN32) + INSTALL(TARGETS openmw RUNTIME DESTINATION ".") +endif (WIN32) + diff --git a/apps/wizard/CMakeLists.txt b/apps/wizard/CMakeLists.txt index dd2e1a748..d2b9ab0f6 100644 --- a/apps/wizard/CMakeLists.txt +++ b/apps/wizard/CMakeLists.txt @@ -140,3 +140,6 @@ if (CMAKE_SYSTEM_NAME MATCHES "Linux") target_link_libraries(openmw-wizard dl Xt) endif() +if (WIN32) + INSTALL(TARGETS openmw-wizard RUNTIME DESTINATION ".") +endif(WIN32) From c18fc113e56efb28b0ddb1ef8f70b6f2b0129965 Mon Sep 17 00:00:00 2001 From: Phillip Andrews Date: Mon, 14 Nov 2016 00:01:22 -0600 Subject: [PATCH 51/94] Changed missing library dependencies to simple fix --- apps/bsatool/CMakeLists.txt | 4 ---- apps/esmtool/CMakeLists.txt | 4 ---- apps/essimporter/CMakeLists.txt | 4 ---- apps/launcher/CMakeLists.txt | 4 ---- apps/mwiniimporter/CMakeLists.txt | 4 ---- apps/opencs/CMakeLists.txt | 1 - apps/openmw/CMakeLists.txt | 1 - components/CMakeLists.txt | 2 +- 8 files changed, 1 insertion(+), 23 deletions(-) diff --git a/apps/bsatool/CMakeLists.txt b/apps/bsatool/CMakeLists.txt index 0c18e6bc1..27baff815 100644 --- a/apps/bsatool/CMakeLists.txt +++ b/apps/bsatool/CMakeLists.txt @@ -18,7 +18,3 @@ if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(bsatool gcov) endif() - -if(MSVC) - target_link_libraries(bsatool imm32.lib winmm.lib version.lib) -endif(MSVC) diff --git a/apps/esmtool/CMakeLists.txt b/apps/esmtool/CMakeLists.txt index 6704e45f4..1d5e662d8 100644 --- a/apps/esmtool/CMakeLists.txt +++ b/apps/esmtool/CMakeLists.txt @@ -21,7 +21,3 @@ if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(esmtool gcov) endif() - -if(MSVC) - target_link_libraries(esmtool imm32.lib winmm.lib version.lib) -endif(MSVC) diff --git a/apps/essimporter/CMakeLists.txt b/apps/essimporter/CMakeLists.txt index 5683a6a86..93f53d0e8 100644 --- a/apps/essimporter/CMakeLists.txt +++ b/apps/essimporter/CMakeLists.txt @@ -46,7 +46,3 @@ endif() if (WIN32) INSTALL(TARGETS openmw-essimporter RUNTIME DESTINATION ".") endif(WIN32) - -if (MSVC) - target_link_libraries(openmw-essimporter imm32.lib winmm.lib version.lib) -endif(MSVC) diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 476451d2a..8cbe18d51 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -96,10 +96,6 @@ target_link_libraries(openmw-launcher components ) -if(MSVC) - target_link_libraries(openmw-launcher imm32.lib winmm.lib version.lib) -endif(MSVC) - if (DESIRED_QT_VERSION MATCHES 4) target_link_libraries(openmw-launcher ${QT_QTGUI_LIBRARY} ${QT_QTCORE_LIBRARY}) if(WIN32) diff --git a/apps/mwiniimporter/CMakeLists.txt b/apps/mwiniimporter/CMakeLists.txt index b0351eb3f..4bd661685 100644 --- a/apps/mwiniimporter/CMakeLists.txt +++ b/apps/mwiniimporter/CMakeLists.txt @@ -25,10 +25,6 @@ if (WIN32) INSTALL(TARGETS openmw-iniimporter RUNTIME DESTINATION ".") endif(WIN32) -if(MSVC) - target_link_libraries(openmw-iniimporter imm32.lib winmm.lib version.lib) -endif(MSVC) - if (MINGW) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -municode") endif() diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 1511a0bc4..acf3cf021 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -232,7 +232,6 @@ if (MSVC) if (CMAKE_CL_64) set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj") endif (CMAKE_CL_64) - target_link_libraries(openmw-cs imm32.lib winmm.lib version.lib) endif (MSVC) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index fa2fed3c6..452629fcf 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -201,7 +201,6 @@ if (MSVC) set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj") endif (CMAKE_CL_64) add_definitions("-D_USE_MATH_DEFINES") - target_link_libraries(openmw imm32.lib winmm.lib version.lib) endif (MSVC) if (WIN32) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 51faaba1d..3f3e1dbde 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -206,7 +206,7 @@ target_link_libraries(components ${OSGFX_LIBRARIES} ${OSGANIMATION_LIBRARIES} ${Bullet_LIBRARIES} - ${SDL2_LIBRARY} + ${SDL2_LIBRARIES} # For MyGUI platform ${GL_LIB} ${MyGUI_LIBRARIES} From 5e46121046eb045446543663b172dd2a23d3dfec Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Wed, 16 Nov 2016 20:15:25 +0100 Subject: [PATCH 52/94] Implement fleeing AI (Closes #1118) --- apps/openmw/mwbase/world.hpp | 6 + apps/openmw/mwmechanics/aicombat.cpp | 243 +++++++++++--- apps/openmw/mwmechanics/aicombat.hpp | 2 + apps/openmw/mwmechanics/aicombataction.cpp | 302 ++++++++++++++++++ apps/openmw/mwmechanics/aicombataction.hpp | 21 ++ apps/openmw/mwmechanics/combat.cpp | 15 + apps/openmw/mwmechanics/combat.hpp | 1 + .../mwmechanics/mechanicsmanagerimp.cpp | 16 +- apps/openmw/mwworld/class.cpp | 21 +- apps/openmw/mwworld/class.hpp | 2 + apps/openmw/mwworld/worldimp.cpp | 20 +- apps/openmw/mwworld/worldimp.hpp | 6 + 12 files changed, 599 insertions(+), 56 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 0178a3f2b..74bc0b7fd 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -560,6 +560,12 @@ namespace MWBase virtual void removeContainerScripts(const MWWorld::Ptr& reference) = 0; virtual bool isPlayerInJail() const = 0; + + /// Return terrain height at \a worldPos position. + virtual float getTerrainHeightAt(const osg::Vec3f& worldPos) const = 0; + + /// Return physical or rendering half extents of the given actor. + virtual osg::Vec3f getHalfExtents(const MWWorld::ConstPtr& actor, bool rendering=false) const = 0; }; } diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 2e1dfbac5..80b343d4f 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -18,6 +18,7 @@ #include "character.hpp" #include "aicombataction.hpp" #include "combat.hpp" +#include "coordinateconverter.hpp" namespace { @@ -50,6 +51,19 @@ namespace MWMechanics bool mForceNoShortcut; ESM::Position mShortcutFailPos; MWMechanics::Movement mMovement; + + enum FleeState + { + FleeState_None, + FleeState_Idle, + FleeState_RunBlindly, + FleeState_RunToDestination + }; + FleeState mFleeState; + bool mFleeLOS; + float mFleeUpdateLOSTimer; + float mFleeBlindRunTimer; + ESM::Pathgrid::Point mFleeDest; AiCombatStorage(): mAttackCooldown(0), @@ -66,7 +80,11 @@ namespace MWMechanics mStrength(), mForceNoShortcut(false), mShortcutFailPos(), - mMovement() + mMovement(), + mFleeState(FleeState_None), + mFleeLOS(false), + mFleeUpdateLOSTimer(0.0f), + mFleeBlindRunTimer(0.0f) {} void startCombatMove(bool isDistantCombat, float distToTarget, float rangeAttack, const MWWorld::Ptr& actor, const MWWorld::Ptr& target); @@ -76,6 +94,10 @@ namespace MWMechanics const ESM::Weapon* weapon, bool distantCombat); void updateAttack(CharacterController& characterController); void stopAttack(); + + void startFleeing(); + void stopFleeing(); + bool isFleeing(); }; AiCombat::AiCombat(const MWWorld::Ptr& actor) : @@ -157,16 +179,23 @@ namespace MWMechanics || target.getClass().getCreatureStats(target).isDead()) return true; - if (storage.mCurrentAction.get()) // need to wait to init action with it's attack range + if (!storage.isFleeing()) { - //Update every frame - bool is_target_reached = pathTo(actor, target.getRefData().getPosition().pos, duration, storage.mAttackRange); - if (is_target_reached) storage.mReadyToAttack = true; - } + if (storage.mCurrentAction.get()) // need to wait to init action with it's attack range + { + //Update every frame + bool is_target_reached = pathTo(actor, target.getRefData().getPosition().pos, duration, storage.mAttackRange); + if (is_target_reached) storage.mReadyToAttack = true; + } - storage.updateCombatMove(duration); - if (storage.mReadyToAttack) updateActorsMovement(actor, duration, storage); - storage.updateAttack(characterController); + storage.updateCombatMove(duration); + if (storage.mReadyToAttack) updateActorsMovement(actor, duration, storage); + storage.updateAttack(characterController); + } + else + { + updateFleeing(actor, target, duration, storage); + } storage.mActionCooldown -= duration; float& timerReact = storage.mTimerReact; @@ -185,12 +214,6 @@ namespace MWMechanics void AiCombat::attack(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, AiCombatStorage& storage, CharacterController& characterController) { - if (isTargetMagicallyHidden(target)) - { - storage.stopAttack(); - return; // TODO: run away instead of doing nothing - } - const MWWorld::CellStore*& currentCell = storage.mCell; bool cellChange = currentCell && (actor.getCell() != currentCell); if(!currentCell || cellChange) @@ -198,30 +221,61 @@ namespace MWMechanics currentCell = actor.getCell(); } + bool forceFlee = false; + if (!canFight(actor, target)) + { + storage.stopAttack(); + characterController.setAttackingOrSpell(false); + storage.mActionCooldown = 0.f; + forceFlee = true; + } + const MWWorld::Class& actorClass = actor.getClass(); actorClass.getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true); float& actionCooldown = storage.mActionCooldown; - if (actionCooldown > 0) - return; - - float &rangeAttack = storage.mAttackRange; boost::shared_ptr& currentAction = storage.mCurrentAction; - if (characterController.readyToPrepareAttack()) + + if (!forceFlee) { - currentAction = prepareNextAction(actor, target); + if (actionCooldown > 0) + return; + + if (characterController.readyToPrepareAttack()) + { + currentAction = prepareNextAction(actor, target); + actionCooldown = currentAction->getActionCooldown(); + } + } + else + { + currentAction.reset(new ActionFlee()); actionCooldown = currentAction->getActionCooldown(); } - const ESM::Weapon *weapon = NULL; - bool isRangedCombat = false; - if (currentAction.get()) + if (!currentAction) + return; + + if (storage.isFleeing() != currentAction->isFleeing()) { - rangeAttack = currentAction->getCombatRange(isRangedCombat); - // Get weapon characteristics - weapon = currentAction->getWeapon(); + if (currentAction->isFleeing()) + { + storage.startFleeing(); + MWBase::Environment::get().getDialogueManager()->say(actor, "flee"); + return; + } + else + storage.stopFleeing(); } + bool isRangedCombat = false; + float &rangeAttack = storage.mAttackRange; + + rangeAttack = currentAction->getCombatRange(isRangedCombat); + + // Get weapon characteristics + const ESM::Weapon* weapon = currentAction->getWeapon(); + ESM::Position pos = actor.getRefData().getPosition(); osg::Vec3f vActorPos(pos.asVec3()); osg::Vec3f vTargetPos(target.getRefData().getPosition().asVec3()); @@ -229,19 +283,7 @@ namespace MWMechanics osg::Vec3f vAimDir = MWBase::Environment::get().getWorld()->aimToTarget(actor, target); float distToTarget = MWBase::Environment::get().getWorld()->getHitDistance(actor, target); - if (!currentAction) - return; - storage.mReadyToAttack = (currentAction->isAttackingOrSpell() && distToTarget <= rangeAttack); - - // can't fight if attacker can't go where target is. E.g. A fish can't attack person on land. - if (distToTarget > rangeAttack - && !actorClass.isNpc() && !MWMechanics::isEnvironmentCompatible(actor, target)) - { - // TODO: start fleeing? - storage.stopAttack(); - return; - } if (storage.mReadyToAttack) { @@ -267,6 +309,106 @@ namespace MWMechanics } } + void MWMechanics::AiCombat::updateFleeing(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, float duration, MWMechanics::AiCombatStorage& storage) + { + static const float LOS_UPDATE_DURATION = 0.5f; + static const float BLIND_RUN_DURATION = 1.0f; + + if (storage.mFleeUpdateLOSTimer <= 0.f) + { + storage.mFleeLOS = MWBase::Environment::get().getWorld()->getLOS(actor, target); + storage.mFleeUpdateLOSTimer = LOS_UPDATE_DURATION; + } + else + storage.mFleeUpdateLOSTimer -= duration; + + AiCombatStorage::FleeState& state = storage.mFleeState; + switch (state) + { + case AiCombatStorage::FleeState_None: + return; + + case AiCombatStorage::FleeState_Idle: + { + float triggerDist = getMaxAttackDistance(target); + + if (storage.mFleeLOS && + (triggerDist >= 1000 || getDistanceMinusHalfExtents(actor, target) <= triggerDist)) + { + const ESM::Pathgrid* pathgrid = + MWBase::Environment::get().getWorld()->getStore().get().search(*storage.mCell->getCell()); + + bool runFallback = true; + + if (pathgrid && !actor.getClass().isPureWaterCreature(actor)) + { + ESM::Pathgrid::PointList points; + CoordinateConverter coords(storage.mCell->getCell()); + + osg::Vec3f localPos = actor.getRefData().getPosition().asVec3(); + coords.toLocal(localPos); + + int closestPointIndex = PathFinder::GetClosestPoint(pathgrid, localPos); + for (int i = 0; i < static_cast(pathgrid->mPoints.size()); i++) + { + if (i != closestPointIndex && storage.mCell->isPointConnected(closestPointIndex, i)) + { + points.push_back(pathgrid->mPoints[static_cast(i)]); + } + } + + if (!points.empty()) + { + ESM::Pathgrid::Point dest = points[Misc::Rng::rollDice(points.size())]; + coords.toWorld(dest); + + state = AiCombatStorage::FleeState_RunToDestination; + storage.mFleeDest = ESM::Pathgrid::Point(dest.mX, dest.mY, dest.mZ); + + runFallback = false; + } + } + + if (runFallback) + { + state = AiCombatStorage::FleeState_RunBlindly; + storage.mFleeBlindRunTimer = 0.0f; + } + } + } + break; + + case AiCombatStorage::FleeState_RunBlindly: + { + // timer to prevent twitchy movement that can be observed in vanilla MW + if (storage.mFleeBlindRunTimer < BLIND_RUN_DURATION) + { + storage.mFleeBlindRunTimer += duration; + + storage.mMovement.mRotation[2] = osg::PI + getZAngleToDir(target.getRefData().getPosition().asVec3()-actor.getRefData().getPosition().asVec3()); + storage.mMovement.mPosition[1] = 1; + updateActorsMovement(actor, duration, storage); + } + else + state = AiCombatStorage::FleeState_Idle; + } + break; + + case AiCombatStorage::FleeState_RunToDestination: + { + static const float fFleeDistance = MWBase::Environment::get().getWorld()->getStore().get().find("fFleeDistance")->getFloat(); + + float dist = (actor.getRefData().getPosition().asVec3() - target.getRefData().getPosition().asVec3()).length(); + if ((dist > fFleeDistance && !storage.mFleeLOS) + || pathTo(actor, storage.mFleeDest, duration)) + { + state = AiCombatStorage::FleeState_Idle; + } + } + break; + }; + } + void AiCombat::updateActorsMovement(const MWWorld::Ptr& actor, float duration, AiCombatStorage& storage) { // apply combat movement @@ -446,6 +588,29 @@ namespace MWMechanics mReadyToAttack = false; mAttack = false; } + + void AiCombatStorage::startFleeing() + { + stopFleeing(); + mFleeState = FleeState_Idle; + } + + void AiCombatStorage::stopFleeing() + { + mMovement.mPosition[0] = 0; + mMovement.mPosition[1] = 0; + mMovement.mPosition[2] = 0; + mFleeState = FleeState_None; + mFleeDest = ESM::Pathgrid::Point(0, 0, 0); + mFleeLOS = false; + mFleeUpdateLOSTimer = 0.0f; + mFleeUpdateLOSTimer = 0.0f; + } + + bool AiCombatStorage::isFleeing() + { + return mFleeState != FleeState_None; + } } diff --git a/apps/openmw/mwmechanics/aicombat.hpp b/apps/openmw/mwmechanics/aicombat.hpp index 4be2ac9da..3f2bde776 100644 --- a/apps/openmw/mwmechanics/aicombat.hpp +++ b/apps/openmw/mwmechanics/aicombat.hpp @@ -61,6 +61,8 @@ namespace MWMechanics void attack(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, AiCombatStorage& storage, CharacterController& characterController); + void updateFleeing(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, float duration, AiCombatStorage& storage); + /// Transfer desired movement (from AiCombatStorage) to Actor void updateActorsMovement(const MWWorld::Ptr& actor, float duration, AiCombatStorage& storage); void rotateActorOnAxis(const MWWorld::Ptr& actor, int axis, diff --git a/apps/openmw/mwmechanics/aicombataction.cpp b/apps/openmw/mwmechanics/aicombataction.cpp index 094df1db3..437aae277 100644 --- a/apps/openmw/mwmechanics/aicombataction.cpp +++ b/apps/openmw/mwmechanics/aicombataction.cpp @@ -5,14 +5,17 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/actionequip.hpp" +#include "../mwworld/cellstore.hpp" #include "npcstats.hpp" #include "spellcasting.hpp" +#include "combat.hpp" namespace { @@ -517,6 +520,7 @@ namespace MWMechanics Spells& spells = actor.getClass().getCreatureStats(actor).getSpells(); float bestActionRating = 0.f; + float antiFleeRating = 0.f; // Default to hand-to-hand combat boost::shared_ptr bestAction (new ActionWeapon(MWWorld::Ptr())); if (actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf()) @@ -536,6 +540,7 @@ namespace MWMechanics { bestActionRating = rating; bestAction.reset(new ActionPotion(*it)); + antiFleeRating = std::numeric_limits::max(); } } @@ -546,6 +551,7 @@ namespace MWMechanics { bestActionRating = rating; bestAction.reset(new ActionEnchantedItem(it)); + antiFleeRating = std::numeric_limits::max(); } } @@ -593,6 +599,7 @@ namespace MWMechanics bestActionRating = rating; bestAction.reset(new ActionWeapon(*it, ammo)); + antiFleeRating = vanillaRateWeaponAndAmmo(*it, ammo, actor, enemy); } } } @@ -606,13 +613,308 @@ namespace MWMechanics { bestActionRating = rating; bestAction.reset(new ActionSpell(spell->mId)); + antiFleeRating = vanillaRateSpell(spell, actor, enemy); } } + if (makeFleeDecision(actor, enemy, antiFleeRating)) + bestAction.reset(new ActionFlee()); + if (bestAction.get()) bestAction->prepare(actor); return bestAction; } + + float getDistanceMinusHalfExtents(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, bool minusZDist) + { + osg::Vec3f actor1Pos = actor1.getRefData().getPosition().asVec3(); + osg::Vec3f actor2Pos = actor2.getRefData().getPosition().asVec3(); + + float dist = (actor1Pos - actor2Pos).length(); + + if (minusZDist) + dist -= std::abs(actor1Pos.z() - actor2Pos.z()); + + return (dist + - MWBase::Environment::get().getWorld()->getHalfExtents(actor1).y() + - MWBase::Environment::get().getWorld()->getHalfExtents(actor2).y()); + } + + float getMaxAttackDistance(const MWWorld::Ptr& actor) + { + const CreatureStats& stats = actor.getClass().getCreatureStats(actor); + const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); + + std::string selectedSpellId = stats.getSpells().getSelectedSpell(); + MWWorld::Ptr selectedEnchItem; + + MWWorld::Ptr activeWeapon, activeAmmo; + if (actor.getClass().hasInventoryStore(actor)) + { + MWWorld::InventoryStore& invStore = actor.getClass().getInventoryStore(actor); + + MWWorld::ContainerStoreIterator item = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); + if (item != invStore.end() && item.getType() == MWWorld::ContainerStore::Type_Weapon) + activeWeapon = *item; + + item = invStore.getSlot(MWWorld::InventoryStore::Slot_Ammunition); + if (item != invStore.end() && item.getType() == MWWorld::ContainerStore::Type_Weapon) + activeAmmo = *item; + + if (invStore.getSelectedEnchantItem() != invStore.end()) + selectedEnchItem = *invStore.getSelectedEnchantItem(); + } + + float dist = 1.0f; + if (activeWeapon.isEmpty() && !selectedSpellId.empty() && !selectedEnchItem.isEmpty()) + { + static const float fHandToHandReach = gmst.find("fHandToHandReach")->getFloat(); + dist = fHandToHandReach; + } + else if (stats.getDrawState() == MWMechanics::DrawState_Spell) + { + dist = 1.0f; + if (!selectedSpellId.empty()) + { + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(selectedSpellId); + for (std::vector::const_iterator effectIt = + spell->mEffects.mList.begin(); effectIt != spell->mEffects.mList.end(); ++effectIt) + { + if (effectIt->mArea == ESM::RT_Target) + { + const ESM::MagicEffect* effect = MWBase::Environment::get().getWorld()->getStore().get().find(effectIt->mEffectID); + dist = effect->mData.mSpeed; + break; + } + } + } + else if (!selectedEnchItem.isEmpty()) + { + std::string enchId = selectedEnchItem.getClass().getEnchantment(selectedEnchItem); + if (!enchId.empty()) + { + const ESM::Enchantment* ench = MWBase::Environment::get().getWorld()->getStore().get().find(enchId); + for (std::vector::const_iterator effectIt = + ench->mEffects.mList.begin(); effectIt != ench->mEffects.mList.end(); ++effectIt) + { + if (effectIt->mArea == ESM::RT_Target) + { + const ESM::MagicEffect* effect = MWBase::Environment::get().getWorld()->getStore().get().find(effectIt->mEffectID); + dist = effect->mData.mSpeed; + break; + } + } + } + } + + static const float fTargetSpellMaxSpeed = gmst.find("fTargetSpellMaxSpeed")->getFloat(); + dist *= std::max(1000.0f, fTargetSpellMaxSpeed); + } + else if (!activeWeapon.isEmpty()) + { + const ESM::Weapon* esmWeap = activeWeapon.get()->mBase; + if (esmWeap->mData.mType >= ESM::Weapon::MarksmanBow) + { + static const float fTargetSpellMaxSpeed = gmst.find("fProjectileMaxSpeed")->getFloat(); + dist = fTargetSpellMaxSpeed; + if (!activeAmmo.isEmpty()) + { + const ESM::Weapon* esmAmmo = activeAmmo.get()->mBase; + dist *= esmAmmo->mData.mSpeed; + } + } + else if (esmWeap->mData.mReach > 1) + { + dist = esmWeap->mData.mReach; + } + } + + dist = (dist > 0.f) ? dist : 1.0f; + + static const float fCombatDistance = gmst.find("fCombatDistance")->getFloat(); + static const float fCombatDistanceWerewolfMod = gmst.find("fCombatDistanceWerewolfMod")->getFloat(); + + float combatDistance = fCombatDistance; + if (actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf()) + combatDistance *= (fCombatDistanceWerewolfMod + 1.0f); + + if (dist < combatDistance) + dist *= combatDistance; + + return dist; + } + + bool canFight(const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy) + { + ESM::Position actorPos = actor.getRefData().getPosition(); + ESM::Position enemyPos = enemy.getRefData().getPosition(); + + const CreatureStats& enemyStats = enemy.getClass().getCreatureStats(enemy); + if (enemyStats.getMagicEffects().get(ESM::MagicEffect::Invisibility).getMagnitude() > 0 + || enemyStats.getMagicEffects().get(ESM::MagicEffect::Chameleon).getMagnitude() > 0) + { + if (!MWBase::Environment::get().getMechanicsManager()->awarenessCheck(enemy, actor)) + return false; + } + + if (actor.getClass().isPureWaterCreature(actor)) + { + if (!MWBase::Environment::get().getWorld()->isWading(enemy)) + return false; + } + + float atDist = getMaxAttackDistance(actor); + if (atDist > getDistanceMinusHalfExtents(actor, enemy) + && atDist > std::abs(actorPos.pos[2] - enemyPos.pos[2])) + { + if (MWBase::Environment::get().getWorld()->getLOS(actor, enemy)) + return true; + } + + if (actor.getClass().isPureFlyingCreature(actor) || actor.getClass().isPureLandCreature(actor)) + { + if (MWBase::Environment::get().getWorld()->isSwimming(enemy)) + return false; + } + + if (actor.getClass().isBipedal(actor) || !actor.getClass().canFly(actor)) + { + if (enemy.getClass().getCreatureStats(enemy).getMagicEffects().get(ESM::MagicEffect::Levitate).getMagnitude() > 0) + { + float attackDistance = getMaxAttackDistance(actor); + if ((attackDistance + actorPos.pos[2]) < enemyPos.pos[2]) + { + if (enemy.getCell()->isExterior()) + { + if (attackDistance < (enemyPos.pos[2] - MWBase::Environment::get().getWorld()->getTerrainHeightAt(enemyPos.asVec3()))) + return false; + } + } + } + } + + if (!actor.getClass().canWalk(actor) && !actor.getClass().isBipedal(actor)) + return true; + + if (actor.getClass().getCreatureStats(actor).getMagicEffects().get(ESM::MagicEffect::Levitate).getMagnitude() > 0) + return true; + + if (MWBase::Environment::get().getWorld()->isSwimming(actor)) + return true; + + if (getDistanceMinusHalfExtents(actor, enemy, true) <= 0.0f) + return false; + + return true; + } + + float vanillaRateSpell(const ESM::Spell* spell, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy) + { + const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); + + static const float fAIMagicSpellMult = gmst.find("fAIMagicSpellMult")->getFloat(); + static const float fAIRangeMagicSpellMult = gmst.find("fAIRangeMagicSpellMult")->getFloat(); + + float mult = fAIMagicSpellMult; + + for (std::vector::const_iterator effectIt = + spell->mEffects.mList.begin(); effectIt != spell->mEffects.mList.end(); ++effectIt) + { + if (effectIt->mArea == ESM::RT_Target) + { + if (!MWBase::Environment::get().getWorld()->isSwimming(enemy)) + mult = fAIRangeMagicSpellMult; + else + mult = 0.0f; + break; + } + } + + return MWMechanics::getSpellSuccessChance(spell, actor) * mult; + } + + float vanillaRateWeaponAndAmmo(const MWWorld::Ptr& weapon, const MWWorld::Ptr& ammo, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy) + { + const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); + + static const float fAIMeleeWeaponMult = gmst.find("fAIMeleeWeaponMult")->getFloat(); + static const float fAIMeleeArmorMult = gmst.find("fAIMeleeArmorMult")->getFloat(); + static const float fAIRangeMeleeWeaponMult = gmst.find("fAIRangeMeleeWeaponMult")->getFloat(); + + if (weapon.isEmpty()) + return 0.f; + + float skillMult = actor.getClass().getSkill(actor, weapon.getClass().getEquipmentSkill(weapon)) * 0.01f; + float chopMult = fAIMeleeWeaponMult; + float bonusDamage = 0.f; + + const ESM::Weapon* esmWeap = weapon.get()->mBase; + + if (esmWeap->mData.mType >= ESM::Weapon::MarksmanBow) + { + if (!ammo.isEmpty() && !MWBase::Environment::get().getWorld()->isSwimming(enemy)) + { + bonusDamage = ammo.get()->mBase->mData.mChop[1]; + chopMult = fAIRangeMeleeWeaponMult; + } + else + chopMult = 0.f; + } + + float chopRating = (esmWeap->mData.mChop[1] + bonusDamage) * skillMult * chopMult; + float slashRating = esmWeap->mData.mSlash[1] * skillMult * fAIMeleeWeaponMult; + float thrustRating = esmWeap->mData.mThrust[1] * skillMult * fAIMeleeWeaponMult; + + return actor.getClass().getArmorRating(actor) * fAIMeleeArmorMult + + std::max(std::max(chopRating, slashRating), thrustRating); + } + + float vanillaRateFlee(const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy) + { + const CreatureStats& stats = actor.getClass().getCreatureStats(actor); + const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); + + int flee = stats.getAiSetting(CreatureStats::AI_Flee).getModified(); + if (flee >= 100) + return flee; + + static const float fAIFleeHealthMult = gmst.find("fAIFleeHealthMult")->getFloat(); + static const float fAIFleeFleeMult = gmst.find("fAIFleeFleeMult")->getFloat(); + + float healthPercentage = (stats.getHealth().getModified() == 0.0f) + ? 1.0f : stats.getHealth().getCurrent() / stats.getHealth().getModified(); + float rating = (1.0f - healthPercentage) * fAIFleeHealthMult + flee * fAIFleeFleeMult; + + static const int iWereWolfLevelToAttack = gmst.find("iWereWolfLevelToAttack")->getInt(); + + if (enemy.getClass().isNpc() && enemy.getClass().getNpcStats(enemy).isWerewolf() && stats.getLevel() < iWereWolfLevelToAttack) + { + static const int iWereWolfFleeMod = gmst.find("iWereWolfFleeMod")->getInt(); + rating = iWereWolfFleeMod; + } + + if (rating != 0.0f) + rating += getFightDistanceBias(actor, enemy); + + return rating; + } + + bool makeFleeDecision(const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy, float antiFleeRating) + { + float fleeRating = vanillaRateFlee(actor, enemy); + if (fleeRating < 100.0f) + fleeRating = 0.0f; + + if (fleeRating > antiFleeRating) + return true; + + // Run away after summoning a creature if we have nothing to use but fists. + if (antiFleeRating == 0.0f && !actor.getClass().getCreatureStats(actor).getSummonedCreatureMap().empty()) + return true; + + return false; + } + } diff --git a/apps/openmw/mwmechanics/aicombataction.hpp b/apps/openmw/mwmechanics/aicombataction.hpp index b36413587..0f1f7dd5b 100644 --- a/apps/openmw/mwmechanics/aicombataction.hpp +++ b/apps/openmw/mwmechanics/aicombataction.hpp @@ -20,6 +20,18 @@ namespace MWMechanics virtual float getActionCooldown() { return 0.f; } virtual const ESM::Weapon* getWeapon() const { return NULL; }; virtual bool isAttackingOrSpell() const { return true; } + virtual bool isFleeing() const { return false; } + }; + + class ActionFlee : public Action + { + public: + ActionFlee() {} + virtual void prepare(const MWWorld::Ptr& actor) {} + virtual float getCombatRange (bool& isRanged) const { return 0.0f; } + virtual float getActionCooldown() { return 3.0f; } + virtual bool isAttackingOrSpell() const { return false; } + virtual bool isFleeing() const { return true; } }; class ActionSpell : public Action @@ -89,6 +101,15 @@ namespace MWMechanics float rateEffects (const ESM::EffectList& list, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); boost::shared_ptr prepareNextAction (const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); + + float getDistanceMinusHalfExtents(const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy, bool minusZDist=false); + float getMaxAttackDistance(const MWWorld::Ptr& actor); + bool canFight(const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); + + float vanillaRateSpell(const ESM::Spell* spell, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); + float vanillaRateWeaponAndAmmo(const MWWorld::Ptr& weapon, const MWWorld::Ptr& ammo, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); + float vanillaRateFlee(const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); + bool makeFleeDecision(const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy, float antiFleeRating); } #endif diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index b454f8e3a..41d8b9595 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -431,4 +431,19 @@ namespace MWMechanics return true; } + + float getFightDistanceBias(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2) + { + osg::Vec3f pos1 (actor1.getRefData().getPosition().asVec3()); + osg::Vec3f pos2 (actor2.getRefData().getPosition().asVec3()); + + float d = (pos1 - pos2).length(); + + static const int iFightDistanceBase = MWBase::Environment::get().getWorld()->getStore().get().find( + "iFightDistanceBase")->getInt(); + static const float fFightDistanceMultiplier = MWBase::Environment::get().getWorld()->getStore().get().find( + "fFightDistanceMultiplier")->getFloat(); + + return (iFightDistanceBase - fFightDistanceMultiplier * d); + } } diff --git a/apps/openmw/mwmechanics/combat.hpp b/apps/openmw/mwmechanics/combat.hpp index 7d0b3b78f..3f733763a 100644 --- a/apps/openmw/mwmechanics/combat.hpp +++ b/apps/openmw/mwmechanics/combat.hpp @@ -42,6 +42,7 @@ void applyFatigueLoss(const MWWorld::Ptr& attacker, const MWWorld::Ptr& weapon, /// e.g. If attacker is a fish, is victim in water? Or, if attacker can't swim, is victim on land? bool isEnvironmentCompatible(const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim); +float getFightDistanceBias(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2); } #endif diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index b10127f74..9661a9b3a 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -25,25 +25,11 @@ #include "autocalcspell.hpp" #include "npcstats.hpp" #include "actorutil.hpp" +#include "combat.hpp" namespace { - float getFightDistanceBias(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2) - { - osg::Vec3f pos1 (actor1.getRefData().getPosition().asVec3()); - osg::Vec3f pos2 (actor2.getRefData().getPosition().asVec3()); - - float d = (pos1 - pos2).length(); - - static const int iFightDistanceBase = MWBase::Environment::get().getWorld()->getStore().get().find( - "iFightDistanceBase")->getInt(); - static const float fFightDistanceMultiplier = MWBase::Environment::get().getWorld()->getStore().get().find( - "fFightDistanceMultiplier")->getFloat(); - - return (iFightDistanceBase - fFightDistanceMultiplier * d); - } - float getFightDispositionBias(float disposition) { static const float fFightDispMult = MWBase::Environment::get().getWorld()->getStore().get().find( diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index d04252a2c..96a56fe39 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -393,7 +393,26 @@ namespace MWWorld bool Class::isPureWaterCreature(const MWWorld::Ptr& ptr) const { - return canSwim(ptr) && !canWalk(ptr); + return canSwim(ptr) + && !isBipedal(ptr) + && !canFly(ptr) + && !canWalk(ptr); + } + + bool Class::isPureFlyingCreature(const Ptr& ptr) const + { + return canFly(ptr) + && !isBipedal(ptr) + && !canSwim(ptr) + && !canWalk(ptr); + } + + bool Class::isPureLandCreature(const Ptr& ptr) const + { + return canWalk(ptr) + && !isBipedal(ptr) + && !canFly(ptr) + && !canSwim(ptr); } bool Class::isMobile(const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 8d3f9b891..06deedc53 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -312,6 +312,8 @@ namespace MWWorld virtual bool canSwim(const MWWorld::ConstPtr& ptr) const; virtual bool canWalk(const MWWorld::ConstPtr& ptr) const; bool isPureWaterCreature(const MWWorld::Ptr& ptr) const; + bool isPureFlyingCreature(const MWWorld::Ptr& ptr) const; + bool isPureLandCreature(const MWWorld::Ptr& ptr) const; bool isMobile(const MWWorld::Ptr& ptr) const; virtual int getSkill(const MWWorld::Ptr& ptr, int skill) const; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index fce3d69db..028cc45c9 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -421,11 +421,16 @@ namespace MWWorld gmst["sBribeFail"] = ESM::Variant("Bribe Fail"); gmst["fNPCHealthBarTime"] = ESM::Variant(5.f); gmst["fNPCHealthBarFade"] = ESM::Variant(1.f); + gmst["fFleeDistance"] = ESM::Variant(3000.f); // Werewolf (BM) gmst["fWereWolfRunMult"] = ESM::Variant(1.f); gmst["fWereWolfSilverWeaponDamageMult"] = ESM::Variant(1.f); gmst["iWerewolfFightMod"] = ESM::Variant(1); + gmst["iWereWolfFleeMod"] = ESM::Variant(100); + gmst["iWereWolfLevelToAttack"] = ESM::Variant(20); + gmst["iWereWolfBounty"] = ESM::Variant(10000); + gmst["fCombatDistanceWerewolfMod"] = ESM::Variant(0.3f); std::map globals; // vanilla Morrowind does not define dayspassed. @@ -1295,7 +1300,7 @@ namespace MWWorld float terrainHeight = -std::numeric_limits::max(); if (ptr.getCell()->isExterior()) - terrainHeight = mRendering->getTerrainHeightAt(pos.asVec3()); + terrainHeight = getTerrainHeightAt(pos.asVec3()); if (pos.pos[2] < terrainHeight) pos.pos[2] = terrainHeight; @@ -3121,6 +3126,19 @@ namespace MWWorld return MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_Jail); } + float World::getTerrainHeightAt(const osg::Vec3f& worldPos) const + { + return mRendering->getTerrainHeightAt(worldPos); + } + + osg::Vec3f World::getHalfExtents(const ConstPtr& actor, bool rendering) const + { + if (rendering) + return mPhysics->getRenderingHalfExtents(actor); + else + return mPhysics->getHalfExtents(actor); + } + void World::spawnRandomCreature(const std::string &creatureList) { const ESM::CreatureLevList* list = getStore().get().find(creatureList); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index a5e250452..a9d3f3397 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -661,6 +661,12 @@ namespace MWWorld virtual float getHitDistance(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target); virtual bool isPlayerInJail() const; + + /// Return terrain height at \a worldPos position. + virtual float getTerrainHeightAt(const osg::Vec3f& worldPos) const; + + /// Return physical or rendering half extents of the given actor. + virtual osg::Vec3f getHalfExtents(const MWWorld::ConstPtr& actor, bool rendering=false) const; }; } From 2368382ea53d57a1811416f25b69607d891c07c0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 17 Nov 2016 17:51:55 +0100 Subject: [PATCH 53/94] Fix upside down rain particle texture --- apps/openmw/mwrender/sky.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index b12f4510b..fba5f17b2 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1329,7 +1329,7 @@ void SkyManager::createRain() mRainParticleSystem = new osgParticle::ParticleSystem; mRainParticleSystem->setParticleAlignment(osgParticle::ParticleSystem::FIXED); mRainParticleSystem->setAlignVectorX(osg::Vec3f(0.1,0,0)); - mRainParticleSystem->setAlignVectorY(osg::Vec3f(0,0,-1)); + mRainParticleSystem->setAlignVectorY(osg::Vec3f(0,0,1)); osg::ref_ptr stateset (mRainParticleSystem->getOrCreateStateSet()); From 7e5ba4d43514cc4125fb2adb9453d046ad096949 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Thu, 17 Nov 2016 19:43:02 +0100 Subject: [PATCH 54/94] Fix default values of some GMSTs --- apps/openmw/mwworld/worldimp.cpp | 9 +++++---- files/mygui/openmw_trade_window.layout | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 028cc45c9..cead4fc92 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -422,14 +422,15 @@ namespace MWWorld gmst["fNPCHealthBarTime"] = ESM::Variant(5.f); gmst["fNPCHealthBarFade"] = ESM::Variant(1.f); gmst["fFleeDistance"] = ESM::Variant(3000.f); + gmst["sMaxSale"] = ESM::Variant("Max Sale"); // Werewolf (BM) - gmst["fWereWolfRunMult"] = ESM::Variant(1.f); - gmst["fWereWolfSilverWeaponDamageMult"] = ESM::Variant(1.f); - gmst["iWerewolfFightMod"] = ESM::Variant(1); + gmst["fWereWolfRunMult"] = ESM::Variant(1.3f); + gmst["fWereWolfSilverWeaponDamageMult"] = ESM::Variant(2.f); + gmst["iWerewolfFightMod"] = ESM::Variant(100); gmst["iWereWolfFleeMod"] = ESM::Variant(100); gmst["iWereWolfLevelToAttack"] = ESM::Variant(20); - gmst["iWereWolfBounty"] = ESM::Variant(10000); + gmst["iWereWolfBounty"] = ESM::Variant(1000); gmst["fCombatDistanceWerewolfMod"] = ESM::Variant(0.3f); std::map globals; diff --git a/files/mygui/openmw_trade_window.layout b/files/mygui/openmw_trade_window.layout index b2017661b..6d5dfb89b 100644 --- a/files/mygui/openmw_trade_window.layout +++ b/files/mygui/openmw_trade_window.layout @@ -61,7 +61,7 @@ - + From 3adf69f91e8d9b4f1fe9c07ab7572586f8d1f4d3 Mon Sep 17 00:00:00 2001 From: Joakim Berg Date: Sat, 19 Nov 2016 14:34:35 +0100 Subject: [PATCH 55/94] Update convert_bump_mapped_mods.rst --- docs/source/openmw-mods/convert_bump_mapped_mods.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/openmw-mods/convert_bump_mapped_mods.rst b/docs/source/openmw-mods/convert_bump_mapped_mods.rst index 37a772f13..791e77353 100644 --- a/docs/source/openmw-mods/convert_bump_mapped_mods.rst +++ b/docs/source/openmw-mods/convert_bump_mapped_mods.rst @@ -22,7 +22,7 @@ General introduction to normal map conversion This page has general information and tutorials on how normal mapping works in OpenMW and how you can make mods using the old fake normal mapping technique (such as `Netch Bump mapped`_ and `Hlaalu Bump mapped`_, and maybe the most (in)famous one to give shiny rocks in OpenMW, the mod `On the Rocks`_!, featured in MGSO and Morrowind Rebirth) work in OpenMW. -*Note:* The conversion made in the `Converting Apel's Various Things - Sacks`_-part of this tutorial require the use of the application NifSkope, which is a Windows-only application. Please inform us if you get that application to work on other OS:es via Wine or similar. +*Note:* The conversion made in the `Converting Apel's Various Things - Sacks`_-part of this tutorial require the use of the application NifSkope. There are binaries available for Windows, but not for Mac or Linux. Reports say that NifSkope versions 1.X will compile on Linux as long as you have Qt packages installed, while the later 2.X versions will not compile. *Another note:* I will use the terms bump mapping and normal mapping simultaneously. Normal mapping is one form of bump mapping. In other words, normal mapping is bump mapping, but bump mapping isn't necessarily normal mapping. There are several techniques for bump mapping, and normal mapping is the most common one today. @@ -160,7 +160,7 @@ Converting Apel's Various Things - Sacks In part one of this tutorial, we converted a mod that only included modified Morrowind model (``.nif``) files so that the normal maps could be loaded in Morrowind with MCP. We ignored those model files since they are not needed with OpenMW. In this tutorial however, we will convert a mod that includes new, custom made models. In other words, we cannot just ignore those files this time. -Before we begin, you need to know that we will be needing a Windows OS for this, unless you can get the application we will be using to work in Wine or something similar. +Before we begin, you need to know that unless you want to build the NifSkope application from source yourself, you will be needing a Windows OS to do this part, since the application only has binaries available for Windows. Tutorial - MCP, Part 2 ********************** @@ -170,7 +170,7 @@ The sacks included in Apel's `Various Things - Sacks`_ come in two versions – #. Start by downloading Apel's `Various Things - Sacks`_ from Nexus. #. Once downloaded, install it the way you'd normally install your mods (**Pro tip**: Install using OpenMW's `Multiple data folders`_ function!). #. Now, if you ran the mod right away, your sacks will be made out of lead_. This is because the normal map is loaded as an environment map which MCP fixes so that it looks less shiny. We don't use MCP, so therefore, it looks kind of like the shack was made out of lead. -#. We need to fix this by removing some tags in the model files. You need to download NifSkope_ for this, which, again, is a Windows-only application. +#. We need to fix this by removing some tags in the model files. You need to download NifSkope_ for this, which, again, only have binaries available for Windows. #. Go the place where you installed the mod and go to ``./Meshes/o/`` to find the model files. - If you installed the mod like I suggested, finding the files will be easy as a pie, but if you installed it by dropping everything into your main Morrowind Data Files folder, then you'll have to scroll a lot to find them. Check the mod's zip file for the file names of the models if this is the case. The same thing applies to when fixing the textures. #. Open up each of the models in NifSkope and look for these certain blocks_: From 8f91732b09ecb941e5fdb5acdbdbbc1e73216418 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Fri, 18 Nov 2016 17:59:05 +0100 Subject: [PATCH 56/94] Show starting abilities, powers and spells in stat-review window (Fixes #2410) --- apps/openmw/mwgui/charactercreation.cpp | 6 + apps/openmw/mwgui/charactercreation.hpp | 2 + apps/openmw/mwgui/review.cpp | 118 +++++++++++++++++- apps/openmw/mwgui/review.hpp | 10 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 3 + apps/openmw/mwmechanics/autocalcspell.cpp | 73 +++++++++++ apps/openmw/mwmechanics/autocalcspell.hpp | 2 + .../mwmechanics/mechanicsmanagerimp.cpp | 65 +--------- 8 files changed, 210 insertions(+), 69 deletions(-) diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index 9a1b43678..d72e6627f 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -132,6 +132,12 @@ namespace MWGui mReviewDialog->configureSkills(major, minor); } + void CharacterCreation::onFrame(float duration) + { + if (mReviewDialog) + mReviewDialog->onFrame(duration); + } + void CharacterCreation::spawnDialog(const char id) { try diff --git a/apps/openmw/mwgui/charactercreation.hpp b/apps/openmw/mwgui/charactercreation.hpp index 75f3a7016..0130222f3 100644 --- a/apps/openmw/mwgui/charactercreation.hpp +++ b/apps/openmw/mwgui/charactercreation.hpp @@ -50,6 +50,8 @@ namespace MWGui void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value); void configureSkills (const SkillList& major, const SkillList& minor); + void onFrame(float duration); + private: osg::Group* mParent; Resource::ResourceSystem* mResourceSystem; diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index d7d6c3cdb..d2971a093 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -10,6 +10,7 @@ #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwmechanics/autocalcspell.hpp" #include "tooltips.hpp" @@ -29,7 +30,8 @@ namespace MWGui const int ReviewDialog::sLineHeight = 18; ReviewDialog::ReviewDialog() - : WindowModal("openmw_chargen_review.layout") + : WindowModal("openmw_chargen_review.layout"), + mUpdateSkillArea(false) { // Centre dialog center(); @@ -102,7 +104,16 @@ namespace MWGui void ReviewDialog::open() { WindowModal::open(); - updateSkillArea(); + mUpdateSkillArea = true; + } + + void ReviewDialog::onFrame(float /*duration*/) + { + if (mUpdateSkillArea) + { + updateSkillArea(); + mUpdateSkillArea = false; + } } void ReviewDialog::setPlayerName(const std::string &name) @@ -121,6 +132,8 @@ namespace MWGui ToolTips::createRaceToolTip(mRaceWidget, race); mRaceWidget->setCaption(race->mName); } + + mUpdateSkillArea = true; } void ReviewDialog::setClass(const ESM::Class& class_) @@ -141,6 +154,8 @@ namespace MWGui mBirthSignWidget->setCaption(sign->mName); ToolTips::createBirthsignToolTip(mBirthSignWidget, mBirthSignId); } + + mUpdateSkillArea = true; } void ReviewDialog::setHealth(const MWMechanics::DynamicStat& value) @@ -170,7 +185,11 @@ namespace MWGui if (attr == mAttributeWidgets.end()) return; - attr->second->setAttributeValue(value); + if (attr->second->getAttributeValue() != value) + { + attr->second->setAttributeValue(value); + mUpdateSkillArea = true; + } } void ReviewDialog::setSkillValue(ESM::Skill::SkillEnum skillId, const MWMechanics::SkillValue& value) @@ -191,6 +210,7 @@ namespace MWGui widget->_setWidgetState(state); } + mUpdateSkillArea = true; } void ReviewDialog::configureSkills(const std::vector& major, const std::vector& minor) @@ -211,7 +231,7 @@ namespace MWGui mMiscSkills.push_back(skill); } - updateSkillArea(); + mUpdateSkillArea = true; } void ReviewDialog::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) @@ -245,7 +265,7 @@ namespace MWGui skillNameWidget->setCaption(text); skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); - skillValueWidget = mSkillView->createWidget("SandTextRight", coord2, MyGUI::Align::Top | MyGUI::Align::Right); + skillValueWidget = mSkillView->createWidget("SandTextRight", coord2, MyGUI::Align::Default); skillValueWidget->setCaption(value); skillValueWidget->_setWidgetState(state); skillValueWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); @@ -273,6 +293,20 @@ namespace MWGui coord2.top += sLineHeight; } + void ReviewDialog::addItem(const ESM::Spell* spell, MyGUI::IntCoord& coord1, MyGUI::IntCoord& coord2) + { + Widgets::MWSpellPtr widget = mSkillView->createWidget("MW_StatName", coord1 + MyGUI::IntSize(coord2.width, 0), MyGUI::Align::Default); + widget->setSpellId(spell->mId); + widget->setUserString("ToolTipType", "Spell"); + widget->setUserString("Spell", spell->mId); + widget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); + + mSkillWidgets.push_back(widget); + + coord1.top += sLineHeight; + coord2.top += sLineHeight; + } + void ReviewDialog::addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) { // Add a line separator if there are items above @@ -332,6 +366,80 @@ namespace MWGui if (!mMiscSkills.empty()) addSkills(mMiscSkills, "sSkillClassMisc", "Misc Skills", coord1, coord2); + // starting spells + std::vector spells; + + const ESM::Race* race = NULL; + if (!mRaceId.empty()) + race = MWBase::Environment::get().getWorld()->getStore().get().find(mRaceId); + + int skills[ESM::Skill::Length]; + for (int i=0; isecond.getBase(); + + int attributes[ESM::Attribute::Length]; + for (int i=0; igetAttributeValue().getBase(); + + std::vector selectedSpells = MWMechanics::autoCalcPlayerSpells(skills, attributes, race); + for (std::vector::iterator iter = selectedSpells.begin(); iter != selectedSpells.end(); ++iter) + { + std::string lower = Misc::StringUtils::lowerCase(*iter); + if (std::find(spells.begin(), spells.end(), lower) == spells.end()) + spells.push_back(lower); + } + + if (race) + { + for (std::vector::const_iterator iter = race->mPowers.mList.begin(); + iter != race->mPowers.mList.end(); ++iter) + { + std::string lower = Misc::StringUtils::lowerCase(*iter); + if (std::find(spells.begin(), spells.end(), lower) == spells.end()) + spells.push_back(lower); + } + } + + if (!mBirthSignId.empty()) + { + const ESM::BirthSign* sign = MWBase::Environment::get().getWorld()->getStore().get().find(mBirthSignId); + for (std::vector::const_iterator iter = sign->mPowers.mList.begin(); + iter != sign->mPowers.mList.end(); ++iter) + { + std::string lower = Misc::StringUtils::lowerCase(*iter); + if (std::find(spells.begin(), spells.end(), lower) == spells.end()) + spells.push_back(lower); + } + } + + if (!mSkillWidgets.empty()) + addSeparator(coord1, coord2); + addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString("sTypeAbility", "Abilities"), coord1, coord2); + for (std::vector::const_iterator iter = spells.begin(); iter != spells.end(); ++iter) + { + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(*iter); + if (spell->mData.mType == ESM::Spell::ST_Ability) + addItem(spell, coord1, coord2); + } + + addSeparator(coord1, coord2); + addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString("sTypePower", "Powers"), coord1, coord2); + for (std::vector::const_iterator iter = spells.begin(); iter != spells.end(); ++iter) + { + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(*iter); + if (spell->mData.mType == ESM::Spell::ST_Power) + addItem(spell, coord1, coord2); + } + + addSeparator(coord1, coord2); + addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString("sTypeSpell", "Spells"), coord1, coord2); + for (std::vector::const_iterator iter = spells.begin(); iter != spells.end(); ++iter) + { + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(*iter); + if (spell->mData.mType == ESM::Spell::ST_Spell) + addItem(spell, coord1, coord2); + } + // Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the scrollbar is hidden mSkillView->setVisibleVScroll(false); mSkillView->setCanvasSize (mSkillView->getWidth(), std::max(mSkillView->getHeight(), coord1.top)); diff --git a/apps/openmw/mwgui/review.hpp b/apps/openmw/mwgui/review.hpp index 111d7de1d..5d57aeb8b 100644 --- a/apps/openmw/mwgui/review.hpp +++ b/apps/openmw/mwgui/review.hpp @@ -6,6 +6,11 @@ #include "windowbase.hpp" #include "widgets.hpp" +namespace ESM +{ + class Spell; +} + namespace MWGui { class WindowManager; @@ -42,6 +47,8 @@ namespace MWGui virtual void open(); + void onFrame(float duration); + // Events typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; typedef MyGUI::delegates::CMultiDelegate1 EventHandle_Int; @@ -75,6 +82,7 @@ namespace MWGui void addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); MyGUI::TextBox* addValueItem(const std::string& text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void addItem(const std::string& text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); + void addItem(const ESM::Spell* spell, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void updateSkillArea(); static const int sLineHeight; @@ -92,6 +100,8 @@ namespace MWGui std::string mName, mRaceId, mBirthSignId; ESM::Class mKlass; std::vector mSkillWidgets; //< Skills and other information + + bool mUpdateSkillArea; }; } #endif diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 5c41fd55b..f679da651 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1006,6 +1006,9 @@ namespace MWGui mScreenFader->update(frameDuration); mDebugWindow->onFrame(frameDuration); + + if (mCharGen) + mCharGen->onFrame(frameDuration); } void WindowManager::changeCell(const MWWorld::CellStore* cell) diff --git a/apps/openmw/mwmechanics/autocalcspell.cpp b/apps/openmw/mwmechanics/autocalcspell.cpp index b798ff5dc..af814edb0 100644 --- a/apps/openmw/mwmechanics/autocalcspell.cpp +++ b/apps/openmw/mwmechanics/autocalcspell.cpp @@ -141,6 +141,79 @@ namespace MWMechanics return selectedSpells; } + std::vector autoCalcPlayerSpells(const int* actorSkills, const int* actorAttributes, const ESM::Race* race) + { + const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); + + static const float fPCbaseMagickaMult = esmStore.get().find("fPCbaseMagickaMult")->getFloat(); + + float baseMagicka = fPCbaseMagickaMult * actorAttributes[ESM::Attribute::Intelligence]; + bool reachedLimit = false; + const ESM::Spell* weakestSpell = NULL; + int minCost = INT_MAX; + + std::vector selectedSpells; + + + const MWWorld::Store &spells = + esmStore.get(); + for (MWWorld::Store::iterator iter = spells.begin(); iter != spells.end(); ++iter) + { + const ESM::Spell* spell = &*iter; + + if (spell->mData.mType != ESM::Spell::ST_Spell) + continue; + if (!(spell->mData.mFlags & ESM::Spell::F_PCStart)) + continue; + 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()) + continue; + if (baseMagicka < spell->mData.mCost) + continue; + + static const float fAutoPCSpellChance = esmStore.get().find("fAutoPCSpellChance")->getFloat(); + if (calcAutoCastChance(spell, actorSkills, actorAttributes, -1) < fAutoPCSpellChance) + continue; + + if (!attrSkillCheck(spell, actorSkills, actorAttributes)) + continue; + + selectedSpells.push_back(spell->mId); + + if (reachedLimit) + { + std::vector::iterator it = std::find(selectedSpells.begin(), selectedSpells.end(), weakestSpell->mId); + if (it != selectedSpells.end()) + selectedSpells.erase(it); + + minCost = INT_MAX; + for (std::vector::iterator weakIt = selectedSpells.begin(); weakIt != selectedSpells.end(); ++weakIt) + { + const ESM::Spell* testSpell = esmStore.get().find(*weakIt); + if (testSpell->mData.mCost < minCost) + { + minCost = testSpell->mData.mCost; + weakestSpell = testSpell; + } + } + } + else + { + if (spell->mData.mCost < minCost) + { + weakestSpell = spell; + minCost = weakestSpell->mData.mCost; + } + static const unsigned int iAutoPCSpellMax = esmStore.get().find("iAutoPCSpellMax")->getInt(); + if (selectedSpells.size() == iAutoPCSpellMax) + reachedLimit = true; + } + } + + return selectedSpells; + } + bool attrSkillCheck (const ESM::Spell* spell, const int* actorSkills, const int* actorAttributes) { const std::vector& effects = spell->mEffects.mList; diff --git a/apps/openmw/mwmechanics/autocalcspell.hpp b/apps/openmw/mwmechanics/autocalcspell.hpp index 1912c75c4..6bf3e834b 100644 --- a/apps/openmw/mwmechanics/autocalcspell.hpp +++ b/apps/openmw/mwmechanics/autocalcspell.hpp @@ -16,6 +16,8 @@ namespace MWMechanics std::vector autoCalcNpcSpells(const int* actorSkills, const int* actorAttributes, const ESM::Race* race); +std::vector autoCalcPlayerSpells(const int* actorSkills, const int* actorAttributes, const ESM::Race* race); + // Helpers bool attrSkillCheck (const ESM::Spell* spell, const int* actorSkills, const int* actorAttributes); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 9661a9b3a..4e57d9771 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -198,15 +198,6 @@ namespace MWMechanics } // F_PCStart spells - static const float fPCbaseMagickaMult = esmStore.get().find("fPCbaseMagickaMult")->getFloat(); - - float baseMagicka = fPCbaseMagickaMult * creatureStats.getAttribute(ESM::Attribute::Intelligence).getBase(); - bool reachedLimit = false; - const ESM::Spell* weakestSpell = NULL; - int minCost = INT_MAX; - - std::vector selectedSpells; - const ESM::Race* race = NULL; if (mRaceSelected) race = esmStore.get().find(player->mRace); @@ -219,61 +210,7 @@ namespace MWMechanics for (int i=0; i &spells = - esmStore.get(); - for (MWWorld::Store::iterator iter = spells.begin(); iter != spells.end(); ++iter) - { - const ESM::Spell* spell = &*iter; - - if (spell->mData.mType != ESM::Spell::ST_Spell) - continue; - if (!(spell->mData.mFlags & ESM::Spell::F_PCStart)) - continue; - 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()) - continue; - if (baseMagicka < spell->mData.mCost) - continue; - - static const float fAutoPCSpellChance = esmStore.get().find("fAutoPCSpellChance")->getFloat(); - if (calcAutoCastChance(spell, skills, attributes, -1) < fAutoPCSpellChance) - continue; - - if (!attrSkillCheck(spell, skills, attributes)) - continue; - - selectedSpells.push_back(spell->mId); - - if (reachedLimit) - { - std::vector::iterator it = std::find(selectedSpells.begin(), selectedSpells.end(), weakestSpell->mId); - if (it != selectedSpells.end()) - selectedSpells.erase(it); - - minCost = INT_MAX; - for (std::vector::iterator weakIt = selectedSpells.begin(); weakIt != selectedSpells.end(); ++weakIt) - { - const ESM::Spell* testSpell = esmStore.get().find(*weakIt); - if (testSpell->mData.mCost < minCost) - { - minCost = testSpell->mData.mCost; - weakestSpell = testSpell; - } - } - } - else - { - if (spell->mData.mCost < minCost) - { - weakestSpell = spell; - minCost = weakestSpell->mData.mCost; - } - static const unsigned int iAutoPCSpellMax = esmStore.get().find("iAutoPCSpellMax")->getInt(); - if (selectedSpells.size() == iAutoPCSpellMax) - reachedLimit = true; - } - } + std::vector selectedSpells = autoCalcPlayerSpells(skills, attributes, race); for (std::vector::iterator it = selectedSpells.begin(); it != selectedSpells.end(); ++it) creatureStats.getSpells().add(*it); From e823cbf018bd0c8406951d3cd2a2f921b886dc63 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Nov 2016 23:20:20 +0100 Subject: [PATCH 57/94] Fix incorrect priority of animation sources (Bug #3626) --- apps/openmw/mwrender/npcanimation.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 8574939af..e031afdff 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -503,10 +503,10 @@ void NpcAnimation::updateNpcBase() if(!isWerewolf) { - if(Misc::StringUtils::lowerCase(mNpc->mRace).find("argonian") != std::string::npos) - addAnimSource("meshes\\xargonian_swimkna.nif"); if(mNpc->mModel.length() > 0) addAnimSource(Misc::ResourceHelpers::correctActorModelPath("meshes\\" + mNpc->mModel, mResourceSystem->getVFS())); + if(Misc::StringUtils::lowerCase(mNpc->mRace).find("argonian") != std::string::npos) + addAnimSource("meshes\\xargonian_swimkna.nif"); } } else From f51e06bc473592880bafc3ac33be0f12c1f67846 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 19 Nov 2016 23:47:33 +0100 Subject: [PATCH 58/94] Recreate shaders if necessary when the NpcAnimation is rebuilt This fixes certain equipment losing the 'invisibility' effect after a view-mode switch with shaders enabled. Because the initial build of shaders done by the resource manager is not aware of the override state in the NpcAnimation's object root, we have to build new shaders here. --- apps/openmw/mwrender/npcanimation.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index e031afdff..d9dd1a89e 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -403,6 +403,9 @@ void NpcAnimation::rebuild() { updateNpcBase(); + if (mAlpha != 1.f) + mResourceSystem->getSceneManager()->recreateShaders(mObjectRoot); + MWBase::Environment::get().getMechanicsManager()->forceStateUpdate(mPtr); } From 0e429ae41d9a768a7ebfc73750794c92dee8cf70 Mon Sep 17 00:00:00 2001 From: Allofich Date: Tue, 15 Nov 2016 00:20:17 +0900 Subject: [PATCH 59/94] Make water walking mechanics closer to original MW --- apps/openmw/mwmechanics/spellcasting.cpp | 2 +- apps/openmw/mwmechanics/spellcasting.hpp | 2 ++ apps/openmw/mwphysics/physicssystem.cpp | 31 +++++++++++------------- apps/openmw/mwphysics/physicssystem.hpp | 2 ++ apps/openmw/mwworld/inventorystore.cpp | 7 ++++-- apps/openmw/mwworld/worldimp.cpp | 15 ++++++++---- 6 files changed, 34 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index aaed6712e..5c5fc3899 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -223,7 +223,7 @@ namespace MWMechanics return 1 - resistance / 100.f; } - /// Check if the given affect can be applied to the target. If \a castByPlayer, emits a message box on failure. + /// Check if the given effect can be applied to the target. If \a castByPlayer, emits a message box on failure. bool checkEffectTarget (int effectId, const MWWorld::Ptr& target, const MWWorld::Ptr& caster, bool castByPlayer) { switch (effectId) diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index 85277401f..852ae79dc 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -59,6 +59,8 @@ namespace MWMechanics float getEffectMultiplier(short effectId, const MWWorld::Ptr& actor, const MWWorld::Ptr& caster, const ESM::Spell* spell = NULL, const MagicEffects* effects = NULL); + bool checkEffectTarget (int effectId, const MWWorld::Ptr& target, const MWWorld::Ptr& caster, bool castByPlayer); + int getEffectiveEnchantmentCastCost (float castCost, const MWWorld::Ptr& actor); void effectTick(CreatureStats& creatureStats, const MWWorld::Ptr& actor, const MWMechanics::EffectKey& effectKey, float magnitude); diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 21867591c..cc3ba40e1 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -985,6 +985,18 @@ namespace MWPhysics } } + bool PhysicsSystem::canMoveToWaterSurface(const MWWorld::ConstPtr &actor, const float waterlevel) + { + const Actor* physicActor = getActor(actor); + const float halfZ = physicActor->getHalfExtents().z(); + const osg::Vec3f actorPosition = physicActor->getPosition(); + const osg::Vec3f startingPosition(actorPosition.x(), actorPosition.y(), actorPosition.z() + halfZ); + const osg::Vec3f destinationPosition(actorPosition.x(), actorPosition.y(), waterlevel + halfZ); + ActorTracer tracer; + tracer.doTrace(physicActor->getCollisionObject(), startingPosition, destinationPosition, mCollisionWorld); + return (tracer.mFraction >= 1.0f); + } + osg::Vec3f PhysicsSystem::getHalfExtents(const MWWorld::ConstPtr &actor) const { const Actor* physactor = getActor(actor); @@ -1326,25 +1338,10 @@ namespace MWPhysics { if (!world->isUnderwater(iter->first.getCell(), osg::Vec3f(iter->first.getRefData().getPosition().asVec3()))) waterCollision = true; - else if (physicActor->getCollisionMode()) + else if (physicActor->getCollisionMode() && canMoveToWaterSurface(iter->first, waterlevel)) { - const float halfZ = physicActor->getHalfExtents().z(); const osg::Vec3f actorPosition = physicActor->getPosition(); - const osg::Vec3f startingPosition(actorPosition.x(), actorPosition.y(), actorPosition.z() + halfZ); - const osg::Vec3f destinationPosition(actorPosition.x(), actorPosition.y(), waterlevel + halfZ); - ActorTracer tracer; - tracer.doTrace(physicActor->getCollisionObject(), startingPosition, destinationPosition, mCollisionWorld); - if (tracer.mFraction >= 1.0f) - { - waterCollision = true; - physicActor->setPosition(osg::Vec3f(actorPosition.x(), actorPosition.y(), waterlevel)); - } - else - { - //Remove the effect to remove the performance hit of casting in a weird spot - //probably makes that Tribunal quest where the water rises a bit safer - iter->first.getClass().getCreatureStats(iter->first).getActiveSpells().purgeEffect(ESM::MagicEffect::WaterWalking); - } + physicActor->setPosition(osg::Vec3f(actorPosition.x(), actorPosition.y(), waterlevel)); } } physicActor->setCanWaterWalk(waterCollision); diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index c12672285..215355316 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -123,6 +123,8 @@ namespace MWPhysics bool isOnGround (const MWWorld::Ptr& actor); + bool canMoveToWaterSurface (const MWWorld::ConstPtr &actor, const float waterlevel); + /// Get physical half extents (scaled) of the given actor. osg::Vec3f getHalfExtents(const MWWorld::ConstPtr& actor) const; diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 98cbad742..9f8bae280 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -515,8 +515,8 @@ void MWWorld::InventoryStore::updateMagicEffects(const Ptr& actor) MWBase::Environment::get().getWorld()->getStore().get().find ( effectIt->mEffectID); - // Fully resisted? - if (params[i].mMultiplier == 0) + // Fully resisted or can't be applied to target? + if (params[i].mMultiplier == 0 || !MWMechanics::checkEffectTarget(effectIt->mEffectID, actor, actor, actor == MWMechanics::getPlayer())) continue; float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * params[i].mRandom; @@ -770,6 +770,9 @@ void MWWorld::InventoryStore::visitEffectSources(MWMechanics::EffectSourceVisito for (std::vector::const_iterator effectIt (enchantment.mEffects.mList.begin()); effectIt!=enchantment.mEffects.mList.end(); ++effectIt) { + // Don't get spell icon display information for enchantments that weren't actually applied + if (mMagicEffects.get(MWMechanics::EffectKey(*effectIt)).getMagnitude() == 0) + continue; const EffectParams& params = mPermanentMagicEffectMagnitudes[(**iter).getCellRef().getRefId()][i]; float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * params.mRandom; magnitude *= params.mMultiplier; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index fce3d69db..482e1a709 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2078,11 +2078,16 @@ namespace MWWorld if (!cell->getCell()->hasWater()) return true; - // Based on observations from the original engine, the depth - // limit at which water walking can still be cast on a target - // in water appears to be the same as what the highest swimmable - // z position would be with SwimHeightScale + 1. - return !isUnderwater(target, mSwimHeightScale + 1); + float waterlevel = cell->getWaterLevel(); + + // SwimHeightScale affects the upper z position an actor can swim to + // while in water. Based on observation from the original engine, + // the upper z position you get with a +1 SwimHeightScale is the depth + // limit for being able to cast water walking on an underwater target. + if (isUnderwater(target, mSwimHeightScale + 1) || (isUnderwater(cell, target.getRefData().getPosition().asVec3()) && !mPhysics->canMoveToWaterSurface(target, waterlevel))) + return false; // not castable if too deep or if not enough room to move actor to surface + else + return true; } bool World::isOnGround(const MWWorld::Ptr &ptr) const From c1e52bbcf7c4d7733e9b86d9a8125e4444bdb3f3 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sun, 20 Nov 2016 15:10:37 +0100 Subject: [PATCH 60/94] Fix -Wmismatched-tags clang warning --- apps/openmw/mwgui/review.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/review.hpp b/apps/openmw/mwgui/review.hpp index 5d57aeb8b..f21f2fa9d 100644 --- a/apps/openmw/mwgui/review.hpp +++ b/apps/openmw/mwgui/review.hpp @@ -8,7 +8,7 @@ namespace ESM { - class Spell; + struct Spell; } namespace MWGui From c82df2553cb6397769f1e56ded4845ba71ca5e3c Mon Sep 17 00:00:00 2001 From: Allofich Date: Sun, 20 Nov 2016 23:54:30 +0900 Subject: [PATCH 61/94] Allow deleting spells that have the "always succeeds" flag (Fixes #3627) --- apps/openmw/mwgui/spellwindow.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 8422bb33f..7c12a8fc2 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -11,6 +11,7 @@ #include "../mwworld/inventorystore.hpp" #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwworld/player.hpp" #include "../mwmechanics/spellcasting.hpp" #include "../mwmechanics/spells.hpp" @@ -122,8 +123,15 @@ namespace MWGui const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(spellId); - if (spell->mData.mFlags & ESM::Spell::F_Always - || spell->mData.mType == ESM::Spell::ST_Power) + MWWorld::Ptr player = MWMechanics::getPlayer(); + std::string raceId = player.get()->mBase->mRace; + const std::string& signId = + MWBase::Environment::get().getWorld()->getPlayer().getBirthSign(); + const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(raceId); + const ESM::BirthSign* birthsign = MWBase::Environment::get().getWorld()->getStore().get().find(signId); + + // can't delete racial spells, birthsign spells or powers + if (race->mPowers.exists(spell->mId) || birthsign->mPowers.exists(spell->mId) || spell->mData.mType == ESM::Spell::ST_Power) { MWBase::Environment::get().getWindowManager()->messageBox("#{sDeleteSpellError}"); } From 16a913c54984c408a24b143edf56348f02d1e721 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 20 Nov 2016 18:46:58 +0100 Subject: [PATCH 62/94] Add emission of water ripple particles for water-walking actors (Fixes #3608) --- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwrender/ripplesimulation.cpp | 7 +++---- apps/openmw/mwworld/worldimp.cpp | 2 +- apps/openmw/mwworld/worldimp.hpp | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 74bc0b7fd..c9c4a22a7 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -548,7 +548,7 @@ namespace MWBase /// Resets all actors in the current active cells to their original location within that cell. virtual void resetActors() = 0; - virtual bool isWalkingOnWater (const MWWorld::ConstPtr& actor) = 0; + virtual bool isWalkingOnWater (const MWWorld::ConstPtr& actor) const = 0; /// Return a vector aiming the actor's weapon towards a target. /// @note The length of the vector is the distance between actor and target. diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index 56302077e..00082f033 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -117,6 +117,7 @@ RippleSimulation::~RippleSimulation() void RippleSimulation::update(float dt) { + const MWBase::World* world = MWBase::Environment::get().getWorld(); for (std::vector::iterator it=mEmitters.begin(); it !=mEmitters.end(); ++it) { if (it->mPtr == MWBase::Environment::get().getWorld ()->getPlayerPtr()) @@ -128,10 +129,8 @@ void RippleSimulation::update(float dt) osg::Vec3f currentPos (it->mPtr.getRefData().getPosition().asVec3()); - if ( (currentPos - it->mLastEmitPosition).length() > 10 - // Only emit when close to the water surface, not above it and not too deep in the water - && MWBase::Environment::get().getWorld ()->isUnderwater (it->mPtr.getCell(), it->mPtr.getRefData().getPosition().asVec3()) - && !MWBase::Environment::get().getWorld()->isSubmerged(it->mPtr)) + bool shouldEmit = ( world->isUnderwater (it->mPtr.getCell(), it->mPtr.getRefData().getPosition().asVec3()) && !world->isSubmerged(it->mPtr) ) || world->isWalkingOnWater(it->mPtr); + if ( shouldEmit && (currentPos - it->mLastEmitPosition).length() > 10 ) { it->mLastEmitPosition = currentPos; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5f652650f..ccd2a25e0 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3313,7 +3313,7 @@ namespace MWWorld } } - bool World::isWalkingOnWater(const ConstPtr &actor) + bool World::isWalkingOnWater(const ConstPtr &actor) const { const MWPhysics::Actor* physicActor = mPhysics->getActor(actor); if (physicActor && physicActor->isWalkingOnWater()) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index a9d3f3397..0d91bc641 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -651,7 +651,7 @@ namespace MWWorld /// Resets all actors in the current active cells to their original location within that cell. virtual void resetActors(); - virtual bool isWalkingOnWater (const MWWorld::ConstPtr& actor); + virtual bool isWalkingOnWater (const MWWorld::ConstPtr& actor) const; /// Return a vector aiming the actor's weapon towards a target. /// @note The length of the vector is the distance between actor and target. From 505250f6ecc83bfd62830065d21a46687f1e2bbf Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 22 Nov 2016 15:46:32 +0100 Subject: [PATCH 63/94] Do not use architecture dependent type size_t in esm format (Fixes #3633) --- components/esm/animationstate.cpp | 13 ++++++++++++- components/esm/animationstate.hpp | 3 ++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/components/esm/animationstate.cpp b/components/esm/animationstate.cpp index 79dcad757..37ea0b186 100644 --- a/components/esm/animationstate.cpp +++ b/components/esm/animationstate.cpp @@ -21,7 +21,18 @@ namespace ESM anim.mGroup = esm.getHString(); esm.getHNOT(anim.mTime, "TIME"); esm.getHNOT(anim.mAbsolute, "ABST"); - esm.getHNT(anim.mLoopCount, "COUN"); + + esm.getSubNameIs("COUN"); + // workaround bug in earlier version where size_t was used + esm.getSubHeader(); + if (esm.getSubSize() == 8) + esm.getT(anim.mLoopCount); + else + { + uint32_t loopcount; + esm.getT(loopcount); + anim.mLoopCount = (uint64_t) loopcount; + } mScriptedAnims.push_back(anim); } diff --git a/components/esm/animationstate.hpp b/components/esm/animationstate.hpp index ce2c437df..2a19eff63 100644 --- a/components/esm/animationstate.hpp +++ b/components/esm/animationstate.hpp @@ -3,6 +3,7 @@ #include #include +#include namespace ESM { @@ -20,7 +21,7 @@ namespace ESM std::string mGroup; float mTime; bool mAbsolute; - size_t mLoopCount; + uint64_t mLoopCount; }; typedef std::vector ScriptedAnimations; From b6d02d9b148720018ede637024f5a284e4aac3ad Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 22 Nov 2016 16:37:49 +0100 Subject: [PATCH 64/94] Fix order of operations when undoing werewolf transformation of an NPC --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 4e57d9771..958869964 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1531,27 +1531,23 @@ namespace MWMechanics player->restoreSkillsAttributes(); } - // Equipped items other than WerewolfRobe may reference bones that do not even - // exist with the werewolf object root, so make sure to unequip all items - // *before* we become a werewolf. - MWWorld::InventoryStore& invStore = actor.getClass().getInventoryStore(actor); - invStore.unequipAll(actor); - // Werewolfs can not cast spells, so we need to unset the prepared spell if there is one. if (npcStats.getDrawState() == MWMechanics::DrawState_Spell) npcStats.setDrawState(MWMechanics::DrawState_Nothing); npcStats.setWerewolf(werewolf); + MWWorld::InventoryStore &inv = actor.getClass().getInventoryStore(actor); + if(werewolf) { - MWWorld::InventoryStore &inv = actor.getClass().getInventoryStore(actor); - + inv.unequipAll(actor); inv.equip(MWWorld::InventoryStore::Slot_Robe, inv.ContainerStore::add("werewolfrobe", 1, actor), actor); } else { - actor.getClass().getContainerStore(actor).remove("werewolfrobe", 1, actor); + inv.unequipSlot(MWWorld::InventoryStore::Slot_Robe, actor); + inv.ContainerStore::remove("werewolfrobe", 1, actor); } if(actor == player->getPlayer()) From 46a3244107eac71182d0ea769267b7ab8f0a5577 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Tue, 22 Nov 2016 18:18:20 +0100 Subject: [PATCH 65/94] Fix thrown weapon sources being used to apply on strike enchantments (Fixes #3634) --- apps/openmw/mwworld/projectilemanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 2f8576bda..35df52a18 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -369,7 +369,7 @@ namespace MWWorld // Try to get a Ptr to the bow that was used. It might no longer exist. MWWorld::Ptr bow = projectileRef.getPtr(); - if (!caster.isEmpty()) + if (!caster.isEmpty() && it->mIdArrow != it->mBowId) { MWWorld::InventoryStore& inv = caster.getClass().getInventoryStore(caster); MWWorld::ContainerStoreIterator invIt = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); From 762460f04200afbc7a95011b4d684be0838fd52d Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 22 Nov 2016 22:41:08 +0100 Subject: [PATCH 66/94] Use negative count when restocking item to ensure that its properly tracked (Fixes #3635) --- apps/openmw/mwworld/containerstore.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index dbdec8081..10388a3b0 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -553,14 +553,14 @@ void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MW if(listInMap != allowedForReplace.end()) restockNum -= std::min(restockNum, listInMap->second); //restock - addInitialItem(itemOrList, owner, restockNum, true); + addInitialItem(itemOrList, owner, -restockNum, true); } else { //Restocking static item - just restock to the max count int currentCount = count(itemOrList); if (currentCount < std::abs(it->mCount)) - addInitialItem(itemOrList, owner, std::abs(it->mCount) - currentCount, true); + addInitialItem(itemOrList, owner, -(std::abs(it->mCount) - currentCount), true); } } flagAsModified(); From db69342b5d9dd36c3c6c70cc1aabec2bf2831725 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Fri, 28 Oct 2016 15:39:27 +0200 Subject: [PATCH 67/94] [macOS] Move all configs & resources into app bundles Fixes #3566 (https://bugs.openmw.org/issues/3566). --- CMakeLists.txt | 38 ++++++++++++++++++---------------- apps/launcher/main.cpp | 8 ------- apps/opencs/CMakeLists.txt | 33 ++++++++++++++++++++++++++--- apps/opencs/main.cpp | 5 ----- apps/openmw/CMakeLists.txt | 15 ++++++++++++++ apps/wizard/main.cpp | 6 ------ components/files/macospath.cpp | 2 +- files/mygui/CMakeLists.txt | 6 +++++- files/shaders/CMakeLists.txt | 6 +++++- 9 files changed, 76 insertions(+), 43 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 939c27310..8795e94b2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -96,7 +96,7 @@ endif() # Set up common paths if (APPLE) set(MORROWIND_DATA_FILES "./data" CACHE PATH "location of Morrowind data files") - set(OPENMW_RESOURCE_FILES "./resources" CACHE PATH "location of OpenMW resources files") + set(OPENMW_RESOURCE_FILES "../Resources/resources" CACHE PATH "location of OpenMW resources files") elseif(UNIX) # Paths SET(BINDIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Where to install binaries") @@ -286,6 +286,11 @@ endif (APPLE) # Set up DEBUG define set_directory_properties(PROPERTIES COMPILE_DEFINITIONS_DEBUG DEBUG=1) +if (NOT APPLE) + set(OPENMW_MYGUI_FILES_ROOT ${OpenMW_BINARY_DIR}) + set(OPENMW_SHADERS_ROOT ${OpenMW_BINARY_DIR}) +endif () + add_subdirectory(files/) # Specify build paths @@ -307,11 +312,15 @@ endif (APPLE) configure_file(${OpenMW_SOURCE_DIR}/files/settings-default.cfg "${OpenMW_BINARY_DIR}/settings-default.cfg") -configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg.local - "${OpenMW_BINARY_DIR}/openmw.cfg") - -configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg - "${OpenMW_BINARY_DIR}/openmw.cfg.install") +if (NOT APPLE) + configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg.local + "${OpenMW_BINARY_DIR}/openmw.cfg") + configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg + "${OpenMW_BINARY_DIR}/openmw.cfg.install") +else () + configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg + "${OpenMW_BINARY_DIR}/openmw.cfg") +endif () configure_file(${OpenMW_SOURCE_DIR}/files/openmw-cs.cfg "${OpenMW_BINARY_DIR}/openmw-cs.cfg") @@ -725,14 +734,7 @@ if (APPLE) configure_file("${QT_COCOA_PLUGIN_PATH}" "${OPENCS_BUNDLE_NAME}/Contents/MacOS/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}" COPYONLY) endif () - set(INSTALL_SUBDIR OpenMW) - - install(DIRECTORY "${APP_BUNDLE_DIR}" USE_SOURCE_PERMISSIONS DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) - install(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) - install(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" RENAME "openmw.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) - install(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) - install(FILES "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) - install(FILES "${OpenMW_BINARY_DIR}/openmw-cs.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) + install(DIRECTORY "${APP_BUNDLE_DIR}" USE_SOURCE_PERMISSIONS DESTINATION "." COMPONENT Runtime) set(CPACK_GENERATOR "DragNDrop") set(CPACK_PACKAGE_VERSION ${OPENMW_VERSION}) @@ -740,8 +742,8 @@ if (APPLE) set(CPACK_PACKAGE_VERSION_MINOR ${OPENMW_VERSION_MINOR}) set(CPACK_PACKAGE_VERSION_PATCH ${OPENMW_VERSION_RELEASE}) - set(INSTALLED_OPENMW_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}") - set(INSTALLED_OPENCS_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}") + set(INSTALLED_OPENMW_APP "\${CMAKE_INSTALL_PREFIX}/${APP_BUNDLE_NAME}") + set(INSTALLED_OPENCS_APP "\${CMAKE_INSTALL_PREFIX}/${OPENCS_BUNDLE_NAME}") install(CODE " set(BU_CHMOD_BUNDLE_ITEMS ON) @@ -785,8 +787,8 @@ if (APPLE) set(${plugins_var} ${PLUGINS} PARENT_SCOPE) endfunction (install_plugins_for_bundle) - install_plugins_for_bundle("${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}" PLUGINS) - install_plugins_for_bundle("${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}" OPENCS_PLUGINS) + install_plugins_for_bundle("${APP_BUNDLE_NAME}" PLUGINS) + install_plugins_for_bundle("${OPENCS_BUNDLE_NAME}" OPENCS_PLUGINS) set(PLUGINS ${PLUGINS} "${INSTALLED_OPENMW_APP}/Contents/MacOS/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}") set(OPENCS_PLUGINS ${OPENCS_PLUGINS} "${INSTALLED_OPENCS_APP}/Contents/MacOS/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}") diff --git a/apps/launcher/main.cpp b/apps/launcher/main.cpp index eadec64d0..96cadc8a7 100644 --- a/apps/launcher/main.cpp +++ b/apps/launcher/main.cpp @@ -35,14 +35,6 @@ int main(int argc, char *argv[]) // Now we make sure the current dir is set to application path QDir dir(QCoreApplication::applicationDirPath()); - #ifdef Q_OS_MAC - if (dir.dirName() == "MacOS") { - dir.cdUp(); - dir.cdUp(); - dir.cdUp(); - } - #endif - QDir::setCurrent(dir.absolutePath()); Launcher::MainDialog mainWin; diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 1f572c3f8..d933b7d3c 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -162,9 +162,15 @@ endif() include_directories(${CMAKE_CURRENT_BINARY_DIR}) if(APPLE) - set (OPENCS_MAC_ICON ${CMAKE_SOURCE_DIR}/files/mac/openmw-cs.icns) + set (OPENCS_MAC_ICON "${CMAKE_SOURCE_DIR}/files/mac/openmw-cs.icns") + set (OPENCS_CFG "${OpenMW_BINARY_DIR}/openmw-cs.cfg") + set (OPENCS_DEFAULT_FILTERS_FILE "${OpenMW_BINARY_DIR}/resources/defaultfilters") + set (OPENCS_OPENMW_CFG "${OpenMW_BINARY_DIR}/openmw.cfg") else() set (OPENCS_MAC_ICON "") + set (OPENCS_CFG "") + set (OPENCS_DEFAULT_FILTERS_FILE "") + set (OPENCS_OPENMW_CFG "") endif(APPLE) add_executable(openmw-cs @@ -174,12 +180,23 @@ add_executable(openmw-cs ${OPENCS_MOC_SRC} ${OPENCS_RES_SRC} ${OPENCS_MAC_ICON} + ${OPENCS_CFG} + ${OPENCS_DEFAULT_FILTERS_FILE} + ${OPENCS_OPENMW_CFG} ) if(APPLE) + set(OPENCS_BUNDLE_NAME "OpenMW-CS") + set(OPENCS_BUNDLE_RESOURCES_DIR "${OpenMW_BINARY_DIR}/${OPENCS_BUNDLE_NAME}.app/Contents/Resources") + + set(OPENMW_MYGUI_FILES_ROOT ${OPENCS_BUNDLE_RESOURCES_DIR}) + set(OPENMW_SHADERS_ROOT ${OPENCS_BUNDLE_RESOURCES_DIR}) + + add_subdirectory(../../files/ ${CMAKE_CURRENT_BINARY_DIR}/files) + set_target_properties(openmw-cs PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}" - OUTPUT_NAME "OpenMW-CS" + OUTPUT_NAME ${OPENCS_BUNDLE_NAME} MACOSX_BUNDLE_ICON_FILE "openmw-cs.icns" MACOSX_BUNDLE_BUNDLE_NAME "OpenCS" MACOSX_BUNDLE_GUI_IDENTIFIER "org.openmw.opencs" @@ -190,6 +207,16 @@ if(APPLE) set_source_files_properties(${OPENCS_MAC_ICON} PROPERTIES MACOSX_PACKAGE_LOCATION Resources) + set_source_files_properties(${OPENCS_CFG} PROPERTIES + MACOSX_PACKAGE_LOCATION Resources) + set_source_files_properties(${OPENCS_DEFAULT_FILTERS_FILE} PROPERTIES + MACOSX_PACKAGE_LOCATION Resources/resources) + set_source_files_properties(${OPENCS_OPENMW_CFG} PROPERTIES + MACOSX_PACKAGE_LOCATION Resources) + + add_custom_command(TARGET openmw-cs + POST_BUILD + COMMAND cp "${OpenMW_BINARY_DIR}/resources/version" "${OPENCS_BUNDLE_RESOURCES_DIR}/resources") endif(APPLE) target_link_libraries(openmw-cs @@ -227,5 +254,5 @@ endif() if(APPLE) - INSTALL(TARGETS openmw-cs BUNDLE DESTINATION OpenMW COMPONENT BUNDLE) + INSTALL(TARGETS openmw-cs BUNDLE DESTINATION "." COMPONENT BUNDLE) endif() diff --git a/apps/opencs/main.cpp b/apps/opencs/main.cpp index c6fe34835..fc5e8fc7a 100644 --- a/apps/opencs/main.cpp +++ b/apps/opencs/main.cpp @@ -62,11 +62,6 @@ int main(int argc, char *argv[]) #ifdef Q_OS_MAC QDir dir(QCoreApplication::applicationDirPath()); - if (dir.dirName() == "MacOS") { - dir.cdUp(); - dir.cdUp(); - dir.cdUp(); - } QDir::setCurrent(dir.absolutePath()); #endif diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 277acea2d..4ddd69284 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -179,6 +179,21 @@ target_link_libraries(openmw ${CMAKE_THREAD_LIBS_INIT}) endif() if(APPLE) + set(BUNDLE_RESOURCES_DIR "${APP_BUNDLE_DIR}/Contents/Resources") + + set(OPENMW_MYGUI_FILES_ROOT ${BUNDLE_RESOURCES_DIR}) + set(OPENMW_SHADERS_ROOT ${BUNDLE_RESOURCES_DIR}) + + add_subdirectory(../../files/ ${CMAKE_CURRENT_BINARY_DIR}/files) + + configure_file("${OpenMW_BINARY_DIR}/settings-default.cfg" ${BUNDLE_RESOURCES_DIR} COPYONLY) + configure_file("${OpenMW_BINARY_DIR}/openmw.cfg" ${BUNDLE_RESOURCES_DIR} COPYONLY) + configure_file("${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" ${BUNDLE_RESOURCES_DIR} COPYONLY) + + add_custom_command(TARGET openmw + POST_BUILD + COMMAND cp "${OpenMW_BINARY_DIR}/resources/version" "${BUNDLE_RESOURCES_DIR}/resources") + find_library(COCOA_FRAMEWORK Cocoa) find_library(IOKIT_FRAMEWORK IOKit) target_link_libraries(openmw ${COCOA_FRAMEWORK} ${IOKIT_FRAMEWORK}) diff --git a/apps/wizard/main.cpp b/apps/wizard/main.cpp index c861a4ac8..e3624742a 100644 --- a/apps/wizard/main.cpp +++ b/apps/wizard/main.cpp @@ -20,12 +20,6 @@ int main(int argc, char *argv[]) QDir dir(QCoreApplication::applicationDirPath()); #ifdef Q_OS_MAC - if (dir.dirName() == "MacOS") { - dir.cdUp(); - dir.cdUp(); - dir.cdUp(); - } - // force Qt to load only LOCAL plugins, don't touch system Qt installation QDir pluginsPath(QCoreApplication::applicationDirPath()); pluginsPath.cdUp(); diff --git a/components/files/macospath.cpp b/components/files/macospath.cpp index 237141960..b49b72e46 100644 --- a/components/files/macospath.cpp +++ b/components/files/macospath.cpp @@ -68,7 +68,7 @@ boost::filesystem::path MacOsPath::getCachePath() const boost::filesystem::path MacOsPath::getLocalPath() const { - return boost::filesystem::path("./"); + return boost::filesystem::path("../Resources/"); } boost::filesystem::path MacOsPath::getGlobalDataPath() const diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index 7494d3ba2..6592de56e 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -1,6 +1,10 @@ +if (NOT DEFINED OPENMW_MYGUI_FILES_ROOT) + return() +endif() + # Copy resource files into the build directory set(SDIR ${CMAKE_CURRENT_SOURCE_DIR}) -set(DDIR ${OpenMW_BINARY_DIR}/resources/mygui) +set(DDIR ${OPENMW_MYGUI_FILES_ROOT}/resources/mygui) set(MYGUI_FILES core.skin diff --git a/files/shaders/CMakeLists.txt b/files/shaders/CMakeLists.txt index 0738b5783..5ca0d1e83 100644 --- a/files/shaders/CMakeLists.txt +++ b/files/shaders/CMakeLists.txt @@ -1,6 +1,10 @@ +if (NOT DEFINED OPENMW_SHADERS_ROOT) + return() +endif() + # Copy resource files into the build directory set(SDIR ${CMAKE_CURRENT_SOURCE_DIR}) -set(DDIR ${OpenMW_BINARY_DIR}/resources/shaders) +set(DDIR ${OPENMW_SHADERS_ROOT}/resources/shaders) set(SHADER_FILES water_vertex.glsl From ea888519c7d8681af0ad2d5891b0ec82fec17097 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Sun, 13 Nov 2016 15:40:54 +0100 Subject: [PATCH 68/94] [macOS] Set OpenMW working dir to /Contents/MacOS --- apps/openmw/main.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index cfe7fe305..43901d579 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -352,9 +352,8 @@ int main(int argc, char**argv) #endif #ifdef __APPLE__ - // FIXME: set current dir to bundle path - //boost::filesystem::path bundlePath = boost::filesystem::path(Ogre::macBundlePath()).parent_path(); - //boost::filesystem::current_path(bundlePath); + boost::filesystem::path binary_path = boost::filesystem::system_complete(boost::filesystem::path(argv[0])); + boost::filesystem::current_path(binary_path.parent_path()); #endif engine.reset(new OMW::Engine(cfgMgr)); From 354a89e3bc534de62a22d3d3147ef7051ea04a3f Mon Sep 17 00:00:00 2001 From: ShadowRadiance Date: Sat, 26 Nov 2016 06:27:11 -0500 Subject: [PATCH 69/94] Slowfall now reduces momentum based on magnitude when jumping (Allows Constant Effect Slowfall to work as in MW) --- apps/openmw/mwphysics/physicssystem.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index cc3ba40e1..246e5eb59 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -450,8 +450,8 @@ namespace MWPhysics if (inertia.z() < 0) inertia.z() *= slowFall; if (slowFall < 1.f) { - inertia.x() = 0; - inertia.y() = 0; + inertia.x() *= slowFall; + inertia.y() *= slowFall; } physicActor->setInertialForce(inertia); } From be14ce414e53cdc84513c84200418ccd9174d943 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 27 Nov 2016 05:36:48 +0100 Subject: [PATCH 70/94] Update AUTHORS.md --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index a876bcbfd..7f1f91892 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -120,6 +120,7 @@ Programmers Scott Howard Sebastian Wick (swick) Sergey Shambir + ShadowRadiance sir_herrbatka smbas Stefan Galowicz (bogglez) From c34d85ffc2caf2240afbcf7fe3a9ab58fa9514f7 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sun, 27 Nov 2016 21:19:52 +0100 Subject: [PATCH 71/94] Implement water sounds (Closes #451) --- apps/openmw/engine.cpp | 2 +- apps/openmw/mwsound/soundmanagerimp.cpp | 102 +++++++++++++++++++++++- apps/openmw/mwsound/soundmanagerimp.hpp | 15 +++- 3 files changed, 116 insertions(+), 3 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 62457cae6..03ec412d1 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -493,7 +493,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mEnvironment.setWindowManager (window); // Create sound system - mEnvironment.setSoundManager (new MWSound::SoundManager(mVFS.get(), mUseSound)); + mEnvironment.setSoundManager (new MWSound::SoundManager(mVFS.get(), mFallbackMap, mUseSound)); if (!mSkipMenu) { diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 663f88852..9b5fb1b3d 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -34,8 +34,9 @@ namespace MWSound { - SoundManager::SoundManager(const VFS::Manager* vfs, bool useSound) + SoundManager::SoundManager(const VFS::Manager* vfs, const std::map& fallbackMap, bool useSound) : mVFS(vfs) + , mFallback(fallbackMap) , mOutput(new DEFAULT_OUTPUT(*this)) , mMasterVolume(1.0f) , mSFXVolume(1.0f) @@ -61,6 +62,13 @@ namespace MWSound mFootstepsVolume = Settings::Manager::getFloat("footsteps volume", "Sound"); mFootstepsVolume = std::min(std::max(mFootstepsVolume, 0.0f), 1.0f); + mNearWaterRadius = mFallback.getFallbackInt("Water_NearWaterRadius"); + mNearWaterPoints = mFallback.getFallbackInt("Water_NearWaterPoints"); + mNearWaterIndoorTolerance = mFallback.getFallbackFloat("Water_NearWaterIndoorTolerance"); + mNearWaterOutdoorTolerance = mFallback.getFallbackFloat("Water_NearWaterOutdoorTolerance"); + mNearWaterIndoorID = mFallback.getFallbackString("Water_NearWaterIndoorID"); + mNearWaterOutdoorID = mFallback.getFallbackString("Water_NearWaterOutdoorID"); + mBufferCacheMin = std::max(Settings::Manager::getInt("buffer cache min", "Sound"), 1); mBufferCacheMax = std::max(Settings::Manager::getInt("buffer cache max", "Sound"), 1); mBufferCacheMax *= 1024*1024; @@ -796,6 +804,96 @@ namespace MWSound } } + void SoundManager::updateWaterSound(float /*duration*/) + { + MWBase::World* world = MWBase::Environment::get().getWorld(); + const MWWorld::ConstPtr player = world->getPlayerPtr(); + osg::Vec3f pos = player.getRefData().getPosition().asVec3(); + + float volume = 0.0f; + const std::string& soundId = player.getCell()->isExterior() ? mNearWaterOutdoorID : mNearWaterIndoorID; + + if (!mListenerUnderwater) + { + if (player.getCell()->getCell()->hasWater()) + { + float dist = std::abs(player.getCell()->getWaterLevel() - pos.z()); + + if (player.getCell()->isExterior() && dist < mNearWaterOutdoorTolerance) + { + volume = (mNearWaterOutdoorTolerance - dist) / mNearWaterOutdoorTolerance; + + if (mNearWaterPoints > 1) + { + int underwaterPoints = 0; + + float step = mNearWaterRadius * 2.0f / (mNearWaterPoints - 1); + + for (int x = 0; x < mNearWaterPoints; x++) + { + for (int y = 0; y < mNearWaterPoints; y++) + { + float height = world->getTerrainHeightAt( + osg::Vec3f(pos.x() - mNearWaterRadius + x*step, pos.y() - mNearWaterRadius + y*step, 0.0f)); + + if (height < 0) + underwaterPoints++; + } + } + + volume *= underwaterPoints * 2.0f / (mNearWaterPoints*mNearWaterPoints); + } + } + else if (!player.getCell()->isExterior() && dist < mNearWaterIndoorTolerance) + { + volume = (mNearWaterIndoorTolerance - dist) / mNearWaterIndoorTolerance; + } + } + } + else + volume = 1.0f; + + volume = std::min(volume, 1.0f); + + if (mNearWaterSound) + { + if (volume == 0.0f) + { + mOutput->finishSound(mNearWaterSound); + mNearWaterSound.reset(); + } + else + { + bool soundIdChanged = false; + + Sound_Buffer* sfx = lookupSound(Misc::StringUtils::lowerCase(soundId)); + + for (SoundMap::const_iterator snditer = mActiveSounds.begin(); snditer != mActiveSounds.end(); ++snditer) + { + for (SoundBufferRefPairList::const_iterator pairiter = snditer->second.begin(); pairiter != snditer->second.end(); ++pairiter) + { + if (pairiter->first == mNearWaterSound) + { + if (pairiter->second != sfx) + soundIdChanged = true; + break; + } + } + } + + if (soundIdChanged) + { + mOutput->finishSound(mNearWaterSound); + mNearWaterSound = playSound(soundId, volume, 1.0f, Play_TypeSfx, Play_Loop); + } + else if (sfx) + mNearWaterSound->setVolume(volume * sfx->mVolume); + } + } + else if (volume > 0.0f) + mNearWaterSound = playSound(soundId, volume, 1.0f, Play_TypeSfx, Play_Loop); + } + void SoundManager::updateSounds(float duration) { static float timePassed = 0.0; @@ -941,6 +1039,7 @@ namespace MWSound { updateSounds(duration); updateRegionSound(duration); + updateWaterSound(duration); } } @@ -1105,6 +1204,7 @@ namespace MWSound mOutput->finishStream(*trkiter); mActiveTracks.clear(); mUnderwaterSound.reset(); + mNearWaterSound.reset(); stopMusic(); } } diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index d499dce7d..abf5edb97 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -11,6 +11,8 @@ #include +#include + #include "../mwbase/soundmanager.hpp" namespace VFS @@ -44,6 +46,8 @@ namespace MWSound { const VFS::Manager* mVFS; + Fallback::Map mFallback; + std::auto_ptr mOutput; // Caches available music tracks by @@ -56,6 +60,13 @@ namespace MWSound float mVoiceVolume; float mFootstepsVolume; + int mNearWaterRadius; + int mNearWaterPoints; + float mNearWaterIndoorTolerance; + float mNearWaterOutdoorTolerance; + std::string mNearWaterIndoorID; + std::string mNearWaterOutdoorID; + typedef std::auto_ptr > SoundBufferList; // List of sound buffers, grown as needed. New enties are added to the // back, allowing existing Sound_Buffer references/pointers to remain @@ -94,6 +105,7 @@ namespace MWSound int mPausedSoundTypes; MWBase::SoundPtr mUnderwaterSound; + MWBase::SoundPtr mNearWaterSound; Sound_Buffer *insertSound(const std::string &soundId, const ESM::Sound *sound); @@ -108,6 +120,7 @@ namespace MWSound void streamMusicFull(const std::string& filename); void updateSounds(float duration); void updateRegionSound(float duration); + void updateWaterSound(float duration); float volumeFromType(PlayType type) const; @@ -119,7 +132,7 @@ namespace MWSound friend class OpenAL_Output; public: - SoundManager(const VFS::Manager* vfs, bool useSound); + SoundManager(const VFS::Manager* vfs, const std::map& fallbackMap, bool useSound); virtual ~SoundManager(); virtual void processChangedSettings(const Settings::CategorySettingVector& settings); From e0afd6d0f78aa2635ee49c2209f63115b9b25f0c Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 2 Dec 2016 02:25:05 +0100 Subject: [PATCH 72/94] Movement solver: performance improvement for the minimum stepping distance check, no need to waste time doing a second stepMove if we did not hit a slope or the step was already large enough to begin with. --- apps/openmw/mwphysics/physicssystem.cpp | 34 +++++++++++++++---------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 246e5eb59..1a97fc6ff 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -69,7 +69,14 @@ namespace MWPhysics return osg::RadiansToDegrees(std::acos(normal * osg::Vec3f(0.f, 0.f, 1.f))); } - static bool stepMove(const btCollisionObject *colobj, osg::Vec3f &position, + enum StepMoveResult + { + Result_Blocked, // unable to move over obstacle + Result_MaxSlope, // unable to end movement on this slope + Result_Success + }; + + static StepMoveResult stepMove(const btCollisionObject *colobj, osg::Vec3f &position, const osg::Vec3f &toMove, float &remainingTime, const btCollisionWorld* collisionWorld) { /* @@ -120,7 +127,7 @@ namespace MWPhysics stepper.doTrace(colobj, position, position+osg::Vec3f(0.0f,0.0f,sStepSizeUp), collisionWorld); if(stepper.mFraction < std::numeric_limits::epsilon()) - return false; // didn't even move the smallest representable amount + return Result_Blocked; // didn't even move the smallest representable amount // (TODO: shouldn't this be larger? Why bother with such a small amount?) /* @@ -138,7 +145,7 @@ namespace MWPhysics */ tracer.doTrace(colobj, stepper.mEndPos, stepper.mEndPos + toMove, collisionWorld); if(tracer.mFraction < std::numeric_limits::epsilon()) - return false; // didn't even move the smallest representable amount + return Result_Blocked; // didn't even move the smallest representable amount /* * Try moving back down sStepSizeDown using stepper. @@ -156,22 +163,22 @@ namespace MWPhysics * ============================================== */ stepper.doTrace(colobj, tracer.mEndPos, tracer.mEndPos-osg::Vec3f(0.0f,0.0f,sStepSizeDown), collisionWorld); - if(stepper.mFraction < 1.0f && getSlope(stepper.mPlaneNormal) <= sMaxSlope) + if (getSlope(stepper.mPlaneNormal) > sMaxSlope) + return Result_MaxSlope; + if(stepper.mFraction < 1.0f) { // don't allow stepping up other actors if (stepper.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Actor) - return false; + return Result_Blocked; // only step down onto semi-horizontal surfaces. don't step down onto the side of a house or a wall. // TODO: stepper.mPlaneNormal does not appear to be reliable - needs more testing // NOTE: caller's variables 'position' & 'remainingTime' are modified here position = stepper.mEndPos; remainingTime *= (1.0f-tracer.mFraction); // remaining time is proportional to remaining distance - return true; + return Result_Success; } - // moved between 0 and just under sStepSize distance but slope was too great, - // or moved full sStepSize distance (FIXME: is this a bug?) - return false; + return Result_Blocked; } @@ -361,14 +368,15 @@ namespace MWPhysics osg::Vec3f oldPosition = newPosition; // We hit something. Try to step up onto it. (NOTE: stepMove does not allow stepping over) // NOTE: stepMove modifies newPosition if successful - bool result = stepMove(colobj, newPosition, velocity*remainingTime, remainingTime, collisionWorld); - if (!result) // to make sure the maximum stepping distance isn't framerate-dependent or movement-speed dependent + const float minStep = 10.f; + StepMoveResult result = stepMove(colobj, newPosition, velocity*remainingTime, remainingTime, collisionWorld); + if (result == Result_MaxSlope && (velocity*remainingTime).length() < minStep) // to make sure the maximum stepping distance isn't framerate-dependent or movement-speed dependent { osg::Vec3f normalizedVelocity = velocity; normalizedVelocity.normalize(); - result = stepMove(colobj, newPosition, normalizedVelocity*10.f, remainingTime, collisionWorld); + result = stepMove(colobj, newPosition, normalizedVelocity*minStep, remainingTime, collisionWorld); } - if(result) + if(result == Result_Success) { // don't let pure water creatures move out of water after stepMove if (ptr.getClass().isPureWaterCreature(ptr) From 28639c3b2f484c1d3a87ad2654496705540f634f Mon Sep 17 00:00:00 2001 From: Kurnevsky Evgeny Date: Sat, 3 Dec 2016 17:13:31 +0300 Subject: [PATCH 73/94] Crash fix when item is disabled before it casts spell. --- apps/openmw/mwmechanics/spellcasting.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 5c5fc3899..5865c32b9 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -913,7 +913,7 @@ namespace MWMechanics MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(mCaster); - if (mCaster.getClass().isActor()) // TODO: Non-actors should also create a spell cast vfx + if (animation && mCaster.getClass().isActor()) // TODO: Non-actors should also create a spell cast vfx even if they are disabled (animation == NULL) { const ESM::Static* castStatic; @@ -927,7 +927,7 @@ namespace MWMechanics animation->addEffect("meshes\\" + castStatic->mModel, effect->mIndex, false, "", texture); } - if (!mCaster.getClass().isActor()) + if (animation && !mCaster.getClass().isActor()) animation->addSpellCastGlow(effect); static const std::string schools[] = { From 83945cf2800292cdc975bbf837bdf4ebddd92ed1 Mon Sep 17 00:00:00 2001 From: mrohrlach Date: Sat, 3 Dec 2016 15:24:21 -0700 Subject: [PATCH 74/94] Added reasonable approximation of magic bolt lights --- apps/openmw/mwworld/projectilemanager.cpp | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 35df52a18..4b373dad0 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -2,6 +2,8 @@ #include +#include +#include #include #include @@ -142,8 +144,8 @@ namespace MWWorld state.mNode->setNodeMask(MWRender::Mask_Effect); state.mNode->setPosition(pos); state.mNode->setAttitude(orient); - - osg::Group* attachTo = state.mNode; + + osg::Group* attachTo = state.mNode; if (rotate) { @@ -167,6 +169,23 @@ namespace MWWorld mResourceSystem->getSceneManager()->getInstance("meshes\\" + weapon->mModel, findVisitor.mFoundNode); } + // Add projectile light + osg::ref_ptr projectileLight(new osg::Light); + projectileLight->setDiffuse(osg::Vec4(0.95f, 0.71f, 0.25f, 1.0f)); + projectileLight->setAmbient(osg::Vec4(0.32f, 0.08f, 0.01f, 1.0f)); + projectileLight->setSpecular(osg::Vec4(0, 0, 0, 0)); + projectileLight->setLinearAttenuation(0.5f / 15); + projectileLight->setPosition(osg::Vec4(pos, 1.0)); + + // Add projectile light source + SceneUtil::LightSource* projectileLightSource = new SceneUtil::LightSource; + projectileLightSource->setNodeMask(MWRender::Mask_Lighting); + projectileLightSource->setRadius(66.f); + + state.mNode->addChild(projectileLightSource); + projectileLightSource->setLight(projectileLight); + + SceneUtil::DisableFreezeOnCullVisitor disableFreezeOnCullVisitor; state.mNode->accept(disableFreezeOnCullVisitor); From 49ce80346c93f14456acb927b81bc0264874e20c Mon Sep 17 00:00:00 2001 From: mrohrlach Date: Sat, 3 Dec 2016 15:42:24 -0700 Subject: [PATCH 75/94] Changed methods slightly to ensure non-magic projectiles do not receive lights --- apps/openmw/mwworld/projectilemanager.cpp | 50 ++++++++++++----------- apps/openmw/mwworld/projectilemanager.hpp | 2 +- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 4b373dad0..a81188046 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -138,7 +138,7 @@ namespace MWWorld }; - void ProjectileManager::createModel(State &state, const std::string &model, const osg::Vec3f& pos, const osg::Quat& orient, bool rotate, std::string texture) + void ProjectileManager::createModel(State &state, const std::string &model, const osg::Vec3f& pos, const osg::Quat& orient, bool rotate, bool isMagic, std::string texture) { state.mNode = new osg::PositionAttitudeTransform; state.mNode->setNodeMask(MWRender::Mask_Effect); @@ -169,21 +169,25 @@ namespace MWWorld mResourceSystem->getSceneManager()->getInstance("meshes\\" + weapon->mModel, findVisitor.mFoundNode); } - // Add projectile light - osg::ref_ptr projectileLight(new osg::Light); - projectileLight->setDiffuse(osg::Vec4(0.95f, 0.71f, 0.25f, 1.0f)); - projectileLight->setAmbient(osg::Vec4(0.32f, 0.08f, 0.01f, 1.0f)); - projectileLight->setSpecular(osg::Vec4(0, 0, 0, 0)); - projectileLight->setLinearAttenuation(0.5f / 15); - projectileLight->setPosition(osg::Vec4(pos, 1.0)); - - // Add projectile light source - SceneUtil::LightSource* projectileLightSource = new SceneUtil::LightSource; - projectileLightSource->setNodeMask(MWRender::Mask_Lighting); - projectileLightSource->setRadius(66.f); - - state.mNode->addChild(projectileLightSource); - projectileLightSource->setLight(projectileLight); + if (isMagic) + { + // Add magic bolt light + osg::ref_ptr projectileLight(new osg::Light); + projectileLight->setDiffuse(osg::Vec4(0.95f, 0.71f, 0.25f, 1.0f)); + projectileLight->setAmbient(osg::Vec4(0.32f, 0.08f, 0.01f, 1.0f)); + projectileLight->setSpecular(osg::Vec4(0, 0, 0, 0)); + projectileLight->setLinearAttenuation(0.5f / 15); + projectileLight->setPosition(osg::Vec4(pos, 1.0)); + + // Add magic bolt light source + SceneUtil::LightSource* projectileLightSource = new SceneUtil::LightSource; + projectileLightSource->setNodeMask(MWRender::Mask_Lighting); + projectileLightSource->setRadius(66.f); + + // Attach to scene node + state.mNode->addChild(projectileLightSource); + projectileLightSource->setLight(projectileLight); + } SceneUtil::DisableFreezeOnCullVisitor disableFreezeOnCullVisitor; @@ -248,7 +252,7 @@ namespace MWWorld MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), state.mIdMagic.at(0)); MWWorld::Ptr ptr = ref.getPtr(); - createModel(state, ptr.getClass().getModel(ptr), pos, orient, true, texture); + createModel(state, ptr.getClass().getModel(ptr), pos, orient, true, true, texture); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); for (size_t it = 0; it != state.mSoundIds.size(); it++) @@ -272,7 +276,7 @@ namespace MWWorld MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), projectile.getCellRef().getRefId()); MWWorld::Ptr ptr = ref.getPtr(); - createModel(state, ptr.getClass().getModel(ptr), pos, orient, false); + createModel(state, ptr.getClass().getModel(ptr), pos, orient, false, false); mProjectiles.push_back(state); } @@ -478,9 +482,9 @@ namespace MWWorld bool ProjectileManager::readRecord(ESM::ESMReader &reader, uint32_t type) { - if (type == ESM::REC_PROJ) + if (type == ESM::REC_PROJ) { - ESM::ProjectileState esm; + ESM::ProjectileState esm; esm.load(reader); ProjectileState state; @@ -502,14 +506,14 @@ namespace MWWorld return true; } - createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), false); + createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), false, false); mProjectiles.push_back(state); return true; } else if (type == ESM::REC_MPRJ) { - ESM::MagicBoltState esm; + ESM::MagicBoltState esm; esm.load(reader); MagicBoltState state; @@ -537,7 +541,7 @@ namespace MWWorld return true; } - createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), true, texture); + createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), true, true, texture); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index a8769fcf9..d17e24b0c 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -122,7 +122,7 @@ namespace MWWorld void moveProjectiles(float dt); void moveMagicBolts(float dt); - void createModel (State& state, const std::string& model, const osg::Vec3f& pos, const osg::Quat& orient, bool rotate, std::string texture = ""); + void createModel (State& state, const std::string& model, const osg::Vec3f& pos, const osg::Quat& orient, bool rotate, bool isMagic, std::string texture = ""); void update (State& state, float duration); void operator=(const ProjectileManager&); From 61097d93b9d72f8c16db35b118e9cffe5ce7cd20 Mon Sep 17 00:00:00 2001 From: mrohrlach Date: Sat, 3 Dec 2016 19:09:03 -0700 Subject: [PATCH 76/94] Replaced tabs with spaces (oops) --- apps/openmw/mwworld/projectilemanager.cpp | 51 +++++++++++------------ 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index a81188046..56a4b75fe 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -144,8 +144,8 @@ namespace MWWorld state.mNode->setNodeMask(MWRender::Mask_Effect); state.mNode->setPosition(pos); state.mNode->setAttitude(orient); - - osg::Group* attachTo = state.mNode; + + osg::Group* attachTo = state.mNode; if (rotate) { @@ -169,27 +169,26 @@ namespace MWWorld mResourceSystem->getSceneManager()->getInstance("meshes\\" + weapon->mModel, findVisitor.mFoundNode); } - if (isMagic) - { - // Add magic bolt light - osg::ref_ptr projectileLight(new osg::Light); - projectileLight->setDiffuse(osg::Vec4(0.95f, 0.71f, 0.25f, 1.0f)); - projectileLight->setAmbient(osg::Vec4(0.32f, 0.08f, 0.01f, 1.0f)); - projectileLight->setSpecular(osg::Vec4(0, 0, 0, 0)); - projectileLight->setLinearAttenuation(0.5f / 15); - projectileLight->setPosition(osg::Vec4(pos, 1.0)); - - // Add magic bolt light source - SceneUtil::LightSource* projectileLightSource = new SceneUtil::LightSource; - projectileLightSource->setNodeMask(MWRender::Mask_Lighting); - projectileLightSource->setRadius(66.f); - - // Attach to scene node - state.mNode->addChild(projectileLightSource); - projectileLightSource->setLight(projectileLight); - } - - + if (isMagic) + { + // Add magic bolt light + osg::ref_ptr projectileLight(new osg::Light); + projectileLight->setDiffuse(osg::Vec4(0.95f, 0.71f, 0.25f, 1.0f)); + projectileLight->setAmbient(osg::Vec4(0.32f, 0.08f, 0.01f, 1.0f)); + projectileLight->setSpecular(osg::Vec4(0, 0, 0, 0)); + projectileLight->setLinearAttenuation(0.5f / 15); + projectileLight->setPosition(osg::Vec4(pos, 1.0)); + + // Add magic bolt light source + SceneUtil::LightSource* projectileLightSource = new SceneUtil::LightSource; + projectileLightSource->setNodeMask(MWRender::Mask_Lighting); + projectileLightSource->setRadius(66.f); + + // Attach to scene node + state.mNode->addChild(projectileLightSource); + projectileLightSource->setLight(projectileLight); + } + SceneUtil::DisableFreezeOnCullVisitor disableFreezeOnCullVisitor; state.mNode->accept(disableFreezeOnCullVisitor); @@ -482,9 +481,9 @@ namespace MWWorld bool ProjectileManager::readRecord(ESM::ESMReader &reader, uint32_t type) { - if (type == ESM::REC_PROJ) + if (type == ESM::REC_PROJ) { - ESM::ProjectileState esm; + ESM::ProjectileState esm; esm.load(reader); ProjectileState state; @@ -513,7 +512,7 @@ namespace MWWorld } else if (type == ESM::REC_MPRJ) { - ESM::MagicBoltState esm; + ESM::MagicBoltState esm; esm.load(reader); MagicBoltState state; From 099e79edbec0d641399d14b2ab8fdb4edf56d3a5 Mon Sep 17 00:00:00 2001 From: mrohrlach Date: Sat, 3 Dec 2016 19:12:25 -0700 Subject: [PATCH 77/94] Changed a line that did not need to be changed apparently --- apps/openmw/mwworld/projectilemanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 56a4b75fe..ba1104f93 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -144,7 +144,7 @@ namespace MWWorld state.mNode->setNodeMask(MWRender::Mask_Effect); state.mNode->setPosition(pos); state.mNode->setAttitude(orient); - + osg::Group* attachTo = state.mNode; if (rotate) From 3816d0f6dc0b6094765c0b44caf24e252d35c0fb Mon Sep 17 00:00:00 2001 From: mrohrlach Date: Sat, 3 Dec 2016 19:44:52 -0700 Subject: [PATCH 78/94] Changed light values to better match vanilla. Still need to pull diffusion properties from spells --- apps/openmw/mwworld/projectilemanager.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index ba1104f93..0842f5d1d 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -173,10 +173,12 @@ namespace MWWorld { // Add magic bolt light osg::ref_ptr projectileLight(new osg::Light); - projectileLight->setDiffuse(osg::Vec4(0.95f, 0.71f, 0.25f, 1.0f)); - projectileLight->setAmbient(osg::Vec4(0.32f, 0.08f, 0.01f, 1.0f)); - projectileLight->setSpecular(osg::Vec4(0, 0, 0, 0)); - projectileLight->setLinearAttenuation(0.5f / 15); + projectileLight->setAmbient(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f)); + projectileLight->setDiffuse(osg::Vec4(0.814f, 0.682f, 0.652f, 1.0f)); + projectileLight->setSpecular(osg::Vec4(30.0f, 30.0f, 30.0f, 1.0f)); + projectileLight->setConstantAttenuation(0.f); + projectileLight->setLinearAttenuation(0.1f); + projectileLight->setQuadraticAttenuation(0.f); projectileLight->setPosition(osg::Vec4(pos, 1.0)); // Add magic bolt light source From 1e654ca4c3ad05f55e9fac6a0ae75de2728b05a9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 4 Dec 2016 15:33:37 +0100 Subject: [PATCH 79/94] Update AUTHORS.md --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 7f1f91892..2a7ed1ed9 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -74,6 +74,7 @@ Programmers Karl-Felix Glatzer (k1ll) Kevin Poitra (PuppyKevin) Koncord + Kurnevsky Evgeny (kurnevsky) Lars Söderberg (Lazaroth) lazydev Leon Saunders (emoose) From ef5cf76ad81b344726d9869f9998818c708795a3 Mon Sep 17 00:00:00 2001 From: mrohrlach Date: Sun, 4 Dec 2016 16:11:21 -0700 Subject: [PATCH 80/94] Implemented retrieval of effect colors for lights, made recommended changes --- apps/openmw/mwworld/projectilemanager.cpp | 37 +++++++++++++++++++---- apps/openmw/mwworld/projectilemanager.hpp | 2 +- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 0842f5d1d..1d290c8a1 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -2,8 +2,6 @@ #include -#include -#include #include #include @@ -138,7 +136,7 @@ namespace MWWorld }; - void ProjectileManager::createModel(State &state, const std::string &model, const osg::Vec3f& pos, const osg::Quat& orient, bool rotate, bool isMagic, std::string texture) + void ProjectileManager::createModel(State &state, const std::string &model, const osg::Vec3f& pos, const osg::Quat& orient, bool rotate, bool createLight, std::string texture) { state.mNode = new osg::PositionAttitudeTransform; state.mNode->setNodeMask(MWRender::Mask_Effect); @@ -169,13 +167,40 @@ namespace MWWorld mResourceSystem->getSceneManager()->getInstance("meshes\\" + weapon->mModel, findVisitor.mFoundNode); } - if (isMagic) + if (createLight) { + // Combine colors of individual effects + osg::Vec4 lightDiffuseColor; + if (state.mIdMagic.size() > 0) + { + float lightDiffuseRed = 0.0f; + float lightDiffuseGreen = 0.0f; + float lightDiffuseBlue = 0.0f; + for (std::vector::const_iterator it = ((MagicBoltState&)state).mEffects.mList.begin(); it != ((MagicBoltState&)state).mEffects.mList.end(); ++it) + { + const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find( + it->mEffectID); + lightDiffuseRed += ((float) magicEffect->mData.mRed / 255.f); + lightDiffuseGreen += ((float) magicEffect->mData.mGreen / 255.f); + lightDiffuseBlue += ((float) magicEffect->mData.mBlue / 255.f); + } + int numberOfEffects = ((MagicBoltState&)state).mEffects.mList.size(); + lightDiffuseColor = osg::Vec4(lightDiffuseRed / numberOfEffects + , lightDiffuseGreen / numberOfEffects + , lightDiffuseBlue / numberOfEffects + , 1.0f); + printf("%f, %f, %f", (lightDiffuseRed / numberOfEffects), (lightDiffuseGreen / numberOfEffects), (lightDiffuseBlue / numberOfEffects)); + } + else + { + lightDiffuseColor = osg::Vec4(0.814f, 0.682f, 0.652f, 1.0f); + } + // Add magic bolt light osg::ref_ptr projectileLight(new osg::Light); projectileLight->setAmbient(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f)); - projectileLight->setDiffuse(osg::Vec4(0.814f, 0.682f, 0.652f, 1.0f)); - projectileLight->setSpecular(osg::Vec4(30.0f, 30.0f, 30.0f, 1.0f)); + projectileLight->setDiffuse(lightDiffuseColor); + projectileLight->setSpecular(osg::Vec4(0.0f, 0.0f, 0.0f, 0.0f)); projectileLight->setConstantAttenuation(0.f); projectileLight->setLinearAttenuation(0.1f); projectileLight->setQuadraticAttenuation(0.f); diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index d17e24b0c..db090eaef 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -122,7 +122,7 @@ namespace MWWorld void moveProjectiles(float dt); void moveMagicBolts(float dt); - void createModel (State& state, const std::string& model, const osg::Vec3f& pos, const osg::Quat& orient, bool rotate, bool isMagic, std::string texture = ""); + void createModel (State& state, const std::string& model, const osg::Vec3f& pos, const osg::Quat& orient, bool rotate, bool createLight, std::string texture = ""); void update (State& state, float duration); void operator=(const ProjectileManager&); From c2e5f24e981ecd4bc826075d274816469f75d4a4 Mon Sep 17 00:00:00 2001 From: mrohrlach Date: Sun, 4 Dec 2016 16:31:11 -0700 Subject: [PATCH 81/94] Tidying up --- apps/openmw/mwworld/projectilemanager.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 1d290c8a1..3d9c4df90 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -169,7 +169,7 @@ namespace MWWorld if (createLight) { - // Combine colors of individual effects + // Case: magical effects (combine colors of individual effects) osg::Vec4 lightDiffuseColor; if (state.mIdMagic.size() > 0) { @@ -189,14 +189,14 @@ namespace MWWorld , lightDiffuseGreen / numberOfEffects , lightDiffuseBlue / numberOfEffects , 1.0f); - printf("%f, %f, %f", (lightDiffuseRed / numberOfEffects), (lightDiffuseGreen / numberOfEffects), (lightDiffuseBlue / numberOfEffects)); } else { + // Case: no magical effects, but still creating light lightDiffuseColor = osg::Vec4(0.814f, 0.682f, 0.652f, 1.0f); } - // Add magic bolt light + // Add light osg::ref_ptr projectileLight(new osg::Light); projectileLight->setAmbient(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f)); projectileLight->setDiffuse(lightDiffuseColor); @@ -206,7 +206,7 @@ namespace MWWorld projectileLight->setQuadraticAttenuation(0.f); projectileLight->setPosition(osg::Vec4(pos, 1.0)); - // Add magic bolt light source + // Add light source SceneUtil::LightSource* projectileLightSource = new SceneUtil::LightSource; projectileLightSource->setNodeMask(MWRender::Mask_Lighting); projectileLightSource->setRadius(66.f); From 3ac66ec9d4d038e6b34facff5cb5020897deb01a Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 5 Dec 2016 00:56:11 +0100 Subject: [PATCH 82/94] Update AUTHORS.md --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 2a7ed1ed9..83777df18 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -23,6 +23,7 @@ Programmers Alexander Olofsson (Ace) Allofich AnyOldName3 + Aussiemon Austin Salgat (Salgat) Artem Kotsynyak (greye) artemutin From 99bcf4716778a4e45bce60b02d1ea210c6928ef8 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Mon, 5 Dec 2016 21:31:17 +0100 Subject: [PATCH 83/94] Implement NiSphericalCollider (Closes #3644) --- components/nif/controlled.cpp | 9 +++++ components/nif/controlled.hpp | 10 +++++ components/nif/niffile.cpp | 1 + components/nif/record.hpp | 3 +- components/nifosg/nifloader.cpp | 7 ++++ components/nifosg/particle.cpp | 69 +++++++++++++++++++++++++++++++++ components/nifosg/particle.hpp | 18 +++++++++ 7 files changed, 116 insertions(+), 1 deletion(-) diff --git a/components/nif/controlled.cpp b/components/nif/controlled.cpp index 5c63094ce..52e7a7302 100644 --- a/components/nif/controlled.cpp +++ b/components/nif/controlled.cpp @@ -87,6 +87,15 @@ namespace Nif nif->skip(17); } + void NiSphericalCollider::read(NIFStream* nif) + { + Controlled::read(nif); + + mBounceFactor = nif->getFloat(); + mRadius = nif->getFloat(); + mCenter = nif->getVector3(); + } + diff --git a/components/nif/controlled.hpp b/components/nif/controlled.hpp index 4bd7ce1f9..5601474ac 100644 --- a/components/nif/controlled.hpp +++ b/components/nif/controlled.hpp @@ -111,6 +111,16 @@ public: float mPlaneDistance; }; +class NiSphericalCollider : public Controlled +{ +public: + float mBounceFactor; + float mRadius; + osg::Vec3f mCenter; + + void read(NIFStream *nif); +}; + class NiParticleRotation : public Controlled { public: diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index f6e489527..b4b1caefc 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -89,6 +89,7 @@ static std::map makeFactory() newFactory.insert(makeEntry("NiStringExtraData", &construct , RC_NiStringExtraData )); newFactory.insert(makeEntry("NiGravity", &construct , RC_NiGravity )); newFactory.insert(makeEntry("NiPlanarCollider", &construct , RC_NiPlanarCollider )); + newFactory.insert(makeEntry("NiSphericalCollider", &construct , RC_NiSphericalCollider )); newFactory.insert(makeEntry("NiParticleGrowFade", &construct , RC_NiParticleGrowFade )); newFactory.insert(makeEntry("NiParticleColorModifier", &construct , RC_NiParticleColorModifier )); newFactory.insert(makeEntry("NiParticleRotation", &construct , RC_NiParticleRotation )); diff --git a/components/nif/record.hpp b/components/nif/record.hpp index bcbdba115..605c4d76e 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -92,7 +92,8 @@ enum RecordType RC_NiSequenceStreamHelper, RC_NiSourceTexture, RC_NiSkinInstance, - RC_RootCollisionNode + RC_RootCollisionNode, + RC_NiSphericalCollider }; /// Base class for all records diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 70ca82875..d4dabd2f9 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -871,6 +871,13 @@ namespace NifOsg const Nif::NiPlanarCollider* planarcollider = static_cast(colliders.getPtr()); program->addOperator(new PlanarCollider(planarcollider)); } + else if (colliders->recType == Nif::RC_NiSphericalCollider) + { + const Nif::NiSphericalCollider* sphericalcollider = static_cast(colliders.getPtr()); + program->addOperator(new SphericalCollider(sphericalcollider)); + } + else + std::cerr << "Unhandled particle collider " << colliders->recName << " in " << mFilename << std::endl; } } diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index f542cf379..0259b27e4 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -376,4 +376,73 @@ void PlanarCollider::operate(osgParticle::Particle *particle, double dt) } } +SphericalCollider::SphericalCollider(const Nif::NiSphericalCollider* collider) + : mBounceFactor(collider->mBounceFactor), + mSphere(collider->mCenter, collider->mRadius) +{ +} + +SphericalCollider::SphericalCollider() + : mBounceFactor(1.0f) +{ + +} + +SphericalCollider::SphericalCollider(const SphericalCollider& copy, const osg::CopyOp& copyop) + : osgParticle::Operator(copy, copyop) + , mBounceFactor(copy.mBounceFactor) + , mSphere(copy.mSphere) + , mSphereInParticleSpace(copy.mSphereInParticleSpace) +{ + +} + +void SphericalCollider::beginOperate(osgParticle::Program* program) +{ + mSphereInParticleSpace = mSphere; + if (program->getReferenceFrame() == osgParticle::ParticleProcessor::ABSOLUTE_RF) + mSphereInParticleSpace.center() = program->transformLocalToWorld(mSphereInParticleSpace.center()); +} + +void SphericalCollider::operate(osgParticle::Particle* particle, double dt) +{ + osg::Vec3f cent = (particle->getPosition() - mSphereInParticleSpace.center()); // vector from sphere center to particle + + bool insideSphere = cent.length2() <= mSphereInParticleSpace.radius2(); + + if (insideSphere + || (cent * particle->getVelocity() < 0.0f)) // if outside, make sure the particle is flying towards the sphere + { + // Collision test (finding point of contact) is performed by solving a quadratic equation: + // ||vec(cent) + vec(vel)*k|| = R /^2 + // k^2 + 2*k*(vec(cent)*vec(vel))/||vec(vel)||^2 + (||vec(cent)||^2 - R^2)/||vec(vel)||^2 = 0 + + float b = -(cent * particle->getVelocity()) / particle->getVelocity().length2(); + + osg::Vec3f u = cent + particle->getVelocity() * b; + + if (insideSphere + || (u.length2() < mSphereInParticleSpace.radius2())) + { + float d = (mSphereInParticleSpace.radius2() - u.length2()) / particle->getVelocity().length2(); + float k = insideSphere ? (std::sqrt(d) + b) : (b - std::sqrt(d)); + + if (k < dt) + { + // collision detected; reflect off the tangent plane + osg::Vec3f contact = particle->getPosition() + particle->getVelocity() * k; + + osg::Vec3 normal = (contact - mSphereInParticleSpace.center()); + normal.normalize(); + + float dotproduct = particle->getVelocity() * normal; + + osg::Vec3 reflectedVelocity = particle->getVelocity() - normal * (2 * dotproduct); + reflectedVelocity *= mBounceFactor; + particle->setVelocity(reflectedVelocity); + } + } + } +} + } diff --git a/components/nifosg/particle.hpp b/components/nifosg/particle.hpp index 6818aa7e0..f9c4abdac 100644 --- a/components/nifosg/particle.hpp +++ b/components/nifosg/particle.hpp @@ -16,6 +16,7 @@ namespace Nif { class NiGravity; class NiPlanarCollider; + class NiSphericalCollider; class NiColorData; } @@ -110,6 +111,23 @@ namespace NifOsg osg::Plane mPlaneInParticleSpace; }; + class SphericalCollider : public osgParticle::Operator + { + public: + SphericalCollider(const Nif::NiSphericalCollider* collider); + SphericalCollider(); + SphericalCollider(const SphericalCollider& copy, const osg::CopyOp& copyop); + + META_Object(NifOsg, SphericalCollider) + + virtual void beginOperate(osgParticle::Program* program); + virtual void operate(osgParticle::Particle* particle, double dt); + private: + float mBounceFactor; + osg::BoundingSphere mSphere; + osg::BoundingSphere mSphereInParticleSpace; + }; + class GrowFadeAffector : public osgParticle::Operator { public: From 6816e935f18aef75d50faf791b72266725333876 Mon Sep 17 00:00:00 2001 From: Allofich Date: Mon, 5 Dec 2016 20:12:13 +0900 Subject: [PATCH 84/94] Fix fortify maximum magicka expiration (Fixes #3648) --- apps/openmw/mwmechanics/actors.cpp | 10 ++++++---- apps/openmw/mwmechanics/spellcasting.cpp | 7 +++++-- apps/openmw/mwmechanics/spellcasting.hpp | 4 +++- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 1a6a62fc3..2a5995e0c 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -512,8 +512,8 @@ namespace MWMechanics if (magnitude > 0 && remainingTime > 0 && remainingTime < mDuration) { CreatureStats& creatureStats = mActor.getClass().getCreatureStats(mActor); - effectTick(creatureStats, mActor, key, magnitude * remainingTime); - creatureStats.getMagicEffects().add(key, -magnitude); + if (effectTick(creatureStats, mActor, key, magnitude * remainingTime)) + creatureStats.getMagicEffects().add(key, -magnitude); } } }; @@ -527,8 +527,10 @@ namespace MWMechanics if (duration > 0) { - // apply correct magnitude for tickable effects that have just expired, - // in case duration > remaining time of effect + // Apply correct magnitude for tickable effects that have just expired, + // in case duration > remaining time of effect. + // One case where this will happen is when the player uses the rest/wait command + // while there is a tickable effect active that should expire before the end of the rest/wait. ExpiryVisitor visitor(ptr, duration); creatureStats.getActiveSpells().visitEffectSources(visitor); diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 5865c32b9..72f0cddff 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -1009,10 +1009,10 @@ namespace MWMechanics creatureStats.setDynamic(index, stat); } - void effectTick(CreatureStats& creatureStats, const MWWorld::Ptr& actor, const EffectKey &effectKey, float magnitude) + bool effectTick(CreatureStats& creatureStats, const MWWorld::Ptr& actor, const EffectKey &effectKey, float magnitude) { if (magnitude == 0.f) - return; + return false; bool receivedMagicDamage = false; @@ -1144,10 +1144,13 @@ namespace MWMechanics case ESM::MagicEffect::RemoveCurse: actor.getClass().getCreatureStats(actor).getSpells().purgeCurses(); break; + default: + return false; } if (receivedMagicDamage && actor == getPlayer()) MWBase::Environment::get().getWindowManager()->activateHitOverlay(false); + return true; } } diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index 852ae79dc..6e25acf50 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -63,7 +63,9 @@ namespace MWMechanics int getEffectiveEnchantmentCastCost (float castCost, const MWWorld::Ptr& actor); - void effectTick(CreatureStats& creatureStats, const MWWorld::Ptr& actor, const MWMechanics::EffectKey& effectKey, float magnitude); + /// Apply a magic effect that is applied in tick intervals until its remaining time ends or it is removed + /// @return Was the effect a tickable effect with a magnitude? + bool effectTick(CreatureStats& creatureStats, const MWWorld::Ptr& actor, const MWMechanics::EffectKey& effectKey, float magnitude); class CastSpell { From a6dae51d87f2529a458c845144d1b6325c556070 Mon Sep 17 00:00:00 2001 From: Allofich Date: Tue, 6 Dec 2016 22:23:06 +0900 Subject: [PATCH 85/94] Require line of sight for AI attacks (Fixes #3646) --- apps/openmw/mwmechanics/aicombat.cpp | 54 +++++++++++++++------------- apps/openmw/mwmechanics/aicombat.hpp | 2 ++ 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 80b343d4f..21eaa0de5 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -60,30 +60,30 @@ namespace MWMechanics FleeState_RunToDestination }; FleeState mFleeState; - bool mFleeLOS; - float mFleeUpdateLOSTimer; + bool mLOS; + float mUpdateLOSTimer; float mFleeBlindRunTimer; ESM::Pathgrid::Point mFleeDest; AiCombatStorage(): - mAttackCooldown(0), + mAttackCooldown(0.0f), mTimerReact(AI_REACTION_TIME), - mTimerCombatMove(0), + mTimerCombatMove(0.0f), mReadyToAttack(false), mAttack(false), - mAttackRange(0), + mAttackRange(0.0f), mCombatMove(false), mLastTargetPos(0,0,0), mCell(NULL), mCurrentAction(), - mActionCooldown(0), + mActionCooldown(0.0f), mStrength(), mForceNoShortcut(false), mShortcutFailPos(), mMovement(), mFleeState(FleeState_None), - mFleeLOS(false), - mFleeUpdateLOSTimer(0.0f), + mLOS(false), + mUpdateLOSTimer(0.0f), mFleeBlindRunTimer(0.0f) {} @@ -181,10 +181,14 @@ namespace MWMechanics if (!storage.isFleeing()) { - if (storage.mCurrentAction.get()) // need to wait to init action with it's attack range + if (storage.mCurrentAction.get()) // need to wait to init action with its attack range { - //Update every frame - bool is_target_reached = pathTo(actor, target.getRefData().getPosition().pos, duration, storage.mAttackRange); + //Update every frame. UpdateLOS uses a timer, so the LOS check does not happen every frame. + updateLOS(actor, target, duration, storage); + float targetReachedTolerance = 0.0f; + if (storage.mLOS) + targetReachedTolerance = storage.mAttackRange; + bool is_target_reached = pathTo(actor, target.getRefData().getPosition().pos, duration, targetReachedTolerance); if (is_target_reached) storage.mReadyToAttack = true; } @@ -283,7 +287,7 @@ namespace MWMechanics osg::Vec3f vAimDir = MWBase::Environment::get().getWorld()->aimToTarget(actor, target); float distToTarget = MWBase::Environment::get().getWorld()->getHitDistance(actor, target); - storage.mReadyToAttack = (currentAction->isAttackingOrSpell() && distToTarget <= rangeAttack); + storage.mReadyToAttack = (currentAction->isAttackingOrSpell() && distToTarget <= rangeAttack && storage.mLOS); if (storage.mReadyToAttack) { @@ -309,18 +313,23 @@ namespace MWMechanics } } - void MWMechanics::AiCombat::updateFleeing(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, float duration, MWMechanics::AiCombatStorage& storage) + void MWMechanics::AiCombat::updateLOS(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, float duration, MWMechanics::AiCombatStorage& storage) { static const float LOS_UPDATE_DURATION = 0.5f; - static const float BLIND_RUN_DURATION = 1.0f; - - if (storage.mFleeUpdateLOSTimer <= 0.f) + if (storage.mUpdateLOSTimer <= 0.f) { - storage.mFleeLOS = MWBase::Environment::get().getWorld()->getLOS(actor, target); - storage.mFleeUpdateLOSTimer = LOS_UPDATE_DURATION; + storage.mLOS = MWBase::Environment::get().getWorld()->getLOS(actor, target); + storage.mUpdateLOSTimer = LOS_UPDATE_DURATION; } else - storage.mFleeUpdateLOSTimer -= duration; + storage.mUpdateLOSTimer -= duration; + } + + void MWMechanics::AiCombat::updateFleeing(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, float duration, MWMechanics::AiCombatStorage& storage) + { + static const float BLIND_RUN_DURATION = 1.0f; + + updateLOS(actor, target, duration, storage); AiCombatStorage::FleeState& state = storage.mFleeState; switch (state) @@ -332,7 +341,7 @@ namespace MWMechanics { float triggerDist = getMaxAttackDistance(target); - if (storage.mFleeLOS && + if (storage.mLOS && (triggerDist >= 1000 || getDistanceMinusHalfExtents(actor, target) <= triggerDist)) { const ESM::Pathgrid* pathgrid = @@ -399,7 +408,7 @@ namespace MWMechanics static const float fFleeDistance = MWBase::Environment::get().getWorld()->getStore().get().find("fFleeDistance")->getFloat(); float dist = (actor.getRefData().getPosition().asVec3() - target.getRefData().getPosition().asVec3()).length(); - if ((dist > fFleeDistance && !storage.mFleeLOS) + if ((dist > fFleeDistance && !storage.mLOS) || pathTo(actor, storage.mFleeDest, duration)) { state = AiCombatStorage::FleeState_Idle; @@ -602,9 +611,6 @@ namespace MWMechanics mMovement.mPosition[2] = 0; mFleeState = FleeState_None; mFleeDest = ESM::Pathgrid::Point(0, 0, 0); - mFleeLOS = false; - mFleeUpdateLOSTimer = 0.0f; - mFleeUpdateLOSTimer = 0.0f; } bool AiCombatStorage::isFleeing() diff --git a/apps/openmw/mwmechanics/aicombat.hpp b/apps/openmw/mwmechanics/aicombat.hpp index 3f2bde776..a2e995cb3 100644 --- a/apps/openmw/mwmechanics/aicombat.hpp +++ b/apps/openmw/mwmechanics/aicombat.hpp @@ -61,6 +61,8 @@ namespace MWMechanics void attack(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, AiCombatStorage& storage, CharacterController& characterController); + void updateLOS(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, float duration, AiCombatStorage& storage); + void updateFleeing(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, float duration, AiCombatStorage& storage); /// Transfer desired movement (from AiCombatStorage) to Actor From 9624d8aade018e5d617bac029273013378c930da Mon Sep 17 00:00:00 2001 From: mrohrlach Date: Fri, 9 Dec 2016 19:48:56 -0700 Subject: [PATCH 86/94] Added new method and variable to track float remainders of disintegration effections --- apps/openmw/mwmechanics/spellcasting.cpp | 6 ++++-- apps/openmw/mwworld/cellref.cpp | 19 +++++++++++++++++++ apps/openmw/mwworld/cellref.hpp | 1 + apps/openmw/mwworld/manualref.cpp | 1 + components/esm/cellref.cpp | 1 + components/esm/cellref.hpp | 1 + 6 files changed, 27 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 72f0cddff..6b1707218 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -980,8 +980,10 @@ namespace MWMechanics if (charge == 0) return false; - // FIXME: charge should be a float, not int so that damage < 1 per frame can be applied. - // This was also a bug in the original engine. + // Store remainder of disintegrate amount (automatically subtracted if > 1) + item->getCellRef().applyChargeRemainderToBeSubtracted(disintegrate - std::floor(disintegrate)); + + charge = item->getClass().getItemHealth(*item); charge -= std::min(static_cast(disintegrate), charge); diff --git a/apps/openmw/mwworld/cellref.cpp b/apps/openmw/mwworld/cellref.cpp index 0d81e0636..9180e9e20 100644 --- a/apps/openmw/mwworld/cellref.cpp +++ b/apps/openmw/mwworld/cellref.cpp @@ -93,6 +93,25 @@ namespace MWWorld } } + void CellRef::applyChargeRemainderToBeSubtracted(float chargeRemainder) + { + mCellRef.mChargeIntRemainder += std::abs(chargeRemainder); + if (mCellRef.mChargeIntRemainder > 1.0f) + { + float newChargeRemainder = (mCellRef.mChargeIntRemainder - std::floor(mCellRef.mChargeIntRemainder)); + if (mCellRef.mChargeInt <= static_cast(mCellRef.mChargeIntRemainder)) + { + mCellRef.mChargeInt = 0; + } + else + { + mCellRef.mChargeInt -= static_cast(mCellRef.mChargeIntRemainder); + } + + mCellRef.mChargeIntRemainder = newChargeRemainder; + } + } + float CellRef::getChargeFloat() const { return mCellRef.mChargeFloat; diff --git a/apps/openmw/mwworld/cellref.hpp b/apps/openmw/mwworld/cellref.hpp index b8e85f286..c8c4529e9 100644 --- a/apps/openmw/mwworld/cellref.hpp +++ b/apps/openmw/mwworld/cellref.hpp @@ -65,6 +65,7 @@ namespace MWWorld float getChargeFloat() const; // Implemented as union with int charge void setCharge(int charge); void setChargeFloat(float charge); + void applyChargeRemainderToBeSubtracted(float chargeRemainder); // The NPC that owns this object (and will get angry if you steal it) std::string getOwner() const; diff --git a/apps/openmw/mwworld/manualref.cpp b/apps/openmw/mwworld/manualref.cpp index c683f7e03..48270d224 100644 --- a/apps/openmw/mwworld/manualref.cpp +++ b/apps/openmw/mwworld/manualref.cpp @@ -16,6 +16,7 @@ namespace cellRef.mScale = 1; cellRef.mFactionRank = 0; cellRef.mChargeInt = -1; + cellRef.mChargeIntRemainder = 0.0f; cellRef.mGoldValue = 1; cellRef.mEnchantmentCharge = -1; cellRef.mTeleport = false; diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index 74d45bb0c..e41201d6e 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -196,6 +196,7 @@ void ESM::CellRef::blank() mFaction.clear(); mFactionRank = -2; mChargeInt = -1; + mChargeIntRemainder = 0.0f; mEnchantmentCharge = -1; mGoldValue = 0; mDestCell.clear(); diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp index 3c646cc61..a3c56cf13 100644 --- a/components/esm/cellref.hpp +++ b/components/esm/cellref.hpp @@ -69,6 +69,7 @@ namespace ESM int mChargeInt; // Used by everything except lights float mChargeFloat; // Used only by lights }; + float mChargeIntRemainder; // Used by everythign except lights (amount of charge not applied to mChargeInt) // Remaining enchantment charge. This could be -1 if the charge was not touched yet (i.e. full). float mEnchantmentCharge; From f0f78c9d644ace8e555bd15ebc1dc496f32b38e5 Mon Sep 17 00:00:00 2001 From: mrohrlach Date: Fri, 9 Dec 2016 19:55:26 -0700 Subject: [PATCH 87/94] Slight adjustments to disintegration fix --- apps/openmw/mwworld/cellref.cpp | 1 - apps/openmw/mwworld/cellref.hpp | 2 +- components/esm/cellref.hpp | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/cellref.cpp b/apps/openmw/mwworld/cellref.cpp index 9180e9e20..72ee56e6a 100644 --- a/apps/openmw/mwworld/cellref.cpp +++ b/apps/openmw/mwworld/cellref.cpp @@ -107,7 +107,6 @@ namespace MWWorld { mCellRef.mChargeInt -= static_cast(mCellRef.mChargeIntRemainder); } - mCellRef.mChargeIntRemainder = newChargeRemainder; } } diff --git a/apps/openmw/mwworld/cellref.hpp b/apps/openmw/mwworld/cellref.hpp index c8c4529e9..7e27e6ef3 100644 --- a/apps/openmw/mwworld/cellref.hpp +++ b/apps/openmw/mwworld/cellref.hpp @@ -65,7 +65,7 @@ namespace MWWorld float getChargeFloat() const; // Implemented as union with int charge void setCharge(int charge); void setChargeFloat(float charge); - void applyChargeRemainderToBeSubtracted(float chargeRemainder); + void applyChargeRemainderToBeSubtracted(float chargeRemainder); // Stores remainders and applies if > 1 // The NPC that owns this object (and will get angry if you steal it) std::string getOwner() const; diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp index a3c56cf13..f14617531 100644 --- a/components/esm/cellref.hpp +++ b/components/esm/cellref.hpp @@ -69,7 +69,7 @@ namespace ESM int mChargeInt; // Used by everything except lights float mChargeFloat; // Used only by lights }; - float mChargeIntRemainder; // Used by everythign except lights (amount of charge not applied to mChargeInt) + float mChargeIntRemainder; // Stores amount of charge not subtracted from mChargeInt // Remaining enchantment charge. This could be -1 if the charge was not touched yet (i.e. full). float mEnchantmentCharge; From 8c97ac269d5c08b8b0efa432bc601d7758e52983 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sat, 10 Dec 2016 22:22:41 +0100 Subject: [PATCH 88/94] Remove item shadows properly (Fixes #3652) --- apps/openmw/mwgui/itemwidget.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwgui/itemwidget.cpp b/apps/openmw/mwgui/itemwidget.cpp index 87fca941e..fe7cb79de 100644 --- a/apps/openmw/mwgui/itemwidget.cpp +++ b/apps/openmw/mwgui/itemwidget.cpp @@ -101,6 +101,8 @@ namespace MWGui { if (mFrame) mFrame->setImageTexture(""); + if (mItemShadow) + mItemShadow->setImageTexture(""); mItem->setImageTexture(""); mText->setCaption(""); return; From 76ee5845ac17b11b82d34e4b43fb0348c062499a Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sun, 11 Dec 2016 19:35:53 +0100 Subject: [PATCH 89/94] Fix swish sound ID and play swish sound effects for all creatures (Fixes #3653) --- apps/openmw/mwmechanics/character.cpp | 24 +++++++++++++++++------- apps/openmw/mwmechanics/character.hpp | 2 ++ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index d9cae3a90..c771d9fcc 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1049,6 +1049,9 @@ bool CharacterController::updateCreatureState() mUpperBodyState = UpperCharState_StartToMinAttack; mAttackStrength = std::min(1.f, 0.1f + Misc::Rng::rollClosedProbability()); + + if (weapType == WeapType_HandToHand) + playSwishSound(0.0f); } } @@ -1370,13 +1373,7 @@ bool CharacterController::updateWeaponState() } else { - std::string sound = "SwishM"; - if(attackStrength < 0.5f) - sndMgr->playSound3D(mPtr, sound, 1.0f, 0.8f); //Weak attack - else if(attackStrength < 1.0f) - sndMgr->playSound3D(mPtr, sound, 1.0f, 1.0f); //Medium attack - else - sndMgr->playSound3D(mPtr, sound, 1.0f, 1.2f); //Strong attack + playSwishSound(attackStrength); } } mAttackStrength = attackStrength; @@ -2271,6 +2268,19 @@ void CharacterController::setHeadTrackTarget(const MWWorld::ConstPtr &target) mHeadTrackTarget = target; } +void CharacterController::playSwishSound(float attackStrength) +{ + MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); + + std::string sound = "Weapon Swish"; + if(attackStrength < 0.5f) + sndMgr->playSound3D(mPtr, sound, 1.0f, 0.8f); //Weak attack + else if(attackStrength < 1.0f) + sndMgr->playSound3D(mPtr, sound, 1.0f, 1.0f); //Medium attack + else + sndMgr->playSound3D(mPtr, sound, 1.0f, 1.2f); //Strong attack +} + void CharacterController::updateHeadTracking(float duration) { const osg::Node* head = mAnimation->getNode("Bip01 Head"); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 3a84f0f78..f393f0619 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -281,6 +281,8 @@ public: /// Make this character turn its head towards \a target. To turn off head tracking, pass an empty Ptr. void setHeadTrackTarget(const MWWorld::ConstPtr& target); + + void playSwishSound(float attackStrength); }; MWWorld::ContainerStoreIterator getActiveWeapon(CreatureStats &stats, MWWorld::InventoryStore &inv, WeaponType *weaptype); From 2d928fac3660835aa80e8c8dd63c352c7992a652 Mon Sep 17 00:00:00 2001 From: jeffreyhaines Date: Tue, 13 Dec 2016 10:46:16 -0500 Subject: [PATCH 90/94] Minor spelling correction --- docs/source/openmw-cs/tour.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/openmw-cs/tour.rst b/docs/source/openmw-cs/tour.rst index 3ddeac4fa..0533529e4 100644 --- a/docs/source/openmw-cs/tour.rst +++ b/docs/source/openmw-cs/tour.rst @@ -5,7 +5,7 @@ In this first chapter we will create a mod that adds a new ring with a simple enchantment to the game. The ring will give its wearer a permanent Night Vision effect while being worn. You don't need prior knowledge about modding Morrowind, but you should be familiar with the game itself. There will be no -scripting necessary, we chan achieve everything using just what the base game +scripting necessary, we can achieve everything using just what the base game offers out of the box. Before continuing make sure that OpenMW is properly installed and playable. From d95a66351040b6ef68003d1534350517e4500eaa Mon Sep 17 00:00:00 2001 From: jeffreyhaines Date: Tue, 13 Dec 2016 11:11:21 -0500 Subject: [PATCH 91/94] Minor grammar and sentence changes --- docs/source/openmw-cs/tour.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/source/openmw-cs/tour.rst b/docs/source/openmw-cs/tour.rst index 3ddeac4fa..dee0ba3a9 100644 --- a/docs/source/openmw-cs/tour.rst +++ b/docs/source/openmw-cs/tour.rst @@ -3,8 +3,8 @@ A Tour through OpenMW CS: making a magic ring In this first chapter we will create a mod that adds a new ring with a simple enchantment to the game. The ring will give its wearer a permanent Night Vision -effect while being worn. You don't need prior knowledge about modding -Morrowind, but you should be familiar with the game itself. There will be no +effect while being worn. You do not need prior Morrowind modding experience, +but you should be familiar with the game itself. There will be no scripting necessary, we chan achieve everything using just what the base game offers out of the box. Before continuing make sure that OpenMW is properly installed and playable. @@ -13,7 +13,7 @@ installed and playable. Adding the ring to the game's records ************************************* -In this first section we will define what our new ring is, what it looks like +In this first section we will define what our new ring is, what it looks like, and what it does. Getting it to work is the first step before we go further. @@ -28,11 +28,11 @@ options: create a new game, create a new addon, edit a content file. :alt: Opening dialogue with three option and setting button (the wrench) The first option is for creating an entirely new game, that's not what we want. -We want to edit an existing game, so choose the second one. When you save your +We want to edit an existing game, so choose the second option. When you save your addon you can use the third option to open it again. -You will be presented with another window where you get to chose the content to -edit and the name of your project. We have to chose at least a base game, and +You will be presented with another window where you get to choose the content to +edit and the name of your project. Then we have to select at least the base game, and optionally a number of other addons we want to depend on. The name of the project is arbitrary, it will be used to identify the addon later in the OpenMW launcher. @@ -41,7 +41,7 @@ launcher. :alt: Creation dialogue for a new project, pick content modules and name Choose Morrowind as your content file and enter `Ring of Night Vision` as the -name. We could also chose further content files as dependencies if we wanted +name. We could also choose further content files as dependencies if we wanted to, but for this mod the base game is enough. Once the addon has been created you will be presented with a table. If you see @@ -58,7 +58,7 @@ detached panel can be re-attached to a window by dragging it by the title bar on top of the window. Now let's look at the panel itself: we have a filter text field, a very large -table and a status bar. The filter will be very useful when we want to find an +table, and a status bar. The filter will be very useful when we want to find an entry in the table, but for now it is irrelevant. The table you are looking at contains all objects in the game, these can be items, NPCs, creatures, whatever. Every object is an entry in that table, visible as a row. The columns @@ -95,7 +95,7 @@ holding Shift to edit it (this is a configurable shortcut), but there is a better way: right-click the row of our new record and chose *Edit Record*, a new panel will open. -We can right-click the row of our new record and chose *Edit Record*, a +We can right-click the row of our new record and choose *Edit Record*, a new panel will open. Alternatively we can also define a configurable shortcut instead of using the context menu; the default is double-clicking while holding down the shift key. From 2fe2b57faa7144d6a63e36a3c76856cc97f83909 Mon Sep 17 00:00:00 2001 From: jeffreyhaines Date: Tue, 13 Dec 2016 13:27:43 -0500 Subject: [PATCH 92/94] Replaced choose with select --- docs/source/openmw-cs/tour.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/openmw-cs/tour.rst b/docs/source/openmw-cs/tour.rst index dee0ba3a9..3dd627aa1 100644 --- a/docs/source/openmw-cs/tour.rst +++ b/docs/source/openmw-cs/tour.rst @@ -95,7 +95,7 @@ holding Shift to edit it (this is a configurable shortcut), but there is a better way: right-click the row of our new record and chose *Edit Record*, a new panel will open. -We can right-click the row of our new record and choose *Edit Record*, a +We can right-click the row of our new record and select *Edit Record*, a new panel will open. Alternatively we can also define a configurable shortcut instead of using the context menu; the default is double-clicking while holding down the shift key. From 6fadcc674848c85dd64acf667b9fa07ccc5e33b5 Mon Sep 17 00:00:00 2001 From: jeffreyhaines Date: Tue, 13 Dec 2016 13:29:22 -0500 Subject: [PATCH 93/94] Replaced "prior" with "previous" --- docs/source/openmw-cs/tour.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/openmw-cs/tour.rst b/docs/source/openmw-cs/tour.rst index 3dd627aa1..f1c72a65d 100644 --- a/docs/source/openmw-cs/tour.rst +++ b/docs/source/openmw-cs/tour.rst @@ -3,7 +3,7 @@ A Tour through OpenMW CS: making a magic ring In this first chapter we will create a mod that adds a new ring with a simple enchantment to the game. The ring will give its wearer a permanent Night Vision -effect while being worn. You do not need prior Morrowind modding experience, +effect while being worn. You do not need previous Morrowind modding experience, but you should be familiar with the game itself. There will be no scripting necessary, we chan achieve everything using just what the base game offers out of the box. Before continuing make sure that OpenMW is properly From 829f6848990312ab004cc0430d8065bcf3740328 Mon Sep 17 00:00:00 2001 From: jeffreyhaines Date: Tue, 13 Dec 2016 15:39:30 -0500 Subject: [PATCH 94/94] Removed Oxford comma --- docs/source/openmw-cs/tour.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/openmw-cs/tour.rst b/docs/source/openmw-cs/tour.rst index f1c72a65d..608a6c1ab 100644 --- a/docs/source/openmw-cs/tour.rst +++ b/docs/source/openmw-cs/tour.rst @@ -32,7 +32,7 @@ We want to edit an existing game, so choose the second option. When you save you addon you can use the third option to open it again. You will be presented with another window where you get to choose the content to -edit and the name of your project. Then we have to select at least the base game, and +edit and the name of your project. Then we have to select at least the base game and optionally a number of other addons we want to depend on. The name of the project is arbitrary, it will be used to identify the addon later in the OpenMW launcher. @@ -58,7 +58,7 @@ detached panel can be re-attached to a window by dragging it by the title bar on top of the window. Now let's look at the panel itself: we have a filter text field, a very large -table, and a status bar. The filter will be very useful when we want to find an +table and a status bar. The filter will be very useful when we want to find an entry in the table, but for now it is irrelevant. The table you are looking at contains all objects in the game, these can be items, NPCs, creatures, whatever. Every object is an entry in that table, visible as a row. The columns @@ -67,7 +67,7 @@ of the table are the attributes of each object. Morrowind uses something called a *relational database* for game data. If you are not familiar with the term, it means that every type of thing can be expressed as a *table*: there is a table for objects, a table for enchantments, -a table for icons, one for meshes, and so on. Properties of an entry must be +a table for icons, one for meshes and so on. Properties of an entry must be simple values, like numbers or text strings. If we want a more complicated property we need to reference an entry from another table. There are a few exceptions to this though, some tables do have subtables. The effects of