resolve conflict in character.cpp

This commit is contained in:
mrcheko 2014-01-04 17:55:09 +02:00
commit 7002412760
124 changed files with 1820 additions and 870 deletions

3
.gitignore vendored
View file

@ -3,7 +3,6 @@ CMakeFiles
*/CMakeFiles */CMakeFiles
CMakeCache.txt CMakeCache.txt
cmake_install.cmake cmake_install.cmake
CMakeLists.txt.user
Makefile Makefile
makefile makefile
build build
@ -22,6 +21,8 @@ Doxygen
.project .project
.settings .settings
.directory .directory
## qt-creator
CMakeLists.txt.user*
## resources ## resources
data data

View file

@ -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 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 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 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 - sudo mkdir /usr/src/gtest/build
- cd /usr/src/gtest/build - cd /usr/src/gtest/build
- sudo cmake .. -DBUILD_SHARED_LIBS=1 - sudo cmake .. -DBUILD_SHARED_LIBS=1

View file

@ -99,8 +99,6 @@ set(OENGINE_BULLET
${LIBDIR}/openengine/bullet/BtOgreExtras.h ${LIBDIR}/openengine/bullet/BtOgreExtras.h
${LIBDIR}/openengine/bullet/BtOgreGP.h ${LIBDIR}/openengine/bullet/BtOgreGP.h
${LIBDIR}/openengine/bullet/BtOgrePG.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.cpp
${LIBDIR}/openengine/bullet/physic.hpp ${LIBDIR}/openengine/bullet/physic.hpp
${LIBDIR}/openengine/bullet/BulletShapeLoader.cpp ${LIBDIR}/openengine/bullet/BulletShapeLoader.cpp
@ -212,7 +210,7 @@ if (HAVE_UNORDERED_MAP)
endif () endif ()
set(BOOST_COMPONENTS system filesystem program_options thread date_time wave) set(BOOST_COMPONENTS system filesystem program_options)
IF(BOOST_STATIC) IF(BOOST_STATIC)
set(Boost_USE_STATIC_LIBS ON) set(Boost_USE_STATIC_LIBS ON)

View file

@ -137,8 +137,3 @@ if (BUILD_WITH_CODE_COVERAGE)
target_link_libraries(omwlauncher gcov) target_link_libraries(omwlauncher gcov)
endif() 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()

View file

@ -143,7 +143,7 @@ if(WIN32)
set(QT_USE_QTMAIN TRUE) set(QT_USE_QTMAIN TRUE)
endif(WIN32) endif(WIN32)
find_package(Qt4 COMPONENTS QtCore QtGui QtNetwork QtXml QtXmlPatterns REQUIRED) find_package(Qt4 COMPONENTS QtCore QtGui QtNetwork REQUIRED)
include(${QT_USE_FILE}) include(${QT_USE_FILE})
qt4_wrap_ui(OPENCS_UI_HDR ${OPENCS_UI}) qt4_wrap_ui(OPENCS_UI_HDR ${OPENCS_UI})

View file

@ -74,6 +74,7 @@ add_openmw_dir (mwmechanics
mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects
drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow
aiescort aiactivate aicombat repair enchanting pathfinding security spellsuccess spellcasting aiescort aiactivate aicombat repair enchanting pathfinding security spellsuccess spellcasting
disease
) )
add_openmw_dir (mwbase add_openmw_dir (mwbase
@ -82,6 +83,8 @@ add_openmw_dir (mwbase
) )
# Main executable # Main executable
set(BOOST_COMPONENTS system filesystem program_options thread wave)
find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS})
IF(OGRE_STATIC) IF(OGRE_STATIC)
ADD_DEFINITIONS(-DENABLE_PLUGIN_OctreeSceneManager -DENABLE_PLUGIN_ParticleFX -DENABLE_PLUGIN_GL) ADD_DEFINITIONS(-DENABLE_PLUGIN_OctreeSceneManager -DENABLE_PLUGIN_ParticleFX -DENABLE_PLUGIN_GL)
@ -111,6 +114,7 @@ add_definitions(${SOUND_DEFINE})
target_link_libraries(openmw target_link_libraries(openmw
${OGRE_LIBRARIES} ${OGRE_LIBRARIES}
${OGRE_STATIC_PLUGINS} ${OGRE_STATIC_PLUGINS}
${SHINY_LIBRARIES}
${Boost_LIBRARIES} ${Boost_LIBRARIES}
${OPENAL_LIBRARY} ${OPENAL_LIBRARY}
${SOUND_INPUT_LIBRARY} ${SOUND_INPUT_LIBRARY}
@ -118,7 +122,6 @@ target_link_libraries(openmw
${MYGUI_LIBRARIES} ${MYGUI_LIBRARIES}
${SDL2_LIBRARY} ${SDL2_LIBRARY}
${MYGUI_PLATFORM_LIBRARIES} ${MYGUI_PLATFORM_LIBRARIES}
${SHINY_LIBRARIES}
"oics" "oics"
"sdl4ogre" "sdl4ogre"
components components
@ -137,12 +140,6 @@ if (UNIX AND NOT APPLE)
target_link_libraries(openmw ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries(openmw ${CMAKE_THREAD_LIBS_INIT})
endif() 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) if(APPLE)
find_library(COCOA_FRAMEWORK Cocoa) find_library(COCOA_FRAMEWORK Cocoa)
find_library(IOKIT_FRAMEWORK IOKit) find_library(IOKIT_FRAMEWORK IOKit)

View file

@ -137,8 +137,8 @@ namespace MWBase
virtual void wmUpdateFps(float fps, unsigned int triangleCount, unsigned int batchCount) = 0; virtual void wmUpdateFps(float fps, unsigned int triangleCount, unsigned int batchCount) = 0;
/// Set value for the given ID. /// Set value for the given ID.
virtual void setValue (const std::string& id, const MWMechanics::Stat<int>& value) = 0; virtual void setValue (const std::string& id, const MWMechanics::AttributeValue& value) = 0;
virtual void setValue (int parSkill, const MWMechanics::Stat<float>& value) = 0; virtual void setValue (int parSkill, const MWMechanics::SkillValue& value) = 0;
virtual void setValue (const std::string& id, const MWMechanics::DynamicStat<float>& value) = 0; virtual void setValue (const std::string& id, const MWMechanics::DynamicStat<float>& value) = 0;
virtual void setValue (const std::string& id, const std::string& value) = 0; virtual void setValue (const std::string& id, const std::string& value) = 0;
virtual void setValue (const std::string& id, int value) = 0; virtual void setValue (const std::string& id, int value) = 0;
@ -236,8 +236,8 @@ namespace MWBase
virtual void onFrame (float frameDuration) = 0; virtual void onFrame (float frameDuration) = 0;
/// \todo get rid of this stuff. Move it to the respective UI element classes, if needed. /// \todo get rid of this stuff. Move it to the respective UI element classes, if needed.
virtual std::map<int, MWMechanics::Stat<float> > getPlayerSkillValues() = 0; virtual std::map<int, MWMechanics::SkillValue > getPlayerSkillValues() = 0;
virtual std::map<int, MWMechanics::Stat<int> > getPlayerAttributeValues() = 0; virtual std::map<int, MWMechanics::AttributeValue > getPlayerAttributeValues() = 0;
virtual SkillList getPlayerMinorSkills() = 0; virtual SkillList getPlayerMinorSkills() = 0;
virtual SkillList getPlayerMajorSkills() = 0; virtual SkillList getPlayerMajorSkills() = 0;

View file

@ -130,7 +130,7 @@ namespace MWBase
virtual Ogre::Vector2 getNorthVector (MWWorld::CellStore* cell) = 0; virtual Ogre::Vector2 getNorthVector (MWWorld::CellStore* cell) = 0;
///< get north vector (OGRE coordinates) for given interior cell ///< get north vector (OGRE coordinates) for given interior cell
virtual std::vector<DoorMarker> getDoorMarkers (MWWorld::CellStore* cell) = 0; virtual void getDoorMarkers (MWWorld::CellStore* cell, std::vector<DoorMarker>& out) = 0;
///< get a list of teleport door markers for a given cell, to be displayed on the local map ///< 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; 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 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<MWWorld::Ptr>& out,
DetectionType type) = 0;
}; };
} }

View file

@ -291,44 +291,36 @@ namespace MWClass
{ {
MWWorld::InventoryStore& invStore = MWWorld::Class::get(npc).getInventoryStore(npc); 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 // slots that this item can be equipped in
std::pair<std::vector<int>, bool> slots_ = MWWorld::Class::get(ptr).getEquipmentSlots(ptr); std::pair<std::vector<int>, bool> slots_ = MWWorld::Class::get(ptr).getEquipmentSlots(ptr);
if (slots_.first.empty())
return std::make_pair(0, "");
std::string npcRace = npc.get<ESM::NPC>()->mBase->mRace; std::string npcRace = npc.get<ESM::NPC>()->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<ESM::Race>().find(npcRace);
if(race->mData.mFlags & ESM::Race::Beast)
{
std::vector<ESM::PartReference> parts = ptr.get<ESM::Armor>()->mBase->mParts.mParts;
for(std::vector<ESM::PartReference>::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<int>::const_iterator slot=slots_.first.begin(); for (std::vector<int>::const_iterator slot=slots_.first.begin();
slot!=slots_.first.end(); ++slot) slot!=slots_.first.end(); ++slot)
{ {
// If equipping a shield, check if there's a twohanded weapon conflicting with it
// Beast races cannot equip shoes / boots, or full helms (head part vs hair part)
const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(npcRace);
if(race->mData.mFlags & ESM::Race::Beast)
{
std::vector<ESM::PartReference> parts = ptr.get<ESM::Armor>()->mBase->mParts.mParts;
if(*slot == MWWorld::InventoryStore::Slot_Helmet)
{
for(std::vector<ESM::PartReference>::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<ESM::PartReference>::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(*slot == MWWorld::InventoryStore::Slot_CarriedLeft) if(*slot == MWWorld::InventoryStore::Slot_CarriedLeft)
{ {
MWWorld::ContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); MWWorld::ContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);

View file

@ -235,37 +235,26 @@ namespace MWClass
// slots that this item can be equipped in // slots that this item can be equipped in
std::pair<std::vector<int>, bool> slots_ = MWWorld::Class::get(ptr).getEquipmentSlots(ptr); std::pair<std::vector<int>, bool> slots_ = MWWorld::Class::get(ptr).getEquipmentSlots(ptr);
if (slots_.first.empty())
return std::make_pair(0, "");
std::string npcRace = npc.get<ESM::NPC>()->mBase->mRace; std::string npcRace = npc.get<ESM::NPC>()->mBase->mRace;
for (std::vector<int>::const_iterator slot=slots_.first.begin(); // Beast races cannot equip shoes / boots, or full helms (head part vs hair part)
slot!=slots_.first.end(); ++slot) const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(npcRace);
if(race->mData.mFlags & ESM::Race::Beast)
{ {
std::vector<ESM::PartReference> parts = ptr.get<ESM::Clothing>()->mBase->mParts.mParts;
// Beast races cannot equip shoes / boots, or full helms (head part vs hair part) for(std::vector<ESM::PartReference>::iterator itr = parts.begin(); itr != parts.end(); ++itr)
const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(npcRace);
if(race->mData.mFlags & ESM::Race::Beast)
{ {
std::vector<ESM::PartReference> parts = ptr.get<ESM::Clothing>()->mBase->mParts.mParts; if((*itr).mPart == ESM::PRT_Head)
return std::make_pair(0, "#{sNotifyMessage13}");
if(*slot == MWWorld::InventoryStore::Slot_Helmet) if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot)
{ return std::make_pair(0, "#{sNotifyMessage15}");
for(std::vector<ESM::PartReference>::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<ESM::PartReference>::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}");
}
}
} }
} }
return std::make_pair (1, ""); return std::make_pair (1, "");
} }

View file

@ -242,7 +242,11 @@ namespace MWClass
item.get<ESM::Miscellaneous>(); item.get<ESM::Miscellaneous>();
return !ref->mBase->mData.mIsKey && (npcServices & ESM::NPC::Misc) 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 float Miscellaneous::getWeight(const MWWorld::Ptr &ptr) const
@ -252,4 +256,11 @@ namespace MWClass
return ref->mBase->mData.mWeight; return ref->mBase->mData.mWeight;
} }
bool Miscellaneous::isKey(const MWWorld::Ptr &ptr) const
{
MWWorld::LiveCellRef<ESM::Miscellaneous> *ref =
ptr.get<ESM::Miscellaneous>();
return ref->mBase->mData.mIsKey;
}
} }

View file

@ -57,6 +57,8 @@ namespace MWClass
virtual float getWeight (const MWWorld::Ptr& ptr) const; virtual float getWeight (const MWWorld::Ptr& ptr) const;
virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const;
virtual bool isKey (const MWWorld::Ptr &ptr) const;
}; };
} }

View file

@ -21,6 +21,7 @@
#include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/npcstats.hpp"
#include "../mwmechanics/movement.hpp" #include "../mwmechanics/movement.hpp"
#include "../mwmechanics/spellcasting.hpp" #include "../mwmechanics/spellcasting.hpp"
#include "../mwmechanics/disease.hpp"
#include "../mwworld/ptr.hpp" #include "../mwworld/ptr.hpp"
#include "../mwworld/actiontalk.hpp" #include "../mwworld/actiontalk.hpp"
@ -179,29 +180,29 @@ namespace
for (int raceSkillIndex = 0; raceSkillIndex < 7; ++raceSkillIndex) for (int raceSkillIndex = 0; raceSkillIndex < 7; ++raceSkillIndex)
{ {
if (race->mData.mBonus[raceSkillIndex].mSkill == skillIndex) if (race->mData.mBonus[raceSkillIndex].mSkill == skillIndex)
{ {
raceBonus = race->mData.mBonus[raceSkillIndex].mBonus; raceBonus = race->mData.mBonus[raceSkillIndex].mBonus;
break; break;
} }
} }
for (int k = 0; k < 5; ++k) for (int k = 0; k < 5; ++k)
{ {
// is this a minor or major skill? // is this a minor or major skill?
if ((class_->mData.mSkills[k][0] == skillIndex) || (class_->mData.mSkills[k][1] == skillIndex)) if ((class_->mData.mSkills[k][0] == skillIndex) || (class_->mData.mSkills[k][1] == skillIndex))
{ {
majorMultiplier = 1.0f; majorMultiplier = 1.0f;
break; break;
} }
} }
// is this skill in the same Specialization as the class? // is this skill in the same Specialization as the class?
const ESM::Skill* skill = MWBase::Environment::get().getWorld()->getStore().get<ESM::Skill>().find(skillIndex); const ESM::Skill* skill = MWBase::Environment::get().getWorld()->getStore().get<ESM::Skill>().find(skillIndex);
if (skill->mData.mSpecialization == class_->mData.mSpecialization) if (skill->mData.mSpecialization == class_->mData.mSpecialization)
{ {
specMultiplier = 0.5f; specMultiplier = 0.5f;
specBonus = 5; specBonus = 5;
} }
npcStats.getSkill(skillIndex).setBase( npcStats.getSkill(skillIndex).setBase(
@ -210,7 +211,7 @@ namespace
+ 5 + 5
+ raceBonus + raceBonus
+ specBonus + specBonus
+ static_cast<int>((level-1) * (majorMultiplier + specMultiplier)), 100.0f)); + static_cast<int>((level-1) * (majorMultiplier + specMultiplier)), 100));
} }
} }
} }
@ -450,8 +451,8 @@ namespace MWClass
(stats.getAttribute(ESM::Attribute::Agility).getModified() / 5.0f) + (stats.getAttribute(ESM::Attribute::Agility).getModified() / 5.0f) +
(stats.getAttribute(ESM::Attribute::Luck).getModified() / 10.0f); (stats.getAttribute(ESM::Attribute::Luck).getModified() / 10.0f);
hitchance *= stats.getFatigueTerm(); hitchance *= stats.getFatigueTerm();
hitchance += mageffects.get(MWMechanics::EffectKey(ESM::MagicEffect::FortifyAttack)).mMagnitude - hitchance += mageffects.get(ESM::MagicEffect::FortifyAttack).mMagnitude -
mageffects.get(MWMechanics::EffectKey(ESM::MagicEffect::Blind)).mMagnitude; mageffects.get(ESM::MagicEffect::Blind).mMagnitude;
hitchance -= otherstats.getEvasion(); hitchance -= otherstats.getEvasion();
if((::rand()/(RAND_MAX+1.0)) > hitchance/100.0f) if((::rand()/(RAND_MAX+1.0)) > hitchance/100.0f)
@ -493,6 +494,11 @@ namespace MWClass
if (!MWBase::Environment::get().getWorld()->getGodModeState()) if (!MWBase::Environment::get().getWorld()->getGodModeState())
weapon.getCellRef().mCharge -= std::min(std::max(1, weapon.getCellRef().mCharge -= std::min(std::max(1,
(int)(damage * gmst.find("fWeaponDamageMult")->getFloat())), weapon.getCellRef().mCharge); (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; healthdmg = true;
} }
@ -512,7 +518,8 @@ namespace MWClass
MWBase::Environment::get().getSoundManager()->playSound3D(victim, "critical damage", 1.0f, 1.0f); 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()) if(stats.isWerewolf())
{ {
healthdmg = true; healthdmg = true;
@ -598,6 +605,9 @@ namespace MWClass
ptr.getRefData().getLocals().setVarByInt(script, "onpchitme", 1); ptr.getRefData().getLocals().setVarByInt(script, "onpchitme", 1);
} }
if (!attacker.isEmpty())
MWMechanics::diseaseContact(ptr, attacker);
if(damage > 0.0f) if(damage > 0.0f)
{ {
// 'ptr' is losing health. Play a 'hit' voiced dialog entry if not already saying // 'ptr' is losing health. Play a 'hit' voiced dialog entry if not already saying
@ -645,6 +655,11 @@ namespace MWClass
armorref.mCharge = armor.get<ESM::Armor>()->mBase->mData.mHealth; armorref.mCharge = armor.get<ESM::Armor>()->mBase->mData.mHealth;
armorref.mCharge -= std::min(std::max(1, (int)damagediff), armorref.mCharge -= std::min(std::max(1, (int)damagediff),
armorref.mCharge); armorref.mCharge);
// Armor broken? unequip it
if (armorref.mCharge == 0)
inv.unequipItem(armor, ptr);
switch(get(armor).getEquipmentSkill(armor)) switch(get(armor).getEquipmentSkill(armor))
{ {
case ESM::Skill::LightArmor: case ESM::Skill::LightArmor:
@ -839,10 +854,11 @@ namespace MWClass
float moveSpeed; float moveSpeed;
if(normalizedEncumbrance >= 1.0f) if(normalizedEncumbrance >= 1.0f)
moveSpeed = 0.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() + 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 = fMinFlySpeed->getFloat() + flySpeed*(fMaxFlySpeed->getFloat() - fMinFlySpeed->getFloat());
flySpeed *= 1.0f - fEncumberedMoveEffect->getFloat() * normalizedEncumbrance; flySpeed *= 1.0f - fEncumberedMoveEffect->getFloat() * normalizedEncumbrance;
flySpeed = std::max(0.0f, flySpeed); flySpeed = std::max(0.0f, flySpeed);
@ -853,7 +869,7 @@ namespace MWClass
float swimSpeed = walkSpeed; float swimSpeed = walkSpeed;
if(Npc::getStance(ptr, Run, false)) if(Npc::getStance(ptr, Run, false))
swimSpeed = runSpeed; 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()* swimSpeed *= fSwimRunBase->getFloat() + 0.01f*npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified()*
fSwimRunAthleticsMult->getFloat(); fSwimRunAthleticsMult->getFloat();
moveSpeed = swimSpeed; moveSpeed = swimSpeed;
@ -887,7 +903,7 @@ namespace MWClass
float x = fJumpAcrobaticsBase->getFloat() + float x = fJumpAcrobaticsBase->getFloat() +
std::pow(a / 15.0f, fJumpAcroMultiplier->getFloat()); std::pow(a / 15.0f, fJumpAcroMultiplier->getFloat());
x += 3.0f * b * 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; x *= encumbranceTerm;
if(Npc::getStance(ptr, Run, false)) 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 float acrobaticsSkill = MWWorld::Class::get(ptr).getNpcStats (ptr).getSkill(ESM::Skill::Acrobatics).getModified();
const CustomData *npcdata = static_cast<const CustomData*>(ptr.getRefData().getCustomData()); const CustomData *npcdata = static_cast<const CustomData*>(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 fallAcroBase = gmst.find("fFallAcroBase")->getFloat();
const float fallAcroMult = gmst.find("fFallAcroMult")->getFloat(); const float fallAcroMult = gmst.find("fFallAcroMult")->getFloat();
const float fallDistanceBase = gmst.find("fFallDistanceBase")->getFloat(); const float fallDistanceBase = gmst.find("fFallDistanceBase")->getFloat();
@ -1015,8 +1031,8 @@ namespace MWClass
if(!stats.isWerewolf()) if(!stats.isWerewolf())
{ {
weight = getContainerStore(ptr).getWeight(); weight = getContainerStore(ptr).getWeight();
weight -= stats.getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::Feather)).mMagnitude; weight -= stats.getMagicEffects().get(ESM::MagicEffect::Feather).mMagnitude;
weight += stats.getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::Burden)).mMagnitude; weight += stats.getMagicEffects().get(ESM::MagicEffect::Burden).mMagnitude;
if(weight < 0.0f) if(weight < 0.0f)
weight = 0.0f; weight = 0.0f;
} }

View file

@ -388,28 +388,26 @@ namespace MWClass
std::pair<int, std::string> Weapon::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const std::pair<int, std::string> Weapon::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const
{ {
if (ptr.getCellRef().mCharge == 0)
return std::make_pair(0, "#{sInventoryMessage1}");
std::pair<std::vector<int>, bool> slots_ = MWWorld::Class::get(ptr).getEquipmentSlots(ptr); std::pair<std::vector<int>, bool> slots_ = MWWorld::Class::get(ptr).getEquipmentSlots(ptr);
// equip the item in the first free slot if (slots_.first.empty())
for (std::vector<int>::const_iterator slot=slots_.first.begin(); return std::make_pair (0, "");
slot!=slots_.first.end(); ++slot)
if(ptr.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand ||
ptr.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::BluntTwoClose ||
ptr.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::BluntTwoWide ||
ptr.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::SpearTwoWide ||
ptr.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::AxeTwoHand ||
ptr.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanBow ||
ptr.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow)
{ {
if(*slot == MWWorld::InventoryStore::Slot_CarriedRight) return std::make_pair (2, "");
{
if(ptr.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand ||
ptr.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::BluntTwoClose ||
ptr.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::BluntTwoWide ||
ptr.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::SpearTwoWide ||
ptr.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::AxeTwoHand ||
ptr.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanBow ||
ptr.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow)
{
return std::make_pair (2, "");
}
}
return std::make_pair(1, "");
} }
return std::make_pair (0, "");
return std::make_pair(1, "");
} }
boost::shared_ptr<MWWorld::Action> Weapon::use (const MWWorld::Ptr& ptr) const boost::shared_ptr<MWWorld::Action> Weapon::use (const MWWorld::Ptr& ptr) const

View file

@ -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); Filter filter (mActor, mChoice, mTalkedTo);
@ -262,12 +262,9 @@ namespace MWDialogue
MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow();
std::vector<const ESM::DialInfo *> infos = filter.list (dialogue, true, true); const ESM::DialInfo* info = filter.search(dialogue, true);
if (info)
if (!infos.empty())
{ {
const ESM::DialInfo* info = infos[randomResponse ? std::rand() % infos.size() : 0];
parseText (info->mResponse); parseText (info->mResponse);
std::string title; std::string title;
@ -509,7 +506,7 @@ namespace MWDialogue
text = "Bribe"; text = "Bribe";
} }
executeTopic (text + (success ? " Success" : " Fail"), true); executeTopic (text + (success ? " Success" : " Fail"));
} }
int DialogueManager::getTemporaryDispositionChange() const int DialogueManager::getTemporaryDispositionChange() const

