diff --git a/.gitignore b/.gitignore index f22f1bd49c..c061ca637e 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,6 @@ CMakeFiles */CMakeFiles CMakeCache.txt cmake_install.cmake -CMakeLists.txt.user Makefile makefile build @@ -22,6 +21,8 @@ Doxygen .project .settings .directory +## qt-creator +CMakeLists.txt.user* ## resources data diff --git a/.travis.yml b/.travis.yml index 112cf94f16..04d019c0d8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,7 +15,7 @@ before_install: - sudo apt-get install -qq libqt4-dev libxaw7-dev libxrandr-dev libfreeimage-dev libpng-dev - sudo apt-get install -qq libopenal-dev libmpg123-dev libsndfile1-dev - sudo apt-get install -qq libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev libpostproc-dev - - sudo apt-get install -qq libbullet-dev libogre-1.8-dev libmygui-dev libsdl2-dev libunshield-dev + - sudo apt-get install -qq libbullet-dev libogre-1.9-dev libmygui-dev libsdl2-dev libunshield-dev - sudo mkdir /usr/src/gtest/build - cd /usr/src/gtest/build - sudo cmake .. -DBUILD_SHARED_LIBS=1 diff --git a/CMakeLists.txt b/CMakeLists.txt index f6014dff6e..64f8121c49 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -99,8 +99,6 @@ set(OENGINE_BULLET ${LIBDIR}/openengine/bullet/BtOgreExtras.h ${LIBDIR}/openengine/bullet/BtOgreGP.h ${LIBDIR}/openengine/bullet/BtOgrePG.h - ${LIBDIR}/openengine/bullet/CMotionState.cpp - ${LIBDIR}/openengine/bullet/CMotionState.h ${LIBDIR}/openengine/bullet/physic.cpp ${LIBDIR}/openengine/bullet/physic.hpp ${LIBDIR}/openengine/bullet/BulletShapeLoader.cpp @@ -212,7 +210,7 @@ if (HAVE_UNORDERED_MAP) endif () -set(BOOST_COMPONENTS system filesystem program_options thread date_time wave) +set(BOOST_COMPONENTS system filesystem program_options) IF(BOOST_STATIC) set(Boost_USE_STATIC_LIBS ON) diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 18c555a249..e4638c31b4 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -137,8 +137,3 @@ if (BUILD_WITH_CODE_COVERAGE) target_link_libraries(omwlauncher gcov) endif() -# Workaround for binutil => 2.23 problem when linking, should be fixed eventually upstream -if (UNIX AND NOT APPLE) -target_link_libraries(omwlauncher dl Xt) -endif() - diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 1197e20140..e2dffdbde4 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -143,7 +143,7 @@ if(WIN32) set(QT_USE_QTMAIN TRUE) endif(WIN32) -find_package(Qt4 COMPONENTS QtCore QtGui QtNetwork QtXml QtXmlPatterns REQUIRED) +find_package(Qt4 COMPONENTS QtCore QtGui QtNetwork REQUIRED) include(${QT_USE_FILE}) qt4_wrap_ui(OPENCS_UI_HDR ${OPENCS_UI}) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index e87da97c30..8c8a1b3248 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -74,6 +74,7 @@ add_openmw_dir (mwmechanics mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow aiescort aiactivate aicombat repair enchanting pathfinding security spellsuccess spellcasting + disease ) add_openmw_dir (mwbase @@ -82,6 +83,8 @@ add_openmw_dir (mwbase ) # Main executable +set(BOOST_COMPONENTS system filesystem program_options thread wave) +find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) IF(OGRE_STATIC) ADD_DEFINITIONS(-DENABLE_PLUGIN_OctreeSceneManager -DENABLE_PLUGIN_ParticleFX -DENABLE_PLUGIN_GL) @@ -111,6 +114,7 @@ add_definitions(${SOUND_DEFINE}) target_link_libraries(openmw ${OGRE_LIBRARIES} ${OGRE_STATIC_PLUGINS} + ${SHINY_LIBRARIES} ${Boost_LIBRARIES} ${OPENAL_LIBRARY} ${SOUND_INPUT_LIBRARY} @@ -118,7 +122,6 @@ target_link_libraries(openmw ${MYGUI_LIBRARIES} ${SDL2_LIBRARY} ${MYGUI_PLATFORM_LIBRARIES} - ${SHINY_LIBRARIES} "oics" "sdl4ogre" components @@ -137,12 +140,6 @@ if (UNIX AND NOT APPLE) target_link_libraries(openmw ${CMAKE_THREAD_LIBS_INIT}) endif() -# Workaround for binutil => 2.23 problem when linking, should be fixed eventually upstream -if (UNIX AND NOT APPLE) -target_link_libraries(openmw dl Xt) -endif() - - if(APPLE) find_library(COCOA_FRAMEWORK Cocoa) find_library(IOKIT_FRAMEWORK IOKit) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 1300efc753..6c85be5fd2 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -137,8 +137,8 @@ namespace MWBase virtual void wmUpdateFps(float fps, unsigned int triangleCount, unsigned int batchCount) = 0; /// Set value for the given ID. - virtual void setValue (const std::string& id, const MWMechanics::Stat& value) = 0; - virtual void setValue (int parSkill, const MWMechanics::Stat& value) = 0; + virtual void setValue (const std::string& id, const MWMechanics::AttributeValue& value) = 0; + virtual void setValue (int parSkill, const MWMechanics::SkillValue& value) = 0; virtual void setValue (const std::string& id, const MWMechanics::DynamicStat& value) = 0; virtual void setValue (const std::string& id, const std::string& value) = 0; virtual void setValue (const std::string& id, int value) = 0; @@ -236,8 +236,8 @@ namespace MWBase virtual void onFrame (float frameDuration) = 0; /// \todo get rid of this stuff. Move it to the respective UI element classes, if needed. - virtual std::map > getPlayerSkillValues() = 0; - virtual std::map > getPlayerAttributeValues() = 0; + virtual std::map getPlayerSkillValues() = 0; + virtual std::map getPlayerAttributeValues() = 0; virtual SkillList getPlayerMinorSkills() = 0; virtual SkillList getPlayerMajorSkills() = 0; diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 48803a2d80..3a88971149 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -130,7 +130,7 @@ namespace MWBase virtual Ogre::Vector2 getNorthVector (MWWorld::CellStore* cell) = 0; ///< get north vector (OGRE coordinates) for given interior cell - virtual std::vector getDoorMarkers (MWWorld::CellStore* cell) = 0; + virtual void getDoorMarkers (MWWorld::CellStore* cell, std::vector& out) = 0; ///< get a list of teleport door markers for a given cell, to be displayed on the local map virtual void getInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y) = 0; @@ -428,7 +428,28 @@ namespace MWBase virtual void breakInvisibility (const MWWorld::Ptr& actor) = 0; - virtual bool isNight() const = 0; + // Are we in an exterior or pseudo-exterior cell and it's night? + virtual bool isDark() const = 0; + + virtual bool findInteriorPositionInWorldSpace(MWWorld::CellStore* cell, Ogre::Vector3& result) = 0; + + /// Teleports \a ptr to the reference of \a id (e.g. DivineMarker, PrisonMarker, TempleMarker) + /// closest to \a worldPos. + /// @note id must be lower case + virtual void teleportToClosestMarker (const MWWorld::Ptr& ptr, + const std::string& id, Ogre::Vector3 worldPos) = 0; + + enum DetectionType + { + Detect_Enchantment, + Detect_Key, + Detect_Creature + }; + /// List all references (filtered by \a type) detected by \a ptr. The range + /// is determined by the current magnitude of the "Detect X" magic effect belonging to \a type. + /// @note This also works for references in containers. + virtual void listDetectedReferences (const MWWorld::Ptr& ptr, std::vector& out, + DetectionType type) = 0; }; } diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 5b2b7caa39..0fae1b05c3 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -291,44 +291,36 @@ namespace MWClass { MWWorld::InventoryStore& invStore = MWWorld::Class::get(npc).getInventoryStore(npc); + if (ptr.getCellRef().mCharge == 0) + return std::make_pair(0, "#{sInventoryMessage1}"); + // slots that this item can be equipped in std::pair, bool> slots_ = MWWorld::Class::get(ptr).getEquipmentSlots(ptr); + if (slots_.first.empty()) + return std::make_pair(0, ""); + std::string npcRace = npc.get()->mBase->mRace; + // Beast races cannot equip shoes / boots, or full helms (head part vs hair part) + const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(npcRace); + if(race->mData.mFlags & ESM::Race::Beast) + { + std::vector parts = ptr.get()->mBase->mParts.mParts; + + for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) + { + if((*itr).mPart == ESM::PRT_Head) + return std::make_pair(0, "#{sNotifyMessage13}"); + if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot) + return std::make_pair(0, "#{sNotifyMessage14}"); + } + } + for (std::vector::const_iterator slot=slots_.first.begin(); slot!=slots_.first.end(); ++slot) { - - // Beast races cannot equip shoes / boots, or full helms (head part vs hair part) - const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(npcRace); - if(race->mData.mFlags & ESM::Race::Beast) - { - std::vector parts = ptr.get()->mBase->mParts.mParts; - - if(*slot == MWWorld::InventoryStore::Slot_Helmet) - { - for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) - { - if((*itr).mPart == ESM::PRT_Head) - { - return std::make_pair(0, "#{sNotifyMessage13}"); - } - } - } - - if (*slot == MWWorld::InventoryStore::Slot_Boots) - { - for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) - { - if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot) - { - return std::make_pair(0, "#{sNotifyMessage14}"); - } - } - } - } - + // If equipping a shield, check if there's a twohanded weapon conflicting with it if(*slot == MWWorld::InventoryStore::Slot_CarriedLeft) { MWWorld::ContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index c162bbe9de..ffa96260df 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -235,37 +235,26 @@ namespace MWClass // slots that this item can be equipped in std::pair, bool> slots_ = MWWorld::Class::get(ptr).getEquipmentSlots(ptr); + if (slots_.first.empty()) + return std::make_pair(0, ""); + std::string npcRace = npc.get()->mBase->mRace; - for (std::vector::const_iterator slot=slots_.first.begin(); - slot!=slots_.first.end(); ++slot) + // Beast races cannot equip shoes / boots, or full helms (head part vs hair part) + const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(npcRace); + if(race->mData.mFlags & ESM::Race::Beast) { + std::vector parts = ptr.get()->mBase->mParts.mParts; - // Beast races cannot equip shoes / boots, or full helms (head part vs hair part) - const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(npcRace); - if(race->mData.mFlags & ESM::Race::Beast) + for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) { - std::vector parts = ptr.get()->mBase->mParts.mParts; - - if(*slot == MWWorld::InventoryStore::Slot_Helmet) - { - for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) - { - if((*itr).mPart == ESM::PRT_Head) - return std::make_pair(0, "#{sNotifyMessage13}"); - } - } - - if (*slot == MWWorld::InventoryStore::Slot_Boots) - { - for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) - { - if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot) - return std::make_pair(0, "#{sNotifyMessage15}"); - } - } + if((*itr).mPart == ESM::PRT_Head) + return std::make_pair(0, "#{sNotifyMessage13}"); + if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot) + return std::make_pair(0, "#{sNotifyMessage15}"); } } + return std::make_pair (1, ""); } diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 1a40c45554..d211891035 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -242,7 +242,11 @@ namespace MWClass item.get(); return !ref->mBase->mData.mIsKey && (npcServices & ESM::NPC::Misc) - && !Misc::StringUtils::ciEqual(item.getCellRef().mRefID, "gold_001"); + && !Misc::StringUtils::ciEqual(item.getCellRef().mRefID, "gold_001") + && !Misc::StringUtils::ciEqual(item.getCellRef().mRefID, "gold_005") + && !Misc::StringUtils::ciEqual(item.getCellRef().mRefID, "gold_010") + && !Misc::StringUtils::ciEqual(item.getCellRef().mRefID, "gold_025") + && !Misc::StringUtils::ciEqual(item.getCellRef().mRefID, "gold_100"); } float Miscellaneous::getWeight(const MWWorld::Ptr &ptr) const @@ -252,4 +256,11 @@ namespace MWClass return ref->mBase->mData.mWeight; } + bool Miscellaneous::isKey(const MWWorld::Ptr &ptr) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + return ref->mBase->mData.mIsKey; + } + } diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index 16a8e8c055..16e9ca10b0 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -57,6 +57,8 @@ namespace MWClass virtual float getWeight (const MWWorld::Ptr& ptr) const; virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; + + virtual bool isKey (const MWWorld::Ptr &ptr) const; }; } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 87d98a5782..b23cb08142 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -21,6 +21,7 @@ #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/movement.hpp" #include "../mwmechanics/spellcasting.hpp" +#include "../mwmechanics/disease.hpp" #include "../mwworld/ptr.hpp" #include "../mwworld/actiontalk.hpp" @@ -179,29 +180,29 @@ namespace for (int raceSkillIndex = 0; raceSkillIndex < 7; ++raceSkillIndex) { - if (race->mData.mBonus[raceSkillIndex].mSkill == skillIndex) - { - raceBonus = race->mData.mBonus[raceSkillIndex].mBonus; - break; - } + if (race->mData.mBonus[raceSkillIndex].mSkill == skillIndex) + { + raceBonus = race->mData.mBonus[raceSkillIndex].mBonus; + break; + } } for (int k = 0; k < 5; ++k) { - // is this a minor or major skill? - if ((class_->mData.mSkills[k][0] == skillIndex) || (class_->mData.mSkills[k][1] == skillIndex)) - { - majorMultiplier = 1.0f; - break; - } + // is this a minor or major skill? + if ((class_->mData.mSkills[k][0] == skillIndex) || (class_->mData.mSkills[k][1] == skillIndex)) + { + majorMultiplier = 1.0f; + break; + } } // is this skill in the same Specialization as the class? const ESM::Skill* skill = MWBase::Environment::get().getWorld()->getStore().get().find(skillIndex); if (skill->mData.mSpecialization == class_->mData.mSpecialization) { - specMultiplier = 0.5f; - specBonus = 5; + specMultiplier = 0.5f; + specBonus = 5; } npcStats.getSkill(skillIndex).setBase( @@ -210,7 +211,7 @@ namespace + 5 + raceBonus + specBonus - + static_cast((level-1) * (majorMultiplier + specMultiplier)), 100.0f)); + + static_cast((level-1) * (majorMultiplier + specMultiplier)), 100)); } } } @@ -450,8 +451,8 @@ namespace MWClass (stats.getAttribute(ESM::Attribute::Agility).getModified() / 5.0f) + (stats.getAttribute(ESM::Attribute::Luck).getModified() / 10.0f); hitchance *= stats.getFatigueTerm(); - hitchance += mageffects.get(MWMechanics::EffectKey(ESM::MagicEffect::FortifyAttack)).mMagnitude - - mageffects.get(MWMechanics::EffectKey(ESM::MagicEffect::Blind)).mMagnitude; + hitchance += mageffects.get(ESM::MagicEffect::FortifyAttack).mMagnitude - + mageffects.get(ESM::MagicEffect::Blind).mMagnitude; hitchance -= otherstats.getEvasion(); if((::rand()/(RAND_MAX+1.0)) > hitchance/100.0f) @@ -493,6 +494,11 @@ namespace MWClass if (!MWBase::Environment::get().getWorld()->getGodModeState()) weapon.getCellRef().mCharge -= std::min(std::max(1, (int)(damage * gmst.find("fWeaponDamageMult")->getFloat())), weapon.getCellRef().mCharge); + + // Weapon broken? unequip it + if (weapon.getCellRef().mCharge == 0) + weapon = *inv.unequipItem(weapon, ptr); + } healthdmg = true; } @@ -512,7 +518,8 @@ namespace MWClass MWBase::Environment::get().getSoundManager()->playSound3D(victim, "critical damage", 1.0f, 1.0f); } - healthdmg = (otherstats.getFatigue().getCurrent() < 1.0f); + healthdmg = (otherstats.getFatigue().getCurrent() < 1.0f) + || (otherstats.getMagicEffects().get(ESM::MagicEffect::Paralyze).mMagnitude > 0); if(stats.isWerewolf()) { healthdmg = true; @@ -598,6 +605,9 @@ namespace MWClass ptr.getRefData().getLocals().setVarByInt(script, "onpchitme", 1); } + if (!attacker.isEmpty()) + MWMechanics::diseaseContact(ptr, attacker); + if(damage > 0.0f) { // 'ptr' is losing health. Play a 'hit' voiced dialog entry if not already saying @@ -645,6 +655,11 @@ namespace MWClass armorref.mCharge = armor.get()->mBase->mData.mHealth; armorref.mCharge -= std::min(std::max(1, (int)damagediff), armorref.mCharge); + + // Armor broken? unequip it + if (armorref.mCharge == 0) + inv.unequipItem(armor, ptr); + switch(get(armor).getEquipmentSkill(armor)) { case ESM::Skill::LightArmor: @@ -839,10 +854,11 @@ namespace MWClass float moveSpeed; if(normalizedEncumbrance >= 1.0f) moveSpeed = 0.0f; - else if(mageffects.get(MWMechanics::EffectKey(10/*levitate*/)).mMagnitude > 0) + else if(mageffects.get(ESM::MagicEffect::Levitate).mMagnitude > 0 && + world->isLevitationEnabled()) { float flySpeed = 0.01f*(npcdata->mNpcStats.getAttribute(ESM::Attribute::Speed).getModified() + - mageffects.get(MWMechanics::EffectKey(10/*levitate*/)).mMagnitude); + mageffects.get(ESM::MagicEffect::Levitate).mMagnitude); flySpeed = fMinFlySpeed->getFloat() + flySpeed*(fMaxFlySpeed->getFloat() - fMinFlySpeed->getFloat()); flySpeed *= 1.0f - fEncumberedMoveEffect->getFloat() * normalizedEncumbrance; flySpeed = std::max(0.0f, flySpeed); @@ -853,7 +869,7 @@ namespace MWClass float swimSpeed = walkSpeed; if(Npc::getStance(ptr, Run, false)) swimSpeed = runSpeed; - swimSpeed *= 1.0f + 0.01f * mageffects.get(MWMechanics::EffectKey(1/*swift swim*/)).mMagnitude; + swimSpeed *= 1.0f + 0.01f * mageffects.get(ESM::MagicEffect::SwiftSwim).mMagnitude; swimSpeed *= fSwimRunBase->getFloat() + 0.01f*npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified()* fSwimRunAthleticsMult->getFloat(); moveSpeed = swimSpeed; @@ -887,7 +903,7 @@ namespace MWClass float x = fJumpAcrobaticsBase->getFloat() + std::pow(a / 15.0f, fJumpAcroMultiplier->getFloat()); x += 3.0f * b * fJumpAcroMultiplier->getFloat(); - x += mageffects.get(MWMechanics::EffectKey(ESM::MagicEffect::Jump)).mMagnitude * 64; + x += mageffects.get(ESM::MagicEffect::Jump).mMagnitude * 64; x *= encumbranceTerm; if(Npc::getStance(ptr, Run, false)) @@ -910,7 +926,7 @@ namespace MWClass { const float acrobaticsSkill = MWWorld::Class::get(ptr).getNpcStats (ptr).getSkill(ESM::Skill::Acrobatics).getModified(); const CustomData *npcdata = static_cast(ptr.getRefData().getCustomData()); - const float jumpSpellBonus = npcdata->mNpcStats.getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::Jump)).mMagnitude; + const float jumpSpellBonus = npcdata->mNpcStats.getMagicEffects().get(ESM::MagicEffect::Jump).mMagnitude; const float fallAcroBase = gmst.find("fFallAcroBase")->getFloat(); const float fallAcroMult = gmst.find("fFallAcroMult")->getFloat(); const float fallDistanceBase = gmst.find("fFallDistanceBase")->getFloat(); @@ -1015,8 +1031,8 @@ namespace MWClass if(!stats.isWerewolf()) { weight = getContainerStore(ptr).getWeight(); - weight -= stats.getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::Feather)).mMagnitude; - weight += stats.getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::Burden)).mMagnitude; + weight -= stats.getMagicEffects().get(ESM::MagicEffect::Feather).mMagnitude; + weight += stats.getMagicEffects().get(ESM::MagicEffect::Burden).mMagnitude; if(weight < 0.0f) weight = 0.0f; } diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index a09e83380c..5e93e0d81b 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -388,28 +388,26 @@ namespace MWClass std::pair Weapon::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const { + if (ptr.getCellRef().mCharge == 0) + return std::make_pair(0, "#{sInventoryMessage1}"); + std::pair, bool> slots_ = MWWorld::Class::get(ptr).getEquipmentSlots(ptr); - // equip the item in the first free slot - for (std::vector::const_iterator slot=slots_.first.begin(); - slot!=slots_.first.end(); ++slot) + if (slots_.first.empty()) + return std::make_pair (0, ""); + + if(ptr.get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || + ptr.get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || + ptr.get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || + ptr.get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || + ptr.get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || + ptr.get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || + ptr.get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) { - if(*slot == MWWorld::InventoryStore::Slot_CarriedRight) - { - if(ptr.get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || - ptr.get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || - ptr.get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || - ptr.get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || - ptr.get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || - ptr.get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || - ptr.get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) - { - return std::make_pair (2, ""); - } - } - return std::make_pair(1, ""); + return std::make_pair (2, ""); } - return std::make_pair (0, ""); + + return std::make_pair(1, ""); } boost::shared_ptr Weapon::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 3951cedcbc..b979865628 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -251,7 +251,7 @@ namespace MWDialogue } } - void DialogueManager::executeTopic (const std::string& topic, bool randomResponse) + void DialogueManager::executeTopic (const std::string& topic) { Filter filter (mActor, mChoice, mTalkedTo); @@ -262,12 +262,9 @@ namespace MWDialogue MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); - std::vector infos = filter.list (dialogue, true, true); - - if (!infos.empty()) + const ESM::DialInfo* info = filter.search(dialogue, true); + if (info) { - const ESM::DialInfo* info = infos[randomResponse ? std::rand() % infos.size() : 0]; - parseText (info->mResponse); std::string title; @@ -509,7 +506,7 @@ namespace MWDialogue text = "Bribe"; } - executeTopic (text + (success ? " Success" : " Fail"), true); + executeTopic (text + (success ? " Success" : " Fail")); } int DialogueManager::getTemporaryDispositionChange() const diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index 1b7abed45a..c9aad10220 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -44,7 +44,7 @@ namespace MWDialogue bool compile (const std::string& cmd,std::vector& code); void executeScript (const std::string& script); - void executeTopic (const std::string& topic, bool randomResponse=false); + void executeTopic (const std::string& topic); public: diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 11dccde42d..9d08debffb 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -5,6 +5,7 @@ #include "../mwbase/world.hpp" #include "../mwbase/journal.hpp" #include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/dialoguemanager.hpp" #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" @@ -133,7 +134,8 @@ bool MWDialogue::Filter::testDisposition (const ESM::DialInfo& info, bool invert if (isCreature) return true; - int actorDisposition = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mActor); + int actorDisposition = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mActor) + + MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange(); // For service refusal, the disposition check is inverted. However, a value of 0 still means "always succeed". return invert ? (info.mData.mDisposition == 0 || actorDisposition < info.mData.mDisposition) : (actorDisposition >= info.mData.mDisposition); diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index efe089689b..c28ef96ef1 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -44,6 +44,11 @@ namespace MWGui adjustButton(mNextPageButton); adjustButton(mPrevPageButton); + mLeftPage->setNeedMouseFocus(true); + mLeftPage->eventMouseWheel += MyGUI::newDelegate(this, &BookWindow::onMouseWheel); + mRightPage->setNeedMouseFocus(true); + mRightPage->eventMouseWheel += MyGUI::newDelegate(this, &BookWindow::onMouseWheel); + if (mNextPageButton->getSize().width == 64) { // english button has a 7 pixel wide strip of garbage on its right edge @@ -54,6 +59,14 @@ namespace MWGui center(); } + void BookWindow::onMouseWheel(MyGUI::Widget *_sender, int _rel) + { + if (_rel < 0) + nextPage(); + else + prevPage(); + } + void BookWindow::clearPages() { for (std::vector::iterator it=mPages.begin(); @@ -89,6 +102,7 @@ namespace MWGui parent = mRightPage; MyGUI::Widget* pageWidget = parent->createWidgetReal("", MyGUI::FloatCoord(0.0,0.0,1.0,1.0), MyGUI::Align::Default, "BookPage" + boost::lexical_cast(i)); + pageWidget->setNeedMouseFocus(false); parser.parsePage(*it, pageWidget, mLeftPage->getSize().width); mPages.push_back(pageWidget); ++i; diff --git a/apps/openmw/mwgui/bookwindow.hpp b/apps/openmw/mwgui/bookwindow.hpp index ef87dd9c4c..f8821ab50b 100644 --- a/apps/openmw/mwgui/bookwindow.hpp +++ b/apps/openmw/mwgui/bookwindow.hpp @@ -25,6 +25,7 @@ namespace MWGui void onPrevPageButtonClicked (MyGUI::Widget* sender); void onCloseButtonClicked (MyGUI::Widget* sender); void onTakeButtonClicked (MyGUI::Widget* sender); + void onMouseWheel(MyGUI::Widget* _sender, int _rel); void updatePages(); void clearPages(); diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index b829f219d7..04507cfc61 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -75,7 +75,7 @@ namespace MWGui mGenerateClassSpecializations[2] = 0; } - void CharacterCreation::setValue (const std::string& id, const MWMechanics::Stat& value) + void CharacterCreation::setValue (const std::string& id, const MWMechanics::AttributeValue& value) { if (mReviewDialog) { @@ -113,7 +113,7 @@ namespace MWGui } } - void CharacterCreation::setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat& value) + void CharacterCreation::setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value) { if (mReviewDialog) mReviewDialog->setSkillValue(parSkill, value); @@ -229,8 +229,8 @@ namespace MWGui } { - std::map > attributes = MWBase::Environment::get().getWindowManager()->getPlayerAttributeValues(); - for (std::map >::iterator it = attributes.begin(); + std::map attributes = MWBase::Environment::get().getWindowManager()->getPlayerAttributeValues(); + for (std::map::iterator it = attributes.begin(); it != attributes.end(); ++it) { mReviewDialog->setAttribute(static_cast (it->first), it->second); @@ -238,8 +238,8 @@ namespace MWGui } { - std::map > skills = MWBase::Environment::get().getWindowManager()->getPlayerSkillValues(); - for (std::map >::iterator it = skills.begin(); + std::map skills = MWBase::Environment::get().getWindowManager()->getPlayerSkillValues(); + for (std::map::iterator it = skills.begin(); it != skills.end(); ++it) { mReviewDialog->setSkillValue(static_cast (it->first), it->second); diff --git a/apps/openmw/mwgui/charactercreation.hpp b/apps/openmw/mwgui/charactercreation.hpp index b80aaae41c..924f40c282 100644 --- a/apps/openmw/mwgui/charactercreation.hpp +++ b/apps/openmw/mwgui/charactercreation.hpp @@ -31,9 +31,9 @@ namespace MWGui //Show a dialog void spawnDialog(const char id); - void setValue (const std::string& id, const MWMechanics::Stat& value); + void setValue (const std::string& id, const MWMechanics::AttributeValue& value); void setValue (const std::string& id, const MWMechanics::DynamicStat& value); - void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat& value); + void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value); void configureSkills (const SkillList& major, const SkillList& minor); void doRenderUpdate(); diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index b8d20709d9..f3805b255a 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -119,8 +119,6 @@ namespace MWGui // Set up the log window mHistory->setOverflowToTheLeft(true); - mHistory->setEditStatic(true); - mHistory->setVisibleVScroll(true); // compiler Compiler::registerExtensions (mExtensions, mConsoleOnlyScripts); @@ -215,7 +213,7 @@ namespace MWGui { std::vector matches; listNames(); - mCommandLine->setCaption(complete( mCommandLine->getCaption(), matches )); + mCommandLine->setCaption(complete( mCommandLine->getOnlyText(), matches )); #if 0 int i = 0; for(std::vector::iterator it=matches.begin(); it < matches.end(); ++it,++i ) @@ -234,7 +232,7 @@ namespace MWGui { // If the user was editing a string, store it for later if(mCurrent == mCommandHistory.end()) - mEditString = mCommandLine->getCaption(); + mEditString = mCommandLine->getOnlyText(); if(mCurrent != mCommandHistory.begin()) { @@ -259,7 +257,7 @@ namespace MWGui void Console::acceptCommand(MyGUI::EditBox* _sender) { - const std::string &cm = mCommandLine->getCaption(); + const std::string &cm = mCommandLine->getOnlyText(); if(cm.empty()) return; // Add the command to the history, and set the current pointer to diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index a78b1a6d1b..8ef5e59d08 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -55,6 +55,8 @@ namespace MWGui , mWorldMouseOver(false) , mEnemyHealthTimer(0) , mIsDrowning(false) + , mWeaponSpellTimer(0.f) + , mDrowningFlashTheta(0.f) { setCoord(0,0, width, height); diff --git a/apps/openmw/mwgui/inventoryitemmodel.cpp b/apps/openmw/mwgui/inventoryitemmodel.cpp index 672ea9c16f..a16e67a7f5 100644 --- a/apps/openmw/mwgui/inventoryitemmodel.cpp +++ b/apps/openmw/mwgui/inventoryitemmodel.cpp @@ -72,7 +72,7 @@ void InventoryItemModel::update() // NOTE: Don't show WerewolfRobe objects in the inventory, or allow them to be taken. // Vanilla likely uses a hack like this since there's no other way to prevent it from // being shown or taken. - if(item.getCellRef().mRefID == "WerewolfRobe") + if(item.getCellRef().mRefID == "werewolfrobe") continue; ItemStack newItem (item, this, item.getRefData().getCount()); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index ffd81e98b2..70295c4c71 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -163,6 +163,14 @@ namespace MWGui MWWorld::Ptr object = item.mBase; int count = item.mCount; + // Bound items may not be moved + if (item.mBase.getCellRef().mRefID.size() > 6 + && item.mBase.getCellRef().mRefID.substr(0,6) == "bound_") + { + MWBase::Environment::get().getWindowManager()->messageBox("#{sBarterDialog12}"); + return; + } + if (item.mType == ItemStack::Type_Equipped) { MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr); @@ -417,7 +425,7 @@ namespace MWGui // NOTE: Don't allow users to select WerewolfRobe objects in the inventory. Vanilla // likely uses a hack like this since there's no other way to prevent it from being // taken. - if(item.getCellRef().mRefID == "WerewolfRobe") + if(item.getCellRef().mRefID == "werewolfrobe") return MWWorld::Ptr(); return item; } diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index a772b3a15a..e3d8f5dd7b 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -166,7 +166,7 @@ namespace MWGui // increase attributes for (int i=0; i<3; ++i) { - MWMechanics::Stat attribute = creatureStats.getAttribute(mSpentAttributes[i]); + MWMechanics::AttributeValue attribute = creatureStats.getAttribute(mSpentAttributes[i]); attribute.setBase (attribute.getBase () + pcStats.getLevelupAttributeMultiplier (mSpentAttributes[i])); if (attribute.getBase() >= 100) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 93e1d11a3d..2f34df2360 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -103,27 +103,80 @@ namespace MWGui void LocalMapBase::onMarkerFocused (MyGUI::Widget* w1, MyGUI::Widget* w2) { + // Workaround to not make the marker visible if it's under fog of war applyFogOfWar (); } void LocalMapBase::onMarkerUnfocused (MyGUI::Widget* w1, MyGUI::Widget* w2) { + // Workaround to not make the marker visible if it's under fog of war applyFogOfWar (); } + MyGUI::IntPoint LocalMapBase::getMarkerPosition(float worldX, float worldY, MarkerPosition& markerPos) + { + MyGUI::IntPoint widgetPos; + // normalized cell coordinates + float nX,nY; + + markerPos.interior = mInterior; + + if (!mInterior) + { + int cellX, cellY; + MWBase::Environment::get().getWorld()->positionToIndex(worldX, worldY, cellX, cellY); + const int cellSize = 8192; + nX = (worldX - cellSize * cellX) / cellSize; + // Image space is -Y up, cells are Y up + nY = 1 - (worldY - cellSize * cellY) / cellSize; + + float cellDx = cellX - mCurX; + float cellDy = cellY - mCurY; + + markerPos.cellX = cellX; + markerPos.cellY = cellY; + + widgetPos = MyGUI::IntPoint(nX * 512 + (1+cellDx) * 512, + nY * 512 - (cellDy-1) * 512); + } + else + { + int cellX, cellY; + Ogre::Vector2 worldPos (worldX, worldY); + MWBase::Environment::get().getWorld ()->getInteriorMapPosition (worldPos, nX, nY, cellX, cellY); + + markerPos.cellX = cellX; + markerPos.cellY = cellY; + + widgetPos = MyGUI::IntPoint(nX * 512 + (1+cellX-mCurX) * 512, + nY * 512 + (1+cellY-mCurY) * 512); + } + + markerPos.nX = nX; + markerPos.nY = nY; + return widgetPos; + } + void LocalMapBase::setActiveCell(const int x, const int y, bool interior) { - if (x==mCurX && y==mCurY && mInterior==interior && !mChanged) return; // don't do anything if we're still in the same cell + if (x==mCurX && y==mCurY && mInterior==interior && !mChanged) + return; // don't do anything if we're still in the same cell + + mCurX = x; + mCurY = y; + mInterior = interior; + mChanged = false; // clear all previous markers for (unsigned int i=0; i< mLocalMap->getChildCount(); ++i) { - if (mLocalMap->getChildAt(i)->getName ().substr (0, 6) == "Marker") + if (mLocalMap->getChildAt(i)->getName ().substr (0, 4) == "Door") { MyGUI::Gui::getInstance ().destroyWidget (mLocalMap->getChildAt(i)); } } + // Update the map textures for (int mx=0; mx<3; ++mx) { for (int my=0; my<3; ++my) @@ -138,78 +191,57 @@ namespace MWGui box->setImageTexture(image); else box->setImageTexture("black.png"); - - - // door markers - - // interior map only consists of one cell, so handle the markers only once - if (interior && (mx != 2 || my != 2)) - continue; - - MWWorld::CellStore* cell; - if (interior) - cell = MWBase::Environment::get().getWorld ()->getInterior (mPrefix); - else - cell = MWBase::Environment::get().getWorld ()->getExterior (x+mx-1, y-(my-1)); - - std::vector doors = MWBase::Environment::get().getWorld ()->getDoorMarkers (cell); - - for (std::vector::iterator it = doors.begin(); it != doors.end(); ++it) - { - MWBase::World::DoorMarker marker = *it; - - // convert world coordinates to normalized cell coordinates - MyGUI::IntCoord widgetCoord; - float nX,nY; - int cellDx, cellDy; - if (!interior) - { - const int cellSize = 8192; - - nX = (marker.x - cellSize * (x+mx-1)) / cellSize; - nY = 1 - (marker.y - cellSize * (y-(my-1))) / cellSize; - - widgetCoord = MyGUI::IntCoord(nX * 512 - 4 + mx * 512, nY * 512 - 4 + my * 512, 8, 8); - } - else - { - Ogre::Vector2 position (marker.x, marker.y); - MWBase::Environment::get().getWorld ()->getInteriorMapPosition (position, nX, nY, cellDx, cellDy); - - widgetCoord = MyGUI::IntCoord(nX * 512 - 4 + (1+cellDx-x) * 512, nY * 512 - 4 + (1+cellDy-y) * 512, 8, 8); - } - - static int counter = 0; - ++counter; - MyGUI::Button* markerWidget = mLocalMap->createWidget("ButtonImage", - widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast(counter)); - markerWidget->setImageResource("DoorMarker"); - markerWidget->setUserString("ToolTipType", "Layout"); - markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); - markerWidget->setUserString("Caption_TextOneLine", marker.name); - markerWidget->setUserString("IsMarker", "true"); - markerWidget->eventMouseSetFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerFocused); - markerWidget->eventMouseLostFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerUnfocused); - - MarkerPosition markerPos; - markerPos.interior = interior; - markerPos.cellX = interior ? cellDx : x + mx - 1; - markerPos.cellY = interior ? cellDy : y + ((my - 1)*-1); - markerPos.nX = nX; - markerPos.nY = nY; - - markerWidget->setUserData(markerPos); - } - - } } - mInterior = interior; - mCurX = x; - mCurY = y; - mChanged = false; - // fog of war + MWBase::World* world = MWBase::Environment::get().getWorld(); + + // Retrieve the door markers we want to show + std::vector doors; + if (interior) + { + MWWorld::CellStore* cell = world->getInterior (mPrefix); + world->getDoorMarkers(cell, doors); + } + else + { + for (int dX=-1; dX<2; ++dX) + { + for (int dY=-1; dY<2; ++dY) + { + MWWorld::CellStore* cell = world->getExterior (mCurX+dX, mCurY+dY); + world->getDoorMarkers(cell, doors); + } + } + } + + // Create a widget for each marker + int counter = 0; + for (std::vector::iterator it = doors.begin(); it != doors.end(); ++it) + { + MWBase::World::DoorMarker marker = *it; + + MarkerPosition markerPos; + MyGUI::IntPoint widgetPos = getMarkerPosition(marker.x, marker.y, markerPos); + MyGUI::IntCoord widgetCoord(widgetPos.left - 4, + widgetPos.top - 4, + 8, 8); + ++counter; + MyGUI::Button* markerWidget = mLocalMap->createWidget("ButtonImage", + widgetCoord, MyGUI::Align::Default, "Door" + boost::lexical_cast(counter)); + markerWidget->setImageResource("DoorMarker"); + markerWidget->setUserString("ToolTipType", "Layout"); + markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); + markerWidget->setUserString("Caption_TextOneLine", marker.name); + markerWidget->eventMouseSetFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerFocused); + markerWidget->eventMouseLostFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerUnfocused); + // Used by tooltips to not show the tooltip if marker is hidden by fog of war + markerWidget->setUserString("IsMarker", "true"); + markerWidget->setUserData(markerPos); + } + + updateMarkers(); + applyFogOfWar(); // set the compass texture again, because MyGUI determines sorting of ImageBox widgets @@ -222,6 +254,8 @@ namespace MWGui void LocalMapBase::setPlayerPos(const float x, const float y) { + updateMarkers(); + if (x == mLastPositionX && y == mLastPositionY) return; @@ -255,6 +289,88 @@ namespace MWGui mLastDirectionY = y; } + void LocalMapBase::addDetectionMarkers(int type) + { + std::vector markers; + MWBase::World* world = MWBase::Environment::get().getWorld(); + world->listDetectedReferences( + world->getPlayer().getPlayer(), + markers, MWBase::World::DetectionType(type)); + if (markers.empty()) + return; + + std::string markerTexture; + MyGUI::Colour markerColour; + if (type == MWBase::World::Detect_Creature) + { + markerTexture = "textures\\menu_map_dcreature.dds"; + markerColour = MyGUI::Colour(1,0,0,1); + } + if (type == MWBase::World::Detect_Key) + { + markerTexture = "textures\\menu_map_dkey.dds"; + markerColour = MyGUI::Colour(0,1,0,1); + } + if (type == MWBase::World::Detect_Enchantment) + { + markerTexture = "textures\\menu_map_dmagic.dds"; + markerColour = MyGUI::Colour(0,0,1,1); + } + + int counter = 0; + for (std::vector::iterator it = markers.begin(); it != markers.end(); ++it) + { + const ESM::Position& worldPos = it->getRefData().getPosition(); + MarkerPosition markerPos; + MyGUI::IntPoint widgetPos = getMarkerPosition(worldPos.pos[0], worldPos.pos[1], markerPos); + MyGUI::IntCoord widgetCoord(widgetPos.left - 4, + widgetPos.top - 4, + 8, 8); + ++counter; + MyGUI::ImageBox* markerWidget = mLocalMap->createWidget("ImageBox", + widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast(counter)); + markerWidget->setImageTexture(markerTexture); + markerWidget->setUserString("IsMarker", "true"); + markerWidget->setUserData(markerPos); + markerWidget->setColour(markerColour); + } + } + + void LocalMapBase::updateMarkers() + { + // clear all previous markers + for (unsigned int i=0; i< mLocalMap->getChildCount(); ++i) + { + if (mLocalMap->getChildAt(i)->getName ().substr (0, 6) == "Marker") + { + MyGUI::Gui::getInstance ().destroyWidget (mLocalMap->getChildAt(i)); + } + } + + addDetectionMarkers(MWBase::World::Detect_Creature); + addDetectionMarkers(MWBase::World::Detect_Key); + addDetectionMarkers(MWBase::World::Detect_Enchantment); + + // Add marker for the spot marked with Mark magic effect + MWWorld::CellStore* markedCell = NULL; + ESM::Position markedPosition; + MWBase::Environment::get().getWorld()->getPlayer().getMarkedPosition(markedCell, markedPosition); + if (markedCell && markedCell->isExterior() == !mInterior + && (!mInterior || Misc::StringUtils::ciEqual(markedCell->mCell->mName, mPrefix))) + { + MarkerPosition markerPos; + MyGUI::IntPoint widgetPos = getMarkerPosition(markedPosition.pos[0], markedPosition.pos[1], markerPos); + MyGUI::IntCoord widgetCoord(widgetPos.left - 4, + widgetPos.top - 4, + 8, 8); + MyGUI::ImageBox* markerWidget = mLocalMap->createWidget("ImageBox", + widgetCoord, MyGUI::Align::Default, "MarkerMarked"); + markerWidget->setImageTexture("textures\\menu_map_smark.dds"); + markerWidget->setUserString("IsMarker", "true"); + markerWidget->setUserData(markerPos); + } + } + // ------------------------------------------------------------------------------------------ MapWindow::MapWindow(const std::string& cacheDir) @@ -319,7 +435,7 @@ namespace MWGui static int _counter=0; MyGUI::Button* markerWidget = mGlobalMapImage->createWidget("ButtonImage", - widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast(_counter)); + widgetCoord, MyGUI::Align::Default, "Door" + boost::lexical_cast(_counter)); markerWidget->setImageResource("DoorMarker"); markerWidget->setUserString("ToolTipType", "Layout"); markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); @@ -385,7 +501,7 @@ namespace MWGui for (unsigned int i=0; igetChildCount (); ++i) { - if (mGlobalMapImage->getChildAt (i)->getName().substr(0,6) == "Marker") + if (mGlobalMapImage->getChildAt (i)->getName().substr(0,4) == "Door") mGlobalMapImage->getChildAt (i)->castType()->setImageResource("DoorMarker"); } @@ -396,20 +512,18 @@ namespace MWGui void MapWindow::globalMapUpdatePlayer () { - Ogre::Vector3 pos = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedPosition (); - Ogre::Quaternion orient = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedOrientation (); - Ogre::Vector2 dir (orient.yAxis ().x, orient.yAxis().y); - - float worldX, worldY; - mGlobalMapRender->worldPosToImageSpace (pos.x, pos.y, worldX, worldY); - worldX *= mGlobalMapRender->getWidth(); - worldY *= mGlobalMapRender->getHeight(); - - - // for interiors, we have no choice other than using the last position & direction. - /// \todo save this last position in the savegame? + // For interiors, position is set by WindowManager via setGlobalMapPlayerPosition if (MWBase::Environment::get().getWorld ()->isCellExterior ()) { + Ogre::Vector3 pos = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedPosition (); + Ogre::Quaternion orient = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedOrientation (); + Ogre::Vector2 dir (orient.yAxis ().x, orient.yAxis().y); + + float worldX, worldY; + mGlobalMapRender->worldPosToImageSpace (pos.x, pos.y, worldX, worldY); + worldX *= mGlobalMapRender->getWidth(); + worldY *= mGlobalMapRender->getHeight(); + mPlayerArrowGlobal->setPosition(MyGUI::IntPoint(worldX - 16, worldY - 16)); MyGUI::ISubWidget* main = mPlayerArrowGlobal->getSubWidgetMain(); @@ -444,4 +558,19 @@ namespace MWGui "#{sWorld}"); } + void MapWindow::setGlobalMapPlayerPosition(float worldX, float worldY) + { + float x, y; + mGlobalMapRender->worldPosToImageSpace (worldX, worldY, x, y); + x *= mGlobalMapRender->getWidth(); + y *= mGlobalMapRender->getHeight(); + + mPlayerArrowGlobal->setPosition(MyGUI::IntPoint(x - 16, y - 16)); + + // set the view offset so that player is in the center + MyGUI::IntSize viewsize = mGlobalMap->getSize(); + MyGUI::IntPoint viewoffs(0.5*viewsize.width - x, 0.5*viewsize.height - y); + mGlobalMap->setViewOffset(viewoffs); + } + } diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 5518ab4a8f..7df2105dcf 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -55,9 +55,16 @@ namespace MWGui void onMarkerFocused(MyGUI::Widget* w1, MyGUI::Widget* w2); void onMarkerUnfocused(MyGUI::Widget* w1, MyGUI::Widget* w2); + MyGUI::IntPoint getMarkerPosition (float worldX, float worldY, MarkerPosition& markerPos); + virtual void notifyPlayerUpdate() {} virtual void notifyMapChanged() {} + // Update markers (Detect X effects, Mark/Recall effects) + // Note, door markers handled in setActiveCell + void updateMarkers(); + void addDetectionMarkers(int type); + OEngine::GUI::Layout* mLayout; bool mMapDragAndDrop; @@ -81,6 +88,8 @@ namespace MWGui void addVisitedLocation(const std::string& name, int x, int y); // adds the marker to the global map void cellExplored(int x, int y); + void setGlobalMapPlayerPosition (float worldX, float worldY); + virtual void open(); private: diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 6718455523..378e76e467 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -16,6 +16,15 @@ namespace MWGui mLastButtonPressed = -1; } + MessageBoxManager::~MessageBoxManager () + { + std::vector::iterator it(mMessageBoxes.begin()); + for (; it != mMessageBoxes.end(); ++it) + { + delete *it; + } + } + void MessageBoxManager::onFrame (float frameDuration) { std::vector::iterator it; diff --git a/apps/openmw/mwgui/messagebox.hpp b/apps/openmw/mwgui/messagebox.hpp index aac4704fa9..0288f366ce 100644 --- a/apps/openmw/mwgui/messagebox.hpp +++ b/apps/openmw/mwgui/messagebox.hpp @@ -23,6 +23,7 @@ namespace MWGui { public: MessageBoxManager (); + ~MessageBoxManager (); void onFrame (float frameDuration); void createMessageBox (const std::string& message, bool stat = false); void removeStaticMessageBox (); diff --git a/apps/openmw/mwgui/pickpocketitemmodel.cpp b/apps/openmw/mwgui/pickpocketitemmodel.cpp index 16be5f6cca..13ee4396d0 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.cpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.cpp @@ -40,6 +40,14 @@ namespace MWGui for (size_t i = 0; igetItemCount(); ++i) { const ItemStack& item = mSourceModel->getItem(i); + + // Bound items may not be stolen + if (item.mBase.getCellRef().mRefID.size() > 6 + && item.mBase.getCellRef().mRefID.substr(0,6) == "bound_") + { + continue; + } + if (std::find(mHiddenItems.begin(), mHiddenItems.end(), item) == mHiddenItems.end() && item.mType != ItemStack::Type_Equipped) mItems.push_back(item); diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index dfc86a547b..e27e40ae64 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -65,7 +65,7 @@ namespace MWGui getWidget(attribute, std::string("Attribute") + boost::lexical_cast(idx)); mAttributeWidgets.insert(std::make_pair(static_cast(ESM::Attribute::sAttributeIds[idx]), attribute)); attribute->setAttributeId(ESM::Attribute::sAttributeIds[idx]); - attribute->setAttributeValue(Widgets::MWAttribute::AttributeValue(0, 0)); + attribute->setAttributeValue(Widgets::MWAttribute::AttributeValue()); } // Setup skills @@ -74,7 +74,7 @@ namespace MWGui for (int i = 0; i < ESM::Skill::Length; ++i) { - mSkillValues.insert(std::make_pair(i, MWMechanics::Stat())); + mSkillValues.insert(std::make_pair(i, MWMechanics::SkillValue())); mSkillWidgetMap.insert(std::make_pair(i, static_cast (0))); } @@ -152,7 +152,7 @@ namespace MWGui mFatigue->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr); } - void ReviewDialog::setAttribute(ESM::Attribute::AttributeID attributeId, const MWMechanics::Stat& value) + void ReviewDialog::setAttribute(ESM::Attribute::AttributeID attributeId, const MWMechanics::AttributeValue& value) { std::map::iterator attr = mAttributeWidgets.find(static_cast(attributeId)); if (attr == mAttributeWidgets.end()) @@ -161,7 +161,7 @@ namespace MWGui attr->second->setAttributeValue(value); } - void ReviewDialog::setSkillValue(ESM::Skill::SkillEnum skillId, const MWMechanics::Stat& value) + void ReviewDialog::setSkillValue(ESM::Skill::SkillEnum skillId, const MWMechanics::SkillValue& value) { mSkillValues[skillId] = value; MyGUI::TextBox* widget = mSkillWidgetMap[skillId]; @@ -279,9 +279,9 @@ namespace MWGui continue; assert(skillId >= 0 && skillId < ESM::Skill::Length); const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId]; - const MWMechanics::Stat &stat = mSkillValues.find(skillId)->second; - float base = stat.getBase(); - float modified = stat.getModified(); + const MWMechanics::SkillValue &stat = mSkillValues.find(skillId)->second; + int base = stat.getBase(); + int modified = stat.getModified(); std::string state = "normal"; if (modified > base) diff --git a/apps/openmw/mwgui/review.hpp b/apps/openmw/mwgui/review.hpp index 1c24fec745..5d0767d217 100644 --- a/apps/openmw/mwgui/review.hpp +++ b/apps/openmw/mwgui/review.hpp @@ -38,10 +38,10 @@ namespace MWGui void setMagicka(const MWMechanics::DynamicStat& value); void setFatigue(const MWMechanics::DynamicStat& value); - void setAttribute(ESM::Attribute::AttributeID attributeId, const MWMechanics::Stat& value); + void setAttribute(ESM::Attribute::AttributeID attributeId, const MWMechanics::AttributeValue& value); void configureSkills(const SkillList& major, const SkillList& minor); - void setSkillValue(ESM::Skill::SkillEnum skillId, const MWMechanics::Stat& value); + void setSkillValue(ESM::Skill::SkillEnum skillId, const MWMechanics::SkillValue& value); virtual void open(); @@ -85,7 +85,7 @@ namespace MWGui std::map mAttributeWidgets; SkillList mMajorSkills, mMinorSkills, mMiscSkills; - std::map > mSkillValues; + std::map mSkillValues; std::map mSkillWidgetMap; std::string mName, mRaceId, mBirthSignId; ESM::Class mKlass; diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index e93e96c4b2..891206532e 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -22,7 +22,8 @@ namespace MWGui { void EffectSourceVisitor::visit (MWMechanics::EffectKey key, - const std::string& sourceName, float magnitude, float remainingTime) + const std::string& sourceName, const std::string& casterHandle, + float magnitude, float remainingTime) { MagicEffectInfo newEffectSource; newEffectSource.mKey = key; diff --git a/apps/openmw/mwgui/spellicons.hpp b/apps/openmw/mwgui/spellicons.hpp index a29e2a00ab..1bb80f3d4c 100644 --- a/apps/openmw/mwgui/spellicons.hpp +++ b/apps/openmw/mwgui/spellicons.hpp @@ -43,7 +43,8 @@ namespace MWGui std::map > mEffectSources; virtual void visit (MWMechanics::EffectKey key, - const std::string& sourceName, float magnitude, float remainingTime = -1); + const std::string& sourceName, const std::string& casterHandle, + float magnitude, float remainingTime = -1); }; class SpellIcons diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index ab6096b7e6..549cf65abf 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -61,7 +61,7 @@ namespace MWGui for (int i = 0; i < ESM::Skill::Length; ++i) { - mSkillValues.insert(std::pair >(i, MWMechanics::Stat())); + mSkillValues.insert(std::pair(i, MWMechanics::SkillValue())); mSkillWidgetMap.insert(std::pair(i, (MyGUI::TextBox*)NULL)); } @@ -102,7 +102,7 @@ namespace MWGui adjustWindowCaption(); } - void StatsWindow::setValue (const std::string& id, const MWMechanics::Stat& value) + void StatsWindow::setValue (const std::string& id, const MWMechanics::AttributeValue& value) { static const char *ids[] = { @@ -179,7 +179,7 @@ namespace MWGui } } - void StatsWindow::setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat& value) + void StatsWindow::setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value) { mSkillValues[parSkill] = value; MyGUI::TextBox* widget = mSkillWidgetMap[(int)parSkill]; @@ -358,22 +358,20 @@ namespace MWGui continue; assert(skillId >= 0 && skillId < ESM::Skill::Length); const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId]; - const MWMechanics::Stat &stat = mSkillValues.find(skillId)->second; - float base = stat.getBase(); - float modified = stat.getModified(); - int progressPercent = (modified - float(static_cast(modified))) * 100; + const MWMechanics::SkillValue &stat = mSkillValues.find(skillId)->second; + int base = stat.getBase(); + int modified = stat.getModified(); + int progressPercent = stat.getProgress() * 100; const MWWorld::ESMStore &esmStore = MWBase::Environment::get().getWorld()->getStore(); const ESM::Skill* skill = esmStore.get().find(skillId); - assert(skill); std::string icon = "icons\\k\\" + ESM::Skill::sIconNames[skillId]; const ESM::Attribute* attr = esmStore.get().find(skill->mData.mAttribute); - assert(attr); std::string state = "normal"; if (modified > base) @@ -484,7 +482,6 @@ namespace MWGui ESM::RankData rankData = faction->mData.mRankData[it->second+1]; const ESM::Attribute* attr1 = store.get().find(faction->mData.mAttribute[0]); const ESM::Attribute* attr2 = store.get().find(faction->mData.mAttribute[1]); - assert(attr1 && attr2); text += "\n#BF9959#{" + attr1->mName + "}: " + boost::lexical_cast(rankData.mAttribute1) + ", #{" + attr2->mName + "}: " + boost::lexical_cast(rankData.mAttribute2); diff --git a/apps/openmw/mwgui/statswindow.hpp b/apps/openmw/mwgui/statswindow.hpp index 49b44a2e16..28d96ca90f 100644 --- a/apps/openmw/mwgui/statswindow.hpp +++ b/apps/openmw/mwgui/statswindow.hpp @@ -26,11 +26,11 @@ namespace MWGui void setPlayerName(const std::string& playerName); /// Set value for the given ID. - void setValue (const std::string& id, const MWMechanics::Stat& value); + void setValue (const std::string& id, const MWMechanics::AttributeValue& value); void setValue (const std::string& id, const MWMechanics::DynamicStat& value); void setValue (const std::string& id, const std::string& value); void setValue (const std::string& id, int value); - void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat& value); + void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value); void configureSkills (const SkillList& major, const SkillList& minor); void setReputation (int reputation) { if (reputation != mReputation) mChanged = true; this->mReputation = reputation; } @@ -61,7 +61,7 @@ namespace MWGui MyGUI::ScrollView* mSkillView; SkillList mMajorSkills, mMinorSkills, mMiscSkills; - std::map > mSkillValues; + std::map mSkillValues; std::map mSkillWidgetMap; std::map mFactionWidgetMap; FactionList mFactions; ///< Stores a list of factions and the current rank diff --git a/apps/openmw/mwgui/tradeitemmodel.cpp b/apps/openmw/mwgui/tradeitemmodel.cpp index e836355d3e..5c12843da0 100644 --- a/apps/openmw/mwgui/tradeitemmodel.cpp +++ b/apps/openmw/mwgui/tradeitemmodel.cpp @@ -154,6 +154,13 @@ namespace MWGui if(!MWWorld::Class::get(base).canSell(base, services)) continue; + // Bound items may not be bought + if (item.mBase.getCellRef().mRefID.size() > 6 + && item.mBase.getCellRef().mRefID.substr(0,6) == "bound_") + { + continue; + } + // don't show equipped items if(mMerchant.getTypeName() == typeid(ESM::NPC).name()) { diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index d544b83cf4..6000de858a 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -24,6 +24,7 @@ #include "containeritemmodel.hpp" #include "tradeitemmodel.hpp" #include "countdialog.hpp" +#include "dialogue.hpp" namespace MWGui { @@ -296,10 +297,10 @@ namespace MWGui const MWMechanics::NpcStats &sellerStats = MWWorld::Class::get(mPtr).getNpcStats(mPtr); const MWMechanics::NpcStats &playerStats = MWWorld::Class::get(playerPtr).getNpcStats(playerPtr); - float a1 = std::min(playerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100.f); + float a1 = std::min(playerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100); float b1 = std::min(0.1f * playerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f); float c1 = std::min(0.2f * playerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f); - float d1 = std::min(sellerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100.f); + float d1 = std::min(sellerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100); float e1 = std::min(0.1f * sellerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f); float f1 = std::min(0.2f * sellerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f); @@ -340,6 +341,9 @@ namespace MWGui addOrRemoveGold(-mCurrentBalance, mPtr); } + MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addResponse( + MWBase::Environment::get().getWorld()->getStore().get().find("sBarterDialog5")->getString()); + std::string sound = "Item Gold Up"; MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 2467f6c40d..0a05cd22b0 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -154,7 +154,7 @@ namespace MWGui float hourlyHealthDelta = stats.getAttribute(ESM::Attribute::Endurance).getModified() * 0.1; - bool stunted = (stats.getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::StuntedMagicka)).mMagnitude > 0); + bool stunted = (stats.getMagicEffects().get(ESM::MagicEffect::StuntedMagicka).mMagnitude > 0); float fRestMagicMult = store.get().find("fRestMagicMult")->getFloat(); float hourlyMagickaDelta = fRestMagicMult * stats.getAttribute(ESM::Attribute::Intelligence).getModified(); diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index c37ae15fa1..b30cf2bae8 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -178,7 +178,7 @@ namespace MWGui } if (mAttributeValueWidget) { - AttributeValue::Type modified = mValue.getModified(), base = mValue.getBase(); + int modified = mValue.getModified(), base = mValue.getBase(); static_cast(mAttributeValueWidget)->setCaption(boost::lexical_cast(modified)); if (modified > base) mAttributeValueWidget->_setWidgetState("increased"); @@ -528,14 +528,9 @@ namespace MWGui if (mBarTextWidget) { - if (mValue >= 0 && mMax > 0) - { - std::stringstream out; - out << mValue << "/" << mMax; - static_cast(mBarTextWidget)->setCaption(out.str().c_str()); - } - else - static_cast(mBarTextWidget)->setCaption(""); + std::stringstream out; + out << mValue << "/" << mMax; + static_cast(mBarTextWidget)->setCaption(out.str().c_str()); } } void MWDynamicStat::setTitle(const std::string& text) diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index 1630ab3c9f..adc56f423f 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -133,7 +133,7 @@ namespace MWGui public: MWAttribute(); - typedef MWMechanics::Stat AttributeValue; + typedef MWMechanics::AttributeValue AttributeValue; void setAttributeId(int attributeId); void setAttributeValue(const AttributeValue& value); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 8818721f43..3accd925f6 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -16,6 +16,7 @@ #include "../mwbase/inputmanager.hpp" #include "../mwworld/class.hpp" +#include "../mwworld/player.hpp" #include "console.hpp" #include "journalwindow.hpp" @@ -174,11 +175,11 @@ namespace MWGui MyGUI::InputManager::getInstance().eventChangeKeyFocus += MyGUI::newDelegate(this, &WindowManager::onKeyFocusChanged); - mCursorManager->setEnabled(true); - onCursorChange(MyGUI::PointerManager::getInstance().getDefaultPointer()); SDL_ShowCursor(false); + mCursorManager->setEnabled(true); + // hide mygui's pointer MyGUI::PointerManager::getInstance().setVisible(false); } @@ -248,12 +249,12 @@ namespace MWGui // Setup player stats for (int i = 0; i < ESM::Attribute::Length; ++i) { - mPlayerAttributes.insert(std::make_pair(ESM::Attribute::sAttributeIds[i], MWMechanics::Stat())); + mPlayerAttributes.insert(std::make_pair(ESM::Attribute::sAttributeIds[i], MWMechanics::AttributeValue())); } for (int i = 0; i < ESM::Skill::Length; ++i) { - mPlayerSkillValues.insert(std::make_pair(ESM::Skill::sSkillIds[i], MWMechanics::Stat())); + mPlayerSkillValues.insert(std::make_pair(ESM::Skill::sSkillIds[i], MWMechanics::SkillValue())); } // Set up visibility @@ -322,6 +323,7 @@ namespace MWGui delete mSoulgemDialog; delete mCursorManager; delete mRecharge; + delete mCompanionWindow; cleanupGarbage(); @@ -542,7 +544,7 @@ namespace MWGui } } - void WindowManager::setValue (const std::string& id, const MWMechanics::Stat& value) + void WindowManager::setValue (const std::string& id, const MWMechanics::AttributeValue& value) { mStatsWindow->setValue (id, value); mCharGen->setValue(id, value); @@ -573,7 +575,7 @@ namespace MWGui } - void WindowManager::setValue (int parSkill, const MWMechanics::Stat& value) + void WindowManager::setValue (int parSkill, const MWMechanics::SkillValue& value) { /// \todo Don't use the skill enum as a parameter type (we will have to drop it anyway, once we /// allow custom skills. @@ -774,6 +776,13 @@ namespace MWGui mHud->setCellName( cell->mCell->mName ); mMap->setCellPrefix( cell->mCell->mName ); mHud->setCellPrefix( cell->mCell->mName ); + + Ogre::Vector3 worldPos; + if (!MWBase::Environment::get().getWorld()->findInteriorPositionInWorldSpace(cell, worldPos)) + worldPos = MWBase::Environment::get().getWorld()->getPlayer().getLastKnownExteriorPosition(); + else + MWBase::Environment::get().getWorld()->getPlayer().setLastKnownExteriorPosition(worldPos); + mMap->setGlobalMapPlayerPosition(worldPos.x, worldPos.y); } } @@ -1169,12 +1178,12 @@ namespace MWGui return mGuiModes.back(); } - std::map > WindowManager::getPlayerSkillValues() + std::map WindowManager::getPlayerSkillValues() { return mPlayerSkillValues; } - std::map > WindowManager::getPlayerAttributeValues() + std::map WindowManager::getPlayerAttributeValues() { return mPlayerAttributes; } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index b332ffc364..a3b135ad4e 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -152,8 +152,8 @@ namespace MWGui virtual void wmUpdateFps(float fps, unsigned int triangleCount, unsigned int batchCount); ///< Set value for the given ID. - virtual void setValue (const std::string& id, const MWMechanics::Stat& value); - virtual void setValue (int parSkill, const MWMechanics::Stat& value); + virtual void setValue (const std::string& id, const MWMechanics::AttributeValue& value); + virtual void setValue (int parSkill, const MWMechanics::SkillValue& value); virtual void setValue (const std::string& id, const MWMechanics::DynamicStat& value); virtual void setValue (const std::string& id, const std::string& value); virtual void setValue (const std::string& id, int value); @@ -229,8 +229,8 @@ namespace MWGui virtual void onFrame (float frameDuration); /// \todo get rid of this stuff. Move it to the respective UI element classes, if needed. - virtual std::map > getPlayerSkillValues(); - virtual std::map > getPlayerAttributeValues(); + virtual std::map getPlayerSkillValues(); + virtual std::map getPlayerAttributeValues(); virtual SkillList getPlayerMinorSkills(); virtual SkillList getPlayerMajorSkills(); @@ -346,9 +346,9 @@ namespace MWGui // Various stats about player as needed by window manager std::string mPlayerName; std::string mPlayerRaceId; - std::map > mPlayerAttributes; + std::map mPlayerAttributes; SkillList mPlayerMajorSkills, mPlayerMinorSkills; - std::map > mPlayerSkillValues; + std::map mPlayerSkillValues; MyGUI::Gui *mGui; // Gui std::vector mGuiModes; diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index ffb2af81e0..8f19fb02eb 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include @@ -19,7 +20,6 @@ #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/soundmanager.hpp" -#include "../mwgui/bookwindow.hpp" #include "../mwmechanics/creaturestats.hpp" using namespace ICS; @@ -497,6 +497,9 @@ namespace MWInput edit->deleteTextSelection(); } } + } + if (edit && !edit->getEditStatic()) + { if (arg.keysym.sym == SDLK_c && (arg.keysym.mod & SDL_Keymod(KMOD_CTRL))) { std::string text = edit->getTextSelection(); @@ -591,15 +594,6 @@ namespace MWInput mMouseWheel = int(arg.z); MyGUI::InputManager::getInstance().injectMouseMove( int(mMouseX), int(mMouseY), mMouseWheel); - - //if the player is reading a book and flicking the mouse wheel - if (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Book && arg.zrel) - { - if (arg.zrel < 0) - MWBase::Environment::get().getWindowManager()->getBookWindow()->nextPage(); - else - MWBase::Environment::get().getWindowManager()->getBookWindow()->prevPage(); - } } if (mMouseLookEnabled) @@ -676,7 +670,7 @@ namespace MWInput if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return; // Not allowed before the magic window is accessible - if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Magic)) + if (!mControlSwitch["playermagic"]) return; MWMechanics::DrawState_ state = mPlayer->getDrawState(); @@ -691,7 +685,7 @@ namespace MWInput if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return; // Not allowed before the inventory window is accessible - if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) + if (!mControlSwitch["playerfighting"]) return; MWMechanics::DrawState_ state = mPlayer->getDrawState(); @@ -831,9 +825,11 @@ namespace MWInput void InputManager::updateIdleTime(float dt) { + static const float vanityDelay = MWBase::Environment::get().getWorld()->getStore().get() + .find("fVanityDelay")->getFloat(); if (mTimeIdle >= 0.f) mTimeIdle += dt; - if (mTimeIdle > 30.f) { + if (mTimeIdle > vanityDelay) { MWBase::Environment::get().getWorld()->toggleVanityMode(true); mTimeIdle = -1.f; } diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index dc79901b0e..2a71659742 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -126,7 +126,8 @@ namespace MWMechanics return mSpells; } - void ActiveSpells::addSpell(const std::string &id, bool stack, std::vector effects, const std::string &displayName) + void ActiveSpells::addSpell(const std::string &id, bool stack, std::vector effects, + const std::string &displayName, const std::string& casterHandle) { bool exists = false; for (TContainer::const_iterator it = begin(); it != end(); ++it) @@ -139,6 +140,7 @@ namespace MWMechanics params.mTimeStamp = MWBase::Environment::get().getWorld()->getTimeStamp(); params.mEffects = effects; params.mDisplayName = displayName; + params.mCasterHandle = casterHandle; if (!exists || stack) mSpells.insert (std::make_pair(id, params)); @@ -148,6 +150,12 @@ namespace MWMechanics mSpellsChanged = true; } + void ActiveSpells::removeEffects(const std::string &id) + { + mSpells.erase(Misc::StringUtils::lowerCase(id)); + mSpellsChanged = true; + } + void ActiveSpells::visitEffectSources(EffectSourceVisitor &visitor) const { for (TContainer::const_iterator it = begin(); it != end(); ++it) @@ -164,14 +172,22 @@ namespace MWMechanics float magnitude = effectIt->mMagnitude; if (magnitude) - visitor.visit(effectIt->mKey, name, magnitude, remainingTime); + visitor.visit(effectIt->mKey, name, it->second.mCasterHandle, magnitude, remainingTime); } } } - void ActiveSpells::purgeAll() + void ActiveSpells::purgeAll(float chance) { - mSpells.clear(); + for (TContainer::iterator it = mSpells.begin(); it != mSpells.end(); ) + { + int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] + if (roll < chance) + mSpells.erase(it++); + else + ++it; + } + mSpellsChanged = true; } void ActiveSpells::purgeEffect(short effectId) @@ -187,6 +203,6 @@ namespace MWMechanics effectIt++; } } - + mSpellsChanged = true; } } diff --git a/apps/openmw/mwmechanics/activespells.hpp b/apps/openmw/mwmechanics/activespells.hpp index b3f499c6b2..2ddb4ec556 100644 --- a/apps/openmw/mwmechanics/activespells.hpp +++ b/apps/openmw/mwmechanics/activespells.hpp @@ -37,8 +37,8 @@ namespace MWMechanics MWWorld::TimeStamp mTimeStamp; std::string mDisplayName; - // TODO: To handle CASTER_LINKED flag (spell is purged when caster dies), - // we should probably store a handle to the caster here. + // Handle to the caster that that inflicted this spell on us + std::string mCasterHandle; }; typedef std::multimap TContainer; @@ -76,14 +76,19 @@ namespace MWMechanics /// \param stack If false, the spell is not added if one with the same ID exists already. /// \param effects /// \param displayName Name for display in magic menu. + /// \param casterHandle /// - void addSpell (const std::string& id, bool stack, std::vector effects, const std::string& displayName); + void addSpell (const std::string& id, bool stack, std::vector effects, + const std::string& displayName, const std::string& casterHandle); - /// Remove all active effects with this id + /// Removes the active effects from this spell/potion/.. with \a id + void removeEffects (const std::string& id); + + /// Remove all active effects with this effect id void purgeEffect (short effectId); - /// Remove all active effects - void purgeAll (); + /// Remove all active effects, if roll succeeds (for each effect) + void purgeAll (float chance); bool isSpellActive (std::string id) const; ///< case insensitive diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 1aa9ce9f5d..f4cf1d4823 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -46,10 +46,110 @@ void adjustBoundItem (const std::string& item, bool bound, const MWWorld::Ptr& a } } +bool disintegrateSlot (MWWorld::Ptr ptr, int slot, float disintegrate) +{ + // TODO: remove this check once creatures support inventory store + if (ptr.getTypeName() == typeid(ESM::NPC).name()) + { + MWWorld::InventoryStore& inv = ptr.getClass().getInventoryStore(ptr); + MWWorld::ContainerStoreIterator item = + inv.getSlot(slot); + if (item != inv.end()) + { + if (!item->getClass().hasItemHealth(*item)) + return false; + if (item->getCellRef().mCharge == -1) + item->getCellRef().mCharge = item->getClass().getItemMaxHealth(*item); + + if (item->getCellRef().mCharge == 0) + return false; + + item->getCellRef().mCharge -= + std::min(disintegrate, + static_cast(item->getCellRef().mCharge)); + + if (item->getCellRef().mCharge == 0) + { + // Will unequip the broken item and try to find a replacement + if (ptr.getRefData().getHandle() != "player") + inv.autoEquip(ptr); + else + inv.unequipItem(*item, ptr); + } + + return true; + } + } + return true; +} + + } namespace MWMechanics { + + class SoulTrap : public MWMechanics::EffectSourceVisitor + { + MWWorld::Ptr mCreature; + MWWorld::Ptr mActor; + public: + SoulTrap(MWWorld::Ptr trappedCreature) + : mCreature(trappedCreature) {} + + virtual void visit (MWMechanics::EffectKey key, + const std::string& sourceName, const std::string& casterHandle, + float magnitude, float remainingTime = -1) + { + if (key.mId != ESM::MagicEffect::Soultrap) + return; + if (magnitude <= 0) + return; + + MWBase::World* world = MWBase::Environment::get().getWorld(); + + MWWorld::Ptr caster = world->searchPtrViaHandle(casterHandle); + if (caster.isEmpty() || !caster.getClass().isActor()) + return; + + static const float fSoulgemMult = world->getStore().get().find("fSoulgemMult")->getFloat(); + + float creatureSoulValue = mCreature.get()->mBase->mData.mSoul; + + // Use the smallest soulgem that is large enough to hold the soul + MWWorld::ContainerStore& container = caster.getClass().getContainerStore(caster); + MWWorld::ContainerStoreIterator gem = container.end(); + float gemCapacity = std::numeric_limits().max(); + std::string soulgemFilter = "misc_soulgem"; // no other way to check for soulgems? :/ + for (MWWorld::ContainerStoreIterator it = container.begin(MWWorld::ContainerStore::Type_Miscellaneous); + it != container.end(); ++it) + { + const std::string& id = it->getCellRef().mRefID; + if (id.size() >= soulgemFilter.size() + && id.substr(0,soulgemFilter.size()) == soulgemFilter) + { + float thisGemCapacity = it->get()->mBase->mData.mValue * fSoulgemMult; + if (thisGemCapacity >= creatureSoulValue && thisGemCapacity < gemCapacity + && it->getCellRef().mSoul.empty()) + { + gem = it; + gemCapacity = thisGemCapacity; + } + } + } + + if (gem == container.end()) + return; + + // Set the soul on just one of the gems, not the whole stack + gem->getContainerStore()->unstack(*gem, caster); + gem->getCellRef().mSoul = mCreature.getCellRef().mRefID; + + if (caster.getRefData().getHandle() == "player") + MWBase::Environment::get().getWindowManager()->messageBox("#{sSoultrapSuccess}"); + } + }; + void Actors::updateActor (const MWWorld::Ptr& ptr, float duration) { // magic effects @@ -178,7 +278,7 @@ namespace MWMechanics { // the actor is sleeping, restore health and magicka - bool stunted = stats.getMagicEffects ().get(MWMechanics::EffectKey(ESM::MagicEffect::StuntedMagicka)).mMagnitude > 0; + bool stunted = stats.getMagicEffects ().get(ESM::MagicEffect::StuntedMagicka).mMagnitude > 0; DynamicStat health = stats.getHealth(); health.setCurrent (health.getCurrent() + 0.1 * endurance); @@ -217,7 +317,7 @@ namespace MWMechanics // attributes for(int i = 0;i < ESM::Attribute::Length;++i) { - Stat stat = creatureStats.getAttribute(i); + AttributeValue stat = creatureStats.getAttribute(i); stat.setModifier(effects.get(EffectKey(ESM::MagicEffect::FortifyAttribute, i)).mMagnitude - effects.get(EffectKey(ESM::MagicEffect::DrainAttribute, i)).mMagnitude - effects.get(EffectKey(ESM::MagicEffect::AbsorbAttribute, i)).mMagnitude); @@ -229,18 +329,45 @@ namespace MWMechanics for(int i = 0;i < 3;++i) { DynamicStat stat = creatureStats.getDynamic(i); - stat.setModifier(effects.get(EffectKey(ESM::MagicEffect::FortifyHealth+i)).mMagnitude - - effects.get(EffectKey(ESM::MagicEffect::DrainHealth+i)).mMagnitude); + stat.setModifier(effects.get(ESM::MagicEffect::FortifyHealth+i).mMagnitude - + effects.get(ESM::MagicEffect::DrainHealth+i).mMagnitude); - float currentDiff = creatureStats.getMagicEffects().get(EffectKey(ESM::MagicEffect::RestoreHealth+i)).mMagnitude - - creatureStats.getMagicEffects().get(EffectKey(ESM::MagicEffect::DamageHealth+i)).mMagnitude - - creatureStats.getMagicEffects().get(EffectKey(ESM::MagicEffect::AbsorbHealth+i)).mMagnitude; + float currentDiff = creatureStats.getMagicEffects().get(ESM::MagicEffect::RestoreHealth+i).mMagnitude + - creatureStats.getMagicEffects().get(ESM::MagicEffect::DamageHealth+i).mMagnitude + - creatureStats.getMagicEffects().get(ESM::MagicEffect::AbsorbHealth+i).mMagnitude; stat.setCurrent(stat.getCurrent() + currentDiff * duration); creatureStats.setDynamic(i, stat); } + // Apply disintegration (reduces item health) + float disintegrateWeapon = effects.get(ESM::MagicEffect::DisintegrateWeapon).mMagnitude; + if (disintegrateWeapon > 0) + disintegrateSlot(ptr, MWWorld::InventoryStore::Slot_CarriedRight, disintegrateWeapon*duration); + float disintegrateArmor = effects.get(ESM::MagicEffect::DisintegrateArmor).mMagnitude; + if (disintegrateArmor > 0) + { + // According to UESP + int priorities[] = { + MWWorld::InventoryStore::Slot_CarriedLeft, + MWWorld::InventoryStore::Slot_Cuirass, + MWWorld::InventoryStore::Slot_LeftPauldron, + MWWorld::InventoryStore::Slot_RightPauldron, + MWWorld::InventoryStore::Slot_LeftGauntlet, + MWWorld::InventoryStore::Slot_RightGauntlet, + MWWorld::InventoryStore::Slot_Helmet, + MWWorld::InventoryStore::Slot_Greaves, + MWWorld::InventoryStore::Slot_Boots + }; + + for (unsigned int i=0; i health = creatureStats.getHealth(); for (unsigned int i=0; i boundItemsMap; if (boundItemsMap.empty()) { - boundItemsMap[ESM::MagicEffect::BoundBattleAxe] = "battle_axe"; - boundItemsMap[ESM::MagicEffect::BoundBoots] = "boots"; - boundItemsMap[ESM::MagicEffect::BoundCuirass] = "cuirass"; - boundItemsMap[ESM::MagicEffect::BoundDagger] = "dagger"; - boundItemsMap[ESM::MagicEffect::BoundGloves] = "gauntlet"; // Note: needs both _left and _right variants, see below - boundItemsMap[ESM::MagicEffect::BoundHelm] = "helm"; - boundItemsMap[ESM::MagicEffect::BoundLongbow] = "longbow"; - boundItemsMap[ESM::MagicEffect::BoundLongsword] = "longsword"; - boundItemsMap[ESM::MagicEffect::BoundMace] = "mace"; - boundItemsMap[ESM::MagicEffect::BoundShield] = "shield"; - boundItemsMap[ESM::MagicEffect::BoundSpear] = "spear"; + boundItemsMap[ESM::MagicEffect::BoundBattleAxe] = "sMagicBoundBattleAxeID"; + boundItemsMap[ESM::MagicEffect::BoundBoots] = "sMagicBoundBootsID"; + boundItemsMap[ESM::MagicEffect::BoundCuirass] = "sMagicBoundCuirassID"; + boundItemsMap[ESM::MagicEffect::BoundDagger] = "sMagicBoundDaggerID"; + boundItemsMap[ESM::MagicEffect::BoundGloves] = "sMagicBoundLeftGauntletID"; // Note: needs RightGauntlet variant too (see below) + boundItemsMap[ESM::MagicEffect::BoundHelm] = "sMagicBoundHelmID"; + boundItemsMap[ESM::MagicEffect::BoundLongbow] = "sMagicBoundLongbowID"; + boundItemsMap[ESM::MagicEffect::BoundLongsword] = "sMagicBoundLongswordID"; + boundItemsMap[ESM::MagicEffect::BoundMace] = "sMagicBoundMaceID"; + boundItemsMap[ESM::MagicEffect::BoundShield] = "sMagicBoundShieldID"; + boundItemsMap[ESM::MagicEffect::BoundSpear] = "sMagicBoundSpearID"; } for (std::map::iterator it = boundItemsMap.begin(); it != boundItemsMap.end(); ++it) { bool found = creatureStats.mBoundItems.find(it->first) != creatureStats.mBoundItems.end(); - int magnitude = creatureStats.getMagicEffects().get(EffectKey(it->first)).mMagnitude; + int magnitude = creatureStats.getMagicEffects().get(it->first).mMagnitude; if (found != (magnitude > 0)) { - std::string item = "bound_" + it->second; + std::string itemGmst = it->second; + std::string item = MWBase::Environment::get().getWorld()->getStore().get().find( + itemGmst)->getString(); if (it->first == ESM::MagicEffect::BoundGloves) { - adjustBoundItem(item + "_left", magnitude > 0, ptr); - adjustBoundItem(item + "_right", magnitude > 0, ptr); + adjustBoundItem("sMagicBoundLeftGauntletID", magnitude > 0, ptr); + adjustBoundItem("sMagicBoundRightGauntletID", magnitude > 0, ptr); } else adjustBoundItem(item, magnitude > 0, ptr); @@ -320,32 +449,34 @@ namespace MWMechanics static std::map summonMap; if (summonMap.empty()) { - summonMap[ESM::MagicEffect::SummonAncestralGhost] = "ancestor_ghost_summon"; - summonMap[ESM::MagicEffect::SummonBear] = "BM_bear_black_summon"; - summonMap[ESM::MagicEffect::SummonBonelord] = "bonelord_summon"; - summonMap[ESM::MagicEffect::SummonBonewalker] = "bonewalker_summon"; - summonMap[ESM::MagicEffect::SummonBonewolf] = "BM_wolf_bone_summon"; - summonMap[ESM::MagicEffect::SummonCenturionSphere] = "centurion_sphere_summon"; - summonMap[ESM::MagicEffect::SummonClannfear] = "clannfear_summon"; - summonMap[ESM::MagicEffect::SummonDaedroth] = "daedroth_summon"; - summonMap[ESM::MagicEffect::SummonDremora] = "dremora_summon"; - summonMap[ESM::MagicEffect::SummonFabricant] = "fabricant_summon"; - summonMap[ESM::MagicEffect::SummonFlameAtronach] = "atronach_flame_summon"; - summonMap[ESM::MagicEffect::SummonFrostAtronach] = "atronach_frost_summon"; - summonMap[ESM::MagicEffect::SummonGoldenSaint] = "golden saint_summon"; - summonMap[ESM::MagicEffect::SummonGreaterBonewalker] = "bonewalker_greater_summ"; - summonMap[ESM::MagicEffect::SummonHunger] = "hunger_summon"; - summonMap[ESM::MagicEffect::SummonScamp] = "scamp_summon"; - summonMap[ESM::MagicEffect::SummonSkeletalMinion] = "skeleton_summon"; - summonMap[ESM::MagicEffect::SummonStormAtronach] = "atronach_storm_summon"; - summonMap[ESM::MagicEffect::SummonWingedTwilight] = "winged twilight_summon"; - summonMap[ESM::MagicEffect::SummonWolf] = "BM_wolf_grey_summon"; + summonMap[ESM::MagicEffect::SummonAncestralGhost] = "sMagicAncestralGhostID"; + summonMap[ESM::MagicEffect::SummonBonelord] = "sMagicBonelordID"; + summonMap[ESM::MagicEffect::SummonBonewalker] = "sMagicLeastBonewalkerID"; + summonMap[ESM::MagicEffect::SummonCenturionSphere] = "sMagicCenturionSphereID"; + summonMap[ESM::MagicEffect::SummonClannfear] = "sMagicClannfearID"; + summonMap[ESM::MagicEffect::SummonDaedroth] = "sMagicDaedrothID"; + summonMap[ESM::MagicEffect::SummonDremora] = "sMagicDremoraID"; + summonMap[ESM::MagicEffect::SummonFabricant] = "sMagicFabricantID"; + summonMap[ESM::MagicEffect::SummonFlameAtronach] = "sMagicFlameAtronachID"; + summonMap[ESM::MagicEffect::SummonFrostAtronach] = "sMagicFrostAtronachID"; + summonMap[ESM::MagicEffect::SummonGoldenSaint] = "sMagicGoldenSaintID"; + summonMap[ESM::MagicEffect::SummonGreaterBonewalker] = "sMagicGreaterBonewalkerID"; + summonMap[ESM::MagicEffect::SummonHunger] = "sMagicHungerID"; + summonMap[ESM::MagicEffect::SummonScamp] = "sMagicScampID"; + summonMap[ESM::MagicEffect::SummonSkeletalMinion] = "sMagicSkeletalMinionID"; + summonMap[ESM::MagicEffect::SummonStormAtronach] = "sMagicStormAtronachID"; + summonMap[ESM::MagicEffect::SummonWingedTwilight] = "sMagicWingedTwilightID"; + summonMap[ESM::MagicEffect::SummonWolf] = "sMagicCreature01ID"; + summonMap[ESM::MagicEffect::SummonBear] = "sMagicCreature02ID"; + summonMap[ESM::MagicEffect::SummonBonewolf] = "sMagicCreature03ID"; + summonMap[ESM::MagicEffect::SummonCreature04] = "sMagicCreature04ID"; + summonMap[ESM::MagicEffect::SummonCreature05] = "sMagicCreature05ID"; } for (std::map::iterator it = summonMap.begin(); it != summonMap.end(); ++it) { bool found = creatureStats.mSummonedCreatures.find(it->first) != creatureStats.mSummonedCreatures.end(); - int magnitude = creatureStats.getMagicEffects().get(EffectKey(it->first)).mMagnitude; + int magnitude = creatureStats.getMagicEffects().get(it->first).mMagnitude; if (found != (magnitude > 0)) { if (magnitude > 0) @@ -362,15 +493,20 @@ namespace MWMechanics ipos.rot[1] = 0; ipos.rot[2] = 0; - MWWorld::CellStore* store = ptr.getCell(); - MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), it->second, 1); - ref.getPtr().getCellRef().mPos = ipos; + std::string creatureID = + MWBase::Environment::get().getWorld()->getStore().get().find(it->second)->getString(); - // TODO: Add AI to follow player and fight for him + if (!creatureID.empty()) + { + MWWorld::CellStore* store = ptr.getCell(); + MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), creatureID, 1); + ref.getPtr().getCellRef().mPos = ipos; - creatureStats.mSummonedCreatures.insert(std::make_pair(it->first, - MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),*store,ipos).getRefData().getHandle())); + // TODO: Add AI to follow player and fight for him + creatureStats.mSummonedCreatures.insert(std::make_pair(it->first, + MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),*store,ipos).getRefData().getHandle())); + } } else { @@ -396,7 +532,7 @@ namespace MWMechanics // skills for(int i = 0;i < ESM::Skill::Length;++i) { - Stat& skill = npcStats.getSkill(i); + SkillValue& skill = npcStats.getSkill(i); skill.setModifier(effects.get(EffectKey(ESM::MagicEffect::FortifySkill, i)).mMagnitude - effects.get(EffectKey(ESM::MagicEffect::DrainSkill, i)).mMagnitude - effects.get(EffectKey(ESM::MagicEffect::AbsorbSkill, i)).mMagnitude); @@ -448,36 +584,57 @@ namespace MWMechanics /** * Automatically equip NPCs torches at night and unequip them at day */ - if (!isPlayer && !MWWorld::Class::get (ptr).getCreatureStats (ptr).isHostile()) + if (!isPlayer) { - if (mTorchPtr.isEmpty()) - { - mTorchPtr = inventoryStore.search("torch_infinite_time"); - } + MWWorld::ContainerStoreIterator torch = inventoryStore.end(); + for (MWWorld::ContainerStoreIterator it = inventoryStore.begin(); it != inventoryStore.end(); ++it) + { + if (it->getTypeName() == typeid(ESM::Light).name()) + { + torch = it; + break; + } + } - if (MWBase::Environment::get().getWorld()->isNight()) - { - if (heldIter != inventoryStore.end() && heldIter->getTypeName() != typeid(ESM::Light).name()) + if (MWBase::Environment::get().getWorld()->isDark()) { - inventoryStore.unequipItem(*heldIter, ptr); + if (torch != inventoryStore.end()) + { + if (!MWWorld::Class::get (ptr).getCreatureStats (ptr).isHostile()) + { + // For non-hostile NPCs, unequip whatever is in the left slot in favor of a light. + if (heldIter != inventoryStore.end() && heldIter->getTypeName() != typeid(ESM::Light).name()) + inventoryStore.unequipItem(*heldIter, ptr); + + // Also unequip twohanded weapons which conflict with anything in CarriedLeft + if (torch->getClass().canBeEquipped(*torch, ptr).first == 3) + inventoryStore.unequipSlot(MWWorld::InventoryStore::Slot_CarriedRight, ptr); + } + + heldIter = inventoryStore.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); + + // If we have a torch and can equip it (left slot free, no + // twohanded weapon in right slot), then equip it now. + if (heldIter == inventoryStore.end() + && torch->getClass().canBeEquipped(*torch, ptr).first == 1) + { + inventoryStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, torch, ptr); + } + } } - else if (heldIter == inventoryStore.end() && !mTorchPtr.isEmpty()) + else { - heldIter = inventoryStore.add(mTorchPtr, ptr); - inventoryStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, heldIter, ptr); + if (heldIter != inventoryStore.end() && heldIter->getTypeName() == typeid(ESM::Light).name()) + { + // At day, unequip lights and auto equip shields or other suitable items + // (Note: autoEquip will ignore lights) + inventoryStore.autoEquip(ptr); + } } - } - else - { - if (heldIter != inventoryStore.end() && heldIter->getTypeName() == typeid(ESM::Light).name()) - { - inventoryStore.unequipItem(*heldIter, ptr); - inventoryStore.add(*heldIter, ptr); - inventoryStore.autoEquip(ptr); - } - } } + heldIter = inventoryStore.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); + //If holding a light... if(heldIter.getType() == MWWorld::ContainerStore::Type_Light) { @@ -516,6 +673,16 @@ namespace MWMechanics Actors::Actors() {} + Actors::~Actors() + { + PtrControllerMap::iterator it(mActors.begin()); + for (; it != mActors.end(); ++it) + { + delete it->second; + it->second = NULL; + } + } + void Actors::addActor (const MWWorld::Ptr& ptr) { // erase previous death events since we are currently only tracking them while in an active cell @@ -609,10 +776,23 @@ namespace MWMechanics iter->second->kill(); + // Apply soultrap + if (iter->first.getTypeName() == typeid(ESM::Creature).name()) + { + SoulTrap soulTrap (iter->first); + stats.getActiveSpells().visitEffectSources(soulTrap); + } + + // Reset magic effects and recalculate derived effects + // One case where we need this is to make sure bound items are removed upon death + stats.setMagicEffects(MWMechanics::MagicEffects()); + calculateCreatureStatModifiers(iter->first, 0); + ++mDeathCount[cls.getId(iter->first)]; if(cls.isEssential(iter->first)) MWBase::Environment::get().getWindowManager()->messageBox("#{sKilledEssential}"); + } } @@ -626,7 +806,12 @@ namespace MWMechanics iter->second->updateContinuousVfx(); for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) + { + if (iter->first.getClass().getCreatureStats(iter->first).getMagicEffects().get( + ESM::MagicEffect::Paralyze).mMagnitude > 0) + iter->second->skipAnim(); iter->second->update(duration); + } } } void Actors::restoreDynamicStats() diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 411ac54ca8..83aff63e3c 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -29,7 +29,6 @@ namespace MWMechanics PtrControllerMap mActors; std::map mDeathCount; - MWWorld::Ptr mTorchPtr; void updateNpc(const MWWorld::Ptr &ptr, float duration, bool paused); @@ -49,6 +48,7 @@ namespace MWMechanics public: Actors(); + ~Actors(); /// Update magic effects for an actor. Usually done automatically once per frame, but if we're currently /// paused we may want to do it manually (after equipping permanent enchantment) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 39a97df6c1..6f643aa68c 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -91,6 +91,8 @@ namespace MWMechanics mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2]); float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]); + + // TODO: use movement settings instead of rotating directly MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false); MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1; @@ -105,6 +107,7 @@ namespace MWMechanics float directionResult = sqrt(directionX * directionX + directionY * directionY); zAngle = Ogre::Radian( acos(directionY / directionResult) * sgn(asin(directionX / directionResult)) ).valueDegrees(); + // TODO: use movement settings instead of rotating directly MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false); mPathFinder.clearPath(); diff --git a/apps/openmw/mwmechanics/aiescort.cpp b/apps/openmw/mwmechanics/aiescort.cpp index 3615c8546e..5099625c06 100644 --- a/apps/openmw/mwmechanics/aiescort.cpp +++ b/apps/openmw/mwmechanics/aiescort.cpp @@ -161,6 +161,7 @@ namespace MWMechanics if(distanceBetweenResult <= mMaxDist * mMaxDist) { float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]); + // TODO: use movement settings instead of rotating directly MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false); MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1; mMaxDist = 470; diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 08d7586388..f56c759967 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -97,6 +97,7 @@ namespace MWMechanics } float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]); + // TODO: use movement settings instead of rotating directly world->rotateObject(actor, 0, 0, zAngle, false); movement.mPosition[1] = 1; diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index f66f7ca620..93c94a3f49 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -236,6 +236,7 @@ namespace MWMechanics if(mWalking) { float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]); + // TODO: use movement settings instead of rotating directly world->rotateObject(actor, 0, 0, zAngle, false); MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 8e2e348b96..299c9dc996 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -36,8 +36,6 @@ #include "../mwworld/player.hpp" #include "../mwworld/class.hpp" #include "../mwworld/inventorystore.hpp" -#include "../mwworld/actionequip.hpp" -#include "../mwworld/actiontake.hpp" namespace { @@ -1063,15 +1061,19 @@ void CharacterController::update(float duration) refreshCurrentAnims(idlestate, movestate, forcestateupdate); - if(mHitState != CharState_KnockDown) + if (!mSkipAnim) { - rot *= duration * Ogre::Math::RadiansToDegrees(1.0f); - world->rotateObject(mPtr, rot.x, rot.y, rot.z, true); - } - else - world->rotateObject(mPtr, rot.x, rot.y, 0.0f, true); + if(mHitState != CharState_KnockDown) + { + rot *= duration * Ogre::Math::RadiansToDegrees(1.0f); + world->rotateObject(mPtr, rot.x, rot.y, rot.z, true); + } + else + world->rotateObject(mPtr, rot.x, rot.y, 0.0f, true); + + world->queueMovement(mPtr, vec); + } - world->queueMovement(mPtr, vec); movement = vec; } else if(cls.getCreatureStats(mPtr).isDead()) diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index 95bd405b1d..a21796ce68 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -74,7 +74,7 @@ namespace MWMechanics - gmst.find ("fFatigueMult")->getFloat() * (1-normalised); } - const Stat &CreatureStats::getAttribute(int index) const + const AttributeValue &CreatureStats::getAttribute(int index) const { if (index < 0 || index > 7) { throw std::runtime_error("attribute index is out of range"); @@ -158,20 +158,20 @@ namespace MWMechanics void CreatureStats::setAttribute(int index, int base) { - MWMechanics::Stat current = getAttribute(index); + AttributeValue current = getAttribute(index); current.setBase(base); setAttribute(index, current); } - void CreatureStats::setAttribute(int index, const Stat &value) + void CreatureStats::setAttribute(int index, const AttributeValue &value) { if (index < 0 || index > 7) { throw std::runtime_error("attribute index is out of range"); } - const Stat& currentValue = !mIsWerewolf ? mAttributes[index] : mWerewolfAttributes[index]; + const AttributeValue& currentValue = !mIsWerewolf ? mAttributes[index] : mWerewolfAttributes[index]; - if (value.getModified() != currentValue.getModified()) + if (value != currentValue) { if (index != ESM::Attribute::Luck && index != ESM::Attribute::Personality @@ -228,8 +228,8 @@ namespace MWMechanics void CreatureStats::setMagicEffects(const MagicEffects &effects) { - if (effects.get(MWMechanics::EffectKey(ESM::MagicEffect::FortifyMaximumMagicka)).mMagnitude - != mMagicEffects.get(MWMechanics::EffectKey(ESM::MagicEffect::FortifyMaximumMagicka)).mMagnitude) + if (effects.get(ESM::MagicEffect::FortifyMaximumMagicka).mMagnitude + != mMagicEffects.get(ESM::MagicEffect::FortifyMaximumMagicka).mMagnitude) mRecalcDynamicStats = true; mMagicEffects = effects; @@ -266,8 +266,10 @@ namespace MWMechanics if (mDead) { if (mDynamic[0].getCurrent()<1) - mDynamic[0].setCurrent (1); - + { + mDynamic[0].setModified(mDynamic[0].getModified(), 1); + mDynamic[0].setCurrent(1); + } if (mDynamic[0].getCurrent()>=1) mDead = false; } @@ -343,7 +345,7 @@ namespace MWMechanics float evasion = (getAttribute(ESM::Attribute::Agility).getModified() / 5.0f) + (getAttribute(ESM::Attribute::Luck).getModified() / 10.0f); evasion *= getFatigueTerm(); - evasion += mMagicEffects.get(EffectKey(ESM::MagicEffect::Sanctuary)).mMagnitude; + evasion += mMagicEffects.get(ESM::MagicEffect::Sanctuary).mMagnitude; return evasion; } diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index 4d9be01324..8a525523dd 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -18,7 +18,7 @@ namespace MWMechanics /// class CreatureStats { - Stat mAttributes[8]; + AttributeValue mAttributes[8]; DynamicStat mDynamic[3]; // health, magicka, fatigue int mLevel; Spells mSpells; @@ -49,7 +49,7 @@ namespace MWMechanics protected: bool mIsWerewolf; - Stat mWerewolfAttributes[8]; + AttributeValue mWerewolfAttributes[8]; public: CreatureStats(); @@ -65,7 +65,7 @@ namespace MWMechanics bool canUsePower (const std::string& power) const; void usePower (const std::string& power); - const Stat & getAttribute(int index) const; + const AttributeValue & getAttribute(int index) const; const DynamicStat & getHealth() const; @@ -94,7 +94,7 @@ namespace MWMechanics MagicEffects & getMagicEffects(); - void setAttribute(int index, const Stat &value); + void setAttribute(int index, const AttributeValue &value); // Shortcut to set only the base void setAttribute(int index, int base); diff --git a/apps/openmw/mwmechanics/disease.hpp b/apps/openmw/mwmechanics/disease.hpp new file mode 100644 index 0000000000..d3ea825cf5 --- /dev/null +++ b/apps/openmw/mwmechanics/disease.hpp @@ -0,0 +1,53 @@ +#ifndef OPENMW_MECHANICS_DISEASE_H +#define OPENMW_MECHANICS_DISEASE_H + +#include "../mwbase/windowmanager.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwworld/ptr.hpp" +#include "../mwworld/class.hpp" +#include "../mwmechanics/spells.hpp" +#include "../mwmechanics/creaturestats.hpp" + +namespace MWMechanics +{ + + /// Call when \a actor has got in contact with \a carrier (e.g. hit by him, or loots him) + inline void diseaseContact (MWWorld::Ptr actor, MWWorld::Ptr carrier) + { + if (!carrier.getClass().isActor()) + return; + + float fDiseaseXferChance = + MWBase::Environment::get().getWorld()->getStore().get().find( + "fDiseaseXferChance")->getFloat(); + + Spells& spells = carrier.getClass().getCreatureStats(carrier).getSpells(); + for (Spells::TIterator it = spells.begin(); it != spells.end(); ++it) + { + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(it->first); + if (spell->mData.mType == ESM::Spell::ST_Disease + || spell->mData.mType == ESM::Spell::ST_Blight) + { + float roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] + if (roll < fDiseaseXferChance) + { + // Contracted disease! + actor.getClass().getCreatureStats(actor).getSpells().add(it->first); + + if (actor.getRefData().getHandle() == "player") + { + std::string msg = "sMagicContractDisease"; + msg = MWBase::Environment::get().getWorld()->getStore().get().find(msg)->getString(); + if (msg.find("%s") != std::string::npos) + msg.replace(msg.find("%s"), 2, spell->mName); + MWBase::Environment::get().getWindowManager()->messageBox(msg); + } + } + } + } + } +} + + +#endif diff --git a/apps/openmw/mwmechanics/magiceffects.hpp b/apps/openmw/mwmechanics/magiceffects.hpp index 2c1b363b7d..45abda21d9 100644 --- a/apps/openmw/mwmechanics/magiceffects.hpp +++ b/apps/openmw/mwmechanics/magiceffects.hpp @@ -56,7 +56,8 @@ namespace MWMechanics struct EffectSourceVisitor { virtual void visit (MWMechanics::EffectKey key, - const std::string& sourceName, float magnitude, float remainingTime = -1) = 0; + const std::string& sourceName, const std::string& casterHandle, + float magnitude, float remainingTime = -1) = 0; }; /// \brief Effects currently affecting a NPC or creature diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index c084c86e5e..2e18fae63a 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -12,6 +12,8 @@ #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" +#include "spellcasting.hpp" + namespace MWMechanics { void MechanicsManager::buildPlayer() @@ -123,6 +125,19 @@ namespace MWMechanics npcStats.getSkill (index).setBase ( npcStats.getSkill (index).getBase() + bonus); } + + if (i==1) + { + // Major skill - add starting spells for this skill if existing + const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + MWWorld::Store::iterator it = store.get().begin(); + for (; it != store.get().end(); ++it) + { + if (it->mData.mFlags & ESM::Spell::F_PCStart + && spellSchoolToSkill(getSpellSchool(&*it, ptr)) == index) + creatureStats.getSpells().add(it->mId); + } + } } } @@ -484,10 +499,10 @@ namespace MWMechanics // otherwise one would get different prices when exiting and re-entering the dialogue window... int clampedDisposition = std::max(0, std::min(getDerivedDisposition(ptr) + MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange(),100)); - float a = std::min(playerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100.f); + float a = std::min(playerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100); float b = std::min(0.1f * playerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f); float c = std::min(0.2f * playerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f); - float d = std::min(sellerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100.f); + float d = std::min(sellerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100); float e = std::min(0.1f * sellerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f); float f = std::min(0.2f * sellerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f); diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index 1fdefc84f9..0a0b51270d 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -84,7 +84,7 @@ void MWMechanics::NpcStats::setMovementFlag (Flag flag, bool state) mMovementFlags &= ~flag; } -const MWMechanics::Stat& MWMechanics::NpcStats::getSkill (int index) const +const MWMechanics::SkillValue& MWMechanics::NpcStats::getSkill (int index) const { if (index<0 || index>=ESM::Skill::Length) throw std::runtime_error ("skill index out of range"); @@ -92,7 +92,7 @@ const MWMechanics::Stat& MWMechanics::NpcStats::getSkill (int index) cons return (!mIsWerewolf ? mSkill[index] : mWerewolfSkill[index]); } -MWMechanics::Stat& MWMechanics::NpcStats::getSkill (int index) +MWMechanics::SkillValue& MWMechanics::NpcStats::getSkill (int index) { if (index<0 || index>=ESM::Skill::Length) throw std::runtime_error ("skill index out of range"); @@ -197,34 +197,25 @@ void MWMechanics::NpcStats::useSkill (int skillIndex, const ESM::Class& class_, if(mIsWerewolf) return; - float base = getSkill (skillIndex).getBase(); + MWMechanics::SkillValue value = getSkill (skillIndex); - int level = static_cast (base); + value.setProgress(value.getProgress() + getSkillGain (skillIndex, class_, usageType)); - base += getSkillGain (skillIndex, class_, usageType); - - if (static_cast (base)!=level) + if (value.getProgress()>=1) { // skill leveled up increaseSkill(skillIndex, class_, false); } - else - getSkill (skillIndex).setBase (base); } void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &class_, bool preserveProgress) { - float base = getSkill (skillIndex).getBase(); + int base = getSkill (skillIndex).getBase(); - int level = static_cast (base); - - if (level >= 100) + if (base >= 100) return; - if (preserveProgress) - base += 1; - else - base = level+1; + base += 1; // if this is a major or minor skill of the class, increase level progress bool levelProgress = false; @@ -260,6 +251,8 @@ void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &clas } getSkill (skillIndex).setBase (base); + if (!preserveProgress) + getSkill(skillIndex).setProgress(0); } int MWMechanics::NpcStats::getLevelProgress () const @@ -387,7 +380,7 @@ void MWMechanics::NpcStats::setWerewolf (bool set) // Oh, Bethesda. It's "Intelligence". std::string name = "fWerewolf"+((i==ESM::Attribute::Intelligence) ? std::string("Intellegence") : ESM::Attribute::sAttributeNames[i]); - mWerewolfAttributes[i].setModified(int(gmst.find(name)->getFloat()), 0); + mWerewolfAttributes[i].setBase(int(gmst.find(name)->getFloat())); } for(size_t i = 0;i < ESM::Skill::Length;i++) @@ -401,7 +394,7 @@ void MWMechanics::NpcStats::setWerewolf (bool set) // "Mercantile"! >_< std::string name = "fWerewolf"+((i==ESM::Skill::Mercantile) ? std::string("Merchantile") : ESM::Skill::sSkillNames[i]); - mWerewolfSkill[i].setModified(int(gmst.find(name)->getFloat()), 0); + mWerewolfSkill[i].setBase(int(gmst.find(name)->getFloat())); } } mIsWerewolf = set; diff --git a/apps/openmw/mwmechanics/npcstats.hpp b/apps/openmw/mwmechanics/npcstats.hpp index 6b7efa5b72..552422d843 100644 --- a/apps/openmw/mwmechanics/npcstats.hpp +++ b/apps/openmw/mwmechanics/npcstats.hpp @@ -45,8 +45,8 @@ namespace MWMechanics DrawState_ mDrawState; int mDisposition; unsigned int mMovementFlags; - Stat mSkill[27]; - Stat mWerewolfSkill[27]; + SkillValue mSkill[27]; + SkillValue mWerewolfSkill[27]; int mBounty; std::set mExpelled; std::map mFactionReputation; @@ -94,8 +94,8 @@ namespace MWMechanics void setMovementFlag (Flag flag, bool state); - const Stat& getSkill (int index) const; - Stat& getSkill (int index); + const SkillValue& getSkill (int index) const; + SkillValue& getSkill (int index); const std::map& getFactionRanks() const; std::map& getFactionRanks(); diff --git a/apps/openmw/mwmechanics/objects.cpp b/apps/openmw/mwmechanics/objects.cpp index 694987855e..41d6b4ffad 100644 --- a/apps/openmw/mwmechanics/objects.cpp +++ b/apps/openmw/mwmechanics/objects.cpp @@ -14,6 +14,16 @@ Objects::Objects() { } +Objects::~Objects() +{ + PtrControllerMap::iterator it(mObjects.begin()); + for (; it != mObjects.end();++it) + { + delete it->second; + it->second = NULL; + } +} + void Objects::addObject(const MWWorld::Ptr& ptr) { removeObject(ptr); diff --git a/apps/openmw/mwmechanics/objects.hpp b/apps/openmw/mwmechanics/objects.hpp index 5cdcdaa0af..32432c130a 100644 --- a/apps/openmw/mwmechanics/objects.hpp +++ b/apps/openmw/mwmechanics/objects.hpp @@ -21,6 +21,7 @@ namespace MWMechanics public: Objects(); + ~Objects(); void addObject (const MWWorld::Ptr& ptr); ///< Register an animated object diff --git a/apps/openmw/mwmechanics/repair.cpp b/apps/openmw/mwmechanics/repair.cpp index 38b2a48d7b..5e8a46fd4a 100644 --- a/apps/openmw/mwmechanics/repair.cpp +++ b/apps/openmw/mwmechanics/repair.cpp @@ -24,21 +24,13 @@ void Repair::repair(const MWWorld::Ptr &itemToRepair) MWWorld::LiveCellRef *ref = mTool.get(); + // unstack tool if required + player.getClass().getContainerStore(player).unstack(mTool, player); + // reduce number of uses left int uses = (mTool.getCellRef().mCharge != -1) ? mTool.getCellRef().mCharge : ref->mBase->mData.mUses; mTool.getCellRef().mCharge = uses-1; - // unstack tool if required - if (mTool.getRefData().getCount() > 1 && uses == ref->mBase->mData.mUses) - { - MWWorld::ContainerStore& store = MWWorld::Class::get(player).getContainerStore(player); - MWWorld::ContainerStoreIterator it = store.add(mTool, player); - it->getRefData().setCount(mTool.getRefData().getCount()-1); - it->getCellRef().mCharge = -1; - - mTool.getRefData().setCount(1); - } - MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player); MWMechanics::NpcStats& npcStats = MWWorld::Class::get(player).getNpcStats(player); diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 025aa6b3a9..52fb0805a5 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -7,6 +7,8 @@ #include "../mwworld/containerstore.hpp" +#include "../mwworld/player.hpp" +#include "../mwworld/actionteleport.hpp" #include "../mwrender/animation.hpp" @@ -66,6 +68,12 @@ namespace MWMechanics MWBase::Environment::get().getWorld()->getStore().get().find ( effectIt->mEffectID); + // If player is healing someone, show the target's HP bar + if (caster.getRefData().getHandle() == "player" && target != caster + && effectIt->mEffectID == ESM::MagicEffect::RestoreHealth + && target.getClass().isActor()) + MWBase::Environment::get().getWindowManager()->setEnemy(target); + float magnitudeMult = 1; if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful && target.getClass().isActor()) { @@ -131,9 +139,10 @@ namespace MWMechanics { float random = std::rand() / static_cast(RAND_MAX); float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * random; - magnitude *= magnitudeMult; + magnitude *= magnitudeMult; - if (target.getClass().isActor() && !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)) + bool hasDuration = !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration); + if (target.getClass().isActor() && hasDuration) { ActiveSpells::Effect effect; effect.mKey = MWMechanics::EffectKey(*effectIt); @@ -152,12 +161,23 @@ namespace MWMechanics ActiveSpells::Effect effect_ = effect; effect_.mMagnitude *= -1; effects.push_back(effect_); - caster.getClass().getCreatureStats(caster).getActiveSpells().addSpell("", true, effects, mSourceName); + caster.getClass().getCreatureStats(caster).getActiveSpells().addSpell("", true, + effects, mSourceName, caster.getRefData().getHandle()); } } } else - applyInstantEffect(target, effectIt->mEffectID, magnitude); + applyInstantEffect(target, EffectKey(*effectIt), magnitude); + + // HACK: Damage attribute/skill actually has a duration, even though the actual effect is instant and permanent. + // This was probably just done to have the effect visible in the magic menu for a while + // to notify the player they've been damaged? + if (effectIt->mEffectID == ESM::MagicEffect::DamageAttribute + || effectIt->mEffectID == ESM::MagicEffect::DamageSkill + || effectIt->mEffectID == ESM::MagicEffect::RestoreAttribute + || effectIt->mEffectID == ESM::MagicEffect::RestoreSkill + ) + applyInstantEffect(target, EffectKey(*effectIt), magnitude); if (target.getClass().isActor() || magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration) { @@ -196,11 +216,13 @@ namespace MWMechanics inflict(caster, target, reflectedEffects, range, true); if (appliedLastingEffects.size()) - target.getClass().getCreatureStats(target).getActiveSpells().addSpell(mId, mStack, appliedLastingEffects, mSourceName); + target.getClass().getCreatureStats(target).getActiveSpells().addSpell(mId, mStack, appliedLastingEffects, + mSourceName, caster.getRefData().getHandle()); } - void CastSpell::applyInstantEffect(const MWWorld::Ptr &target, short effectId, float magnitude) + void CastSpell::applyInstantEffect(const MWWorld::Ptr &target, MWMechanics::EffectKey effect, float magnitude) { + short effectId = effect.mId; if (!target.getClass().isActor()) { if (effectId == ESM::MagicEffect::Lock) @@ -223,6 +245,28 @@ namespace MWMechanics } else { + if (effectId == ESM::MagicEffect::DamageAttribute || effectId == ESM::MagicEffect::RestoreAttribute) + { + int attribute = effect.mArg; + AttributeValue value = target.getClass().getCreatureStats(target).getAttribute(attribute); + if (effectId == ESM::MagicEffect::DamageAttribute) + value.damage(magnitude); + else + value.restore(magnitude); + target.getClass().getCreatureStats(target).setAttribute(attribute, value); + } + else if (effectId == ESM::MagicEffect::DamageSkill || effectId == ESM::MagicEffect::RestoreSkill) + { + if (target.getTypeName() != typeid(ESM::NPC).name()) + return; + int skill = effect.mArg; + SkillValue& value = target.getClass().getNpcStats(target).getSkill(skill); + if (effectId == ESM::MagicEffect::DamageSkill) + value.damage(magnitude); + else + value.restore(magnitude); + } + if (effectId == ESM::MagicEffect::CurePoison) target.getClass().getCreatureStats(target).getActiveSpells().purgeEffect(ESM::MagicEffect::Poison); else if (effectId == ESM::MagicEffect::CureParalyzation) @@ -234,27 +278,45 @@ namespace MWMechanics else if (effectId == ESM::MagicEffect::CureCorprusDisease) target.getClass().getCreatureStats(target).getSpells().purgeCorprusDisease(); else if (effectId == ESM::MagicEffect::Dispel) - target.getClass().getCreatureStats(target).getActiveSpells().purgeAll(); + target.getClass().getCreatureStats(target).getActiveSpells().purgeAll(magnitude); else if (effectId == ESM::MagicEffect::RemoveCurse) target.getClass().getCreatureStats(target).getSpells().purgeCurses(); - else if (effectId == ESM::MagicEffect::DivineIntervention) + if (target.getRefData().getHandle() != "player") + return; + if (!MWBase::Environment::get().getWorld()->isTeleportingEnabled()) + return; + + Ogre::Vector3 worldPos; + if (!MWBase::Environment::get().getWorld()->findInteriorPositionInWorldSpace(target.getCell(), worldPos)) + worldPos = MWBase::Environment::get().getWorld()->getPlayer().getLastKnownExteriorPosition(); + + if (effectId == ESM::MagicEffect::DivineIntervention) { - // We need to be able to get the world location of an interior cell before implementing this - // or alternatively, the last known exterior location of the player, which is how vanilla does it. + MWBase::Environment::get().getWorld()->teleportToClosestMarker(target, "divinemarker", worldPos); } else if (effectId == ESM::MagicEffect::AlmsiviIntervention) { - // Same as above + MWBase::Environment::get().getWorld()->teleportToClosestMarker(target, "templemarker", worldPos); } else if (effectId == ESM::MagicEffect::Mark) { - // TODO + MWBase::Environment::get().getWorld()->getPlayer().markPosition( + target.getCell(), target.getRefData().getPosition()); } else if (effectId == ESM::MagicEffect::Recall) { - // TODO + MWWorld::CellStore* markedCell = NULL; + ESM::Position markedPosition; + + MWBase::Environment::get().getWorld()->getPlayer().getMarkedPosition(markedCell, markedPosition); + if (markedCell) + { + MWWorld::ActionTeleport action(markedCell->isExterior() ? "" : markedCell->mCell->mName, + markedPosition); + action.execute(target); + } } } } @@ -378,7 +440,8 @@ namespace MWMechanics int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] if (!fail && roll >= successChance) { - MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicSkillFail}"); + if (mCaster.getRefData().getHandle() == "player") + MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicSkillFail}"); fail = true; } diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index e2efaa140b..a55c45fd16 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -203,7 +203,7 @@ namespace MWMechanics void inflict (const MWWorld::Ptr& target, const MWWorld::Ptr& caster, const ESM::EffectList& effects, ESM::RangeType range, bool reflected=false); - void applyInstantEffect (const MWWorld::Ptr& target, short effectId, float magnitude); + void applyInstantEffect (const MWWorld::Ptr& target, MWMechanics::EffectKey effect, float magnitude); }; } diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index 0088bcb603..21781c530c 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -34,13 +34,14 @@ namespace MWMechanics random.resize(spell->mEffects.mList.size()); for (unsigned int i=0; i (std::rand()) / RAND_MAX; - mSpells.insert (std::make_pair (spellId, random)); + mSpells.insert (std::make_pair (Misc::StringUtils::lowerCase(spellId), random)); } } void Spells::remove (const std::string& spellId) { - TContainer::iterator iter = mSpells.find (spellId); + std::string lower = Misc::StringUtils::lowerCase(spellId); + TContainer::iterator iter = mSpells.find (lower); if (iter!=mSpells.end()) mSpells.erase (iter); @@ -192,7 +193,7 @@ namespace MWMechanics effectIt != list.mList.end(); ++effectIt, ++i) { float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * it->second[i]; - visitor.visit(MWMechanics::EffectKey(*effectIt), spell->mName, magnitude); + visitor.visit(MWMechanics::EffectKey(*effectIt), spell->mName, "", magnitude); } } } diff --git a/apps/openmw/mwmechanics/stat.hpp b/apps/openmw/mwmechanics/stat.hpp index cb6c09014b..77b3f63645 100644 --- a/apps/openmw/mwmechanics/stat.hpp +++ b/apps/openmw/mwmechanics/stat.hpp @@ -205,6 +205,46 @@ namespace MWMechanics { return !(left==right); } + + class AttributeValue + { + int mBase; + int mModifier; + int mDamage; + + public: + AttributeValue() : mBase(0), mModifier(0), mDamage(0) {} + + int getModified() const { return std::max(0, mBase - mDamage + mModifier); } + int getBase() const { return mBase; } + int getModifier() const { return mModifier; } + + void setBase(int base) { mBase = std::max(0, base); } + void setModifier(int mod) { mModifier = mod; } + + void damage(int damage) { mDamage += damage; } + void restore(int amount) { mDamage -= std::min(mDamage, amount); } + int getDamage() const { return mDamage; } + }; + + class SkillValue : public AttributeValue + { + float mProgress; + public: + float getProgress() const { return mProgress; } + void setProgress(float progress) { mProgress = progress; } + }; + + inline bool operator== (const AttributeValue& left, const AttributeValue& right) + { + return left.getBase() == right.getBase() + && left.getModifier() == right.getModifier() + && left.getDamage() == right.getDamage(); + } + inline bool operator!= (const AttributeValue& left, const AttributeValue& right) + { + return !(left == right); + } } #endif diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index c7537aa901..664b0343de 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1224,7 +1224,8 @@ void ObjectAnimation::fillBatch(Ogre::StaticGeometry *sg) for(;iter != mObjectRoot->mEntities.rend();++iter) { Ogre::Node *node = (*iter)->getParentNode(); - sg->addEntity(*iter, node->_getDerivedPosition(), node->_getDerivedOrientation(), node->_getDerivedScale()); + if ((*iter)->isVisible()) + sg->addEntity(*iter, node->_getDerivedPosition(), node->_getDerivedOrientation(), node->_getDerivedScale()); } } diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index 8f54be3f88..9a35725ee3 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -19,25 +19,27 @@ namespace MWRender Camera::Camera (Ogre::Camera *camera) : mCamera(camera), mCameraNode(NULL), + mAnimation(NULL), mFirstPersonView(true), mPreviewMode(false), mFreeLook(true), - mHeight(128.f), - mCameraDistance(300.f), - mDistanceAdjusted(false), - mAnimation(NULL), mNearest(30.f), mFurthest(800.f), mIsNearest(false), mIsFurthest(false), + mHeight(128.f), + mCameraDistance(300.f), + mDistanceAdjusted(false), mVanityToggleQueued(false), mViewModeToggleQueued(false) { mVanity.enabled = false; mVanity.allowed = true; + mPreviewCam.pitch = 0.f; mPreviewCam.yaw = 0.f; mPreviewCam.offset = 400.f; + mMainCam.pitch = 0.f; mMainCam.yaw = 0.f; mMainCam.offset = 400.f; } @@ -278,6 +280,11 @@ namespace MWRender } } + float Camera::getCameraDistance() const + { + return mCamera->getPosition().z; + } + void Camera::setCameraDistance(float dist, bool adjust, bool override) { if(mFirstPersonView && !mPreviewMode && !mVanity.enabled) diff --git a/apps/openmw/mwrender/camera.hpp b/apps/openmw/mwrender/camera.hpp index 87e4866296..d31d9e56c0 100644 --- a/apps/openmw/mwrender/camera.hpp +++ b/apps/openmw/mwrender/camera.hpp @@ -105,6 +105,8 @@ namespace MWRender /// Restore default camera distance for current mode. void setCameraDistance(); + float getCameraDistance() const; + void setAnimation(NpcAnimation *anim); /// Stores focal and camera world positions in passed arguments diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 5e659ca1d7..a0ba01b37b 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -128,7 +128,7 @@ namespace MWRender InventoryPreview::InventoryPreview(MWWorld::Ptr character) - : CharacterPreview(character, 512, 1024, "CharacterPreview", Ogre::Vector3(0, 65, -180), Ogre::Vector3(0,65,0)) + : CharacterPreview(character, 512, 1024, "CharacterPreview", Ogre::Vector3(0, 62, -200), Ogre::Vector3(0, 62, 0)) , mSelectionBuffer(NULL) { } diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 5f41289788..3ea3380e85 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -225,64 +225,54 @@ void LocalMap::render(const float x, const float y, tex = TextureManager::getSingleton().getByName(texture); if (tex.isNull()) { - // try loading from disk - //if (boost::filesystem::exists(texture+".jpg")) - //{ - /// \todo - //} - //else + // render + tex = TextureManager::getSingleton().createManual( + texture, + ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, + TEX_TYPE_2D, + xw*sMapResolution/sSize, yw*sMapResolution/sSize, + 0, + PF_R8G8B8, + TU_RENDERTARGET); + + RenderTarget* rtt = tex->getBuffer()->getRenderTarget(); + + rtt->setAutoUpdated(false); + Viewport* vp = rtt->addViewport(mCellCamera); + vp->setOverlaysEnabled(false); + vp->setShadowsEnabled(false); + vp->setBackgroundColour(ColourValue(0, 0, 0)); + vp->setVisibilityMask(RV_Map); + vp->setMaterialScheme("local_map"); + + rtt->update(); + + // create "fog of war" texture + TexturePtr tex2 = TextureManager::getSingleton().createManual( + texture + "_fog", + ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, + TEX_TYPE_2D, + xw*sFogOfWarResolution/sSize, yw*sFogOfWarResolution/sSize, + 0, + PF_A8R8G8B8, + TU_DYNAMIC_WRITE_ONLY_DISCARDABLE); + + // create a buffer to use for dynamic operations + std::vector buffer; + buffer.resize(sFogOfWarResolution*sFogOfWarResolution); + + // initialize to (0, 0, 0, 1) + for (int p=0; pgetBuffer()->getRenderTarget(); - - rtt->setAutoUpdated(false); - Viewport* vp = rtt->addViewport(mCellCamera); - vp->setOverlaysEnabled(false); - vp->setShadowsEnabled(false); - vp->setBackgroundColour(ColourValue(0, 0, 0)); - vp->setVisibilityMask(RV_Map); - vp->setMaterialScheme("local_map"); - - rtt->update(); - - // create "fog of war" texture - TexturePtr tex2 = TextureManager::getSingleton().createManual( - texture + "_fog", - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - TEX_TYPE_2D, - xw*sFogOfWarResolution/sSize, yw*sFogOfWarResolution/sSize, - 0, - PF_A8R8G8B8, - TU_DYNAMIC_WRITE_ONLY_DISCARDABLE); - - // create a buffer to use for dynamic operations - std::vector buffer; - buffer.resize(sFogOfWarResolution*sFogOfWarResolution); - - // initialize to (0, 0, 0, 1) - for (int p=0; pgetBuffer()->lock(HardwareBuffer::HBL_DISCARD), &buffer[0], sFogOfWarResolution*sFogOfWarResolution*4); - tex2->getBuffer()->unlock(); - - mBuffers[texture] = buffer; - - // save to cache for next time - //rtt->writeContentsToFile("./" + texture + ".jpg"); + buffer[p] = (255 << 24); } + + memcpy(tex2->getBuffer()->lock(HardwareBuffer::HBL_DISCARD), &buffer[0], sFogOfWarResolution*sFogOfWarResolution*4); + tex2->getBuffer()->unlock(); + + mBuffers[texture] = buffer; } + mRenderingManager->enableLights(true); mLight->setVisible(false); @@ -339,8 +329,6 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni Vector3 playerdirection = mCameraRotNode->convertWorldToLocalOrientation(orientation).yAxis(); - Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y); - if (!mInterior) { x = std::ceil(pos.x / sSize)-1; diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index ddbdde83a6..b1455f0dc6 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -664,11 +664,12 @@ void NpcAnimation::showCarriedLeft(bool show) { Ogre::Vector3 glowColor = getEnchantmentColor(*iter); std::string mesh = MWWorld::Class::get(*iter).getModel(*iter); - addOrReplaceIndividualPart(ESM::PRT_Shield, MWWorld::InventoryStore::Slot_CarriedLeft, 1, - mesh, !iter->getClass().getEnchantment(*iter).empty(), &glowColor); - - if (iter->getTypeName() == typeid(ESM::Light).name()) - addExtraLight(mInsert->getCreator(), mObjectParts[ESM::PRT_Shield], iter->get()->mBase); + if (addOrReplaceIndividualPart(ESM::PRT_Shield, MWWorld::InventoryStore::Slot_CarriedLeft, 1, + mesh, !iter->getClass().getEnchantment(*iter).empty(), &glowColor)) + { + if (iter->getTypeName() == typeid(ESM::Light).name()) + addExtraLight(mInsert->getCreator(), mObjectParts[ESM::PRT_Shield], iter->get()->mBase); + } } else removeIndividualPart(ESM::PRT_Shield); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 8ee292de1e..a40535030d 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -109,10 +109,13 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b mFactory->loadAllFiles(); - // Set default mipmap level (NB some APIs ignore this) - // Mipmap generation is currently disabled because it causes issues on Intel/AMD - //TextureManager::getSingleton().setDefaultNumMipmaps(Settings::Manager::getInt("num mipmaps", "General")); + // Compressed textures with 0 mip maps are bugged in 1.8, so disable mipmap generator in that case + // ( https://ogre3d.atlassian.net/browse/OGRE-259 ) +#if OGRE_VERSION >= (1 << 16 | 9 << 8 | 0) + TextureManager::getSingleton().setDefaultNumMipmaps(Settings::Manager::getInt("num mipmaps", "General")); +#else TextureManager::getSingleton().setDefaultNumMipmaps(0); +#endif // Set default texture filtering options TextureFilterOptions tfo; @@ -325,7 +328,7 @@ void RenderingManager::update (float duration, bool paused) MWWorld::Ptr player = world->getPlayer().getPlayer(); - int blind = MWWorld::Class::get(player).getCreatureStats(player).getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::Blind)).mMagnitude; + int blind = MWWorld::Class::get(player).getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::Blind).mMagnitude; mRendering.getFader()->setFactor(std::max(0.f, 1.f-(blind / 100.f))); setAmbientMode(); @@ -590,7 +593,7 @@ void RenderingManager::setAmbientColour(const Ogre::ColourValue& colour) mAmbientColor = colour; MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - int nightEye = MWWorld::Class::get(player).getCreatureStats(player).getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::NightEye)).mMagnitude; + int nightEye = MWWorld::Class::get(player).getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::NightEye).mMagnitude; Ogre::ColourValue final = colour; final += Ogre::ColourValue(0.7,0.7,0.7,0) * std::min(1.f, (nightEye/100.f)); @@ -1023,4 +1026,9 @@ void RenderingManager::enableTerrain(bool enable) mTerrain->setVisible(false); } +float RenderingManager::getCameraDistance() const +{ + return mCamera->getCameraDistance(); +} + } // namespace diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index abc8fd71a7..b13e546e83 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -90,6 +90,7 @@ public: bool vanityRotateCamera(const float *rot); void setCameraDistance(float dist, bool adjust = false, bool override = true); + float getCameraDistance() const; void setupPlayer(const MWWorld::Ptr &ptr); void renderPlayer(const MWWorld::Ptr &ptr); diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 88bc6d8ac2..adf20dc633 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -949,9 +949,25 @@ void VideoState::init(const std::string& resourceName) this->format_ctx->pb = ioCtx; // Open video file - /// \todo leak here, ffmpeg or valgrind bug ? + /// + /// format_ctx->pb->buffer must be freed by hand, + /// if not, valgrind will show memleak, see: + /// + /// https://trac.ffmpeg.org/ticket/1357 + /// if(!this->format_ctx || avformat_open_input(&this->format_ctx, resourceName.c_str(), NULL, NULL)) { + if (this->format_ctx != NULL) + { + if (this->format_ctx->pb != NULL) + { + av_free(this->format_ctx->pb->buffer); + this->format_ctx->pb->buffer = NULL; + + av_free(this->format_ctx->pb); + this->format_ctx->pb = NULL; + } + } // "Note that a user-supplied AVFormatContext will be freed on failure." this->format_ctx = NULL; av_free(ioCtx); @@ -1009,9 +1025,21 @@ void VideoState::deinit() if(this->format_ctx) { - AVIOContext *ioContext = this->format_ctx->pb; + /// + /// format_ctx->pb->buffer must be freed by hand, + /// if not, valgrind will show memleak, see: + /// + /// https://trac.ffmpeg.org/ticket/1357 + /// + if (this->format_ctx->pb != NULL) + { + av_free(this->format_ctx->pb->buffer); + this->format_ctx->pb->buffer = NULL; + + av_free(this->format_ctx->pb); + this->format_ctx->pb = NULL;; + } avformat_close_input(&this->format_ctx); - av_free(ioContext); } } diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 082551f371..0a4db30e9c 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -292,6 +292,7 @@ Water::~Water() delete mReflection; delete mRefraction; + delete mSimulation; } void Water::changeCell(const ESM::Cell* cell) diff --git a/apps/openmw/mwscript/cellextensions.cpp b/apps/openmw/mwscript/cellextensions.cpp index 316f912dad..f26602f7a7 100644 --- a/apps/openmw/mwscript/cellextensions.cpp +++ b/apps/openmw/mwscript/cellextensions.cpp @@ -43,10 +43,13 @@ namespace MWScript ESM::Position pos; MWBase::World *world = MWBase::Environment::get().getWorld(); - if (world->findExteriorPosition(cell, pos)) { + world->getPlayer().setTeleported(true); + if (world->findExteriorPosition(cell, pos)) + { world->changeToExteriorCell(pos); } - else { + else + { // Change to interior even if findInteriorPosition() // yields false. In this case position will be zero-point. world->findInteriorPosition(cell, pos); @@ -68,13 +71,14 @@ namespace MWScript runtime.pop(); ESM::Position pos; - - MWBase::Environment::get().getWorld()->indexToPosition (x, y, pos.pos[0], pos.pos[1], true); + MWBase::World *world = MWBase::Environment::get().getWorld(); + world->getPlayer().setTeleported(true); + world->indexToPosition (x, y, pos.pos[0], pos.pos[1], true); pos.pos[2] = 0; pos.rot[0] = pos.rot[1] = pos.rot[2] = 0; - MWBase::Environment::get().getWorld()->changeToExteriorCell (pos); + world->changeToExteriorCell (pos); } }; diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 9e024f8723..b4ac8e154d 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -127,7 +127,6 @@ op 0x200007e-0x2000084: Enable Controls op 0x2000085-0x200008b: Disable Controls op 0x200008c: Unlock op 0x200008d: Unlock, explicit reference -op 0x200008e: COE op 0x200008e-0x20000a8: GetSkill op 0x20000a9-0x20000c3: GetSkill, explicit reference op 0x20000c4-0x20000de: SetSkill @@ -358,5 +357,17 @@ op 0x2000222: GetLineOfSight op 0x2000223: GetLineOfSightExplicit op 0x2000224: ToggleAI op 0x2000225: ToggleAIExplicit - -opcodes 0x2000226-0x3ffffff unused +op 0x2000226: COE +op 0x2000227: Cast +op 0x2000228: Cast, explicit +op 0x2000229: ExplodeSpell +op 0x200022a: ExplodeSpell, explicit +op 0x200022b: RemoveSpellEffects +op 0x200022c: RemoveSpellEffects, explicit +op 0x200022d: RemoveEffects +op 0x200022e: RemoveEffects, explicit +op 0x200022f: Resurrect +op 0x2000230: Resurrect, explicit +op 0x2000231: GetSpellReadied +op 0x2000232: GetSpellReadied, explicit +opcodes 0x2000233-0x3ffffff unused diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 8e2a8af8c4..8d435959b1 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -23,6 +23,7 @@ #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/spellcasting.hpp" #include "interpretercontext.hpp" #include "ref.hpp" @@ -464,7 +465,20 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); - runtime.push(MWWorld::Class::get(ptr).getNpcStats (ptr).getDrawState () == MWMechanics::DrawState_Weapon); + runtime.push(ptr.getClass().getNpcStats (ptr).getDrawState () == MWMechanics::DrawState_Weapon); + } + }; + + template + class OpGetSpellReadied : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + runtime.push(ptr.getClass().getNpcStats (ptr).getDrawState () == MWMechanics::DrawState_Spell); } }; @@ -700,6 +714,42 @@ namespace MWScript } }; + template + class OpCast : public Interpreter::Opcode0 + { + public: + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string spell = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + std::string targetId = ::Misc::StringUtils::lowerCase(runtime.getStringLiteral (runtime[0].mInteger)); + runtime.pop(); + + MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr (targetId, false); + + MWMechanics::CastSpell cast(ptr, target); + cast.cast(spell); + } + }; + + template + class OpExplodeSpell : public Interpreter::Opcode0 + { + public: + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string spell = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + MWMechanics::CastSpell cast(ptr, ptr); + cast.cast(spell); + } + }; void installOpcodes (Interpreter::Interpreter& interpreter) { @@ -739,6 +789,8 @@ namespace MWScript interpreter.installSegment5 (Compiler::Misc::opcodeGetAttackedExplicit, new OpGetAttacked); interpreter.installSegment5 (Compiler::Misc::opcodeGetWeaponDrawn, new OpGetWeaponDrawn); interpreter.installSegment5 (Compiler::Misc::opcodeGetWeaponDrawnExplicit, new OpGetWeaponDrawn); + interpreter.installSegment5 (Compiler::Misc::opcodeGetSpellReadied, new OpGetSpellReadied); + interpreter.installSegment5 (Compiler::Misc::opcodeGetSpellReadiedExplicit, new OpGetSpellReadied); interpreter.installSegment5 (Compiler::Misc::opcodeGetSpellEffects, new OpGetSpellEffects); interpreter.installSegment5 (Compiler::Misc::opcodeGetSpellEffectsExplicit, new OpGetSpellEffects); interpreter.installSegment5 (Compiler::Misc::opcodeGetCurrentTime, new OpGetCurrentTime); @@ -761,6 +813,10 @@ namespace MWScript interpreter.installSegment5 (Compiler::Misc::opcodeToggleGodMode, new OpToggleGodMode); interpreter.installSegment5 (Compiler::Misc::opcodeDisableLevitation, new OpEnableLevitation); interpreter.installSegment5 (Compiler::Misc::opcodeEnableLevitation, new OpEnableLevitation); + interpreter.installSegment5 (Compiler::Misc::opcodeCast, new OpCast); + interpreter.installSegment5 (Compiler::Misc::opcodeCastExplicit, new OpCast); + interpreter.installSegment5 (Compiler::Misc::opcodeExplodeSpell, new OpExplodeSpell); + interpreter.installSegment5 (Compiler::Misc::opcodeExplodeSpellExplicit, new OpExplodeSpell); } } } diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index dc6b1d4a71..f053e9a97e 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -124,8 +124,8 @@ namespace MWScript Interpreter::Type_Integer value = runtime[0].mInteger; runtime.pop(); - MWMechanics::Stat attribute = ptr.getClass().getCreatureStats(ptr).getAttribute(mIndex); - attribute.setModified (value, 0); + MWMechanics::AttributeValue attribute = ptr.getClass().getCreatureStats(ptr).getAttribute(mIndex); + attribute.setBase (value - (attribute.getModified() - attribute.getBase())); ptr.getClass().getCreatureStats(ptr).setAttribute(mIndex, attribute); } }; @@ -146,15 +146,11 @@ namespace MWScript Interpreter::Type_Integer value = runtime[0].mInteger; runtime.pop(); - MWMechanics::Stat attribute = MWWorld::Class::get(ptr) + MWMechanics::AttributeValue attribute = MWWorld::Class::get(ptr) .getCreatureStats(ptr) .getAttribute(mIndex); - value += - attribute.getModified(); - - attribute - .setModified (value, 0, 100); + attribute.setBase (std::min(100, attribute.getBase() + value)); ptr.getClass().getCreatureStats(ptr).setAttribute(mIndex, attribute); } }; @@ -346,17 +342,13 @@ namespace MWScript const ESM::Class& class_ = *MWBase::Environment::get().getWorld()->getStore().get().find (ref->mBase->mClass); - float level = 0; - float progress = std::modf (stats.getSkill (mIndex).getBase(), &level); + float level = stats.getSkill(mIndex).getBase(); + float progress = stats.getSkill(mIndex).getProgress(); - float modifier = stats.getSkill (mIndex).getModifier(); - - int newLevel = static_cast (value-modifier); + int newLevel = value - (stats.getSkill(mIndex).getModified() - stats.getSkill(mIndex).getBase()); if (newLevel<0) newLevel = 0; - else if (newLevel>100) - newLevel = 100; progress = (progress / stats.getSkillGain (mIndex, class_, -1, level)) * stats.getSkillGain (mIndex, class_, -1, newLevel); @@ -364,8 +356,8 @@ namespace MWScript if (progress>=1) progress = 0.999999999; - stats.getSkill (mIndex).set (newLevel + progress); - stats.getSkill (mIndex).setModifier (modifier); + stats.getSkill (mIndex).setBase (newLevel); + stats.getSkill (mIndex).setProgress(progress); } }; @@ -385,11 +377,10 @@ namespace MWScript Interpreter::Type_Integer value = runtime[0].mInteger; runtime.pop(); - value += MWWorld::Class::get (ptr).getNpcStats (ptr).getSkill (mIndex). - getModified(); + MWMechanics::NpcStats& stats = ptr.getClass().getNpcStats(ptr); - MWWorld::Class::get (ptr).getNpcStats (ptr).getSkill (mIndex). - setModified (value, 0, 100); + stats.getSkill(mIndex). + setBase (std::min(100, stats.getSkill(mIndex).getBase() + value)); } }; @@ -468,6 +459,38 @@ namespace MWScript } }; + template + class OpRemoveSpellEffects : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string spellid = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + MWWorld::Class::get (ptr).getCreatureStats (ptr).getActiveSpells().removeEffects(spellid); + } + }; + + template + class OpRemoveEffects : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + Interpreter::Type_Integer effectId = runtime[0].mInteger; + runtime.pop(); + + MWWorld::Class::get (ptr).getCreatureStats (ptr).getActiveSpells().purgeEffect(effectId); + } + }; + template class OpGetSpell : public Interpreter::Opcode0 { @@ -1081,6 +1104,18 @@ namespace MWScript } }; + template + class OpResurrect : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + ptr.getClass().getCreatureStats(ptr).resurrect(); + } + }; + void installOpcodes (Interpreter::Interpreter& interpreter) { for (int i=0; i); interpreter.installSegment5 (Compiler::Stats::opcodeRemoveSpellExplicit, new OpRemoveSpell); + interpreter.installSegment5 (Compiler::Stats::opcodeRemoveSpellEffects, new OpRemoveSpellEffects); + interpreter.installSegment5 (Compiler::Stats::opcodeRemoveSpellEffectsExplicit, + new OpRemoveSpellEffects); + interpreter.installSegment5 (Compiler::Stats::opcodeResurrect, new OpResurrect); + interpreter.installSegment5 (Compiler::Stats::opcodeResurrectExplicit, + new OpResurrect); + interpreter.installSegment5 (Compiler::Stats::opcodeRemoveEffects, new OpRemoveEffects); + interpreter.installSegment5 (Compiler::Stats::opcodeRemoveEffectsExplicit, + new OpRemoveEffects); interpreter.installSegment5 (Compiler::Stats::opcodeGetSpell, new OpGetSpell); interpreter.installSegment5 (Compiler::Stats::opcodeGetSpellExplicit, new OpGetSpell); diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index ae9ac041e1..e441809778 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -208,6 +208,14 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); + if (!ptr.isInCell()) + return; + + if (ptr.getRefData().getHandle() == "player") + { + MWBase::Environment::get().getWorld()->getPlayer().setTeleported(true); + } + std::string axis = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); Interpreter::Type_Float pos = runtime[0].mFloat; @@ -272,6 +280,14 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); + if (!ptr.isInCell()) + return; + + if (ptr.getRefData().getHandle() == "player") + { + MWBase::Environment::get().getWorld()->getPlayer().setTeleported(true); + } + Interpreter::Type_Float x = runtime[0].mFloat; runtime.pop(); Interpreter::Type_Float y = runtime[0].mFloat; @@ -329,6 +345,14 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); + if (!ptr.isInCell()) + return; + + if (ptr.getRefData().getHandle() == "player") + { + MWBase::Environment::get().getWorld()->getPlayer().setTeleported(true); + } + Interpreter::Type_Float x = runtime[0].mFloat; runtime.pop(); Interpreter::Type_Float y = runtime[0].mFloat; @@ -593,6 +617,10 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { MWWorld::Ptr ptr = R()(runtime); + + if (!ptr.isInCell()) + return; + ptr.getRefData().getLocalRotation().rot[0] = 0; ptr.getRefData().getLocalRotation().rot[1] = 0; ptr.getRefData().getLocalRotation().rot[2] = 0; @@ -612,6 +640,9 @@ namespace MWScript { const MWWorld::Ptr& ptr = R()(runtime); + if (!ptr.isInCell()) + return; + std::string axis = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); Interpreter::Type_Float movement = (runtime[0].mFloat*MWBase::Environment::get().getFrameDuration()); @@ -647,6 +678,9 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); + if (!ptr.isInCell()) + return; + std::string axis = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); Interpreter::Type_Float movement = (runtime[0].mFloat*MWBase::Environment::get().getFrameDuration()); diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index d5c382a419..c836974425 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -158,6 +158,16 @@ void FFmpeg_Decoder::open(const std::string &fname) mFormatCtx->pb = avio_alloc_context(NULL, 0, 0, this, readPacket, writePacket, seek); if(!mFormatCtx->pb || avformat_open_input(&mFormatCtx, fname.c_str(), NULL, NULL) != 0) { + if (mFormatCtx->pb != NULL) + { + if (mFormatCtx->pb->buffer != NULL) + { + av_free(mFormatCtx->pb->buffer); + mFormatCtx->pb->buffer = NULL; + } + av_free(mFormatCtx->pb); + mFormatCtx->pb = NULL; + } avformat_free_context(mFormatCtx); mFormatCtx = NULL; fail("Failed to allocate input stream"); @@ -195,6 +205,14 @@ void FFmpeg_Decoder::open(const std::string &fname) } catch(std::exception &e) { + if (mFormatCtx->pb->buffer != NULL) + { + av_free(mFormatCtx->pb->buffer); + mFormatCtx->pb->buffer = NULL; + } + av_free(mFormatCtx->pb); + mFormatCtx->pb = NULL; + avformat_close_input(&mFormatCtx); throw; } @@ -211,9 +229,22 @@ void FFmpeg_Decoder::close() if(mFormatCtx) { - AVIOContext* context = mFormatCtx->pb; + if (mFormatCtx->pb != NULL) + { + // mFormatCtx->pb->buffer must be freed by hand, + // if not, valgrind will show memleak, see: + // + // https://trac.ffmpeg.org/ticket/1357 + // + if (mFormatCtx->pb->buffer != NULL) + { + av_free(mFormatCtx->pb->buffer); + mFormatCtx->pb->buffer = NULL; + } + av_free(mFormatCtx->pb); + mFormatCtx->pb = NULL; + } avformat_close_input(&mFormatCtx); - av_free(context); } mDataStream.setNull(); diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 372be83938..2e52739ac5 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -252,7 +252,7 @@ namespace MWSound float basevol = volumeFromType(Play_TypeVoice); std::string filePath = "Sound/"+filename; const ESM::Position &pos = ptr.getRefData().getPosition(); - const Ogre::Vector3 objpos(pos.pos[0], pos.pos[1], pos.pos[2]); + const Ogre::Vector3 objpos(pos.pos); MWBase::SoundPtr sound = mOutput->playSound3D(filePath, objpos, 1.0f, basevol, 1.0f, 20.0f, 12750.0f, Play_Normal|Play_TypeVoice, 0); @@ -354,7 +354,7 @@ namespace MWSound float min, max; std::string file = lookup(soundId, volume, min, max); const ESM::Position &pos = ptr.getRefData().getPosition(); - const Ogre::Vector3 objpos(pos.pos[0], pos.pos[1], pos.pos[2]); + const Ogre::Vector3 objpos(pos.pos); sound = mOutput->playSound3D(file, objpos, volume, basevol, pitch, min, max, mode|type, offset); if((mode&Play_NoTrack)) @@ -584,7 +584,7 @@ namespace MWSound if(!ptr.isEmpty()) { const ESM::Position &pos = ptr.getRefData().getPosition(); - const Ogre::Vector3 objpos(pos.pos[0], pos.pos[1], pos.pos[2]); + const Ogre::Vector3 objpos(pos.pos); snditer->first->setPosition(objpos); } //update fade out diff --git a/apps/openmw/mwworld/actionopen.cpp b/apps/openmw/mwworld/actionopen.cpp index 728b6e32bf..e9d8b47161 100644 --- a/apps/openmw/mwworld/actionopen.cpp +++ b/apps/openmw/mwworld/actionopen.cpp @@ -5,6 +5,8 @@ #include "../mwgui/container.hpp" +#include "../mwmechanics/disease.hpp" + #include "class.hpp" #include "containerstore.hpp" @@ -21,6 +23,8 @@ namespace MWWorld if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) return; + MWMechanics::diseaseContact(actor, getTarget()); + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Container); MWBase::Environment::get().getWindowManager()->getContainerWindow()->open(getTarget(), mLoot); } diff --git a/apps/openmw/mwworld/actionteleport.cpp b/apps/openmw/mwworld/actionteleport.cpp index ae5ffc3b90..773fde81e3 100644 --- a/apps/openmw/mwworld/actionteleport.cpp +++ b/apps/openmw/mwworld/actionteleport.cpp @@ -3,6 +3,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" +#include "player.hpp" namespace MWWorld { @@ -14,9 +15,12 @@ namespace MWWorld void ActionTeleport::executeImp (const Ptr& actor) { + MWBase::World* world = MWBase::Environment::get().getWorld(); + world->getPlayer().setTeleported(true); + if (mCellName.empty()) - MWBase::Environment::get().getWorld()->changeToExteriorCell (mPosition); + world->changeToExteriorCell (mPosition); else - MWBase::Environment::get().getWorld()->changeToInteriorCell (mCellName, mPosition); + world->changeToInteriorCell (mCellName, mPosition); } } diff --git a/apps/openmw/mwworld/cellfunctors.hpp b/apps/openmw/mwworld/cellfunctors.hpp index 4b1f70096a..5115fa02db 100644 --- a/apps/openmw/mwworld/cellfunctors.hpp +++ b/apps/openmw/mwworld/cellfunctors.hpp @@ -4,7 +4,7 @@ #include #include -#include "refdata.hpp" +#include "ptr.hpp" namespace ESM { @@ -18,13 +18,13 @@ namespace MWWorld { std::vector mHandles; - bool operator() (ESM::CellRef& ref, RefData& data) + bool operator() (MWWorld::Ptr ptr) { - Ogre::SceneNode* handle = data.getBaseNode(); + Ogre::SceneNode* handle = ptr.getRefData().getBaseNode(); if (handle) mHandles.push_back (handle); - data.setBaseNode(0); + ptr.getRefData().setBaseNode(0); return true; } }; diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index 37c4b6a3f4..865c0d01fc 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -129,9 +129,7 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name, Ptr::CellStore& ce if (cell.mState==Ptr::CellStore::State_Preloaded) { - std::string lowerCase = Misc::StringUtils::lowerCase(name); - - if (std::binary_search (cell.mIds.begin(), cell.mIds.end(), lowerCase)) + if (std::binary_search (cell.mIds.begin(), cell.mIds.end(), name)) { cell.load (mStore, mReader); } @@ -261,3 +259,15 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name) // giving up return Ptr(); } + +void MWWorld::Cells::getExteriorPtrs(const std::string &name, std::vector &out) +{ + for (std::map, Ptr::CellStore>::iterator iter = mExteriors.begin(); + iter!=mExteriors.end(); ++iter) + { + Ptr ptr = getPtrAndCache (name, iter->second); + if (!ptr.isEmpty()) + out.push_back(ptr); + } + +} diff --git a/apps/openmw/mwworld/cells.hpp b/apps/openmw/mwworld/cells.hpp index 0c51cf4520..31de2f60e8 100644 --- a/apps/openmw/mwworld/cells.hpp +++ b/apps/openmw/mwworld/cells.hpp @@ -47,8 +47,15 @@ namespace MWWorld Ptr getPtr (const std::string& name, CellStore& cellStore, bool searchInContainers = false); ///< \param searchInContainers Only affect loaded cells. + /// @note name must be lower case + /// @note name must be lower case Ptr getPtr (const std::string& name); + + /// Get all Ptrs referencing \a name in exterior cells + /// @note Due to the current implementation of getPtr this only supports one Ptr per cell. + /// @note name must be lower case + void getExteriorPtrs (const std::string& name, std::vector& out); }; } diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 8a01caf183..8731c42dc6 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -143,7 +143,7 @@ namespace MWWorld { if (!iter->mData.getCount()) continue; - if (!functor (iter->mRef, iter->mData)) + if (!functor (MWWorld::Ptr(&*iter, this))) return false; } return true; diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index cb6690a464..d737c18a22 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -290,6 +290,8 @@ namespace MWWorld virtual bool isPersistent (const MWWorld::Ptr& ptr) const; + virtual bool isKey (const MWWorld::Ptr& ptr) const { return false; } + virtual Ptr copyToCell(const Ptr &ptr, CellStore &cell) const; diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 849e9ff26c..509c34afb3 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -179,7 +179,7 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) // Don't autoEquip lights if (test.getTypeName() == typeid(ESM::Light).name()) { - continue; + continue; } int testSkill = MWWorld::Class::get (test).getEquipmentSkill (test); @@ -607,7 +607,7 @@ void MWWorld::InventoryStore::visitEffectSources(MWMechanics::EffectSourceVisito const EffectParams& params = mPermanentMagicEffectMagnitudes[(**iter).getCellRef().mRefID][i]; float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * params.mRandom; magnitude *= params.mMultiplier; - visitor.visit(MWMechanics::EffectKey(*effectIt), (**iter).getClass().getName(**iter), magnitude); + visitor.visit(MWMechanics::EffectKey(*effectIt), (**iter).getClass().getName(**iter), "", magnitude); ++i; } diff --git a/apps/openmw/mwworld/manualref.hpp b/apps/openmw/mwworld/manualref.hpp index 1cdcd8484e..0b21fd78b4 100644 --- a/apps/openmw/mwworld/manualref.hpp +++ b/apps/openmw/mwworld/manualref.hpp @@ -64,7 +64,7 @@ namespace MWWorld // initialise ESM::CellRef& cellRef = mPtr.getCellRef(); - cellRef.mRefID = name; + cellRef.mRefID = Misc::StringUtils::lowerCase(name); cellRef.mRefnum = -1; cellRef.mScale = 1; cellRef.mFactIndex = 0; diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 451e093aee..2a7f5948e4 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -577,10 +577,28 @@ namespace MWWorld float oldHeight = iter->first.getRefData().getPosition().pos[2]; + bool waterCollision = false; + if (iter->first.getClass().getCreatureStats(iter->first).getMagicEffects() + .get(ESM::MagicEffect::WaterWalking).mMagnitude + && cell->hasWater() + && !world->isUnderwater(iter->first.getCell(), + Ogre::Vector3(iter->first.getRefData().getPosition().pos))) + waterCollision = true; + + btStaticPlaneShape planeShape(btVector3(0,0,1), waterlevel); + btCollisionObject object; + object.setCollisionShape(&planeShape); + + if (waterCollision) + mEngine->dynamicsWorld->addCollisionObject(&object); + Ogre::Vector3 newpos = MovementSolver::move(iter->first, iter->second, mTimeAccum, world->isFlying(iter->first), waterlevel, mEngine); + if (waterCollision) + mEngine->dynamicsWorld->removeCollisionObject(&object); + float heightDiff = newpos.z - oldHeight; if (heightDiff < 0) diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index e26c2e2a52..c594454028 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -18,8 +18,11 @@ namespace MWWorld { Player::Player (const ESM::NPC *player, const MWBase::World& world) : mCellStore(0), + mLastKnownExteriorPosition(0,0,0), mAutoMove(false), - mForwardBackward (0) + mForwardBackward (0), + mTeleported(false), + mMarkedCell(NULL) { mPlayer.mBase = player; mPlayer.mRef.mRefID = "player"; @@ -145,4 +148,27 @@ namespace MWWorld MWWorld::Ptr ptr = getPlayer(); return MWWorld::Class::get(ptr).getNpcStats(ptr).getDrawState(); } + + bool Player::wasTeleported() const + { + return mTeleported; + } + + void Player::setTeleported(bool teleported) + { + mTeleported = teleported; + } + + void Player::markPosition(CellStore *markedCell, ESM::Position markedPosition) + { + mMarkedCell = markedCell; + mMarkedPosition = markedPosition; + } + + void Player::getMarkedPosition(CellStore*& markedCell, ESM::Position &markedPosition) const + { + markedCell = mMarkedCell; + if (mMarkedCell) + markedPosition = mMarkedPosition; + } } diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index d78b1901c4..1df848111b 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -6,6 +6,8 @@ #include "../mwmechanics/drawstate.hpp" +#include + namespace ESM { struct NPC; @@ -28,13 +30,30 @@ namespace MWWorld MWWorld::CellStore *mCellStore; std::string mSign; + Ogre::Vector3 mLastKnownExteriorPosition; + + ESM::Position mMarkedPosition; + // If no position was marked, this is NULL + CellStore* mMarkedCell; + bool mAutoMove; int mForwardBackward; - + bool mTeleported; public: Player(const ESM::NPC *player, const MWBase::World& world); + // For mark/recall magic effects + void markPosition (CellStore* markedCell, ESM::Position markedPosition); + void getMarkedPosition (CellStore*& markedCell, ESM::Position& markedPosition) const; + + /// Interiors can not always be mapped to a world position. However + /// world position is still required for divine / almsivi magic effects + /// and the player arrow on the global map. + /// TODO: This should be stored in the savegame, too. + void setLastKnownExteriorPosition (const Ogre::Vector3& position) { mLastKnownExteriorPosition = position; } + Ogre::Vector3 getLastKnownExteriorPosition() const { return mLastKnownExteriorPosition; } + void set (const ESM::NPC *player); void setCell (MWWorld::CellStore *cellStore); @@ -64,6 +83,9 @@ namespace MWWorld void yaw(float yaw); void pitch(float pitch); void roll(float roll); + + bool wasTeleported() const; + void setTeleported(bool teleported); }; } #endif diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index c355d86a8a..513dcf6c72 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -195,7 +195,7 @@ void WeatherManager::setWeather(const String& weather, bool instant) } mNextWeather = weather; - mRemainingTransitionTime = mWeatherSettings[mCurrentWeather].mTransitionDelta * 24.f * 3600; + mRemainingTransitionTime = mWeatherSettings[mCurrentWeather].mTransitionDelta * 24.f * 3600.f; } mFirstUpdate = false; } @@ -324,7 +324,8 @@ void WeatherManager::update(float duration) mWeatherUpdateTime -= timePassed; - const bool exterior = (MWBase::Environment::get().getWorld()->isCellExterior() || MWBase::Environment::get().getWorld()->isCellQuasiExterior()); + MWBase::World* world = MWBase::Environment::get().getWorld(); + const bool exterior = (world->isCellExterior() || world->isCellQuasiExterior()); if (!exterior) { mRendering->sunDisable(false); @@ -334,32 +335,7 @@ void WeatherManager::update(float duration) return; } - // Exterior - std::string regionstr = Misc::StringUtils::lowerCase(MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell()->mCell->mRegion); - - if (mWeatherUpdateTime <= 0 || regionstr != mCurrentRegion) - { - mCurrentRegion = regionstr; - mWeatherUpdateTime = mHoursBetweenWeatherChanges * 3600; - - std::string weatherType = "clear"; - - if (mRegionOverrides.find(regionstr) != mRegionOverrides.end()) - weatherType = mRegionOverrides[regionstr]; - else - { - // get weather probabilities for the current region - const ESM::Region *region = - MWBase::Environment::get().getWorld()->getStore().get().search (regionstr); - - if (region != 0) - { - weatherType = nextWeather(region); - } - } - - setWeather(weatherType, false); - } + switchToNextWeather(false); if (mNextWeather != "") { @@ -708,7 +684,43 @@ float WeatherManager::getWindSpeed() const return mWindSpeed; } -bool WeatherManager::isNight() const +bool WeatherManager::isDark() const { - return (mHour < mSunriseTime || mHour > mNightStart - 1); + bool exterior = (MWBase::Environment::get().getWorld()->isCellExterior() + || MWBase::Environment::get().getWorld()->isCellQuasiExterior()); + return exterior && (mHour < mSunriseTime || mHour > mNightStart - 1); +} + +void WeatherManager::switchToNextWeather(bool instantly) +{ + MWBase::World* world = MWBase::Environment::get().getWorld(); + if (world->isCellExterior() || world->isCellQuasiExterior()) + { + std::string regionstr = Misc::StringUtils::lowerCase(world->getPlayer().getPlayer().getCell()->mCell->mRegion); + + if (mWeatherUpdateTime <= 0 || regionstr != mCurrentRegion) + { + mCurrentRegion = regionstr; + mWeatherUpdateTime = mHoursBetweenWeatherChanges * 3600; + + std::string weatherType = "clear"; + + if (mRegionOverrides.find(regionstr) != mRegionOverrides.end()) + { + weatherType = mRegionOverrides[regionstr]; + } + else + { + // get weather probabilities for the current region + const ESM::Region *region = world->getStore().get().search (regionstr); + + if (region != 0) + { + weatherType = nextWeather(region); + } + } + + setWeather(weatherType, instantly); + } + } } diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 4c412c4498..fa2d9bd8e1 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -128,6 +128,7 @@ namespace MWWorld * @param ID of the weather setting to shift to */ void changeWeather(const std::string& region, const unsigned int id); + void switchToNextWeather(bool instantly = true); /** * Per-frame update @@ -152,7 +153,8 @@ namespace MWWorld void modRegion(const std::string ®ionid, const std::vector &chances); - bool isNight() const; + /// @see World::isDark + bool isDark() const; private: float mHour; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index cf32217b62..c23c63e2e7 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -39,6 +39,7 @@ #include "cellfunctors.hpp" #include "containerstore.hpp" #include "inventorystore.hpp" +#include "actionteleport.hpp" #include "contentloader.hpp" #include "esmloader.hpp" @@ -498,12 +499,14 @@ namespace MWWorld if (!ptr.isEmpty()) return ptr; + std::string lowerCaseName = Misc::StringUtils::lowerCase(name); + // active cells for (Scene::CellStoreCollection::const_iterator iter (mWorldScene->getActiveCells().begin()); iter!=mWorldScene->getActiveCells().end(); ++iter) { Ptr::CellStore* cellstore = *iter; - Ptr ptr = mCells.getPtr (name, *cellstore, true); + Ptr ptr = mCells.getPtr (lowerCaseName, *cellstore, true); if (!ptr.isEmpty()) return ptr; @@ -511,7 +514,7 @@ namespace MWWorld if (!activeOnly) { - Ptr ptr = mCells.getPtr (name); + Ptr ptr = mCells.getPtr (lowerCaseName); if (!ptr.isEmpty()) return ptr; @@ -793,32 +796,9 @@ namespace MWWorld MWWorld::Ptr World::getFacedObject() { - std::pair result; - - if (!mRendering->occlusionQuerySupported()) - result = mPhysics->getFacedHandle (getMaxActivationDistance ()); - else - result = std::make_pair (mFacedDistance, mFacedHandle); - - if (result.second.empty()) - return MWWorld::Ptr (); - - MWWorld::Ptr object = searchPtrViaHandle (result.second); - if (object.isEmpty()) - return object; - float ActivationDistance; - - if (MWBase::Environment::get().getWindowManager()->isConsoleMode()) - ActivationDistance = getObjectActivationDistance ()*50; - else if (object.getTypeName ().find("NPC") != std::string::npos) - ActivationDistance = getNpcActivationDistance (); - else - ActivationDistance = getObjectActivationDistance (); - - if (result.first > ActivationDistance) - return MWWorld::Ptr (); - - return object; + if (mFacedHandle.empty()) + return MWWorld::Ptr(); + return searchPtrViaHandle(mFacedHandle); } std::pair World::getHitContact(const MWWorld::Ptr &ptr, float distance) @@ -931,7 +911,7 @@ namespace MWWorld ptr.getRefData().setCount(0); } } - if (haveToMove) + if (haveToMove && ptr.getRefData().getBaseNode()) { mRendering->moveObject(ptr, vec); mPhysics->moveObject (ptr); @@ -1060,7 +1040,7 @@ namespace MWWorld void World::adjustPosition(const Ptr &ptr) { - Ogre::Vector3 pos (ptr.getRefData().getPosition().pos[0], ptr.getRefData().getPosition().pos[1], ptr.getRefData().getPosition().pos[2]); + Ogre::Vector3 pos (ptr.getRefData().getPosition().pos); if(!ptr.getRefData().getBaseNode()) { @@ -1287,7 +1267,7 @@ namespace MWWorld mRendering->playVideo(mFallback.getFallbackString("Movies_New_Game"), true); } - mWeatherManager->update (duration); + updateWeather(duration); mWorldScene->update (duration, paused); @@ -1297,6 +1277,12 @@ namespace MWWorld performUpdateSceneQueries (); updateWindowManager (); + + if (mPlayer->getPlayer().getCell()->isExterior()) + { + ESM::Position pos = mPlayer->getPlayer().getRefData().getPosition(); + mPlayer->setLastKnownExteriorPosition(Ogre::Vector3(pos.pos)); + } } void World::updateWindowManager () @@ -1337,6 +1323,14 @@ namespace MWWorld void World::updateFacedHandle () { + float telekinesisRangeBonus = + mPlayer->getPlayer().getClass().getCreatureStats(mPlayer->getPlayer()).getMagicEffects() + .get(ESM::MagicEffect::Telekinesis).mMagnitude; + telekinesisRangeBonus = feetToGameUnits(telekinesisRangeBonus); + + float activationDistance = getMaxActivationDistance() + telekinesisRangeBonus; + activationDistance += mRendering->getCameraDistance(); + // send new query // figure out which object we want to test against std::vector < std::pair < float, std::string > > results; @@ -1344,13 +1338,13 @@ namespace MWWorld { float x, y; MWBase::Environment::get().getWindowManager()->getMousePosition(x, y); - results = mPhysics->getFacedHandles(x, y, getMaxActivationDistance ()); + results = mPhysics->getFacedHandles(x, y, activationDistance); if (MWBase::Environment::get().getWindowManager()->isConsoleMode()) results = mPhysics->getFacedHandles(x, y, getMaxActivationDistance ()*50); } else { - results = mPhysics->getFacedHandles(getMaxActivationDistance ()); + results = mPhysics->getFacedHandles(activationDistance); } // ignore the player and other things we're not interested in @@ -1433,10 +1427,8 @@ namespace MWWorld return d; } - std::vector World::getDoorMarkers (CellStore* cell) + void World::getDoorMarkers (CellStore* cell, std::vector& out) { - std::vector result; - MWWorld::CellRefList& doors = cell->mDoors; CellRefList::List& refList = doors.mList; for (CellRefList::List::iterator it = refList.begin(); it != refList.end(); ++it) @@ -1452,11 +1444,9 @@ namespace MWWorld newMarker.x = pos.pos[0]; newMarker.y = pos.pos[1]; - result.push_back(newMarker); + out.push_back(newMarker); } } - - return result; } void World::getInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y) @@ -1579,7 +1569,7 @@ namespace MWWorld pos.rot[1] = 0; Ogre::Vector3 orig = - Ogre::Vector3(pos.pos[0], pos.pos[1], pos.pos[2]); + Ogre::Vector3(pos.pos); Ogre::Vector3 dir = Ogre::Vector3(0, 0, -1); float len = (pos.pos[2] >= 0) ? pos.pos[2] : -pos.pos[2]; @@ -1616,7 +1606,8 @@ namespace MWWorld return false; const MWMechanics::CreatureStats &stats = ptr.getClass().getCreatureStats(ptr); - if(stats.getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::Levitate)).mMagnitude > 0) + if(stats.getMagicEffects().get(ESM::MagicEffect::Levitate).mMagnitude > 0 + && isLevitationEnabled()) return true; // TODO: Check if flying creature @@ -1635,7 +1626,7 @@ namespace MWWorld return false; const MWMechanics::CreatureStats &stats = ptr.getClass().getCreatureStats(ptr); - if(stats.getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::SlowFall)).mMagnitude > 0) + if(stats.getMagicEffects().get(ESM::MagicEffect::SlowFall).mMagnitude > 0) return true; return false; @@ -1820,9 +1811,9 @@ namespace MWWorld { std::vector mHandles; - bool operator() (ESM::CellRef& ref, RefData& data) + bool operator() (Ptr ptr) { - Ogre::SceneNode* handle = data.getBaseNode(); + Ogre::SceneNode* handle = ptr.getRefData().getBaseNode(); if (handle) mHandles.push_back(handle->getName()); return true; @@ -1931,17 +1922,8 @@ namespace MWWorld int y = ext->getGridY(); indexToPosition(x, y, pos.pos[0], pos.pos[1], true); - ESM::Land* land = getStore().get().search(x, y); - if (land) { - if (!land->isDataLoaded(ESM::Land::DATA_VHGT)) { - land->loadData(ESM::Land::DATA_VHGT); - } - pos.pos[2] = land->mLandData->mHeights[ESM::Land::LAND_NUM_VERTS / 2 + 1]; - } - else { - std::cerr << "Land data for cell at (" << x << ", " << y << ") not found\n"; - pos.pos[2] = 0; - } + // Note: Z pos will be adjusted by adjustPosition later + pos.pos[2] = 0; return true; } @@ -1985,11 +1967,11 @@ namespace MWWorld { InventoryStore &inv = actor.getClass().getInventoryStore(actor); - inv.equip(InventoryStore::Slot_Robe, inv.ContainerStore::add("WerewolfRobe", 1, actor), actor); + inv.equip(InventoryStore::Slot_Robe, inv.ContainerStore::add("werewolfrobe", 1, actor), actor); } else { - actor.getClass().getContainerStore(actor).remove("WerewolfRobe", 1, actor); + actor.getClass().getContainerStore(actor).remove("werewolfrobe", 1, actor); } if(actor.getRefData().getHandle() == "player") @@ -2018,7 +2000,7 @@ namespace MWWorld const Store &gmst = getStore().get(); MWMechanics::NpcStats &stats = Class::get(actor).getNpcStats(actor); - stats.getSkill(ESM::Skill::Acrobatics).setModified(gmst.find("fWerewolfAcrobatics")->getFloat(), 0); + stats.getSkill(ESM::Skill::Acrobatics).setBase(gmst.find("fWerewolfAcrobatics")->getFloat()); } bool World::getGodModeState() @@ -2286,8 +2268,153 @@ namespace MWWorld actor.getClass().getInventoryStore(actor).purgeEffect(ESM::MagicEffect::Invisibility); } - bool World::isNight() const + bool World::isDark() const { - return mWeatherManager->isNight(); + return mWeatherManager->isDark(); + } + + bool World::findInteriorPositionInWorldSpace(MWWorld::CellStore* cell, Ogre::Vector3& result) + { + MWWorld::CellRefList& doors = cell->mDoors; + CellRefList::List& refList = doors.mList; + + // Check if any door in the cell leads to an exterior directly + for (CellRefList::List::iterator it = refList.begin(); it != refList.end(); ++it) + { + MWWorld::LiveCellRef& ref = *it; + if (ref.mRef.mTeleport && ref.mRef.mDestCell.empty()) + { + ESM::Position pos = ref.mRef.mDoorDest; + result = Ogre::Vector3(pos.pos); + return true; + } + } + + // No luck :( + return false; + } + + void World::teleportToClosestMarker (const MWWorld::Ptr& ptr, + const std::string& id, Ogre::Vector3 worldPos) + { + MWWorld::Ptr closestMarker; + float closestDistance = FLT_MAX; + + std::vector markers; + mCells.getExteriorPtrs(id, markers); + + for (std::vector::iterator it = markers.begin(); it != markers.end(); ++it) + { + ESM::Position pos = it->getRefData().getPosition(); + Ogre::Vector3 markerPos = Ogre::Vector3(pos.pos); + float distance = worldPos.squaredDistance(markerPos); + if (distance < closestDistance) + { + closestDistance = distance; + closestMarker = *it; + } + + } + + MWWorld::ActionTeleport action("", closestMarker.getRefData().getPosition()); + action.execute(ptr); + } + + void World::updateWeather(float duration) + { + if (mPlayer->wasTeleported()) + { + mPlayer->setTeleported(false); + mWeatherManager->switchToNextWeather(true); + } + + mWeatherManager->update(duration); + } + + struct AddDetectedReference + { + AddDetectedReference(std::vector& out, Ptr detector, World::DetectionType type, float squaredDist) + : mOut(out), mDetector(detector), mType(type), mSquaredDist(squaredDist) + { + } + + std::vector& mOut; + Ptr mDetector; + float mSquaredDist; + World::DetectionType mType; + bool operator() (MWWorld::Ptr ptr) + { + if (Ogre::Vector3(ptr.getRefData().getPosition().pos).squaredDistance( + Ogre::Vector3(mDetector.getRefData().getPosition().pos)) >= mSquaredDist) + return true; + + if (!ptr.getRefData().isEnabled()) + return true; + + // Consider references inside containers as well + if (ptr.getClass().isActor() || ptr.getClass().getTypeName() == typeid(ESM::Container).name()) + { + MWWorld::ContainerStore& store = ptr.getClass().getContainerStore(ptr); + { + for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) + { + if (needToAdd(*it)) + { + mOut.push_back(ptr); + return true; + } + } + } + } + + if (needToAdd(ptr)) + mOut.push_back(ptr); + + return true; + } + + bool needToAdd (MWWorld::Ptr ptr) + { + if (mType == World::Detect_Creature && ptr.getClass().getTypeName() != typeid(ESM::Creature).name()) + return false; + if (mType == World::Detect_Key && !ptr.getClass().isKey(ptr)) + return false; + if (mType == World::Detect_Enchantment && ptr.getClass().getEnchantment(ptr).empty()) + return false; + return true; + } + }; + + void World::listDetectedReferences(const Ptr &ptr, std::vector &out, DetectionType type) + { + const MWMechanics::MagicEffects& effects = ptr.getClass().getCreatureStats(ptr).getMagicEffects(); + float dist=0; + if (type == World::Detect_Creature) + dist = effects.get(ESM::MagicEffect::DetectAnimal).mMagnitude; + else if (type == World::Detect_Key) + dist = effects.get(ESM::MagicEffect::DetectKey).mMagnitude; + else if (type == World::Detect_Enchantment) + dist = effects.get(ESM::MagicEffect::DetectEnchantment).mMagnitude; + + if (!dist) + return; + + dist = feetToGameUnits(dist); + + AddDetectedReference functor (out, ptr, type, dist*dist); + + const Scene::CellStoreCollection& active = mWorldScene->getActiveCells(); + for (Scene::CellStoreCollection::const_iterator it = active.begin(); it != active.end(); ++it) + { + MWWorld::CellStore* cellStore = *it; + cellStore->forEach(functor); + } + } + + float World::feetToGameUnits(float feet) + { + // Looks like there is no GMST for this. This factor was determined in experiments + // with the Telekinesis effect. + return feet * 22; } } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 2c2f096ee3..1aecb6fb64 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -106,7 +106,7 @@ namespace MWWorld }; std::map mProjectiles; - + void updateWeather(float duration); int getDaysPerMonth (int month) const; void rotateObjectImp (const Ptr& ptr, Ogre::Vector3 rot, bool adjust); @@ -155,6 +155,8 @@ namespace MWWorld /// Called when \a object is moved to an inactive cell void objectLeftActiveCell (MWWorld::Ptr object, MWWorld::Ptr movedPtr); + float feetToGameUnits(float feet); + public: World (OEngine::Render::OgreRenderer& renderer, @@ -202,7 +204,7 @@ namespace MWWorld virtual Ogre::Vector2 getNorthVector (CellStore* cell); ///< get north vector (OGRE coordinates) for given interior cell - virtual std::vector getDoorMarkers (MWWorld::CellStore* cell); + virtual void getDoorMarkers (MWWorld::CellStore* cell, std::vector& out); ///< get a list of teleport door markers for a given cell, to be displayed on the local map virtual void getInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y); @@ -516,7 +518,22 @@ namespace MWWorld const MWWorld::Ptr& actor, const std::string& sourceName); virtual void breakInvisibility (const MWWorld::Ptr& actor); - virtual bool isNight() const; + // Are we in an exterior or pseudo-exterior cell and it's night? + virtual bool isDark() const; + + virtual bool findInteriorPositionInWorldSpace(MWWorld::CellStore* cell, Ogre::Vector3& result); + + /// Teleports \a ptr to the reference of \a id (e.g. DivineMarker, PrisonMarker, TempleMarker) + /// closest to \a worldPos. + /// @note id must be lower case + virtual void teleportToClosestMarker (const MWWorld::Ptr& ptr, + const std::string& id, Ogre::Vector3 worldPos); + + /// List all references (filtered by \a type) detected by \a ptr. The range + /// is determined by the current magnitude of the "Detect X" magic effect belonging to \a type. + /// @note This also works for references in containers. + virtual void listDetectedReferences (const MWWorld::Ptr& ptr, std::vector& out, + DetectionType type); }; } diff --git a/cmake/FindBullet.cmake b/cmake/FindBullet.cmake index 97feddffeb..b75f3105a6 100644 --- a/cmake/FindBullet.cmake +++ b/cmake/FindBullet.cmake @@ -60,8 +60,6 @@ _FIND_BULLET_LIBRARY(BULLET_COLLISION_LIBRARY BulletCollision) _FIND_BULLET_LIBRARY(BULLET_COLLISION_LIBRARY_DEBUG BulletCollision_Debug BulletCollision_d) _FIND_BULLET_LIBRARY(BULLET_MATH_LIBRARY BulletMath LinearMath) _FIND_BULLET_LIBRARY(BULLET_MATH_LIBRARY_DEBUG BulletMath_Debug BulletMath_d LinearMath_debug LinearMath_d) -_FIND_BULLET_LIBRARY(BULLET_SOFTBODY_LIBRARY BulletSoftBody) -_FIND_BULLET_LIBRARY(BULLET_SOFTBODY_LIBRARY_DEBUG BulletSoftBody_Debug BulletSoftBody_d) # handle the QUIETLY and REQUIRED arguments and set BULLET_FOUND to TRUE if @@ -69,12 +67,11 @@ _FIND_BULLET_LIBRARY(BULLET_SOFTBODY_LIBRARY_DEBUG BulletSoftBody_Debug BulletS include(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(Bullet DEFAULT_MSG BULLET_DYNAMICS_LIBRARY BULLET_COLLISION_LIBRARY BULLET_MATH_LIBRARY - BULLET_SOFTBODY_LIBRARY BULLET_INCLUDE_DIR) + BULLET_INCLUDE_DIR) set(BULLET_INCLUDE_DIRS ${BULLET_INCLUDE_DIR}) if(BULLET_FOUND) _BULLET_APPEND_LIBRARIES(BULLET_LIBRARIES BULLET_DYNAMICS_LIBRARY) _BULLET_APPEND_LIBRARIES(BULLET_LIBRARIES BULLET_COLLISION_LIBRARY) _BULLET_APPEND_LIBRARIES(BULLET_LIBRARIES BULLET_MATH_LIBRARY) - _BULLET_APPEND_LIBRARIES(BULLET_LIBRARIES BULLET_SOFTBODY_LIBRARY) endif() diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index e95f6f6985..43dcf0ba46 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -222,6 +222,8 @@ namespace Compiler extensions.registerInstruction ("activate", "", opcodeActivate); extensions.registerInstruction ("lock", "/l", opcodeLock, opcodeLockExplicit); extensions.registerInstruction ("unlock", "", opcodeUnlock, opcodeUnlockExplicit); + extensions.registerInstruction ("cast", "SS", opcodeCast, opcodeCastExplicit); + extensions.registerInstruction ("explodespell", "S", opcodeExplodeSpell, opcodeExplodeSpellExplicit); extensions.registerInstruction ("togglecollisionboxes", "", opcodeToggleCollisionBoxes); extensions.registerInstruction ("togglecollisiongrid", "", opcodeToggleCollisionDebug); extensions.registerInstruction ("tcb", "", opcodeToggleCollisionBoxes); @@ -249,6 +251,7 @@ namespace Compiler extensions.registerInstruction ("dropsoulgem", "c", opcodeDropSoulGem, opcodeDropSoulGemExplicit); extensions.registerFunction ("getattacked", 'l', "", opcodeGetAttacked, opcodeGetAttackedExplicit); extensions.registerFunction ("getweapondrawn", 'l', "", opcodeGetWeaponDrawn, opcodeGetWeaponDrawnExplicit); + extensions.registerFunction ("getspellreadied", 'l', "", opcodeGetSpellReadied, opcodeGetSpellReadiedExplicit); extensions.registerFunction ("getspelleffects", 'l', "c", opcodeGetSpellEffects, opcodeGetSpellEffectsExplicit); extensions.registerFunction ("getcurrenttime", 'f', "", opcodeGetCurrentTime); extensions.registerInstruction ("setdelete", "l", opcodeSetDelete, opcodeSetDeleteExplicit); @@ -389,6 +392,12 @@ namespace Compiler extensions.registerInstruction ("addspell", "c", opcodeAddSpell, opcodeAddSpellExplicit); extensions.registerInstruction ("removespell", "c", opcodeRemoveSpell, opcodeRemoveSpellExplicit); + extensions.registerInstruction ("removespelleffects", "c", opcodeRemoveSpellEffects, + opcodeRemoveSpellEffectsExplicit); + extensions.registerInstruction ("removeeffects", "l", opcodeRemoveEffects, + opcodeRemoveEffectsExplicit); + extensions.registerInstruction ("resurrect", "", opcodeResurrect, + opcodeResurrectExplicit); extensions.registerFunction ("getspell", 'l', "c", opcodeGetSpell, opcodeGetSpellExplicit); extensions.registerInstruction("pcraiserank","/S",opcodePCRaiseRank); diff --git a/components/compiler/opcodes.hpp b/components/compiler/opcodes.hpp index a885a373de..8742ba946d 100644 --- a/components/compiler/opcodes.hpp +++ b/components/compiler/opcodes.hpp @@ -25,7 +25,7 @@ namespace Compiler const int opcodeAiFollowExplicit = 0x20023; const int opcodeAiFollowCell = 0x20024; const int opcodeAiFollowCellExplicit = 0x20025; - const int opcodeSetHello = 0x200015e; + const int opcodeSetHello = 0x200015c; const int opcodeSetHelloExplicit = 0x200015d; const int opcodeSetFight = 0x200015e; const int opcodeSetFightExplicit = 0x200015f; @@ -69,7 +69,7 @@ namespace Compiler { const int opcodeCellChanged = 0x2000000; const int opcodeCOC = 0x2000026; - const int opcodeCOE = 0x200008e; + const int opcodeCOE = 0x2000226; const int opcodeGetInterior = 0x2000131; const int opcodeGetPCCell = 0x2000136; const int opcodeGetWaterLevel = 0x2000141; @@ -205,6 +205,8 @@ namespace Compiler const int opcodeGetAttackedExplicit = 0x20001d4; const int opcodeGetWeaponDrawn = 0x20001d7; const int opcodeGetWeaponDrawnExplicit = 0x20001d8; + const int opcodeGetSpellReadied = 0x2000231; + const int opcodeGetSpellReadiedExplicit = 0x2000232; const int opcodeGetSpellEffects = 0x20001db; const int opcodeGetSpellEffectsExplicit = 0x20001dc; const int opcodeGetCurrentTime = 0x20001dd; @@ -228,6 +230,10 @@ namespace Compiler const int opcodeToggleGodMode = 0x200021f; const int opcodeDisableLevitation = 0x2000220; const int opcodeEnableLevitation = 0x2000221; + const int opcodeCast = 0x2000227; + const int opcodeCastExplicit = 0x2000228; + const int opcodeExplodeSpell = 0x2000229; + const int opcodeExplodeSpellExplicit = 0x200022a; } namespace Sky @@ -365,6 +371,13 @@ namespace Compiler const int opcodeIsWerewolfExplicit = 0x20001fe; const int opcodeGetWerewolfKills = 0x20001e2; + + const int opcodeRemoveSpellEffects = 0x200022b; + const int opcodeRemoveSpellEffectsExplicit = 0x200022c; + const int opcodeRemoveEffects = 0x200022d; + const int opcodeRemoveEffectsExplicit = 0x200022e; + const int opcodeResurrect = 0x200022f; + const int opcodeResurrectExplicit = 0x2000230; } namespace Transformation diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp index 47cb0b99ed..5f1066cf8d 100644 --- a/components/esm/cellref.hpp +++ b/components/esm/cellref.hpp @@ -20,7 +20,7 @@ namespace ESM public: int mRefnum; // Reference number - std::string mRefID; // ID of object being referenced + std::string mRefID; // ID of object being referenced (must be lowercase) float mScale; // Scale applied to mesh @@ -89,4 +89,4 @@ namespace ESM }; } -#endif \ No newline at end of file +#endif diff --git a/components/interpreter/interpreter.cpp b/components/interpreter/interpreter.cpp index 10937e6bca..ea1e9fc912 100644 --- a/components/interpreter/interpreter.cpp +++ b/components/interpreter/interpreter.cpp @@ -166,31 +166,37 @@ namespace Interpreter void Interpreter::installSegment0 (int code, Opcode1 *opcode) { + assert(mSegment0.find(code) == mSegment0.end()); mSegment0.insert (std::make_pair (code, opcode)); } void Interpreter::installSegment1 (int code, Opcode2 *opcode) { + assert(mSegment1.find(code) == mSegment1.end()); mSegment1.insert (std::make_pair (code, opcode)); } void Interpreter::installSegment2 (int code, Opcode1 *opcode) { + assert(mSegment2.find(code) == mSegment2.end()); mSegment2.insert (std::make_pair (code, opcode)); } void Interpreter::installSegment3 (int code, Opcode1 *opcode) { + assert(mSegment3.find(code) == mSegment3.end()); mSegment3.insert (std::make_pair (code, opcode)); } void Interpreter::installSegment4 (int code, Opcode2 *opcode) { + assert(mSegment4.find(code) == mSegment4.end()); mSegment4.insert (std::make_pair (code, opcode)); } void Interpreter::installSegment5 (int code, Opcode0 *opcode) { + assert(mSegment5.find(code) == mSegment5.end()); mSegment5.insert (std::make_pair (code, opcode)); } diff --git a/components/nif/niffile.hpp b/components/nif/niffile.hpp index 6e629772e6..91ae93b40b 100644 --- a/components/nif/niffile.hpp +++ b/components/nif/niffile.hpp @@ -200,7 +200,7 @@ struct KeyListT { } } else - nif->file->warn("Unhandled interpolation type: "+Ogre::StringConverter::toString(mInterpolationType)); + nif->file->fail("Unhandled interpolation type: "+Ogre::StringConverter::toString(mInterpolationType)); } }; typedef KeyListT FloatKeyList; diff --git a/components/nifogre/material.cpp b/components/nifogre/material.cpp index c7c9abfc10..8ae86b64a8 100644 --- a/components/nifogre/material.cpp +++ b/components/nifogre/material.cpp @@ -152,7 +152,8 @@ Ogre::String NIFMaterialLoader::getMaterial(const Nif::ShapeData *shapedata, Nif::ControllerPtr ctrls = texprop->controller; while(!ctrls.empty()) { - warn("Unhandled texture controller "+ctrls->recName+" in "+name); + if (ctrls->recType != Nif::RC_NiFlipController) // Handled in ogrenifloader + warn("Unhandled texture controller "+ctrls->recName+" in "+name); ctrls = ctrls->next; } } diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 345e7d6fd4..63e9057664 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -607,6 +607,14 @@ class NIFObjectLoader NIFMeshLoader::createMesh(name, fullname, group, shape->recIndex); Ogre::Entity *entity = sceneMgr->createEntity(fullname); + +#if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0) + // Enable skeleton-based bounding boxes. With the static bounding box, + // the animation may cause parts to go outside the box and cause culling problems. + if (entity->hasSkeleton()) + entity->setUpdateBoundingBoxFromSkeleton(true); +#endif + entity->setVisible(!(flags&Nif::NiNode::Flag_Hidden)); scene->mEntities.push_back(entity); @@ -831,8 +839,6 @@ class NIFObjectLoader vertprop, zprop, specprop, wireprop, needTangents)); - partsys->setDefaultDimensions(particledata->particleRadius*2.0f, - particledata->particleRadius*2.0f); partsys->setCullIndividually(false); partsys->setParticleQuota(particledata->numParticles); partsys->setKeepParticlesInLocalSpace(partflags & (Nif::NiNode::ParticleFlag_LocalSpace)); @@ -848,6 +854,8 @@ class NIFObjectLoader { const Nif::NiParticleSystemController *partctrl = static_cast(ctrl.getPtr()); + partsys->setDefaultDimensions(partctrl->size*2, partctrl->size*2); + if(!partctrl->emitter.empty()) { int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, partctrl->emitter->recIndex); diff --git a/components/nifogre/skeleton.cpp b/components/nifogre/skeleton.cpp index 9ec6f15b0c..e01ae22efd 100644 --- a/components/nifogre/skeleton.cpp +++ b/components/nifogre/skeleton.cpp @@ -86,14 +86,23 @@ bool NIFSkeletonLoader::needSkeleton(const Nif::Node *node) { /* We need to be a little aggressive here, since some NIFs have a crap-ton * of nodes and Ogre only supports 256 bones. We will skip a skeleton if: - * There are no bones used for skinning, there are no controllers, there + * There are no bones used for skinning, there are no keyframe controllers, there * are no nodes named "AttachLight", and the tree consists of NiNode, * NiTriShape, and RootCollisionNode types only. */ if(node->boneTrafo) return true; - if(!node->controller.empty() || node->name == "AttachLight") + if(!node->controller.empty()) + { + Nif::ControllerPtr ctrl = node->controller; + do { + if(ctrl->recType == Nif::RC_NiKeyframeController) + return true; + } while(!(ctrl=ctrl->next).empty()); + } + + if (node->name == "AttachLight") return true; if(node->recType == Nif::RC_NiNode || node->recType == Nif::RC_RootCollisionNode) diff --git a/components/terrain/quadtreenode.cpp b/components/terrain/quadtreenode.cpp index e16ae55ddb..02225cb02d 100644 --- a/components/terrain/quadtreenode.cpp +++ b/components/terrain/quadtreenode.cpp @@ -140,17 +140,19 @@ namespace } QuadTreeNode::QuadTreeNode(World* terrain, ChildDirection dir, float size, const Ogre::Vector2 ¢er, QuadTreeNode* parent) - : mSize(size) - , mCenter(center) - , mParent(parent) - , mDirection(dir) + : mMaterialGenerator(NULL) + , mIsActive(false) , mIsDummy(false) - , mSceneNode(NULL) - , mTerrain(terrain) - , mChunk(NULL) - , mMaterialGenerator(NULL) + , mSize(size) + , mLodLevel(Log2(mSize)) , mBounds(Ogre::AxisAlignedBox::BOX_NULL) , mWorldBounds(Ogre::AxisAlignedBox::BOX_NULL) + , mDirection(dir) + , mCenter(center) + , mSceneNode(NULL) + , mParent(parent) + , mTerrain(terrain) + , mChunk(NULL) { mBounds.setNull(); for (int i=0; i<4; ++i) @@ -168,8 +170,6 @@ QuadTreeNode::QuadTreeNode(World* terrain, ChildDirection dir, float size, const pos = mCenter - pos; mSceneNode->setPosition(Ogre::Vector3(pos.x*8192, pos.y*8192, 0)); - mLodLevel = Log2(mSize); - mMaterialGenerator = new MaterialGenerator(mTerrain->getShadersEnabled()); } diff --git a/files/materials/water.mat b/files/materials/water.mat index 1e5f8c8e04..ade55f326f 100644 --- a/files/materials/water.mat +++ b/files/materials/water.mat @@ -37,7 +37,7 @@ material Water texture_unit normalMap { - texture water_nm.png 5 + texture water_nm.png } texture_unit rippleNormalMap diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index 70fdf42489..ef223a6177 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -8,7 +8,6 @@ set(MYGUI_FILES black.png core.skin core.xml - EBGaramond-Regular.ttf openmw_alchemy_window.layout openmw_book.layout openmw_box.skin.xml diff --git a/files/mygui/EBGaramond-Regular.ttf b/files/mygui/EBGaramond-Regular.ttf deleted file mode 100644 index 3f6f6c191d..0000000000 Binary files a/files/mygui/EBGaramond-Regular.ttf and /dev/null differ diff --git a/files/mygui/openmw_console.layout b/files/mygui/openmw_console.layout index 7d24a283e1..0c9a97d043 100644 --- a/files/mygui/openmw_console.layout +++ b/files/mygui/openmw_console.layout @@ -7,9 +7,12 @@ - + + + + diff --git a/files/mygui/openmw_console.skin.xml b/files/mygui/openmw_console.skin.xml index 219cce39ae..470451a0ed 100644 --- a/files/mygui/openmw_console.skin.xml +++ b/files/mygui/openmw_console.skin.xml @@ -2,19 +2,6 @@ - - - - - - - - - - - - - diff --git a/files/mygui/openmw_font.xml b/files/mygui/openmw_font.xml index 726bfb281c..e4037561d7 100644 --- a/files/mygui/openmw_font.xml +++ b/files/mygui/openmw_font.xml @@ -1,31 +1,8 @@ - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 2ca59159bb..22391fe936 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -53,8 +53,7 @@ texture filtering = anisotropic anisotropy = 4 # Number of texture mipmaps to generate -# This setting is currently ignored due to mipmap generation problems on Intel/AMD -#num mipmaps = 5 +num mipmaps = 8 shader mode = diff --git a/libs/openengine/bullet/CMotionState.cpp b/libs/openengine/bullet/CMotionState.cpp deleted file mode 100644 index c20415884a..0000000000 --- a/libs/openengine/bullet/CMotionState.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "CMotionState.h" -#include "physic.hpp" - -#include -#include -#include - -namespace OEngine { -namespace Physic -{ - - CMotionState::CMotionState(PhysicEngine* eng,std::string name) - : isPC(false) - , isNPC(true) - { - pEng = eng; - tr.setIdentity(); - pName = name; - } - - void CMotionState::getWorldTransform(btTransform &worldTrans) const - { - worldTrans = tr; - } - - void CMotionState::setWorldTransform(const btTransform &worldTrans) - { - tr = worldTrans; - - PhysicEvent evt; - evt.isNPC = isNPC; - evt.isPC = isPC; - evt.newTransform = tr; - evt.RigidBodyName = pName; - - if(isPC) - { - pEng->PEventList.push_back(evt); - } - else - { - pEng->NPEventList.push_back(evt); - } - } - -}} diff --git a/libs/openengine/bullet/CMotionState.h b/libs/openengine/bullet/CMotionState.h deleted file mode 100644 index 3508ab4ef1..0000000000 --- a/libs/openengine/bullet/CMotionState.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef OENGINE_CMOTIONSTATE_H -#define OENGINE_CMOTIONSTATE_H - -#include -#include - -namespace OEngine { -namespace Physic -{ - class PhysicEngine; - - /** - * A CMotionState is associated with a single RigidBody. - * When the RigidBody is moved by bullet, bullet will call the function setWorldTransform. - * for more info, see the bullet Wiki at btMotionState. - */ - class CMotionState:public btMotionState - { - public: - - CMotionState(PhysicEngine* eng,std::string name); - - /** - * Return the position of the RigidBody. - */ - virtual void getWorldTransform(btTransform &worldTrans) const; - - /** - * Function called by bullet when the RigidBody is moved. - * It add an event to the EventList of the PhysicEngine class. - */ - virtual void setWorldTransform(const btTransform &worldTrans); - - protected: - PhysicEngine* pEng; - btTransform tr; - bool isNPC; - bool isPC; - - std::string pName; - }; - - struct PhysicEvent - { - bool isNPC; - bool isPC; - btTransform newTransform; - std::string RigidBodyName; - }; - -}} -#endif diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index e33edda183..4e80088bf7 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -3,7 +3,6 @@ #include #include #include -#include "CMotionState.h" #include "OgreRoot.h" #include "btKinematicCharacterController.h" #include "BtOgrePG.h" @@ -318,9 +317,7 @@ namespace Physic btVector3 scl(triSize, triSize, 1); hfShape->setLocalScaling(scl); - CMotionState* newMotionState = new CMotionState(this,name); - - btRigidBody::btRigidBodyConstructionInfo CI = btRigidBody::btRigidBodyConstructionInfo(0,newMotionState,hfShape); + btRigidBody::btRigidBodyConstructionInfo CI = btRigidBody::btRigidBodyConstructionInfo(0,0,hfShape); RigidBody* body = new RigidBody(CI,name); body->getWorldTransform().setOrigin(btVector3( (x+0.5)*triSize*(sqrtVerts-1), (y+0.5)*triSize*(sqrtVerts-1), (maxh+minh)/2.f)); @@ -401,12 +398,9 @@ namespace Physic else shape->mRaycastingShape->setLocalScaling( btVector3(scale,scale,scale)); - //create the motionState - CMotionState* newMotionState = new CMotionState(this,name); - //create the real body btRigidBody::btRigidBodyConstructionInfo CI = btRigidBody::btRigidBodyConstructionInfo - (0,newMotionState, raycasting ? shape->mRaycastingShape : shape->mCollisionShape); + (0,0, raycasting ? shape->mRaycastingShape : shape->mCollisionShape); RigidBody* body = new RigidBody(CI,name); body->mPlaceable = placeable; diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index f28f95ccb8..6cd7244b85 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -38,7 +38,6 @@ namespace MWWorld namespace OEngine { namespace Physic { - class CMotionState; struct PhysicEvent; class PhysicEngine; class RigidBody; @@ -157,17 +156,7 @@ namespace Physic private: void disableCollisionBody(); void enableCollisionBody(); -public: -//HACK: in Visual Studio 2010 and presumably above, this structures alignment -// must be 16, but the built in operator new & delete don't properly -// perform this alignment. -#if _MSC_VER >= 1600 - void * operator new (size_t Size) { return _aligned_malloc (Size, 16); } - void operator delete (void * Data) { _aligned_free (Data); } -#endif - - private: OEngine::Physic::RigidBody* mBody; OEngine::Physic::RigidBody* mRaycastingBody; @@ -329,12 +318,6 @@ public: const btVector3 &origin, btCollisionObject *object); - //event list of non player object - std::list NPEventList; - - //event list affecting the player - std::list PEventList; - //Bullet Stuff btOverlappingPairCache* pairCache; btBroadphaseInterface* broadphase; diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index 07bc8f3c90..9e5ec5414d 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -25,7 +25,8 @@ void OgreRenderer::cleanup() delete mFader; mFader = NULL; - Ogre::Root::getSingleton().destroyRenderTarget(mWindow); + if (mWindow) + Ogre::Root::getSingleton().destroyRenderTarget(mWindow); mWindow = NULL; delete mOgreInit; diff --git a/libs/openengine/ogre/renderer.hpp b/libs/openengine/ogre/renderer.hpp index f45f09b01c..767e7cf99e 100644 --- a/libs/openengine/ogre/renderer.hpp +++ b/libs/openengine/ogre/renderer.hpp @@ -74,8 +74,9 @@ namespace OEngine , mScene(NULL) , mCamera(NULL) , mView(NULL) - , mWindowListener(NULL) + , mOgreInit(NULL) , mFader(NULL) + , mWindowListener(NULL) { }