View file

@ -44,7 +44,7 @@ namespace MWDialogue
bool compile (const std::string& cmd,std::vector<Interpreter::Type_Code>& code); bool compile (const std::string& cmd,std::vector<Interpreter::Type_Code>& code);
void executeScript (const std::string& script); void executeScript (const std::string& script);
void executeTopic (const std::string& topic, bool randomResponse=false); void executeTopic (const std::string& topic);
public: public:

View file

@ -5,6 +5,7 @@
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwbase/journal.hpp" #include "../mwbase/journal.hpp"
#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/mechanicsmanager.hpp"
#include "../mwbase/dialoguemanager.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/player.hpp" #include "../mwworld/player.hpp"
@ -133,7 +134,8 @@ bool MWDialogue::Filter::testDisposition (const ESM::DialInfo& info, bool invert
if (isCreature) if (isCreature)
return true; 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". // 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) return invert ? (info.mData.mDisposition == 0 || actorDisposition < info.mData.mDisposition)
: (actorDisposition >= info.mData.mDisposition); : (actorDisposition >= info.mData.mDisposition);

View file

@ -44,6 +44,11 @@ namespace MWGui
adjustButton(mNextPageButton); adjustButton(mNextPageButton);
adjustButton(mPrevPageButton); 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) if (mNextPageButton->getSize().width == 64)
{ {
// english button has a 7 pixel wide strip of garbage on its right edge // english button has a 7 pixel wide strip of garbage on its right edge
@ -54,6 +59,14 @@ namespace MWGui
center(); center();
} }
void BookWindow::onMouseWheel(MyGUI::Widget *_sender, int _rel)
{
if (_rel < 0)
nextPage();
else
prevPage();
}
void BookWindow::clearPages() void BookWindow::clearPages()
{ {
for (std::vector<MyGUI::Widget*>::iterator it=mPages.begin(); for (std::vector<MyGUI::Widget*>::iterator it=mPages.begin();
@ -89,6 +102,7 @@ namespace MWGui
parent = mRightPage; parent = mRightPage;
MyGUI::Widget* pageWidget = parent->createWidgetReal<MyGUI::Widget>("", MyGUI::FloatCoord(0.0,0.0,1.0,1.0), MyGUI::Align::Default, "BookPage" + boost::lexical_cast<std::string>(i)); MyGUI::Widget* pageWidget = parent->createWidgetReal<MyGUI::Widget>("", MyGUI::FloatCoord(0.0,0.0,1.0,1.0), MyGUI::Align::Default, "BookPage" + boost::lexical_cast<std::string>(i));
pageWidget->setNeedMouseFocus(false);
parser.parsePage(*it, pageWidget, mLeftPage->getSize().width); parser.parsePage(*it, pageWidget, mLeftPage->getSize().width);
mPages.push_back(pageWidget); mPages.push_back(pageWidget);
++i; ++i;

View file

@ -25,6 +25,7 @@ namespace MWGui
void onPrevPageButtonClicked (MyGUI::Widget* sender); void onPrevPageButtonClicked (MyGUI::Widget* sender);
void onCloseButtonClicked (MyGUI::Widget* sender); void onCloseButtonClicked (MyGUI::Widget* sender);
void onTakeButtonClicked (MyGUI::Widget* sender); void onTakeButtonClicked (MyGUI::Widget* sender);
void onMouseWheel(MyGUI::Widget* _sender, int _rel);
void updatePages(); void updatePages();
void clearPages(); void clearPages();

View file

@ -75,7 +75,7 @@ namespace MWGui
mGenerateClassSpecializations[2] = 0; mGenerateClassSpecializations[2] = 0;
} }
void CharacterCreation::setValue (const std::string& id, const MWMechanics::Stat<int>& value) void CharacterCreation::setValue (const std::string& id, const MWMechanics::AttributeValue& value)
{ {
if (mReviewDialog) if (mReviewDialog)
{ {
@ -113,7 +113,7 @@ namespace MWGui
} }
} }
void CharacterCreation::setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat<float>& value) void CharacterCreation::setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value)
{ {
if (mReviewDialog) if (mReviewDialog)
mReviewDialog->setSkillValue(parSkill, value); mReviewDialog->setSkillValue(parSkill, value);
@ -229,8 +229,8 @@ namespace MWGui
} }
{ {
std::map<int, MWMechanics::Stat<int> > attributes = MWBase::Environment::get().getWindowManager()->getPlayerAttributeValues(); std::map<int, MWMechanics::AttributeValue > attributes = MWBase::Environment::get().getWindowManager()->getPlayerAttributeValues();
for (std::map<int, MWMechanics::Stat<int> >::iterator it = attributes.begin(); for (std::map<int, MWMechanics::AttributeValue >::iterator it = attributes.begin();
it != attributes.end(); ++it) it != attributes.end(); ++it)
{ {
mReviewDialog->setAttribute(static_cast<ESM::Attribute::AttributeID> (it->first), it->second); mReviewDialog->setAttribute(static_cast<ESM::Attribute::AttributeID> (it->first), it->second);
@ -238,8 +238,8 @@ namespace MWGui
} }
{ {
std::map<int, MWMechanics::Stat<float> > skills = MWBase::Environment::get().getWindowManager()->getPlayerSkillValues(); std::map<int, MWMechanics::SkillValue > skills = MWBase::Environment::get().getWindowManager()->getPlayerSkillValues();
for (std::map<int, MWMechanics::Stat<float> >::iterator it = skills.begin(); for (std::map<int, MWMechanics::SkillValue >::iterator it = skills.begin();
it != skills.end(); ++it) it != skills.end(); ++it)
{ {
mReviewDialog->setSkillValue(static_cast<ESM::Skill::SkillEnum> (it->first), it->second); mReviewDialog->setSkillValue(static_cast<ESM::Skill::SkillEnum> (it->first), it->second);

View file

@ -31,9 +31,9 @@ namespace MWGui
//Show a dialog //Show a dialog
void spawnDialog(const char id); void spawnDialog(const char id);
void setValue (const std::string& id, const MWMechanics::Stat<int>& value); void setValue (const std::string& id, const MWMechanics::AttributeValue& value);
void setValue (const std::string& id, const MWMechanics::DynamicStat<float>& value); void setValue (const std::string& id, const MWMechanics::DynamicStat<float>& value);
void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat<float>& value); void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value);
void configureSkills (const SkillList& major, const SkillList& minor); void configureSkills (const SkillList& major, const SkillList& minor);
void doRenderUpdate(); void doRenderUpdate();

View file

@ -119,8 +119,6 @@ namespace MWGui
// Set up the log window // Set up the log window
mHistory->setOverflowToTheLeft(true); mHistory->setOverflowToTheLeft(true);
mHistory->setEditStatic(true);
mHistory->setVisibleVScroll(true);
// compiler // compiler
Compiler::registerExtensions (mExtensions, mConsoleOnlyScripts); Compiler::registerExtensions (mExtensions, mConsoleOnlyScripts);
@ -215,7 +213,7 @@ namespace MWGui
{ {
std::vector<std::string> matches; std::vector<std::string> matches;
listNames(); listNames();
mCommandLine->setCaption(complete( mCommandLine->getCaption(), matches )); mCommandLine->setCaption(complete( mCommandLine->getOnlyText(), matches ));
#if 0 #if 0
int i = 0; int i = 0;
for(std::vector<std::string>::iterator it=matches.begin(); it < matches.end(); ++it,++i ) for(std::vector<std::string>::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 the user was editing a string, store it for later
if(mCurrent == mCommandHistory.end()) if(mCurrent == mCommandHistory.end())
mEditString = mCommandLine->getCaption(); mEditString = mCommandLine->getOnlyText();
if(mCurrent != mCommandHistory.begin()) if(mCurrent != mCommandHistory.begin())
{ {
@ -259,7 +257,7 @@ namespace MWGui
void Console::acceptCommand(MyGUI::EditBox* _sender) void Console::acceptCommand(MyGUI::EditBox* _sender)
{ {
const std::string &cm = mCommandLine->getCaption(); const std::string &cm = mCommandLine->getOnlyText();
if(cm.empty()) return; if(cm.empty()) return;
// Add the command to the history, and set the current pointer to // Add the command to the history, and set the current pointer to

View file

@ -55,6 +55,8 @@ namespace MWGui
, mWorldMouseOver(false) , mWorldMouseOver(false)
, mEnemyHealthTimer(0) , mEnemyHealthTimer(0)
, mIsDrowning(false) , mIsDrowning(false)
, mWeaponSpellTimer(0.f)
, mDrowningFlashTheta(0.f)
{ {
setCoord(0,0, width, height); setCoord(0,0, width, height);

View file

@ -72,7 +72,7 @@ void InventoryItemModel::update()
// NOTE: Don't show WerewolfRobe objects in the inventory, or allow them to be taken. // 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 // Vanilla likely uses a hack like this since there's no other way to prevent it from
// being shown or taken. // being shown or taken.
if(item.getCellRef().mRefID == "WerewolfRobe") if(item.getCellRef().mRefID == "werewolfrobe")
continue; continue;
ItemStack newItem (item, this, item.getRefData().getCount()); ItemStack newItem (item, this, item.getRefData().getCount());

View file

@ -163,6 +163,14 @@ namespace MWGui
MWWorld::Ptr object = item.mBase; MWWorld::Ptr object = item.mBase;
int count = item.mCount; 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) if (item.mType == ItemStack::Type_Equipped)
{ {
MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr); 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 // 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 // likely uses a hack like this since there's no other way to prevent it from being
// taken. // taken.
if(item.getCellRef().mRefID == "WerewolfRobe") if(item.getCellRef().mRefID == "werewolfrobe")
return MWWorld::Ptr(); return MWWorld::Ptr();
return item; return item;
} }

View file

@ -166,7 +166,7 @@ namespace MWGui
// increase attributes // increase attributes
for (int i=0; i<3; ++i) for (int i=0; i<3; ++i)
{ {
MWMechanics::Stat<int> attribute = creatureStats.getAttribute(mSpentAttributes[i]); MWMechanics::AttributeValue attribute = creatureStats.getAttribute(mSpentAttributes[i]);
attribute.setBase (attribute.getBase () + pcStats.getLevelupAttributeMultiplier (mSpentAttributes[i])); attribute.setBase (attribute.getBase () + pcStats.getLevelupAttributeMultiplier (mSpentAttributes[i]));
if (attribute.getBase() >= 100) if (attribute.getBase() >= 100)

View file

@ -103,27 +103,80 @@ namespace MWGui
void LocalMapBase::onMarkerFocused (MyGUI::Widget* w1, MyGUI::Widget* w2) void LocalMapBase::onMarkerFocused (MyGUI::Widget* w1, MyGUI::Widget* w2)
{ {
// Workaround to not make the marker visible if it's under fog of war
applyFogOfWar (); applyFogOfWar ();
} }
void LocalMapBase::onMarkerUnfocused (MyGUI::Widget* w1, MyGUI::Widget* w2) void LocalMapBase::onMarkerUnfocused (MyGUI::Widget* w1, MyGUI::Widget* w2)
{ {
// Workaround to not make the marker visible if it's under fog of war
applyFogOfWar (); 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) 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 // clear all previous markers
for (unsigned int i=0; i< mLocalMap->getChildCount(); ++i) 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)); MyGUI::Gui::getInstance ().destroyWidget (mLocalMap->getChildAt(i));
} }
} }
// Update the map textures
for (int mx=0; mx<3; ++mx) for (int mx=0; mx<3; ++mx)
{ {
for (int my=0; my<3; ++my) for (int my=0; my<3; ++my)
@ -138,78 +191,57 @@ namespace MWGui
box->setImageTexture(image); box->setImageTexture(image);
else else
box->setImageTexture("black.png"); 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<MWBase::World::DoorMarker> doors = MWBase::Environment::get().getWorld ()->getDoorMarkers (cell);
for (std::vector<MWBase::World::DoorMarker>::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<MyGUI::Button>("ButtonImage",
widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast<std::string>(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<MWBase::World::DoorMarker> 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<MWBase::World::DoorMarker>::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<MyGUI::Button>("ButtonImage",
widgetCoord, MyGUI::Align::Default, "Door" + boost::lexical_cast<std::string>(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(); applyFogOfWar();
// set the compass texture again, because MyGUI determines sorting of ImageBox widgets // 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) void LocalMapBase::setPlayerPos(const float x, const float y)
{ {
updateMarkers();
if (x == mLastPositionX && y == mLastPositionY) if (x == mLastPositionX && y == mLastPositionY)
return; return;
@ -255,6 +289,88 @@ namespace MWGui
mLastDirectionY = y; mLastDirectionY = y;
} }
void LocalMapBase::addDetectionMarkers(int type)
{
std::vector<MWWorld::Ptr> 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<MWWorld::Ptr>::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<MyGUI::ImageBox>("ImageBox",
widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast<std::string>(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<MyGUI::ImageBox>("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) MapWindow::MapWindow(const std::string& cacheDir)
@ -319,7 +435,7 @@ namespace MWGui
static int _counter=0; static int _counter=0;
MyGUI::Button* markerWidget = mGlobalMapImage->createWidget<MyGUI::Button>("ButtonImage", MyGUI::Button* markerWidget = mGlobalMapImage->createWidget<MyGUI::Button>("ButtonImage",
widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast<std::string>(_counter)); widgetCoord, MyGUI::Align::Default, "Door" + boost::lexical_cast<std::string>(_counter));
markerWidget->setImageResource("DoorMarker"); markerWidget->setImageResource("DoorMarker");
markerWidget->setUserString("ToolTipType", "Layout"); markerWidget->setUserString("ToolTipType", "Layout");
markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine");
@ -385,7 +501,7 @@ namespace MWGui
for (unsigned int i=0; i<mGlobalMapImage->getChildCount (); ++i) for (unsigned int i=0; i<mGlobalMapImage->getChildCount (); ++i)
{ {
if (mGlobalMapImage->getChildAt (i)->getName().substr(0,6) == "Marker") if (mGlobalMapImage->getChildAt (i)->getName().substr(0,4) == "Door")
mGlobalMapImage->getChildAt (i)->castType<MyGUI::Button>()->setImageResource("DoorMarker"); mGlobalMapImage->getChildAt (i)->castType<MyGUI::Button>()->setImageResource("DoorMarker");
} }
@ -396,20 +512,18 @@ namespace MWGui
void MapWindow::globalMapUpdatePlayer () void MapWindow::globalMapUpdatePlayer ()
{ {
Ogre::Vector3 pos = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedPosition (); // For interiors, position is set by WindowManager via setGlobalMapPlayerPosition
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?
if (MWBase::Environment::get().getWorld ()->isCellExterior ()) 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)); mPlayerArrowGlobal->setPosition(MyGUI::IntPoint(worldX - 16, worldY - 16));
MyGUI::ISubWidget* main = mPlayerArrowGlobal->getSubWidgetMain(); MyGUI::ISubWidget* main = mPlayerArrowGlobal->getSubWidgetMain();
@ -444,4 +558,19 @@ namespace MWGui
"#{sWorld}"); "#{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);
}
} }

View file

@ -55,9 +55,16 @@ namespace MWGui
void onMarkerFocused(MyGUI::Widget* w1, MyGUI::Widget* w2); void onMarkerFocused(MyGUI::Widget* w1, MyGUI::Widget* w2);
void onMarkerUnfocused(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 notifyPlayerUpdate() {}
virtual void notifyMapChanged() {} 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; OEngine::GUI::Layout* mLayout;
bool mMapDragAndDrop; 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 addVisitedLocation(const std::string& name, int x, int y); // adds the marker to the global map
void cellExplored(int x, int y); void cellExplored(int x, int y);
void setGlobalMapPlayerPosition (float worldX, float worldY);
virtual void open(); virtual void open();
private: private:

View file

@ -16,6 +16,15 @@ namespace MWGui
mLastButtonPressed = -1; mLastButtonPressed = -1;
} }
MessageBoxManager::~MessageBoxManager ()
{
std::vector<MessageBox*>::iterator it(mMessageBoxes.begin());
for (; it != mMessageBoxes.end(); ++it)
{
delete *it;
}
}
void MessageBoxManager::onFrame (float frameDuration) void MessageBoxManager::onFrame (float frameDuration)
{ {
std::vector<MessageBox*>::iterator it; std::vector<MessageBox*>::iterator it;

View file

@ -23,6 +23,7 @@ namespace MWGui
{ {
public: public:
MessageBoxManager (); MessageBoxManager ();
~MessageBoxManager ();
void onFrame (float frameDuration); void onFrame (float frameDuration);
void createMessageBox (const std::string& message, bool stat = false); void createMessageBox (const std::string& message, bool stat = false);
void removeStaticMessageBox (); void removeStaticMessageBox ();

View file

@ -40,6 +40,14 @@ namespace MWGui
for (size_t i = 0; i<mSourceModel->getItemCount(); ++i) for (size_t i = 0; i<mSourceModel->getItemCount(); ++i)
{ {
const ItemStack& item = mSourceModel->getItem(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() if (std::find(mHiddenItems.begin(), mHiddenItems.end(), item) == mHiddenItems.end()
&& item.mType != ItemStack::Type_Equipped) && item.mType != ItemStack::Type_Equipped)
mItems.push_back(item); mItems.push_back(item);

View file

@ -65,7 +65,7 @@ namespace MWGui
getWidget(attribute, std::string("Attribute") + boost::lexical_cast<std::string>(idx)); getWidget(attribute, std::string("Attribute") + boost::lexical_cast<std::string>(idx));
mAttributeWidgets.insert(std::make_pair(static_cast<int>(ESM::Attribute::sAttributeIds[idx]), attribute)); mAttributeWidgets.insert(std::make_pair(static_cast<int>(ESM::Attribute::sAttributeIds[idx]), attribute));
attribute->setAttributeId(ESM::Attribute::sAttributeIds[idx]); attribute->setAttributeId(ESM::Attribute::sAttributeIds[idx]);
attribute->setAttributeValue(Widgets::MWAttribute::AttributeValue(0, 0)); attribute->setAttributeValue(Widgets::MWAttribute::AttributeValue());
} }
// Setup skills // Setup skills
@ -74,7 +74,7 @@ namespace MWGui
for (int i = 0; i < ESM::Skill::Length; ++i) for (int i = 0; i < ESM::Skill::Length; ++i)
{ {
mSkillValues.insert(std::make_pair(i, MWMechanics::Stat<float>())); mSkillValues.insert(std::make_pair(i, MWMechanics::SkillValue()));
mSkillWidgetMap.insert(std::make_pair(i, static_cast<MyGUI::TextBox*> (0))); mSkillWidgetMap.insert(std::make_pair(i, static_cast<MyGUI::TextBox*> (0)));
} }
@ -152,7 +152,7 @@ namespace MWGui
mFatigue->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr); mFatigue->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr);
} }
void ReviewDialog::setAttribute(ESM::Attribute::AttributeID attributeId, const MWMechanics::Stat<int>& value) void ReviewDialog::setAttribute(ESM::Attribute::AttributeID attributeId, const MWMechanics::AttributeValue& value)
{ {
std::map<int, Widgets::MWAttributePtr>::iterator attr = mAttributeWidgets.find(static_cast<int>(attributeId)); std::map<int, Widgets::MWAttributePtr>::iterator attr = mAttributeWidgets.find(static_cast<int>(attributeId));
if (attr == mAttributeWidgets.end()) if (attr == mAttributeWidgets.end())
@ -161,7 +161,7 @@ namespace MWGui
attr->second->setAttributeValue(value); attr->second->setAttributeValue(value);
} }
void ReviewDialog::setSkillValue(ESM::Skill::SkillEnum skillId, const MWMechanics::Stat<float>& value) void ReviewDialog::setSkillValue(ESM::Skill::SkillEnum skillId, const MWMechanics::SkillValue& value)
{ {
mSkillValues[skillId] = value; mSkillValues[skillId] = value;
MyGUI::TextBox* widget = mSkillWidgetMap[skillId]; MyGUI::TextBox* widget = mSkillWidgetMap[skillId];
@ -279,9 +279,9 @@ namespace MWGui
continue; continue;
assert(skillId >= 0 && skillId < ESM::Skill::Length); assert(skillId >= 0 && skillId < ESM::Skill::Length);
const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId]; const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId];
const MWMechanics::Stat<float> &stat = mSkillValues.find(skillId)->second; const MWMechanics::SkillValue &stat = mSkillValues.find(skillId)->second;
float base = stat.getBase(); int base = stat.getBase();
float modified = stat.getModified(); int modified = stat.getModified();
std::string state = "normal"; std::string state = "normal";
if (modified > base) if (modified > base)

View file

@ -38,10 +38,10 @@ namespace MWGui
void setMagicka(const MWMechanics::DynamicStat<float>& value); void setMagicka(const MWMechanics::DynamicStat<float>& value);
void setFatigue(const MWMechanics::DynamicStat<float>& value); void setFatigue(const MWMechanics::DynamicStat<float>& value);
void setAttribute(ESM::Attribute::AttributeID attributeId, const MWMechanics::Stat<int>& value); void setAttribute(ESM::Attribute::AttributeID attributeId, const MWMechanics::AttributeValue& value);
void configureSkills(const SkillList& major, const SkillList& minor); void configureSkills(const SkillList& major, const SkillList& minor);
void setSkillValue(ESM::Skill::SkillEnum skillId, const MWMechanics::Stat<float>& value); void setSkillValue(ESM::Skill::SkillEnum skillId, const MWMechanics::SkillValue& value);
virtual void open(); virtual void open();
@ -85,7 +85,7 @@ namespace MWGui
std::map<int, Widgets::MWAttributePtr> mAttributeWidgets; std::map<int, Widgets::MWAttributePtr> mAttributeWidgets;
SkillList mMajorSkills, mMinorSkills, mMiscSkills; SkillList mMajorSkills, mMinorSkills, mMiscSkills;
std::map<int, MWMechanics::Stat<float> > mSkillValues; std::map<int, MWMechanics::SkillValue > mSkillValues;
std::map<int, MyGUI::TextBox*> mSkillWidgetMap; std::map<int, MyGUI::TextBox*> mSkillWidgetMap;
std::string mName, mRaceId, mBirthSignId; std::string mName, mRaceId, mBirthSignId;
ESM::Class mKlass; ESM::Class mKlass;

View file

@ -22,7 +22,8 @@ namespace MWGui
{ {
void EffectSourceVisitor::visit (MWMechanics::EffectKey key, 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; MagicEffectInfo newEffectSource;
newEffectSource.mKey = key; newEffectSource.mKey = key;

View file

@ -43,7 +43,8 @@ namespace MWGui
std::map <int, std::vector<MagicEffectInfo> > mEffectSources; std::map <int, std::vector<MagicEffectInfo> > mEffectSources;
virtual void visit (MWMechanics::EffectKey key, 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 class SpellIcons

View file

@ -61,7 +61,7 @@ namespace MWGui
for (int i = 0; i < ESM::Skill::Length; ++i) for (int i = 0; i < ESM::Skill::Length; ++i)
{ {
mSkillValues.insert(std::pair<int, MWMechanics::Stat<float> >(i, MWMechanics::Stat<float>())); mSkillValues.insert(std::pair<int, MWMechanics::SkillValue >(i, MWMechanics::SkillValue()));
mSkillWidgetMap.insert(std::pair<int, MyGUI::TextBox*>(i, (MyGUI::TextBox*)NULL)); mSkillWidgetMap.insert(std::pair<int, MyGUI::TextBox*>(i, (MyGUI::TextBox*)NULL));
} }
@ -102,7 +102,7 @@ namespace MWGui
adjustWindowCaption(); adjustWindowCaption();
} }
void StatsWindow::setValue (const std::string& id, const MWMechanics::Stat<int>& value) void StatsWindow::setValue (const std::string& id, const MWMechanics::AttributeValue& value)
{ {
static const char *ids[] = static const char *ids[] =
{ {
@ -179,7 +179,7 @@ namespace MWGui
} }
} }
void StatsWindow::setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat<float>& value) void StatsWindow::setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value)
{ {
mSkillValues[parSkill] = value; mSkillValues[parSkill] = value;
MyGUI::TextBox* widget = mSkillWidgetMap[(int)parSkill]; MyGUI::TextBox* widget = mSkillWidgetMap[(int)parSkill];
@ -358,22 +358,20 @@ namespace MWGui
continue; continue;
assert(skillId >= 0 && skillId < ESM::Skill::Length); assert(skillId >= 0 && skillId < ESM::Skill::Length);
const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId]; const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId];
const MWMechanics::Stat<float> &stat = mSkillValues.find(skillId)->second; const MWMechanics::SkillValue &stat = mSkillValues.find(skillId)->second;
float base = stat.getBase(); int base = stat.getBase();
float modified = stat.getModified(); int modified = stat.getModified();
int progressPercent = (modified - float(static_cast<int>(modified))) * 100; int progressPercent = stat.getProgress() * 100;
const MWWorld::ESMStore &esmStore = const MWWorld::ESMStore &esmStore =
MWBase::Environment::get().getWorld()->getStore(); MWBase::Environment::get().getWorld()->getStore();
const ESM::Skill* skill = esmStore.get<ESM::Skill>().find(skillId); const ESM::Skill* skill = esmStore.get<ESM::Skill>().find(skillId);
assert(skill);
std::string icon = "icons\\k\\" + ESM::Skill::sIconNames[skillId]; std::string icon = "icons\\k\\" + ESM::Skill::sIconNames[skillId];
const ESM::Attribute* attr = const ESM::Attribute* attr =
esmStore.get<ESM::Attribute>().find(skill->mData.mAttribute); esmStore.get<ESM::Attribute>().find(skill->mData.mAttribute);
assert(attr);
std::string state = "normal"; std::string state = "normal";
if (modified > base) if (modified > base)
@ -484,7 +482,6 @@ namespace MWGui
ESM::RankData rankData = faction->mData.mRankData[it->second+1]; ESM::RankData rankData = faction->mData.mRankData[it->second+1];
const ESM::Attribute* attr1 = store.get<ESM::Attribute>().find(faction->mData.mAttribute[0]); const ESM::Attribute* attr1 = store.get<ESM::Attribute>().find(faction->mData.mAttribute[0]);
const ESM::Attribute* attr2 = store.get<ESM::Attribute>().find(faction->mData.mAttribute[1]); const ESM::Attribute* attr2 = store.get<ESM::Attribute>().find(faction->mData.mAttribute[1]);
assert(attr1 && attr2);
text += "\n#BF9959#{" + attr1->mName + "}: " + boost::lexical_cast<std::string>(rankData.mAttribute1) text += "\n#BF9959#{" + attr1->mName + "}: " + boost::lexical_cast<std::string>(rankData.mAttribute1)
+ ", #{" + attr2->mName + "}: " + boost::lexical_cast<std::string>(rankData.mAttribute2); + ", #{" + attr2->mName + "}: " + boost::lexical_cast<std::string>(rankData.mAttribute2);

View file

@ -26,11 +26,11 @@ namespace MWGui
void setPlayerName(const std::string& playerName); void setPlayerName(const std::string& playerName);
/// Set value for the given ID. /// Set value for the given ID.
void setValue (const std::string& id, const MWMechanics::Stat<int>& value); void setValue (const std::string& id, const MWMechanics::AttributeValue& value);
void setValue (const std::string& id, const MWMechanics::DynamicStat<float>& value); void setValue (const std::string& id, const MWMechanics::DynamicStat<float>& value);
void setValue (const std::string& id, const std::string& value); void setValue (const std::string& id, const std::string& value);
void setValue (const std::string& id, int value); void setValue (const std::string& id, int value);
void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat<float>& value); void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value);
void configureSkills (const SkillList& major, const SkillList& minor); void configureSkills (const SkillList& major, const SkillList& minor);
void setReputation (int reputation) { if (reputation != mReputation) mChanged = true; this->mReputation = reputation; } void setReputation (int reputation) { if (reputation != mReputation) mChanged = true; this->mReputation = reputation; }
@ -61,7 +61,7 @@ namespace MWGui
MyGUI::ScrollView* mSkillView; MyGUI::ScrollView* mSkillView;
SkillList mMajorSkills, mMinorSkills, mMiscSkills; SkillList mMajorSkills, mMinorSkills, mMiscSkills;
std::map<int, MWMechanics::Stat<float> > mSkillValues; std::map<int, MWMechanics::SkillValue > mSkillValues;
std::map<int, MyGUI::TextBox*> mSkillWidgetMap; std::map<int, MyGUI::TextBox*> mSkillWidgetMap;
std::map<std::string, MyGUI::Widget*> mFactionWidgetMap; std::map<std::string, MyGUI::Widget*> mFactionWidgetMap;
FactionList mFactions; ///< Stores a list of factions and the current rank FactionList mFactions; ///< Stores a list of factions and the current rank

View file

@ -154,6 +154,13 @@ namespace MWGui
if(!MWWorld::Class::get(base).canSell(base, services)) if(!MWWorld::Class::get(base).canSell(base, services))
continue; 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 // don't show equipped items
if(mMerchant.getTypeName() == typeid(ESM::NPC).name()) if(mMerchant.getTypeName() == typeid(ESM::NPC).name())
{ {

View file

@ -24,6 +24,7 @@
#include "containeritemmodel.hpp" #include "containeritemmodel.hpp"
#include "tradeitemmodel.hpp" #include "tradeitemmodel.hpp"
#include "countdialog.hpp" #include "countdialog.hpp"
#include "dialogue.hpp"
namespace MWGui namespace MWGui
{ {
@ -296,10 +297,10 @@ namespace MWGui
const MWMechanics::NpcStats &sellerStats = MWWorld::Class::get(mPtr).getNpcStats(mPtr); const MWMechanics::NpcStats &sellerStats = MWWorld::Class::get(mPtr).getNpcStats(mPtr);
const MWMechanics::NpcStats &playerStats = MWWorld::Class::get(playerPtr).getNpcStats(playerPtr); 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 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 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 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); float f1 = std::min(0.2f * sellerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f);
@ -340,6 +341,9 @@ namespace MWGui
addOrRemoveGold(-mCurrentBalance, mPtr); addOrRemoveGold(-mCurrentBalance, mPtr);
} }
MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addResponse(
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("sBarterDialog5")->getString());
std::string sound = "Item Gold Up"; std::string sound = "Item Gold Up";
MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0);

View file

@ -154,7 +154,7 @@ namespace MWGui
float hourlyHealthDelta = stats.getAttribute(ESM::Attribute::Endurance).getModified() * 0.1; 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<ESM::GameSetting>().find("fRestMagicMult")->getFloat(); float fRestMagicMult = store.get<ESM::GameSetting>().find("fRestMagicMult")->getFloat();
float hourlyMagickaDelta = fRestMagicMult * stats.getAttribute(ESM::Attribute::Intelligence).getModified(); float hourlyMagickaDelta = fRestMagicMult * stats.getAttribute(ESM::Attribute::Intelligence).getModified();

View file

@ -178,7 +178,7 @@ namespace MWGui
} }
if (mAttributeValueWidget) if (mAttributeValueWidget)
{ {
AttributeValue::Type modified = mValue.getModified(), base = mValue.getBase(); int modified = mValue.getModified(), base = mValue.getBase();
static_cast<MyGUI::TextBox*>(mAttributeValueWidget)->setCaption(boost::lexical_cast<std::string>(modified)); static_cast<MyGUI::TextBox*>(mAttributeValueWidget)->setCaption(boost::lexical_cast<std::string>(modified));
if (modified > base) if (modified > base)
mAttributeValueWidget->_setWidgetState("increased"); mAttributeValueWidget->_setWidgetState("increased");
@ -528,14 +528,9 @@ namespace MWGui
if (mBarTextWidget) if (mBarTextWidget)
{ {
if (mValue >= 0 && mMax > 0) std::stringstream out;
{ out << mValue << "/" << mMax;
std::stringstream out; static_cast<MyGUI::TextBox*>(mBarTextWidget)->setCaption(out.str().c_str());
out << mValue << "/" << mMax;
static_cast<MyGUI::TextBox*>(mBarTextWidget)->setCaption(out.str().c_str());
}
else
static_cast<MyGUI::TextBox*>(mBarTextWidget)->setCaption("");
} }
} }
void MWDynamicStat::setTitle(const std::string& text) void MWDynamicStat::setTitle(const std::string& text)

View file

@ -133,7 +133,7 @@ namespace MWGui
public: public:
MWAttribute(); MWAttribute();
typedef MWMechanics::Stat<int> AttributeValue; typedef MWMechanics::AttributeValue AttributeValue;
void setAttributeId(int attributeId); void setAttributeId(int attributeId);
void setAttributeValue(const AttributeValue& value); void setAttributeValue(const AttributeValue& value);

View file

@ -16,6 +16,7 @@
#include "../mwbase/inputmanager.hpp" #include "../mwbase/inputmanager.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/player.hpp"
#include "console.hpp" #include "console.hpp"
#include "journalwindow.hpp" #include "journalwindow.hpp"
@ -174,11 +175,11 @@ namespace MWGui
MyGUI::InputManager::getInstance().eventChangeKeyFocus += MyGUI::newDelegate(this, &WindowManager::onKeyFocusChanged); MyGUI::InputManager::getInstance().eventChangeKeyFocus += MyGUI::newDelegate(this, &WindowManager::onKeyFocusChanged);
mCursorManager->setEnabled(true);
onCursorChange(MyGUI::PointerManager::getInstance().getDefaultPointer()); onCursorChange(MyGUI::PointerManager::getInstance().getDefaultPointer());
SDL_ShowCursor(false); SDL_ShowCursor(false);
mCursorManager->setEnabled(true);
// hide mygui's pointer // hide mygui's pointer
MyGUI::PointerManager::getInstance().setVisible(false); MyGUI::PointerManager::getInstance().setVisible(false);
} }
@ -248,12 +249,12 @@ namespace MWGui
// Setup player stats // Setup player stats
for (int i = 0; i < ESM::Attribute::Length; ++i) for (int i = 0; i < ESM::Attribute::Length; ++i)
{ {
mPlayerAttributes.insert(std::make_pair(ESM::Attribute::sAttributeIds[i], MWMechanics::Stat<int>())); mPlayerAttributes.insert(std::make_pair(ESM::Attribute::sAttributeIds[i], MWMechanics::AttributeValue()));
} }
for (int i = 0; i < ESM::Skill::Length; ++i) for (int i = 0; i < ESM::Skill::Length; ++i)
{ {
mPlayerSkillValues.insert(std::make_pair(ESM::Skill::sSkillIds[i], MWMechanics::Stat<float>())); mPlayerSkillValues.insert(std::make_pair(ESM::Skill::sSkillIds[i], MWMechanics::SkillValue()));
} }
// Set up visibility // Set up visibility
@ -322,6 +323,7 @@ namespace MWGui
delete mSoulgemDialog; delete mSoulgemDialog;
delete mCursorManager; delete mCursorManager;
delete mRecharge; delete mRecharge;
delete mCompanionWindow;
cleanupGarbage(); cleanupGarbage();
@ -542,7 +544,7 @@ namespace MWGui
} }
} }
void WindowManager::setValue (const std::string& id, const MWMechanics::Stat<int>& value) void WindowManager::setValue (const std::string& id, const MWMechanics::AttributeValue& value)
{ {
mStatsWindow->setValue (id, value); mStatsWindow->setValue (id, value);
mCharGen->setValue(id, value); mCharGen->setValue(id, value);
@ -573,7 +575,7 @@ namespace MWGui
} }
void WindowManager::setValue (int parSkill, const MWMechanics::Stat<float>& 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 /// \todo Don't use the skill enum as a parameter type (we will have to drop it anyway, once we
/// allow custom skills. /// allow custom skills.
@ -774,6 +776,13 @@ namespace MWGui
mHud->setCellName( cell->mCell->mName ); mHud->setCellName( cell->mCell->mName );
mMap->setCellPrefix( cell->mCell->mName ); mMap->setCellPrefix( cell->mCell->mName );
mHud->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(); return mGuiModes.back();
} }
std::map<int, MWMechanics::Stat<float> > WindowManager::getPlayerSkillValues() std::map<int, MWMechanics::SkillValue > WindowManager::getPlayerSkillValues()
{ {
return mPlayerSkillValues; return mPlayerSkillValues;
} }
std::map<int, MWMechanics::Stat<int> > WindowManager::getPlayerAttributeValues() std::map<int, MWMechanics::AttributeValue > WindowManager::getPlayerAttributeValues()
{ {
return mPlayerAttributes; return mPlayerAttributes;
} }

View file

@ -152,8 +152,8 @@ namespace MWGui
virtual void wmUpdateFps(float fps, unsigned int triangleCount, unsigned int batchCount); virtual void wmUpdateFps(float fps, unsigned int triangleCount, unsigned int batchCount);
///< Set value for the given ID. ///< Set value for the given ID.
virtual void setValue (const std::string& id, const MWMechanics::Stat<int>& value); virtual void setValue (const std::string& id, const MWMechanics::AttributeValue& value);
virtual void setValue (int parSkill, const MWMechanics::Stat<float>& value); virtual void setValue (int parSkill, const MWMechanics::SkillValue& value);
virtual void setValue (const std::string& id, const MWMechanics::DynamicStat<float>& value); virtual void setValue (const std::string& id, const MWMechanics::DynamicStat<float>& value);
virtual void setValue (const std::string& id, const std::string& value); virtual void setValue (const std::string& id, const std::string& value);
virtual void setValue (const std::string& id, int value); virtual void setValue (const std::string& id, int value);
@ -229,8 +229,8 @@ namespace MWGui
virtual void onFrame (float frameDuration); virtual void onFrame (float frameDuration);
/// \todo get rid of this stuff. Move it to the respective UI element classes, if needed. /// \todo get rid of this stuff. Move it to the respective UI element classes, if needed.
virtual std::map<int, MWMechanics::Stat<float> > getPlayerSkillValues(); virtual std::map<int, MWMechanics::SkillValue > getPlayerSkillValues();
virtual std::map<int, MWMechanics::Stat<int> > getPlayerAttributeValues(); virtual std::map<int, MWMechanics::AttributeValue > getPlayerAttributeValues();
virtual SkillList getPlayerMinorSkills(); virtual SkillList getPlayerMinorSkills();
virtual SkillList getPlayerMajorSkills(); virtual SkillList getPlayerMajorSkills();
@ -346,9 +346,9 @@ namespace MWGui
// Various stats about player as needed by window manager // Various stats about player as needed by window manager
std::string mPlayerName; std::string mPlayerName;
std::string mPlayerRaceId; std::string mPlayerRaceId;
std::map<int, MWMechanics::Stat<int> > mPlayerAttributes; std::map<int, MWMechanics::AttributeValue > mPlayerAttributes;
SkillList mPlayerMajorSkills, mPlayerMinorSkills; SkillList mPlayerMajorSkills, mPlayerMinorSkills;
std::map<int, MWMechanics::Stat<float> > mPlayerSkillValues; std::map<int, MWMechanics::SkillValue > mPlayerSkillValues;
MyGUI::Gui *mGui; // Gui MyGUI::Gui *mGui; // Gui
std::vector<GuiMode> mGuiModes; std::vector<GuiMode> mGuiModes;

View file

@ -9,6 +9,7 @@
#include <MyGUI_RenderManager.h> #include <MyGUI_RenderManager.h>
#include <MyGUI_Widget.h> #include <MyGUI_Widget.h>
#include <MyGUI_Button.h> #include <MyGUI_Button.h>
#include <MyGUI_EditBox.h>
#include <openengine/ogre/renderer.hpp> #include <openengine/ogre/renderer.hpp>
@ -19,7 +20,6 @@
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwbase/soundmanager.hpp" #include "../mwbase/soundmanager.hpp"
#include "../mwgui/bookwindow.hpp"
#include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/creaturestats.hpp"
using namespace ICS; using namespace ICS;
@ -497,6 +497,9 @@ namespace MWInput
edit->deleteTextSelection(); edit->deleteTextSelection();
} }
} }
}
if (edit && !edit->getEditStatic())
{
if (arg.keysym.sym == SDLK_c && (arg.keysym.mod & SDL_Keymod(KMOD_CTRL))) if (arg.keysym.sym == SDLK_c && (arg.keysym.mod & SDL_Keymod(KMOD_CTRL)))
{ {
std::string text = edit->getTextSelection(); std::string text = edit->getTextSelection();
@ -591,15 +594,6 @@ namespace MWInput
mMouseWheel = int(arg.z); mMouseWheel = int(arg.z);
MyGUI::InputManager::getInstance().injectMouseMove( int(mMouseX), int(mMouseY), mMouseWheel); 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) if (mMouseLookEnabled)
@ -676,7 +670,7 @@ namespace MWInput
if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return; if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return;
// Not allowed before the magic window is accessible // Not allowed before the magic window is accessible
if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Magic)) if (!mControlSwitch["playermagic"])
return; return;
MWMechanics::DrawState_ state = mPlayer->getDrawState(); MWMechanics::DrawState_ state = mPlayer->getDrawState();
@ -691,7 +685,7 @@ namespace MWInput
if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return; if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return;
// Not allowed before the inventory window is accessible // Not allowed before the inventory window is accessible
if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) if (!mControlSwitch["playerfighting"])
return; return;
MWMechanics::DrawState_ state = mPlayer->getDrawState(); MWMechanics::DrawState_ state = mPlayer->getDrawState();
@ -831,9 +825,11 @@ namespace MWInput
void InputManager::updateIdleTime(float dt) void InputManager::updateIdleTime(float dt)
{ {
static const float vanityDelay = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
.find("fVanityDelay")->getFloat();
if (mTimeIdle >= 0.f) if (mTimeIdle >= 0.f)
mTimeIdle += dt; mTimeIdle += dt;
if (mTimeIdle > 30.f) { if (mTimeIdle > vanityDelay) {
MWBase::Environment::get().getWorld()->toggleVanityMode(true); MWBase::Environment::get().getWorld()->toggleVanityMode(true);
mTimeIdle = -1.f; mTimeIdle = -1.f;
} }

View file

@ -126,7 +126,8 @@ namespace MWMechanics
return mSpells; return mSpells;
} }
void ActiveSpells::addSpell(const std::string &id, bool stack, std::vector<Effect> effects, const std::string &displayName) void ActiveSpells::addSpell(const std::string &id, bool stack, std::vector<Effect> effects,
const std::string &displayName, const std::string& casterHandle)
{ {
bool exists = false; bool exists = false;
for (TContainer::const_iterator it = begin(); it != end(); ++it) for (TContainer::const_iterator it = begin(); it != end(); ++it)
@ -139,6 +140,7 @@ namespace MWMechanics
params.mTimeStamp = MWBase::Environment::get().getWorld()->getTimeStamp(); params.mTimeStamp = MWBase::Environment::get().getWorld()->getTimeStamp();
params.mEffects = effects; params.mEffects = effects;
params.mDisplayName = displayName; params.mDisplayName = displayName;
params.mCasterHandle = casterHandle;
if (!exists || stack) if (!exists || stack)
mSpells.insert (std::make_pair(id, params)); mSpells.insert (std::make_pair(id, params));
@ -148,6 +150,12 @@ namespace MWMechanics
mSpellsChanged = true; mSpellsChanged = true;
} }
void ActiveSpells::removeEffects(const std::string &id)
{
mSpells.erase(Misc::StringUtils::lowerCase(id));
mSpellsChanged = true;
}
void ActiveSpells::visitEffectSources(EffectSourceVisitor &visitor) const void ActiveSpells::visitEffectSources(EffectSourceVisitor &visitor) const
{ {
for (TContainer::const_iterator it = begin(); it != end(); ++it) for (TContainer::const_iterator it = begin(); it != end(); ++it)
@ -164,14 +172,22 @@ namespace MWMechanics
float magnitude = effectIt->mMagnitude; float magnitude = effectIt->mMagnitude;
if (magnitude) 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<double> (RAND_MAX) + 1) * 100; // [0, 99]
if (roll < chance)
mSpells.erase(it++);
else
++it;
}
mSpellsChanged = true;
} }
void ActiveSpells::purgeEffect(short effectId) void ActiveSpells::purgeEffect(short effectId)
@ -187,6 +203,6 @@ namespace MWMechanics
effectIt++; effectIt++;
} }
} }
mSpellsChanged = true;
} }
} }

View file

@ -37,8 +37,8 @@ namespace MWMechanics
MWWorld::TimeStamp mTimeStamp; MWWorld::TimeStamp mTimeStamp;
std::string mDisplayName; std::string mDisplayName;
// TODO: To handle CASTER_LINKED flag (spell is purged when caster dies), // Handle to the caster that that inflicted this spell on us
// we should probably store a handle to the caster here. std::string mCasterHandle;
}; };
typedef std::multimap<std::string, ActiveSpellParams > TContainer; typedef std::multimap<std::string, ActiveSpellParams > 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 stack If false, the spell is not added if one with the same ID exists already.
/// \param effects /// \param effects
/// \param displayName Name for display in magic menu. /// \param displayName Name for display in magic menu.
/// \param casterHandle
/// ///
void addSpell (const std::string& id, bool stack, std::vector<Effect> effects, const std::string& displayName); void addSpell (const std::string& id, bool stack, std::vector<Effect> 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); void purgeEffect (short effectId);
/// Remove all active effects /// Remove all active effects, if roll succeeds (for each effect)
void purgeAll (); void purgeAll (float chance);
bool isSpellActive (std::string id) const; bool isSpellActive (std::string id) const;
///< case insensitive ///< case insensitive

View file

@ -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<float>(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 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<ESM::GameSetting>().find("fSoulgemMult")->getFloat();
float creatureSoulValue = mCreature.get<ESM::Creature>()->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<float>().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<ESM::Miscellaneous>()->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) void Actors::updateActor (const MWWorld::Ptr& ptr, float duration)
{ {
// magic effects // magic effects
@ -178,7 +278,7 @@ namespace MWMechanics
{ {
// the actor is sleeping, restore health and magicka // 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<float> health = stats.getHealth(); DynamicStat<float> health = stats.getHealth();
health.setCurrent (health.getCurrent() + 0.1 * endurance); health.setCurrent (health.getCurrent() + 0.1 * endurance);
@ -217,7 +317,7 @@ namespace MWMechanics
// attributes // attributes
for(int i = 0;i < ESM::Attribute::Length;++i) for(int i = 0;i < ESM::Attribute::Length;++i)
{ {
Stat<int> stat = creatureStats.getAttribute(i); AttributeValue stat = creatureStats.getAttribute(i);
stat.setModifier(effects.get(EffectKey(ESM::MagicEffect::FortifyAttribute, i)).mMagnitude - stat.setModifier(effects.get(EffectKey(ESM::MagicEffect::FortifyAttribute, i)).mMagnitude -
effects.get(EffectKey(ESM::MagicEffect::DrainAttribute, i)).mMagnitude - effects.get(EffectKey(ESM::MagicEffect::DrainAttribute, i)).mMagnitude -
effects.get(EffectKey(ESM::MagicEffect::AbsorbAttribute, i)).mMagnitude); effects.get(EffectKey(ESM::MagicEffect::AbsorbAttribute, i)).mMagnitude);
@ -229,18 +329,45 @@ namespace MWMechanics
for(int i = 0;i < 3;++i) for(int i = 0;i < 3;++i)
{ {
DynamicStat<float> stat = creatureStats.getDynamic(i); DynamicStat<float> stat = creatureStats.getDynamic(i);
stat.setModifier(effects.get(EffectKey(ESM::MagicEffect::FortifyHealth+i)).mMagnitude - stat.setModifier(effects.get(ESM::MagicEffect::FortifyHealth+i).mMagnitude -
effects.get(EffectKey(ESM::MagicEffect::DrainHealth+i)).mMagnitude); effects.get(ESM::MagicEffect::DrainHealth+i).mMagnitude);
float currentDiff = creatureStats.getMagicEffects().get(EffectKey(ESM::MagicEffect::RestoreHealth+i)).mMagnitude float currentDiff = creatureStats.getMagicEffects().get(ESM::MagicEffect::RestoreHealth+i).mMagnitude
- creatureStats.getMagicEffects().get(EffectKey(ESM::MagicEffect::DamageHealth+i)).mMagnitude - creatureStats.getMagicEffects().get(ESM::MagicEffect::DamageHealth+i).mMagnitude
- creatureStats.getMagicEffects().get(EffectKey(ESM::MagicEffect::AbsorbHealth+i)).mMagnitude; - creatureStats.getMagicEffects().get(ESM::MagicEffect::AbsorbHealth+i).mMagnitude;
stat.setCurrent(stat.getCurrent() + currentDiff * duration); stat.setCurrent(stat.getCurrent() + currentDiff * duration);
creatureStats.setDynamic(i, stat); 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<sizeof(priorities)/sizeof(int); ++i)
{
if (disintegrateSlot(ptr, priorities[i], disintegrateArmor*duration))
break;
}
}
// Apply damage ticks // Apply damage ticks
int damageEffects[] = { int damageEffects[] = {
ESM::MagicEffect::FireDamage, ESM::MagicEffect::ShockDamage, ESM::MagicEffect::FrostDamage, ESM::MagicEffect::Poison, ESM::MagicEffect::FireDamage, ESM::MagicEffect::ShockDamage, ESM::MagicEffect::FrostDamage, ESM::MagicEffect::Poison,
@ -250,7 +377,7 @@ namespace MWMechanics
DynamicStat<float> health = creatureStats.getHealth(); DynamicStat<float> health = creatureStats.getHealth();
for (unsigned int i=0; i<sizeof(damageEffects)/sizeof(int); ++i) for (unsigned int i=0; i<sizeof(damageEffects)/sizeof(int); ++i)
{ {
float magnitude = creatureStats.getMagicEffects().get(EffectKey(damageEffects[i])).mMagnitude; float magnitude = creatureStats.getMagicEffects().get(damageEffects[i]).mMagnitude;
if (damageEffects[i] == ESM::MagicEffect::SunDamage) if (damageEffects[i] == ESM::MagicEffect::SunDamage)
{ {
@ -281,30 +408,32 @@ namespace MWMechanics
static std::map<int, std::string> boundItemsMap; static std::map<int, std::string> boundItemsMap;
if (boundItemsMap.empty()) if (boundItemsMap.empty())
{ {
boundItemsMap[ESM::MagicEffect::BoundBattleAxe] = "battle_axe"; boundItemsMap[ESM::MagicEffect::BoundBattleAxe] = "sMagicBoundBattleAxeID";
boundItemsMap[ESM::MagicEffect::BoundBoots] = "boots"; boundItemsMap[ESM::MagicEffect::BoundBoots] = "sMagicBoundBootsID";
boundItemsMap[ESM::MagicEffect::BoundCuirass] = "cuirass"; boundItemsMap[ESM::MagicEffect::BoundCuirass] = "sMagicBoundCuirassID";
boundItemsMap[ESM::MagicEffect::BoundDagger] = "dagger"; boundItemsMap[ESM::MagicEffect::BoundDagger] = "sMagicBoundDaggerID";
boundItemsMap[ESM::MagicEffect::BoundGloves] = "gauntlet"; // Note: needs both _left and _right variants, see below boundItemsMap[ESM::MagicEffect::BoundGloves] = "sMagicBoundLeftGauntletID"; // Note: needs RightGauntlet variant too (see below)
boundItemsMap[ESM::MagicEffect::BoundHelm] = "helm"; boundItemsMap[ESM::MagicEffect::BoundHelm] = "sMagicBoundHelmID";
boundItemsMap[ESM::MagicEffect::BoundLongbow] = "longbow"; boundItemsMap[ESM::MagicEffect::BoundLongbow] = "sMagicBoundLongbowID";
boundItemsMap[ESM::MagicEffect::BoundLongsword] = "longsword"; boundItemsMap[ESM::MagicEffect::BoundLongsword] = "sMagicBoundLongswordID";
boundItemsMap[ESM::MagicEffect::BoundMace] = "mace"; boundItemsMap[ESM::MagicEffect::BoundMace] = "sMagicBoundMaceID";
boundItemsMap[ESM::MagicEffect::BoundShield] = "shield"; boundItemsMap[ESM::MagicEffect::BoundShield] = "sMagicBoundShieldID";
boundItemsMap[ESM::MagicEffect::BoundSpear] = "spear"; boundItemsMap[ESM::MagicEffect::BoundSpear] = "sMagicBoundSpearID";
} }
for (std::map<int, std::string>::iterator it = boundItemsMap.begin(); it != boundItemsMap.end(); ++it) for (std::map<int, std::string>::iterator it = boundItemsMap.begin(); it != boundItemsMap.end(); ++it)
{ {
bool found = creatureStats.mBoundItems.find(it->first) != creatureStats.mBoundItems.end(); 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)) if (found != (magnitude > 0))
{ {
std::string item = "bound_" + it->second; std::string itemGmst = it->second;
std::string item = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
itemGmst)->getString();
if (it->first == ESM::MagicEffect::BoundGloves) if (it->first == ESM::MagicEffect::BoundGloves)
{ {
adjustBoundItem(item + "_left", magnitude > 0, ptr); adjustBoundItem("sMagicBoundLeftGauntletID", magnitude > 0, ptr);
adjustBoundItem(item + "_right", magnitude > 0, ptr); adjustBoundItem("sMagicBoundRightGauntletID", magnitude > 0, ptr);
} }
else else
adjustBoundItem(item, magnitude > 0, ptr); adjustBoundItem(item, magnitude > 0, ptr);
@ -320,32 +449,34 @@ namespace MWMechanics
static std::map<int, std::string> summonMap; static std::map<int, std::string> summonMap;
if (summonMap.empty()) if (summonMap.empty())
{ {
summonMap[ESM::MagicEffect::SummonAncestralGhost] = "ancestor_ghost_summon"; summonMap[ESM::MagicEffect::SummonAncestralGhost] = "sMagicAncestralGhostID";
summonMap[ESM::MagicEffect::SummonBear] = "BM_bear_black_summon"; summonMap[ESM::MagicEffect::SummonBonelord] = "sMagicBonelordID";
summonMap[ESM::MagicEffect::SummonBonelord] = "bonelord_summon"; summonMap[ESM::MagicEffect::SummonBonewalker] = "sMagicLeastBonewalkerID";
summonMap[ESM::MagicEffect::SummonBonewalker] = "bonewalker_summon"; summonMap[ESM::MagicEffect::SummonCenturionSphere] = "sMagicCenturionSphereID";
summonMap[ESM::MagicEffect::SummonBonewolf] = "BM_wolf_bone_summon"; summonMap[ESM::MagicEffect::SummonClannfear] = "sMagicClannfearID";
summonMap[ESM::MagicEffect::SummonCenturionSphere] = "centurion_sphere_summon"; summonMap[ESM::MagicEffect::SummonDaedroth] = "sMagicDaedrothID";
summonMap[ESM::MagicEffect::SummonClannfear] = "clannfear_summon"; summonMap[ESM::MagicEffect::SummonDremora] = "sMagicDremoraID";
summonMap[ESM::MagicEffect::SummonDaedroth] = "daedroth_summon"; summonMap[ESM::MagicEffect::SummonFabricant] = "sMagicFabricantID";
summonMap[ESM::MagicEffect::SummonDremora] = "dremora_summon"; summonMap[ESM::MagicEffect::SummonFlameAtronach] = "sMagicFlameAtronachID";
summonMap[ESM::MagicEffect::SummonFabricant] = "fabricant_summon"; summonMap[ESM::MagicEffect::SummonFrostAtronach] = "sMagicFrostAtronachID";
summonMap[ESM::MagicEffect::SummonFlameAtronach] = "atronach_flame_summon"; summonMap[ESM::MagicEffect::SummonGoldenSaint] = "sMagicGoldenSaintID";
summonMap[ESM::MagicEffect::SummonFrostAtronach] = "atronach_frost_summon"; summonMap[ESM::MagicEffect::SummonGreaterBonewalker] = "sMagicGreaterBonewalkerID";
summonMap[ESM::MagicEffect::SummonGoldenSaint] = "golden saint_summon"; summonMap[ESM::MagicEffect::SummonHunger] = "sMagicHungerID";
summonMap[ESM::MagicEffect::SummonGreaterBonewalker] = "bonewalker_greater_summ"; summonMap[ESM::MagicEffect::SummonScamp] = "sMagicScampID";
summonMap[ESM::MagicEffect::SummonHunger] = "hunger_summon"; summonMap[ESM::MagicEffect::SummonSkeletalMinion] = "sMagicSkeletalMinionID";
summonMap[ESM::MagicEffect::SummonScamp] = "scamp_summon"; summonMap[ESM::MagicEffect::SummonStormAtronach] = "sMagicStormAtronachID";
summonMap[ESM::MagicEffect::SummonSkeletalMinion] = "skeleton_summon"; summonMap[ESM::MagicEffect::SummonWingedTwilight] = "sMagicWingedTwilightID";
summonMap[ESM::MagicEffect::SummonStormAtronach] = "atronach_storm_summon"; summonMap[ESM::MagicEffect::SummonWolf] = "sMagicCreature01ID";
summonMap[ESM::MagicEffect::SummonWingedTwilight] = "winged twilight_summon"; summonMap[ESM::MagicEffect::SummonBear] = "sMagicCreature02ID";
summonMap[ESM::MagicEffect::SummonWolf] = "BM_wolf_grey_summon"; summonMap[ESM::MagicEffect::SummonBonewolf] = "sMagicCreature03ID";
summonMap[ESM::MagicEffect::SummonCreature04] = "sMagicCreature04ID";
summonMap[ESM::MagicEffect::SummonCreature05] = "sMagicCreature05ID";
} }
for (std::map<int, std::string>::iterator it = summonMap.begin(); it != summonMap.end(); ++it) for (std::map<int, std::string>::iterator it = summonMap.begin(); it != summonMap.end(); ++it)
{ {
bool found = creatureStats.mSummonedCreatures.find(it->first) != creatureStats.mSummonedCreatures.end(); 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 (found != (magnitude > 0))
{ {
if (magnitude > 0) if (magnitude > 0)
@ -362,15 +493,20 @@ namespace MWMechanics
ipos.rot[1] = 0; ipos.rot[1] = 0;
ipos.rot[2] = 0; ipos.rot[2] = 0;
MWWorld::CellStore* store = ptr.getCell(); std::string creatureID =
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), it->second, 1); MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(it->second)->getString();
ref.getPtr().getCellRef().mPos = ipos;
// 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, // TODO: Add AI to follow player and fight for him
MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),*store,ipos).getRefData().getHandle()));
creatureStats.mSummonedCreatures.insert(std::make_pair(it->first,
MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),*store,ipos).getRefData().getHandle()));
}
} }
else else
{ {
@ -396,7 +532,7 @@ namespace MWMechanics
// skills // skills
for(int i = 0;i < ESM::Skill::Length;++i) for(int i = 0;i < ESM::Skill::Length;++i)
{ {
Stat<float>& skill = npcStats.getSkill(i); SkillValue& skill = npcStats.getSkill(i);
skill.setModifier(effects.get(EffectKey(ESM::MagicEffect::FortifySkill, i)).mMagnitude - skill.setModifier(effects.get(EffectKey(ESM::MagicEffect::FortifySkill, i)).mMagnitude -
effects.get(EffectKey(ESM::MagicEffect::DrainSkill, i)).mMagnitude - effects.get(EffectKey(ESM::MagicEffect::DrainSkill, i)).mMagnitude -
effects.get(EffectKey(ESM::MagicEffect::AbsorbSkill, 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 * 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()) MWWorld::ContainerStoreIterator torch = inventoryStore.end();
{ for (MWWorld::ContainerStoreIterator it = inventoryStore.begin(); it != inventoryStore.end(); ++it)
mTorchPtr = inventoryStore.search("torch_infinite_time"); {
} if (it->getTypeName() == typeid(ESM::Light).name())
{
torch = it;
break;
}
}
if (MWBase::Environment::get().getWorld()->isNight()) if (MWBase::Environment::get().getWorld()->isDark())
{
if (heldIter != inventoryStore.end() && heldIter->getTypeName() != typeid(ESM::Light).name())
{ {
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); if (heldIter != inventoryStore.end() && heldIter->getTypeName() == typeid(ESM::Light).name())
inventoryStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, heldIter, ptr); {
// 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 holding a light...
if(heldIter.getType() == MWWorld::ContainerStore::Type_Light) if(heldIter.getType() == MWWorld::ContainerStore::Type_Light)
{ {
@ -516,6 +673,16 @@ namespace MWMechanics
Actors::Actors() {} 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) void Actors::addActor (const MWWorld::Ptr& ptr)
{ {
// erase previous death events since we are currently only tracking them while in an active cell // 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(); 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)]; ++mDeathCount[cls.getId(iter->first)];
if(cls.isEssential(iter->first)) if(cls.isEssential(iter->first))
MWBase::Environment::get().getWindowManager()->messageBox("#{sKilledEssential}"); MWBase::Environment::get().getWindowManager()->messageBox("#{sKilledEssential}");
} }
} }
@ -626,7 +806,12 @@ namespace MWMechanics
iter->second->updateContinuousVfx(); iter->second->updateContinuousVfx();
for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) 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); iter->second->update(duration);
}
} }
} }
void Actors::restoreDynamicStats() void Actors::restoreDynamicStats()

View file

@ -29,7 +29,6 @@ namespace MWMechanics
PtrControllerMap mActors; PtrControllerMap mActors;
std::map<std::string, int> mDeathCount; std::map<std::string, int> mDeathCount;
MWWorld::Ptr mTorchPtr;
void updateNpc(const MWWorld::Ptr &ptr, float duration, bool paused); void updateNpc(const MWWorld::Ptr &ptr, float duration, bool paused);
@ -49,6 +48,7 @@ namespace MWMechanics
public: public:
Actors(); Actors();
~Actors();
/// Update magic effects for an actor. Usually done automatically once per frame, but if we're currently /// 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) /// paused we may want to do it manually (after equipping permanent enchantment)

View file

@ -91,6 +91,8 @@ namespace MWMechanics
mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2]); mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2]);
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]); 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); MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false);
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1; MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1;
@ -105,6 +107,7 @@ namespace MWMechanics
float directionResult = sqrt(directionX * directionX + directionY * directionY); float directionResult = sqrt(directionX * directionX + directionY * directionY);
zAngle = Ogre::Radian( acos(directionY / directionResult) * sgn(asin(directionX / directionResult)) ).valueDegrees(); 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); MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false);
mPathFinder.clearPath(); mPathFinder.clearPath();

View file

@ -161,6 +161,7 @@ namespace MWMechanics
if(distanceBetweenResult <= mMaxDist * mMaxDist) if(distanceBetweenResult <= mMaxDist * mMaxDist)
{ {
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]); 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); MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false);
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1; MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1;
mMaxDist = 470; mMaxDist = 470;

View file

@ -97,6 +97,7 @@ namespace MWMechanics
} }
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]); 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); world->rotateObject(actor, 0, 0, zAngle, false);
movement.mPosition[1] = 1; movement.mPosition[1] = 1;

View file

@ -236,6 +236,7 @@ namespace MWMechanics
if(mWalking) if(mWalking)
{ {
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]); 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); world->rotateObject(actor, 0, 0, zAngle, false);
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1; MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1;

View file

@ -36,8 +36,6 @@
#include "../mwworld/player.hpp" #include "../mwworld/player.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/inventorystore.hpp" #include "../mwworld/inventorystore.hpp"
#include "../mwworld/actionequip.hpp"
#include "../mwworld/actiontake.hpp"
namespace namespace
{ {
@ -1063,15 +1061,19 @@ void CharacterController::update(float duration)
refreshCurrentAnims(idlestate, movestate, forcestateupdate); refreshCurrentAnims(idlestate, movestate, forcestateupdate);
if(mHitState != CharState_KnockDown) if (!mSkipAnim)
{ {
rot *= duration * Ogre::Math::RadiansToDegrees(1.0f); if(mHitState != CharState_KnockDown)
world->rotateObject(mPtr, rot.x, rot.y, rot.z, true); {
} rot *= duration * Ogre::Math::RadiansToDegrees(1.0f);
else world->rotateObject(mPtr, rot.x, rot.y, rot.z, true);
world->rotateObject(mPtr, rot.x, rot.y, 0.0f, true); }
else
world->rotateObject(mPtr, rot.x, rot.y, 0.0f, true);
world->queueMovement(mPtr, vec);
}
world->queueMovement(mPtr, vec);
movement = vec; movement = vec;
} }
else if(cls.getCreatureStats(mPtr).isDead()) else if(cls.getCreatureStats(mPtr).isDead())

View file

@ -74,7 +74,7 @@ namespace MWMechanics
- gmst.find ("fFatigueMult")->getFloat() * (1-normalised); - gmst.find ("fFatigueMult")->getFloat() * (1-normalised);
} }
const Stat<int> &CreatureStats::getAttribute(int index) const const AttributeValue &CreatureStats::getAttribute(int index) const
{ {
if (index < 0 || index > 7) { if (index < 0 || index > 7) {
throw std::runtime_error("attribute index is out of range"); throw std::runtime_error("attribute index is out of range");
@ -158,20 +158,20 @@ namespace MWMechanics
void CreatureStats::setAttribute(int index, int base) void CreatureStats::setAttribute(int index, int base)
{ {
MWMechanics::Stat<int> current = getAttribute(index); AttributeValue current = getAttribute(index);
current.setBase(base); current.setBase(base);
setAttribute(index, current); setAttribute(index, current);
} }
void CreatureStats::setAttribute(int index, const Stat<int> &value) void CreatureStats::setAttribute(int index, const AttributeValue &value)
{ {
if (index < 0 || index > 7) { if (index < 0 || index > 7) {
throw std::runtime_error("attribute index is out of range"); throw std::runtime_error("attribute index is out of range");
} }
const Stat<int>& 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 if (index != ESM::Attribute::Luck
&& index != ESM::Attribute::Personality && index != ESM::Attribute::Personality
@ -228,8 +228,8 @@ namespace MWMechanics
void CreatureStats::setMagicEffects(const MagicEffects &effects) void CreatureStats::setMagicEffects(const MagicEffects &effects)
{ {
if (effects.get(MWMechanics::EffectKey(ESM::MagicEffect::FortifyMaximumMagicka)).mMagnitude if (effects.get(ESM::MagicEffect::FortifyMaximumMagicka).mMagnitude
!= mMagicEffects.get(MWMechanics::EffectKey(ESM::MagicEffect::FortifyMaximumMagicka)).mMagnitude) != mMagicEffects.get(ESM::MagicEffect::FortifyMaximumMagicka).mMagnitude)
mRecalcDynamicStats = true; mRecalcDynamicStats = true;
mMagicEffects = effects; mMagicEffects = effects;
@ -266,8 +266,10 @@ namespace MWMechanics
if (mDead) if (mDead)
{ {
if (mDynamic[0].getCurrent()<1) 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) if (mDynamic[0].getCurrent()>=1)
mDead = false; mDead = false;
} }
@ -343,7 +345,7 @@ namespace MWMechanics
float evasion = (getAttribute(ESM::Attribute::Agility).getModified() / 5.0f) + float evasion = (getAttribute(ESM::Attribute::Agility).getModified() / 5.0f) +
(getAttribute(ESM::Attribute::Luck).getModified() / 10.0f); (getAttribute(ESM::Attribute::Luck).getModified() / 10.0f);
evasion *= getFatigueTerm(); evasion *= getFatigueTerm();
evasion += mMagicEffects.get(EffectKey(ESM::MagicEffect::Sanctuary)).mMagnitude; evasion += mMagicEffects.get(ESM::MagicEffect::Sanctuary).mMagnitude;
return evasion; return evasion;
} }

View file

@ -18,7 +18,7 @@ namespace MWMechanics
/// ///
class CreatureStats class CreatureStats
{ {
Stat<int> mAttributes[8]; AttributeValue mAttributes[8];
DynamicStat<float> mDynamic[3]; // health, magicka, fatigue DynamicStat<float> mDynamic[3]; // health, magicka, fatigue
int mLevel; int mLevel;
Spells mSpells; Spells mSpells;
@ -49,7 +49,7 @@ namespace MWMechanics
protected: protected:
bool mIsWerewolf; bool mIsWerewolf;
Stat<int> mWerewolfAttributes[8]; AttributeValue mWerewolfAttributes[8];
public: public:
CreatureStats(); CreatureStats();
@ -65,7 +65,7 @@ namespace MWMechanics
bool canUsePower (const std::string& power) const; bool canUsePower (const std::string& power) const;
void usePower (const std::string& power); void usePower (const std::string& power);
const Stat<int> & getAttribute(int index) const; const AttributeValue & getAttribute(int index) const;
const DynamicStat<float> & getHealth() const; const DynamicStat<float> & getHealth() const;
@ -94,7 +94,7 @@ namespace MWMechanics
MagicEffects & getMagicEffects(); MagicEffects & getMagicEffects();
void setAttribute(int index, const Stat<int> &value); void setAttribute(int index, const AttributeValue &value);
// Shortcut to set only the base // Shortcut to set only the base
void setAttribute(int index, int base); void setAttribute(int index, int base);

View file

@ -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<ESM::GameSetting>().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<ESM::Spell>().find(it->first);
if (spell->mData.mType == ESM::Spell::ST_Disease
|| spell->mData.mType == ESM::Spell::ST_Blight)
{
float roll = std::rand()/ (static_cast<double> (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<ESM::GameSetting>().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

View file

@ -56,7 +56,8 @@ namespace MWMechanics
struct EffectSourceVisitor struct EffectSourceVisitor
{ {
virtual void visit (MWMechanics::EffectKey key, 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 /// \brief Effects currently affecting a NPC or creature

View file

@ -12,6 +12,8 @@
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/player.hpp" #include "../mwworld/player.hpp"
#include "spellcasting.hpp"
namespace MWMechanics namespace MWMechanics
{ {
void MechanicsManager::buildPlayer() void MechanicsManager::buildPlayer()
@ -123,6 +125,19 @@ namespace MWMechanics
npcStats.getSkill (index).setBase ( npcStats.getSkill (index).setBase (
npcStats.getSkill (index).getBase() + bonus); 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<ESM::Spell>::iterator it = store.get<ESM::Spell>().begin();
for (; it != store.get<ESM::Spell>().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... // otherwise one would get different prices when exiting and re-entering the dialogue window...
int clampedDisposition = std::max(0, std::min(getDerivedDisposition(ptr) int clampedDisposition = std::max(0, std::min(getDerivedDisposition(ptr)
+ MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange(),100)); + 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 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 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 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); float f = std::min(0.2f * sellerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f);

View file

@ -84,7 +84,7 @@ void MWMechanics::NpcStats::setMovementFlag (Flag flag, bool state)
mMovementFlags &= ~flag; mMovementFlags &= ~flag;
} }
const MWMechanics::Stat<float>& MWMechanics::NpcStats::getSkill (int index) const const MWMechanics::SkillValue& MWMechanics::NpcStats::getSkill (int index) const
{ {
if (index<0 || index>=ESM::Skill::Length) if (index<0 || index>=ESM::Skill::Length)
throw std::runtime_error ("skill index out of range"); throw std::runtime_error ("skill index out of range");
@ -92,7 +92,7 @@ const MWMechanics::Stat<float>& MWMechanics::NpcStats::getSkill (int index) cons
return (!mIsWerewolf ? mSkill[index] : mWerewolfSkill[index]); return (!mIsWerewolf ? mSkill[index] : mWerewolfSkill[index]);
} }
MWMechanics::Stat<float>& MWMechanics::NpcStats::getSkill (int index) MWMechanics::SkillValue& MWMechanics::NpcStats::getSkill (int index)
{ {
if (index<0 || index>=ESM::Skill::Length) if (index<0 || index>=ESM::Skill::Length)
throw std::runtime_error ("skill index out of range"); 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) if(mIsWerewolf)
return; return;
float base = getSkill (skillIndex).getBase(); MWMechanics::SkillValue value = getSkill (skillIndex);
int level = static_cast<int> (base); value.setProgress(value.getProgress() + getSkillGain (skillIndex, class_, usageType));
base += getSkillGain (skillIndex, class_, usageType); if (value.getProgress()>=1)
if (static_cast<int> (base)!=level)
{ {
// skill leveled up // skill leveled up
increaseSkill(skillIndex, class_, false); increaseSkill(skillIndex, class_, false);
} }
else
getSkill (skillIndex).setBase (base);
} }
void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &class_, bool preserveProgress) 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<int> (base); if (base >= 100)
if (level >= 100)
return; return;
if (preserveProgress) base += 1;
base += 1;
else
base = level+1;
// if this is a major or minor skill of the class, increase level progress // if this is a major or minor skill of the class, increase level progress
bool levelProgress = false; bool levelProgress = false;
@ -260,6 +251,8 @@ void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &clas
} }
getSkill (skillIndex).setBase (base); getSkill (skillIndex).setBase (base);
if (!preserveProgress)
getSkill(skillIndex).setProgress(0);
} }
int MWMechanics::NpcStats::getLevelProgress () const int MWMechanics::NpcStats::getLevelProgress () const
@ -387,7 +380,7 @@ void MWMechanics::NpcStats::setWerewolf (bool set)
// Oh, Bethesda. It's "Intelligence". // Oh, Bethesda. It's "Intelligence".
std::string name = "fWerewolf"+((i==ESM::Attribute::Intelligence) ? std::string("Intellegence") : std::string name = "fWerewolf"+((i==ESM::Attribute::Intelligence) ? std::string("Intellegence") :
ESM::Attribute::sAttributeNames[i]); 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++) for(size_t i = 0;i < ESM::Skill::Length;i++)
@ -401,7 +394,7 @@ void MWMechanics::NpcStats::setWerewolf (bool set)
// "Mercantile"! >_< // "Mercantile"! >_<
std::string name = "fWerewolf"+((i==ESM::Skill::Mercantile) ? std::string("Merchantile") : std::string name = "fWerewolf"+((i==ESM::Skill::Mercantile) ? std::string("Merchantile") :
ESM::Skill::sSkillNames[i]); ESM::Skill::sSkillNames[i]);
mWerewolfSkill[i].setModified(int(gmst.find(name)->getFloat()), 0); mWerewolfSkill[i].setBase(int(gmst.find(name)->getFloat()));
} }
} }
mIsWerewolf = set; mIsWerewolf = set;

View file

@ -45,8 +45,8 @@ namespace MWMechanics
DrawState_ mDrawState; DrawState_ mDrawState;
int mDisposition; int mDisposition;
unsigned int mMovementFlags; unsigned int mMovementFlags;
Stat<float> mSkill[27]; SkillValue mSkill[27];
Stat<float> mWerewolfSkill[27]; SkillValue mWerewolfSkill[27];
int mBounty; int mBounty;
std::set<std::string> mExpelled; std::set<std::string> mExpelled;
std::map<std::string, int> mFactionReputation; std::map<std::string, int> mFactionReputation;
@ -94,8 +94,8 @@ namespace MWMechanics
void setMovementFlag (Flag flag, bool state); void setMovementFlag (Flag flag, bool state);
const Stat<float>& getSkill (int index) const; const SkillValue& getSkill (int index) const;
Stat<float>& getSkill (int index); SkillValue& getSkill (int index);
const std::map<std::string, int>& getFactionRanks() const; const std::map<std::string, int>& getFactionRanks() const;
std::map<std::string, int>& getFactionRanks(); std::map<std::string, int>& getFactionRanks();

View file

@ -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) void Objects::addObject(const MWWorld::Ptr& ptr)
{ {
removeObject(ptr); removeObject(ptr);

View file

@ -21,6 +21,7 @@ namespace MWMechanics
public: public:
Objects(); Objects();
~Objects();
void addObject (const MWWorld::Ptr& ptr); void addObject (const MWWorld::Ptr& ptr);
///< Register an animated object ///< Register an animated object

View file

@ -24,21 +24,13 @@ void Repair::repair(const MWWorld::Ptr &itemToRepair)
MWWorld::LiveCellRef<ESM::Repair> *ref = MWWorld::LiveCellRef<ESM::Repair> *ref =
mTool.get<ESM::Repair>(); mTool.get<ESM::Repair>();
// unstack tool if required
player.getClass().getContainerStore(player).unstack(mTool, player);
// reduce number of uses left // reduce number of uses left
int uses = (mTool.getCellRef().mCharge != -1) ? mTool.getCellRef().mCharge : ref->mBase->mData.mUses; int uses = (mTool.getCellRef().mCharge != -1) ? mTool.getCellRef().mCharge : ref->mBase->mData.mUses;
mTool.getCellRef().mCharge = uses-1; 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::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player);
MWMechanics::NpcStats& npcStats = MWWorld::Class::get(player).getNpcStats(player); MWMechanics::NpcStats& npcStats = MWWorld::Class::get(player).getNpcStats(player);

View file

@ -7,6 +7,8 @@
#include "../mwworld/containerstore.hpp" #include "../mwworld/containerstore.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/actionteleport.hpp"
#include "../mwrender/animation.hpp" #include "../mwrender/animation.hpp"
@ -66,6 +68,12 @@ namespace MWMechanics
MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find ( MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find (
effectIt->mEffectID); 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; float magnitudeMult = 1;
if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful && target.getClass().isActor()) if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful && target.getClass().isActor())
{ {
@ -133,7 +141,8 @@ namespace MWMechanics
float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * random; 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; ActiveSpells::Effect effect;
effect.mKey = MWMechanics::EffectKey(*effectIt); effect.mKey = MWMechanics::EffectKey(*effectIt);
@ -152,12 +161,23 @@ namespace MWMechanics
ActiveSpells::Effect effect_ = effect; ActiveSpells::Effect effect_ = effect;
effect_.mMagnitude *= -1; effect_.mMagnitude *= -1;
effects.push_back(effect_); 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 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) if (target.getClass().isActor() || magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)
{ {
@ -196,11 +216,13 @@ namespace MWMechanics
inflict(caster, target, reflectedEffects, range, true); inflict(caster, target, reflectedEffects, range, true);
if (appliedLastingEffects.size()) 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 (!target.getClass().isActor())
{ {
if (effectId == ESM::MagicEffect::Lock) if (effectId == ESM::MagicEffect::Lock)
@ -223,6 +245,28 @@ namespace MWMechanics
} }
else 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) if (effectId == ESM::MagicEffect::CurePoison)
target.getClass().getCreatureStats(target).getActiveSpells().purgeEffect(ESM::MagicEffect::Poison); target.getClass().getCreatureStats(target).getActiveSpells().purgeEffect(ESM::MagicEffect::Poison);
else if (effectId == ESM::MagicEffect::CureParalyzation) else if (effectId == ESM::MagicEffect::CureParalyzation)
@ -234,27 +278,45 @@ namespace MWMechanics
else if (effectId == ESM::MagicEffect::CureCorprusDisease) else if (effectId == ESM::MagicEffect::CureCorprusDisease)
target.getClass().getCreatureStats(target).getSpells().purgeCorprusDisease(); target.getClass().getCreatureStats(target).getSpells().purgeCorprusDisease();
else if (effectId == ESM::MagicEffect::Dispel) 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) else if (effectId == ESM::MagicEffect::RemoveCurse)
target.getClass().getCreatureStats(target).getSpells().purgeCurses(); 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 MWBase::Environment::get().getWorld()->teleportToClosestMarker(target, "divinemarker", worldPos);
// or alternatively, the last known exterior location of the player, which is how vanilla does it.
} }
else if (effectId == ESM::MagicEffect::AlmsiviIntervention) else if (effectId == ESM::MagicEffect::AlmsiviIntervention)
{ {
// Same as above MWBase::Environment::get().getWorld()->teleportToClosestMarker(target, "templemarker", worldPos);
} }
else if (effectId == ESM::MagicEffect::Mark) else if (effectId == ESM::MagicEffect::Mark)
{ {
// TODO MWBase::Environment::get().getWorld()->getPlayer().markPosition(
target.getCell(), target.getRefData().getPosition());
} }
else if (effectId == ESM::MagicEffect::Recall) 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<double> (RAND_MAX) + 1) * 100; // [0, 99] int roll = std::rand()/ (static_cast<double> (RAND_MAX) + 1) * 100; // [0, 99]
if (!fail && roll >= successChance) if (!fail && roll >= successChance)
{ {
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicSkillFail}"); if (mCaster.getRefData().getHandle() == "player")
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicSkillFail}");
fail = true; fail = true;
} }

View file

@ -203,7 +203,7 @@ namespace MWMechanics
void inflict (const MWWorld::Ptr& target, const MWWorld::Ptr& caster, void inflict (const MWWorld::Ptr& target, const MWWorld::Ptr& caster,
const ESM::EffectList& effects, ESM::RangeType range, bool reflected=false); 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);
}; };
} }

View file

@ -34,13 +34,14 @@ namespace MWMechanics
random.resize(spell->mEffects.mList.size()); random.resize(spell->mEffects.mList.size());
for (unsigned int i=0; i<random.size();++i) for (unsigned int i=0; i<random.size();++i)
random[i] = static_cast<float> (std::rand()) / RAND_MAX; random[i] = static_cast<float> (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) 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()) if (iter!=mSpells.end())
mSpells.erase (iter); mSpells.erase (iter);
@ -192,7 +193,7 @@ namespace MWMechanics
effectIt != list.mList.end(); ++effectIt, ++i) effectIt != list.mList.end(); ++effectIt, ++i)
{ {
float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * it->second[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);
} }
} }
} }

View file

@ -205,6 +205,46 @@ namespace MWMechanics
{ {
return !(left==right); 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 #endif

View file

@ -1224,7 +1224,8 @@ void ObjectAnimation::fillBatch(Ogre::StaticGeometry *sg)
for(;iter != mObjectRoot->mEntities.rend();++iter) for(;iter != mObjectRoot->mEntities.rend();++iter)
{ {
Ogre::Node *node = (*iter)->getParentNode(); 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());
} }
} }

View file

@ -19,25 +19,27 @@ namespace MWRender
Camera::Camera (Ogre::Camera *camera) Camera::Camera (Ogre::Camera *camera)
: mCamera(camera), : mCamera(camera),
mCameraNode(NULL), mCameraNode(NULL),
mAnimation(NULL),
mFirstPersonView(true), mFirstPersonView(true),
mPreviewMode(false), mPreviewMode(false),
mFreeLook(true), mFreeLook(true),
mHeight(128.f),
mCameraDistance(300.f),
mDistanceAdjusted(false),
mAnimation(NULL),
mNearest(30.f), mNearest(30.f),
mFurthest(800.f), mFurthest(800.f),
mIsNearest(false), mIsNearest(false),
mIsFurthest(false), mIsFurthest(false),
mHeight(128.f),
mCameraDistance(300.f),
mDistanceAdjusted(false),
mVanityToggleQueued(false), mVanityToggleQueued(false),
mViewModeToggleQueued(false) mViewModeToggleQueued(false)
{ {
mVanity.enabled = false; mVanity.enabled = false;
mVanity.allowed = true; mVanity.allowed = true;
mPreviewCam.pitch = 0.f;
mPreviewCam.yaw = 0.f; mPreviewCam.yaw = 0.f;
mPreviewCam.offset = 400.f; mPreviewCam.offset = 400.f;
mMainCam.pitch = 0.f;
mMainCam.yaw = 0.f; mMainCam.yaw = 0.f;
mMainCam.offset = 400.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) void Camera::setCameraDistance(float dist, bool adjust, bool override)
{ {
if(mFirstPersonView && !mPreviewMode && !mVanity.enabled) if(mFirstPersonView && !mPreviewMode && !mVanity.enabled)

View file

@ -105,6 +105,8 @@ namespace MWRender
/// Restore default camera distance for current mode. /// Restore default camera distance for current mode.
void setCameraDistance(); void setCameraDistance();
float getCameraDistance() const;
void setAnimation(NpcAnimation *anim); void setAnimation(NpcAnimation *anim);
/// Stores focal and camera world positions in passed arguments /// Stores focal and camera world positions in passed arguments

View file

@ -128,7 +128,7 @@ namespace MWRender
InventoryPreview::InventoryPreview(MWWorld::Ptr character) 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) , mSelectionBuffer(NULL)
{ {
} }

View file

@ -225,64 +225,54 @@ void LocalMap::render(const float x, const float y,
tex = TextureManager::getSingleton().getByName(texture); tex = TextureManager::getSingleton().getByName(texture);
if (tex.isNull()) if (tex.isNull())
{ {
// try loading from disk // render
//if (boost::filesystem::exists(texture+".jpg")) tex = TextureManager::getSingleton().createManual(
//{ texture,
/// \todo ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
//} TEX_TYPE_2D,
//else 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<uint32> buffer;
buffer.resize(sFogOfWarResolution*sFogOfWarResolution);
// initialize to (0, 0, 0, 1)
for (int p=0; p<sFogOfWarResolution*sFogOfWarResolution; ++p)
{ {
// render buffer[p] = (255 << 24);
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<uint32> buffer;
buffer.resize(sFogOfWarResolution*sFogOfWarResolution);
// initialize to (0, 0, 0, 1)
for (int p=0; p<sFogOfWarResolution*sFogOfWarResolution; ++p)
{
buffer[p] = (255 << 24);
}
memcpy(tex2->getBuffer()->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");
} }
memcpy(tex2->getBuffer()->lock(HardwareBuffer::HBL_DISCARD), &buffer[0], sFogOfWarResolution*sFogOfWarResolution*4);
tex2->getBuffer()->unlock();
mBuffers[texture] = buffer;
} }
mRenderingManager->enableLights(true); mRenderingManager->enableLights(true);
mLight->setVisible(false); mLight->setVisible(false);
@ -339,8 +329,6 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni
Vector3 playerdirection = mCameraRotNode->convertWorldToLocalOrientation(orientation).yAxis(); Vector3 playerdirection = mCameraRotNode->convertWorldToLocalOrientation(orientation).yAxis();
Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y);
if (!mInterior) if (!mInterior)
{ {
x = std::ceil(pos.x / sSize)-1; x = std::ceil(pos.x / sSize)-1;

View file

@ -664,11 +664,12 @@ void NpcAnimation::showCarriedLeft(bool show)
{ {
Ogre::Vector3 glowColor = getEnchantmentColor(*iter); Ogre::Vector3 glowColor = getEnchantmentColor(*iter);
std::string mesh = MWWorld::Class::get(*iter).getModel(*iter); std::string mesh = MWWorld::Class::get(*iter).getModel(*iter);
addOrReplaceIndividualPart(ESM::PRT_Shield, MWWorld::InventoryStore::Slot_CarriedLeft, 1, if (addOrReplaceIndividualPart(ESM::PRT_Shield, MWWorld::InventoryStore::Slot_CarriedLeft, 1,
mesh, !iter->getClass().getEnchantment(*iter).empty(), &glowColor); mesh, !iter->getClass().getEnchantment(*iter).empty(), &glowColor))
{
if (iter->getTypeName() == typeid(ESM::Light).name()) if (iter->getTypeName() == typeid(ESM::Light).name())
addExtraLight(mInsert->getCreator(), mObjectParts[ESM::PRT_Shield], iter->get<ESM::Light>()->mBase); addExtraLight(mInsert->getCreator(), mObjectParts[ESM::PRT_Shield], iter->get<ESM::Light>()->mBase);
}
} }
else else
removeIndividualPart(ESM::PRT_Shield); removeIndividualPart(ESM::PRT_Shield);

View file

@ -109,10 +109,13 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b
mFactory->loadAllFiles(); mFactory->loadAllFiles();
// Set default mipmap level (NB some APIs ignore this) // Compressed textures with 0 mip maps are bugged in 1.8, so disable mipmap generator in that case
// Mipmap generation is currently disabled because it causes issues on Intel/AMD // ( https://ogre3d.atlassian.net/browse/OGRE-259 )
//TextureManager::getSingleton().setDefaultNumMipmaps(Settings::Manager::getInt("num mipmaps", "General")); #if OGRE_VERSION >= (1 << 16 | 9 << 8 | 0)
TextureManager::getSingleton().setDefaultNumMipmaps(Settings::Manager::getInt("num mipmaps", "General"));
#else
TextureManager::getSingleton().setDefaultNumMipmaps(0); TextureManager::getSingleton().setDefaultNumMipmaps(0);
#endif
// Set default texture filtering options // Set default texture filtering options
TextureFilterOptions tfo; TextureFilterOptions tfo;
@ -325,7 +328,7 @@ void RenderingManager::update (float duration, bool paused)
MWWorld::Ptr player = world->getPlayer().getPlayer(); 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))); mRendering.getFader()->setFactor(std::max(0.f, 1.f-(blind / 100.f)));
setAmbientMode(); setAmbientMode();
@ -590,7 +593,7 @@ void RenderingManager::setAmbientColour(const Ogre::ColourValue& colour)
mAmbientColor = colour; mAmbientColor = colour;
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); 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; Ogre::ColourValue final = colour;
final += Ogre::ColourValue(0.7,0.7,0.7,0) * std::min(1.f, (nightEye/100.f)); 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); mTerrain->setVisible(false);
} }
float RenderingManager::getCameraDistance() const
{
return mCamera->getCameraDistance();
}
} // namespace } // namespace

View file

@ -90,6 +90,7 @@ public:
bool vanityRotateCamera(const float *rot); bool vanityRotateCamera(const float *rot);
void setCameraDistance(float dist, bool adjust = false, bool override = true); void setCameraDistance(float dist, bool adjust = false, bool override = true);
float getCameraDistance() const;
void setupPlayer(const MWWorld::Ptr &ptr); void setupPlayer(const MWWorld::Ptr &ptr);
void renderPlayer(const MWWorld::Ptr &ptr); void renderPlayer(const MWWorld::Ptr &ptr);

View file

@ -949,9 +949,25 @@ void VideoState::init(const std::string& resourceName)
this->format_ctx->pb = ioCtx; this->format_ctx->pb = ioCtx;
// Open video file // 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 || 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." // "Note that a user-supplied AVFormatContext will be freed on failure."
this->format_ctx = NULL; this->format_ctx = NULL;
av_free(ioCtx); av_free(ioCtx);
@ -1009,9 +1025,21 @@ void VideoState::deinit()
if(this->format_ctx) 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); avformat_close_input(&this->format_ctx);
av_free(ioContext);
} }
} }

View file

@ -292,6 +292,7 @@ Water::~Water()
delete mReflection; delete mReflection;
delete mRefraction; delete mRefraction;
delete mSimulation;
} }
void Water::changeCell(const ESM::Cell* cell) void Water::changeCell(const ESM::Cell* cell)

View file

@ -43,10 +43,13 @@ namespace MWScript
ESM::Position pos; ESM::Position pos;
MWBase::World *world = MWBase::Environment::get().getWorld(); MWBase::World *world = MWBase::Environment::get().getWorld();
if (world->findExteriorPosition(cell, pos)) { world->getPlayer().setTeleported(true);
if (world->findExteriorPosition(cell, pos))
{
world->changeToExteriorCell(pos); world->changeToExteriorCell(pos);
} }
else { else
{
// Change to interior even if findInteriorPosition() // Change to interior even if findInteriorPosition()
// yields false. In this case position will be zero-point. // yields false. In this case position will be zero-point.
world->findInteriorPosition(cell, pos); world->findInteriorPosition(cell, pos);
@ -68,13 +71,14 @@ namespace MWScript
runtime.pop(); runtime.pop();
ESM::Position pos; ESM::Position pos;
MWBase::World *world = MWBase::Environment::get().getWorld();
MWBase::Environment::get().getWorld()->indexToPosition (x, y, pos.pos[0], pos.pos[1], true); world->getPlayer().setTeleported(true);
world->indexToPosition (x, y, pos.pos[0], pos.pos[1], true);
pos.pos[2] = 0; pos.pos[2] = 0;
pos.rot[0] = pos.rot[1] = pos.rot[2] = 0; pos.rot[0] = pos.rot[1] = pos.rot[2] = 0;
MWBase::Environment::get().getWorld()->changeToExteriorCell (pos); world->changeToExteriorCell (pos);
} }
}; };

View file

@ -127,7 +127,6 @@ op 0x200007e-0x2000084: Enable Controls
op 0x2000085-0x200008b: Disable Controls op 0x2000085-0x200008b: Disable Controls
op 0x200008c: Unlock op 0x200008c: Unlock
op 0x200008d: Unlock, explicit reference op 0x200008d: Unlock, explicit reference
op 0x200008e: COE
op 0x200008e-0x20000a8: GetSkill op 0x200008e-0x20000a8: GetSkill
op 0x20000a9-0x20000c3: GetSkill, explicit reference op 0x20000a9-0x20000c3: GetSkill, explicit reference
op 0x20000c4-0x20000de: SetSkill op 0x20000c4-0x20000de: SetSkill
@ -358,5 +357,17 @@ op 0x2000222: GetLineOfSight
op 0x2000223: GetLineOfSightExplicit op 0x2000223: GetLineOfSightExplicit
op 0x2000224: ToggleAI op 0x2000224: ToggleAI
op 0x2000225: ToggleAIExplicit op 0x2000225: ToggleAIExplicit
op 0x2000226: COE
opcodes 0x2000226-0x3ffffff unused 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

View file

@ -23,6 +23,7 @@
#include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/npcstats.hpp"
#include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/creaturestats.hpp"
#include "../mwmechanics/spellcasting.hpp"
#include "interpretercontext.hpp" #include "interpretercontext.hpp"
#include "ref.hpp" #include "ref.hpp"
@ -464,7 +465,20 @@ namespace MWScript
{ {
MWWorld::Ptr ptr = R()(runtime); 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 R>
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 R>
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 R>
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) void installOpcodes (Interpreter::Interpreter& interpreter)
{ {
@ -739,6 +789,8 @@ namespace MWScript
interpreter.installSegment5 (Compiler::Misc::opcodeGetAttackedExplicit, new OpGetAttacked<ExplicitRef>); interpreter.installSegment5 (Compiler::Misc::opcodeGetAttackedExplicit, new OpGetAttacked<ExplicitRef>);
interpreter.installSegment5 (Compiler::Misc::opcodeGetWeaponDrawn, new OpGetWeaponDrawn<ImplicitRef>); interpreter.installSegment5 (Compiler::Misc::opcodeGetWeaponDrawn, new OpGetWeaponDrawn<ImplicitRef>);
interpreter.installSegment5 (Compiler::Misc::opcodeGetWeaponDrawnExplicit, new OpGetWeaponDrawn<ExplicitRef>); interpreter.installSegment5 (Compiler::Misc::opcodeGetWeaponDrawnExplicit, new OpGetWeaponDrawn<ExplicitRef>);
interpreter.installSegment5 (Compiler::Misc::opcodeGetSpellReadied, new OpGetSpellReadied<ImplicitRef>);
interpreter.installSegment5 (Compiler::Misc::opcodeGetSpellReadiedExplicit, new OpGetSpellReadied<ExplicitRef>);
interpreter.installSegment5 (Compiler::Misc::opcodeGetSpellEffects, new OpGetSpellEffects<ImplicitRef>); interpreter.installSegment5 (Compiler::Misc::opcodeGetSpellEffects, new OpGetSpellEffects<ImplicitRef>);
interpreter.installSegment5 (Compiler::Misc::opcodeGetSpellEffectsExplicit, new OpGetSpellEffects<ExplicitRef>); interpreter.installSegment5 (Compiler::Misc::opcodeGetSpellEffectsExplicit, new OpGetSpellEffects<ExplicitRef>);
interpreter.installSegment5 (Compiler::Misc::opcodeGetCurrentTime, new OpGetCurrentTime); interpreter.installSegment5 (Compiler::Misc::opcodeGetCurrentTime, new OpGetCurrentTime);
@ -761,6 +813,10 @@ namespace MWScript
interpreter.installSegment5 (Compiler::Misc::opcodeToggleGodMode, new OpToggleGodMode); interpreter.installSegment5 (Compiler::Misc::opcodeToggleGodMode, new OpToggleGodMode);
interpreter.installSegment5 (Compiler::Misc::opcodeDisableLevitation, new OpEnableLevitation<false>); interpreter.installSegment5 (Compiler::Misc::opcodeDisableLevitation, new OpEnableLevitation<false>);
interpreter.installSegment5 (Compiler::Misc::opcodeEnableLevitation, new OpEnableLevitation<true>); interpreter.installSegment5 (Compiler::Misc::opcodeEnableLevitation, new OpEnableLevitation<true>);
interpreter.installSegment5 (Compiler::Misc::opcodeCast, new OpCast<ImplicitRef>);
interpreter.installSegment5 (Compiler::Misc::opcodeCastExplicit, new OpCast<ExplicitRef>);
interpreter.installSegment5 (Compiler::Misc::opcodeExplodeSpell, new OpExplodeSpell<ImplicitRef>);
interpreter.installSegment5 (Compiler::Misc::opcodeExplodeSpellExplicit, new OpExplodeSpell<ExplicitRef>);
} }
} }
} }

View file

@ -124,8 +124,8 @@ namespace MWScript
Interpreter::Type_Integer value = runtime[0].mInteger; Interpreter::Type_Integer value = runtime[0].mInteger;
runtime.pop(); runtime.pop();
MWMechanics::Stat<int> attribute = ptr.getClass().getCreatureStats(ptr).getAttribute(mIndex); MWMechanics::AttributeValue attribute = ptr.getClass().getCreatureStats(ptr).getAttribute(mIndex);
attribute.setModified (value, 0); attribute.setBase (value - (attribute.getModified() - attribute.getBase()));
ptr.getClass().getCreatureStats(ptr).setAttribute(mIndex, attribute); ptr.getClass().getCreatureStats(ptr).setAttribute(mIndex, attribute);
} }
}; };
@ -146,15 +146,11 @@ namespace MWScript
Interpreter::Type_Integer value = runtime[0].mInteger; Interpreter::Type_Integer value = runtime[0].mInteger;
runtime.pop(); runtime.pop();
MWMechanics::Stat<int> attribute = MWWorld::Class::get(ptr) MWMechanics::AttributeValue attribute = MWWorld::Class::get(ptr)
.getCreatureStats(ptr) .getCreatureStats(ptr)
.getAttribute(mIndex); .getAttribute(mIndex);
value += attribute.setBase (std::min(100, attribute.getBase() + value));
attribute.getModified();
attribute
.setModified (value, 0, 100);
ptr.getClass().getCreatureStats(ptr).setAttribute(mIndex, attribute); ptr.getClass().getCreatureStats(ptr).setAttribute(mIndex, attribute);
} }
}; };
@ -346,17 +342,13 @@ namespace MWScript
const ESM::Class& class_ = const ESM::Class& class_ =
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Class>().find (ref->mBase->mClass); *MWBase::Environment::get().getWorld()->getStore().get<ESM::Class>().find (ref->mBase->mClass);
float level = 0; float level = stats.getSkill(mIndex).getBase();
float progress = std::modf (stats.getSkill (mIndex).getBase(), &level); float progress = stats.getSkill(mIndex).getProgress();
float modifier = stats.getSkill (mIndex).getModifier(); int newLevel = value - (stats.getSkill(mIndex).getModified() - stats.getSkill(mIndex).getBase());
int newLevel = static_cast<int> (value-modifier);
if (newLevel<0) if (newLevel<0)
newLevel = 0; newLevel = 0;
else if (newLevel>100)
newLevel = 100;
progress = (progress / stats.getSkillGain (mIndex, class_, -1, level)) progress = (progress / stats.getSkillGain (mIndex, class_, -1, level))
* stats.getSkillGain (mIndex, class_, -1, newLevel); * stats.getSkillGain (mIndex, class_, -1, newLevel);
@ -364,8 +356,8 @@ namespace MWScript
if (progress>=1) if (progress>=1)
progress = 0.999999999; progress = 0.999999999;
stats.getSkill (mIndex).set (newLevel + progress); stats.getSkill (mIndex).setBase (newLevel);
stats.getSkill (mIndex).setModifier (modifier); stats.getSkill (mIndex).setProgress(progress);
} }
}; };
@ -385,11 +377,10 @@ namespace MWScript
Interpreter::Type_Integer value = runtime[0].mInteger; Interpreter::Type_Integer value = runtime[0].mInteger;
runtime.pop(); runtime.pop();
value += MWWorld::Class::get (ptr).getNpcStats (ptr).getSkill (mIndex). MWMechanics::NpcStats& stats = ptr.getClass().getNpcStats(ptr);
getModified();
MWWorld::Class::get (ptr).getNpcStats (ptr).getSkill (mIndex). stats.getSkill(mIndex).
setModified (value, 0, 100); setBase (std::min(100, stats.getSkill(mIndex).getBase() + value));
} }
}; };
@ -468,6 +459,38 @@ namespace MWScript
} }
}; };
template<class R>
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 R>
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 R> template<class R>
class OpGetSpell : public Interpreter::Opcode0 class OpGetSpell : public Interpreter::Opcode0
{ {
@ -1081,6 +1104,18 @@ namespace MWScript
} }
}; };
template <class R>
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) void installOpcodes (Interpreter::Interpreter& interpreter)
{ {
for (int i=0; i<Compiler::Stats::numberOfAttributes; ++i) for (int i=0; i<Compiler::Stats::numberOfAttributes; ++i)
@ -1144,6 +1179,15 @@ namespace MWScript
interpreter.installSegment5 (Compiler::Stats::opcodeRemoveSpell, new OpRemoveSpell<ImplicitRef>); interpreter.installSegment5 (Compiler::Stats::opcodeRemoveSpell, new OpRemoveSpell<ImplicitRef>);
interpreter.installSegment5 (Compiler::Stats::opcodeRemoveSpellExplicit, interpreter.installSegment5 (Compiler::Stats::opcodeRemoveSpellExplicit,
new OpRemoveSpell<ExplicitRef>); new OpRemoveSpell<ExplicitRef>);
interpreter.installSegment5 (Compiler::Stats::opcodeRemoveSpellEffects, new OpRemoveSpellEffects<ImplicitRef>);
interpreter.installSegment5 (Compiler::Stats::opcodeRemoveSpellEffectsExplicit,
new OpRemoveSpellEffects<ExplicitRef>);
interpreter.installSegment5 (Compiler::Stats::opcodeResurrect, new OpResurrect<ImplicitRef>);
interpreter.installSegment5 (Compiler::Stats::opcodeResurrectExplicit,
new OpResurrect<ExplicitRef>);
interpreter.installSegment5 (Compiler::Stats::opcodeRemoveEffects, new OpRemoveEffects<ImplicitRef>);
interpreter.installSegment5 (Compiler::Stats::opcodeRemoveEffectsExplicit,
new OpRemoveEffects<ExplicitRef>);
interpreter.installSegment5 (Compiler::Stats::opcodeGetSpell, new OpGetSpell<ImplicitRef>); interpreter.installSegment5 (Compiler::Stats::opcodeGetSpell, new OpGetSpell<ImplicitRef>);
interpreter.installSegment5 (Compiler::Stats::opcodeGetSpellExplicit, new OpGetSpell<ExplicitRef>); interpreter.installSegment5 (Compiler::Stats::opcodeGetSpellExplicit, new OpGetSpell<ExplicitRef>);

View file

@ -208,6 +208,14 @@ namespace MWScript
{ {
MWWorld::Ptr ptr = R()(runtime); 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); std::string axis = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop(); runtime.pop();
Interpreter::Type_Float pos = runtime[0].mFloat; Interpreter::Type_Float pos = runtime[0].mFloat;
@ -272,6 +280,14 @@ namespace MWScript
{ {
MWWorld::Ptr ptr = R()(runtime); 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; Interpreter::Type_Float x = runtime[0].mFloat;
runtime.pop(); runtime.pop();
Interpreter::Type_Float y = runtime[0].mFloat; Interpreter::Type_Float y = runtime[0].mFloat;
@ -329,6 +345,14 @@ namespace MWScript
{ {
MWWorld::Ptr ptr = R()(runtime); 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; Interpreter::Type_Float x = runtime[0].mFloat;
runtime.pop(); runtime.pop();
Interpreter::Type_Float y = runtime[0].mFloat; Interpreter::Type_Float y = runtime[0].mFloat;
@ -593,6 +617,10 @@ namespace MWScript
virtual void execute (Interpreter::Runtime& runtime) virtual void execute (Interpreter::Runtime& runtime)
{ {
MWWorld::Ptr ptr = R()(runtime); MWWorld::Ptr ptr = R()(runtime);
if (!ptr.isInCell())
return;
ptr.getRefData().getLocalRotation().rot[0] = 0; ptr.getRefData().getLocalRotation().rot[0] = 0;
ptr.getRefData().getLocalRotation().rot[1] = 0; ptr.getRefData().getLocalRotation().rot[1] = 0;
ptr.getRefData().getLocalRotation().rot[2] = 0; ptr.getRefData().getLocalRotation().rot[2] = 0;
@ -612,6 +640,9 @@ namespace MWScript
{ {
const MWWorld::Ptr& ptr = R()(runtime); const MWWorld::Ptr& ptr = R()(runtime);
if (!ptr.isInCell())
return;
std::string axis = runtime.getStringLiteral (runtime[0].mInteger); std::string axis = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop(); runtime.pop();
Interpreter::Type_Float movement = (runtime[0].mFloat*MWBase::Environment::get().getFrameDuration()); Interpreter::Type_Float movement = (runtime[0].mFloat*MWBase::Environment::get().getFrameDuration());
@ -647,6 +678,9 @@ namespace MWScript
{ {
MWWorld::Ptr ptr = R()(runtime); MWWorld::Ptr ptr = R()(runtime);
if (!ptr.isInCell())
return;
std::string axis = runtime.getStringLiteral (runtime[0].mInteger); std::string axis = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop(); runtime.pop();
Interpreter::Type_Float movement = (runtime[0].mFloat*MWBase::Environment::get().getFrameDuration()); Interpreter::Type_Float movement = (runtime[0].mFloat*MWBase::Environment::get().getFrameDuration());

View file

@ -158,6 +158,16 @@ void FFmpeg_Decoder::open(const std::string &fname)
mFormatCtx->pb = avio_alloc_context(NULL, 0, 0, this, readPacket, writePacket, seek); 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 || 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); avformat_free_context(mFormatCtx);
mFormatCtx = NULL; mFormatCtx = NULL;
fail("Failed to allocate input stream"); fail("Failed to allocate input stream");
@ -195,6 +205,14 @@ void FFmpeg_Decoder::open(const std::string &fname)
} }
catch(std::exception &e) 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); avformat_close_input(&mFormatCtx);
throw; throw;
} }
@ -211,9 +229,22 @@ void FFmpeg_Decoder::close()
if(mFormatCtx) 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); avformat_close_input(&mFormatCtx);
av_free(context);
} }
mDataStream.setNull(); mDataStream.setNull();

View file

@ -252,7 +252,7 @@ namespace MWSound
float basevol = volumeFromType(Play_TypeVoice); float basevol = volumeFromType(Play_TypeVoice);
std::string filePath = "Sound/"+filename; std::string filePath = "Sound/"+filename;
const ESM::Position &pos = ptr.getRefData().getPosition(); 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, MWBase::SoundPtr sound = mOutput->playSound3D(filePath, objpos, 1.0f, basevol, 1.0f,
20.0f, 12750.0f, Play_Normal|Play_TypeVoice, 0); 20.0f, 12750.0f, Play_Normal|Play_TypeVoice, 0);
@ -354,7 +354,7 @@ namespace MWSound
float min, max; float min, max;
std::string file = lookup(soundId, volume, min, max); std::string file = lookup(soundId, volume, min, max);
const ESM::Position &pos = ptr.getRefData().getPosition(); 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); sound = mOutput->playSound3D(file, objpos, volume, basevol, pitch, min, max, mode|type, offset);
if((mode&Play_NoTrack)) if((mode&Play_NoTrack))
@ -584,7 +584,7 @@ namespace MWSound
if(!ptr.isEmpty()) if(!ptr.isEmpty())
{ {
const ESM::Position &pos = ptr.getRefData().getPosition(); 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); snditer->first->setPosition(objpos);
} }
//update fade out //update fade out

View file

@ -5,6 +5,8 @@
#include "../mwgui/container.hpp" #include "../mwgui/container.hpp"
#include "../mwmechanics/disease.hpp"
#include "class.hpp" #include "class.hpp"
#include "containerstore.hpp" #include "containerstore.hpp"
@ -21,6 +23,8 @@ namespace MWWorld
if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory))
return; return;
MWMechanics::diseaseContact(actor, getTarget());
MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Container); MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Container);
MWBase::Environment::get().getWindowManager()->getContainerWindow()->open(getTarget(), mLoot); MWBase::Environment::get().getWindowManager()->getContainerWindow()->open(getTarget(), mLoot);
} }

View file

@ -3,6 +3,7 @@
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "player.hpp"
namespace MWWorld namespace MWWorld
{ {
@ -14,9 +15,12 @@ namespace MWWorld
void ActionTeleport::executeImp (const Ptr& actor) void ActionTeleport::executeImp (const Ptr& actor)
{ {
MWBase::World* world = MWBase::Environment::get().getWorld();
world->getPlayer().setTeleported(true);
if (mCellName.empty()) if (mCellName.empty())
MWBase::Environment::get().getWorld()->changeToExteriorCell (mPosition); world->changeToExteriorCell (mPosition);
else else
MWBase::Environment::get().getWorld()->changeToInteriorCell (mCellName, mPosition); world->changeToInteriorCell (mCellName, mPosition);
} }
} }

View file

@ -4,7 +4,7 @@
#include <vector> #include <vector>
#include <string> #include <string>
#include "refdata.hpp" #include "ptr.hpp"
namespace ESM namespace ESM
{ {
@ -18,13 +18,13 @@ namespace MWWorld
{ {
std::vector<Ogre::SceneNode*> mHandles; std::vector<Ogre::SceneNode*> 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) if (handle)
mHandles.push_back (handle); mHandles.push_back (handle);
data.setBaseNode(0); ptr.getRefData().setBaseNode(0);
return true; return true;
} }
}; };

View file

@ -129,9 +129,7 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name, Ptr::CellStore& ce
if (cell.mState==Ptr::CellStore::State_Preloaded) if (cell.mState==Ptr::CellStore::State_Preloaded)
{ {
std::string lowerCase = Misc::StringUtils::lowerCase(name); if (std::binary_search (cell.mIds.begin(), cell.mIds.end(), name))
if (std::binary_search (cell.mIds.begin(), cell.mIds.end(), lowerCase))
{ {
cell.load (mStore, mReader); cell.load (mStore, mReader);
} }
@ -261,3 +259,15 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name)
// giving up // giving up
return Ptr(); return Ptr();
} }
void MWWorld::Cells::getExteriorPtrs(const std::string &name, std::vector<MWWorld::Ptr> &out)
{
for (std::map<std::pair<int, int>, Ptr::CellStore>::iterator iter = mExteriors.begin();
iter!=mExteriors.end(); ++iter)
{
Ptr ptr = getPtrAndCache (name, iter->second);
if (!ptr.isEmpty())
out.push_back(ptr);
}
}

View file

@ -47,8 +47,15 @@ namespace MWWorld
Ptr getPtr (const std::string& name, CellStore& cellStore, bool searchInContainers = false); Ptr getPtr (const std::string& name, CellStore& cellStore, bool searchInContainers = false);
///< \param searchInContainers Only affect loaded cells. ///< \param searchInContainers Only affect loaded cells.
/// @note name must be lower case
/// @note name must be lower case
Ptr getPtr (const std::string& name); 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<MWWorld::Ptr>& out);
}; };
} }

View file

@ -143,7 +143,7 @@ namespace MWWorld
{ {
if (!iter->mData.getCount()) if (!iter->mData.getCount())
continue; continue;
if (!functor (iter->mRef, iter->mData)) if (!functor (MWWorld::Ptr(&*iter, this)))
return false; return false;
} }
return true; return true;

View file

@ -290,6 +290,8 @@ namespace MWWorld
virtual bool isPersistent (const MWWorld::Ptr& ptr) const; virtual bool isPersistent (const MWWorld::Ptr& ptr) const;
virtual bool isKey (const MWWorld::Ptr& ptr) const { return false; }
virtual Ptr virtual Ptr
copyToCell(const Ptr &ptr, CellStore &cell) const; copyToCell(const Ptr &ptr, CellStore &cell) const;

View file

@ -179,7 +179,7 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor)
// Don't autoEquip lights // Don't autoEquip lights
if (test.getTypeName() == typeid(ESM::Light).name()) if (test.getTypeName() == typeid(ESM::Light).name())
{ {
continue; continue;
} }
int testSkill = MWWorld::Class::get (test).getEquipmentSkill (test); 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]; const EffectParams& params = mPermanentMagicEffectMagnitudes[(**iter).getCellRef().mRefID][i];
float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * params.mRandom; float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * params.mRandom;
magnitude *= params.mMultiplier; magnitude *= params.mMultiplier;
visitor.visit(MWMechanics::EffectKey(*effectIt), (**iter).getClass().getName(**iter), magnitude); visitor.visit(MWMechanics::EffectKey(*effectIt), (**iter).getClass().getName(**iter), "", magnitude);
++i; ++i;
} }

View file

@ -64,7 +64,7 @@ namespace MWWorld
// initialise // initialise
ESM::CellRef& cellRef = mPtr.getCellRef(); ESM::CellRef& cellRef = mPtr.getCellRef();
cellRef.mRefID = name; cellRef.mRefID = Misc::StringUtils::lowerCase(name);
cellRef.mRefnum = -1; cellRef.mRefnum = -1;
cellRef.mScale = 1; cellRef.mScale = 1;
cellRef.mFactIndex = 0; cellRef.mFactIndex = 0;

View file

@ -577,10 +577,28 @@ namespace MWWorld
float oldHeight = iter->first.getRefData().getPosition().pos[2]; 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, Ogre::Vector3 newpos = MovementSolver::move(iter->first, iter->second, mTimeAccum,
world->isFlying(iter->first), world->isFlying(iter->first),
waterlevel, mEngine); waterlevel, mEngine);
if (waterCollision)
mEngine->dynamicsWorld->removeCollisionObject(&object);
float heightDiff = newpos.z - oldHeight; float heightDiff = newpos.z - oldHeight;
if (heightDiff < 0) if (heightDiff < 0)

View file

@ -18,8 +18,11 @@ namespace MWWorld
{ {
Player::Player (const ESM::NPC *player, const MWBase::World& world) Player::Player (const ESM::NPC *player, const MWBase::World& world)
: mCellStore(0), : mCellStore(0),
mLastKnownExteriorPosition(0,0,0),
mAutoMove(false), mAutoMove(false),
mForwardBackward (0) mForwardBackward (0),
mTeleported(false),
mMarkedCell(NULL)
{ {
mPlayer.mBase = player; mPlayer.mBase = player;
mPlayer.mRef.mRefID = "player"; mPlayer.mRef.mRefID = "player";
@ -145,4 +148,27 @@ namespace MWWorld
MWWorld::Ptr ptr = getPlayer(); MWWorld::Ptr ptr = getPlayer();
return MWWorld::Class::get(ptr).getNpcStats(ptr).getDrawState(); 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;
}
} }

View file

@ -6,6 +6,8 @@
#include "../mwmechanics/drawstate.hpp" #include "../mwmechanics/drawstate.hpp"
#include <OgreVector3.h>
namespace ESM namespace ESM
{ {
struct NPC; struct NPC;
@ -28,13 +30,30 @@ namespace MWWorld
MWWorld::CellStore *mCellStore; MWWorld::CellStore *mCellStore;
std::string mSign; std::string mSign;
Ogre::Vector3 mLastKnownExteriorPosition;
ESM::Position mMarkedPosition;
// If no position was marked, this is NULL
CellStore* mMarkedCell;
bool mAutoMove; bool mAutoMove;
int mForwardBackward; int mForwardBackward;
bool mTeleported;
public: public:
Player(const ESM::NPC *player, const MWBase::World& world); 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 set (const ESM::NPC *player);
void setCell (MWWorld::CellStore *cellStore); void setCell (MWWorld::CellStore *cellStore);
@ -64,6 +83,9 @@ namespace MWWorld
void yaw(float yaw); void yaw(float yaw);
void pitch(float pitch); void pitch(float pitch);
void roll(float roll); void roll(float roll);
bool wasTeleported() const;
void setTeleported(bool teleported);
}; };
} }
#endif #endif

View file

@ -195,7 +195,7 @@ void WeatherManager::setWeather(const String& weather, bool instant)
} }
mNextWeather = weather; mNextWeather = weather;
mRemainingTransitionTime = mWeatherSettings[mCurrentWeather].mTransitionDelta * 24.f * 3600; mRemainingTransitionTime = mWeatherSettings[mCurrentWeather].mTransitionDelta * 24.f * 3600.f;
} }
mFirstUpdate = false; mFirstUpdate = false;
} }
@ -324,7 +324,8 @@ void WeatherManager::update(float duration)
mWeatherUpdateTime -= timePassed; 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) if (!exterior)
{ {
mRendering->sunDisable(false); mRendering->sunDisable(false);
@ -334,32 +335,7 @@ void WeatherManager::update(float duration)
return; return;
} }
// Exterior switchToNextWeather(false);
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<ESM::Region>().search (regionstr);
if (region != 0)
{
weatherType = nextWeather(region);
}
}
setWeather(weatherType, false);
}
if (mNextWeather != "") if (mNextWeather != "")
{ {
@ -708,7 +684,43 @@ float WeatherManager::getWindSpeed() const
return mWindSpeed; 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<ESM::Region>().search (regionstr);
if (region != 0)
{
weatherType = nextWeather(region);
}
}
setWeather(weatherType, instantly);
}
}
} }

View file

@ -128,6 +128,7 @@ namespace MWWorld
* @param ID of the weather setting to shift to * @param ID of the weather setting to shift to
*/ */
void changeWeather(const std::string& region, const unsigned int id); void changeWeather(const std::string& region, const unsigned int id);
void switchToNextWeather(bool instantly = true);
/** /**
* Per-frame update * Per-frame update
@ -152,7 +153,8 @@ namespace MWWorld
void modRegion(const std::string &regionid, const std::vector<char> &chances); void modRegion(const std::string &regionid, const std::vector<char> &chances);
bool isNight() const; /// @see World::isDark
bool isDark() const;
private: private:
float mHour; float mHour;

View file

@ -39,6 +39,7 @@
#include "cellfunctors.hpp" #include "cellfunctors.hpp"
#include "containerstore.hpp" #include "containerstore.hpp"
#include "inventorystore.hpp" #include "inventorystore.hpp"
#include "actionteleport.hpp"
#include "contentloader.hpp" #include "contentloader.hpp"
#include "esmloader.hpp" #include "esmloader.hpp"
@ -498,12 +499,14 @@ namespace MWWorld
if (!ptr.isEmpty()) if (!ptr.isEmpty())
return ptr; return ptr;
std::string lowerCaseName = Misc::StringUtils::lowerCase(name);
// active cells // active cells
for (Scene::CellStoreCollection::const_iterator iter (mWorldScene->getActiveCells().begin()); for (Scene::CellStoreCollection::const_iterator iter (mWorldScene->getActiveCells().begin());
iter!=mWorldScene->getActiveCells().end(); ++iter) iter!=mWorldScene->getActiveCells().end(); ++iter)
{ {
Ptr::CellStore* cellstore = *iter; Ptr::CellStore* cellstore = *iter;
Ptr ptr = mCells.getPtr (name, *cellstore, true); Ptr ptr = mCells.getPtr (lowerCaseName, *cellstore, true);
if (!ptr.isEmpty()) if (!ptr.isEmpty())
return ptr; return ptr;
@ -511,7 +514,7 @@ namespace MWWorld
if (!activeOnly) if (!activeOnly)
{ {
Ptr ptr = mCells.getPtr (name); Ptr ptr = mCells.getPtr (lowerCaseName);
if (!ptr.isEmpty()) if (!ptr.isEmpty())
return ptr; return ptr;
@ -793,32 +796,9 @@ namespace MWWorld
MWWorld::Ptr World::getFacedObject() MWWorld::Ptr World::getFacedObject()
{ {
std::pair<float, std::string> result; if (mFacedHandle.empty())
return MWWorld::Ptr();
if (!mRendering->occlusionQuerySupported()) return searchPtrViaHandle(mFacedHandle);
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;
} }
std::pair<MWWorld::Ptr,Ogre::Vector3> World::getHitContact(const MWWorld::Ptr &ptr, float distance) std::pair<MWWorld::Ptr,Ogre::Vector3> World::getHitContact(const MWWorld::Ptr &ptr, float distance)
@ -931,7 +911,7 @@ namespace MWWorld
ptr.getRefData().setCount(0); ptr.getRefData().setCount(0);
} }
} }
if (haveToMove) if (haveToMove && ptr.getRefData().getBaseNode())
{ {
mRendering->moveObject(ptr, vec); mRendering->moveObject(ptr, vec);
mPhysics->moveObject (ptr); mPhysics->moveObject (ptr);
@ -1060,7 +1040,7 @@ namespace MWWorld
void World::adjustPosition(const Ptr &ptr) 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()) if(!ptr.getRefData().getBaseNode())
{ {
@ -1287,7 +1267,7 @@ namespace MWWorld
mRendering->playVideo(mFallback.getFallbackString("Movies_New_Game"), true); mRendering->playVideo(mFallback.getFallbackString("Movies_New_Game"), true);
} }
mWeatherManager->update (duration); updateWeather(duration);
mWorldScene->update (duration, paused); mWorldScene->update (duration, paused);
@ -1297,6 +1277,12 @@ namespace MWWorld
performUpdateSceneQueries (); performUpdateSceneQueries ();
updateWindowManager (); updateWindowManager ();
if (mPlayer->getPlayer().getCell()->isExterior())
{
ESM::Position pos = mPlayer->getPlayer().getRefData().getPosition();
mPlayer->setLastKnownExteriorPosition(Ogre::Vector3(pos.pos));
}
} }
void World::updateWindowManager () void World::updateWindowManager ()
@ -1337,6 +1323,14 @@ namespace MWWorld
void World::updateFacedHandle () 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 // send new query
// figure out which object we want to test against // figure out which object we want to test against
std::vector < std::pair < float, std::string > > results; std::vector < std::pair < float, std::string > > results;
@ -1344,13 +1338,13 @@ namespace MWWorld
{ {
float x, y; float x, y;
MWBase::Environment::get().getWindowManager()->getMousePosition(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()) if (MWBase::Environment::get().getWindowManager()->isConsoleMode())
results = mPhysics->getFacedHandles(x, y, getMaxActivationDistance ()*50); results = mPhysics->getFacedHandles(x, y, getMaxActivationDistance ()*50);
} }
else else
{ {
results = mPhysics->getFacedHandles(getMaxActivationDistance ()); results = mPhysics->getFacedHandles(activationDistance);
} }
// ignore the player and other things we're not interested in // ignore the player and other things we're not interested in
@ -1433,10 +1427,8 @@ namespace MWWorld
return d; return d;
} }
std::vector<World::DoorMarker> World::getDoorMarkers (CellStore* cell) void World::getDoorMarkers (CellStore* cell, std::vector<World::DoorMarker>& out)
{ {
std::vector<World::DoorMarker> result;
MWWorld::CellRefList<ESM::Door>& doors = cell->mDoors; MWWorld::CellRefList<ESM::Door>& doors = cell->mDoors;
CellRefList<ESM::Door>::List& refList = doors.mList; CellRefList<ESM::Door>::List& refList = doors.mList;
for (CellRefList<ESM::Door>::List::iterator it = refList.begin(); it != refList.end(); ++it) for (CellRefList<ESM::Door>::List::iterator it = refList.begin(); it != refList.end(); ++it)
@ -1452,11 +1444,9 @@ namespace MWWorld
newMarker.x = pos.pos[0]; newMarker.x = pos.pos[0];
newMarker.y = pos.pos[1]; 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) void World::getInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y)
@ -1579,7 +1569,7 @@ namespace MWWorld
pos.rot[1] = 0; pos.rot[1] = 0;
Ogre::Vector3 orig = 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); Ogre::Vector3 dir = Ogre::Vector3(0, 0, -1);
float len = (pos.pos[2] >= 0) ? pos.pos[2] : -pos.pos[2]; float len = (pos.pos[2] >= 0) ? pos.pos[2] : -pos.pos[2];
@ -1616,7 +1606,8 @@ namespace MWWorld
return false; return false;
const MWMechanics::CreatureStats &stats = ptr.getClass().getCreatureStats(ptr); 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; return true;
// TODO: Check if flying creature // TODO: Check if flying creature
@ -1635,7 +1626,7 @@ namespace MWWorld
return false; return false;
const MWMechanics::CreatureStats &stats = ptr.getClass().getCreatureStats(ptr); 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 true;
return false; return false;
@ -1820,9 +1811,9 @@ namespace MWWorld
{ {
std::vector<std::string> mHandles; std::vector<std::string> 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) if (handle)
mHandles.push_back(handle->getName()); mHandles.push_back(handle->getName());
return true; return true;
@ -1931,17 +1922,8 @@ namespace MWWorld
int y = ext->getGridY(); int y = ext->getGridY();
indexToPosition(x, y, pos.pos[0], pos.pos[1], true); indexToPosition(x, y, pos.pos[0], pos.pos[1], true);
ESM::Land* land = getStore().get<ESM::Land>().search(x, y); // Note: Z pos will be adjusted by adjustPosition later
if (land) { pos.pos[2] = 0;
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;
}
return true; return true;
} }
@ -1985,11 +1967,11 @@ namespace MWWorld
{ {
InventoryStore &inv = actor.getClass().getInventoryStore(actor); 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 else
{ {
actor.getClass().getContainerStore(actor).remove("WerewolfRobe", 1, actor); actor.getClass().getContainerStore(actor).remove("werewolfrobe", 1, actor);
} }
if(actor.getRefData().getHandle() == "player") if(actor.getRefData().getHandle() == "player")
@ -2018,7 +2000,7 @@ namespace MWWorld
const Store<ESM::GameSetting> &gmst = getStore().get<ESM::GameSetting>(); const Store<ESM::GameSetting> &gmst = getStore().get<ESM::GameSetting>();
MWMechanics::NpcStats &stats = Class::get(actor).getNpcStats(actor); 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() bool World::getGodModeState()
@ -2286,8 +2268,153 @@ namespace MWWorld
actor.getClass().getInventoryStore(actor).purgeEffect(ESM::MagicEffect::Invisibility); 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<ESM::Door>& doors = cell->mDoors;
CellRefList<ESM::Door>::List& refList = doors.mList;
// Check if any door in the cell leads to an exterior directly
for (CellRefList<ESM::Door>::List::iterator it = refList.begin(); it != refList.end(); ++it)
{
MWWorld::LiveCellRef<ESM::Door>& 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<MWWorld::Ptr> markers;
mCells.getExteriorPtrs(id, markers);
for (std::vector<MWWorld::Ptr>::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<Ptr>& out, Ptr detector, World::DetectionType type, float squaredDist)
: mOut(out), mDetector(detector), mType(type), mSquaredDist(squaredDist)
{
}
std::vector<Ptr>& 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<Ptr> &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;
} }
} }

Some files were not shown because too many files have changed in this diff Show more