1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-01-20 17:53:53 +00:00

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
CMakeCache.txt
cmake_install.cmake
CMakeLists.txt.user
Makefile
makefile
build
@ -22,6 +21,8 @@ Doxygen
.project
.settings
.directory
## qt-creator
CMakeLists.txt.user*
## resources
data

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 libopenal-dev libmpg123-dev libsndfile1-dev
- sudo apt-get install -qq libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev libpostproc-dev
- sudo apt-get install -qq libbullet-dev libogre-1.8-dev libmygui-dev libsdl2-dev libunshield-dev
- sudo apt-get install -qq libbullet-dev libogre-1.9-dev libmygui-dev libsdl2-dev libunshield-dev
- sudo mkdir /usr/src/gtest/build
- cd /usr/src/gtest/build
- sudo cmake .. -DBUILD_SHARED_LIBS=1

View file

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

View file

@ -137,8 +137,3 @@ if (BUILD_WITH_CODE_COVERAGE)
target_link_libraries(omwlauncher gcov)
endif()
# Workaround for binutil => 2.23 problem when linking, should be fixed eventually upstream
if (UNIX AND NOT APPLE)
target_link_libraries(omwlauncher dl Xt)
endif()

View file

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

View file

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

View file

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

View file

@ -130,7 +130,7 @@ namespace MWBase
virtual Ogre::Vector2 getNorthVector (MWWorld::CellStore* cell) = 0;
///< get north vector (OGRE coordinates) for given interior cell
virtual std::vector<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
virtual void getInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y) = 0;
@ -428,7 +428,28 @@ namespace MWBase
virtual void breakInvisibility (const MWWorld::Ptr& actor) = 0;
virtual bool isNight() const = 0;
// Are we in an exterior or pseudo-exterior cell and it's night?
virtual bool isDark() const = 0;
virtual bool findInteriorPositionInWorldSpace(MWWorld::CellStore* cell, Ogre::Vector3& result) = 0;
/// Teleports \a ptr to the reference of \a id (e.g. DivineMarker, PrisonMarker, TempleMarker)
/// closest to \a worldPos.
/// @note id must be lower case
virtual void teleportToClosestMarker (const MWWorld::Ptr& ptr,
const std::string& id, Ogre::Vector3 worldPos) = 0;
enum DetectionType
{
Detect_Enchantment,
Detect_Key,
Detect_Creature
};
/// List all references (filtered by \a type) detected by \a ptr. The range
/// is determined by the current magnitude of the "Detect X" magic effect belonging to \a type.
/// @note This also works for references in containers.
virtual void listDetectedReferences (const MWWorld::Ptr& ptr, std::vector<MWWorld::Ptr>& out,
DetectionType type) = 0;
};
}

View file

@ -291,14 +291,16 @@ namespace MWClass
{
MWWorld::InventoryStore& invStore = MWWorld::Class::get(npc).getInventoryStore(npc);
if (ptr.getCellRef().mCharge == 0)
return std::make_pair(0, "#{sInventoryMessage1}");
// slots that this item can be equipped in
std::pair<std::vector<int>, bool> slots_ = MWWorld::Class::get(ptr).getEquipmentSlots(ptr);
std::string npcRace = npc.get<ESM::NPC>()->mBase->mRace;
if (slots_.first.empty())
return std::make_pair(0, "");
for (std::vector<int>::const_iterator slot=slots_.first.begin();
slot!=slots_.first.end(); ++slot)
{
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);
@ -306,29 +308,19 @@ namespace MWClass
{
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}");
}
}
}
}
for (std::vector<int>::const_iterator slot=slots_.first.begin();
slot!=slots_.first.end(); ++slot)
{
// If equipping a shield, check if there's a twohanded weapon conflicting with it
if(*slot == MWWorld::InventoryStore::Slot_CarriedLeft)
{
MWWorld::ContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);

View file

@ -235,11 +235,10 @@ namespace MWClass
// slots that this item can be equipped in
std::pair<std::vector<int>, bool> slots_ = MWWorld::Class::get(ptr).getEquipmentSlots(ptr);
std::string npcRace = npc.get<ESM::NPC>()->mBase->mRace;
if (slots_.first.empty())
return std::make_pair(0, "");
for (std::vector<int>::const_iterator slot=slots_.first.begin();
slot!=slots_.first.end(); ++slot)
{
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);
@ -247,25 +246,15 @@ namespace MWClass
{
std::vector<ESM::PartReference> parts = ptr.get<ESM::Clothing>()->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, "#{sNotifyMessage15}");
}
}
}
}
return std::make_pair (1, "");
}

View file

@ -242,7 +242,11 @@ namespace MWClass
item.get<ESM::Miscellaneous>();
return !ref->mBase->mData.mIsKey && (npcServices & ESM::NPC::Misc)
&& !Misc::StringUtils::ciEqual(item.getCellRef().mRefID, "gold_001");
&& !Misc::StringUtils::ciEqual(item.getCellRef().mRefID, "gold_001")
&& !Misc::StringUtils::ciEqual(item.getCellRef().mRefID, "gold_005")
&& !Misc::StringUtils::ciEqual(item.getCellRef().mRefID, "gold_010")
&& !Misc::StringUtils::ciEqual(item.getCellRef().mRefID, "gold_025")
&& !Misc::StringUtils::ciEqual(item.getCellRef().mRefID, "gold_100");
}
float Miscellaneous::getWeight(const MWWorld::Ptr &ptr) const
@ -252,4 +256,11 @@ namespace MWClass
return ref->mBase->mData.mWeight;
}
bool Miscellaneous::isKey(const MWWorld::Ptr &ptr) const
{
MWWorld::LiveCellRef<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 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/movement.hpp"
#include "../mwmechanics/spellcasting.hpp"
#include "../mwmechanics/disease.hpp"
#include "../mwworld/ptr.hpp"
#include "../mwworld/actiontalk.hpp"
@ -210,7 +211,7 @@ namespace
+ 5
+ raceBonus
+ 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::Luck).getModified() / 10.0f);
hitchance *= stats.getFatigueTerm();
hitchance += mageffects.get(MWMechanics::EffectKey(ESM::MagicEffect::FortifyAttack)).mMagnitude -
mageffects.get(MWMechanics::EffectKey(ESM::MagicEffect::Blind)).mMagnitude;
hitchance += mageffects.get(ESM::MagicEffect::FortifyAttack).mMagnitude -
mageffects.get(ESM::MagicEffect::Blind).mMagnitude;
hitchance -= otherstats.getEvasion();
if((::rand()/(RAND_MAX+1.0)) > hitchance/100.0f)
@ -493,6 +494,11 @@ namespace MWClass
if (!MWBase::Environment::get().getWorld()->getGodModeState())
weapon.getCellRef().mCharge -= std::min(std::max(1,
(int)(damage * gmst.find("fWeaponDamageMult")->getFloat())), weapon.getCellRef().mCharge);
// Weapon broken? unequip it
if (weapon.getCellRef().mCharge == 0)
weapon = *inv.unequipItem(weapon, ptr);
}
healthdmg = true;
}
@ -512,7 +518,8 @@ namespace MWClass
MWBase::Environment::get().getSoundManager()->playSound3D(victim, "critical damage", 1.0f, 1.0f);
}
healthdmg = (otherstats.getFatigue().getCurrent() < 1.0f);
healthdmg = (otherstats.getFatigue().getCurrent() < 1.0f)
|| (otherstats.getMagicEffects().get(ESM::MagicEffect::Paralyze).mMagnitude > 0);
if(stats.isWerewolf())
{
healthdmg = true;
@ -598,6 +605,9 @@ namespace MWClass
ptr.getRefData().getLocals().setVarByInt(script, "onpchitme", 1);
}
if (!attacker.isEmpty())
MWMechanics::diseaseContact(ptr, attacker);
if(damage > 0.0f)
{
// 'ptr' is losing health. Play a 'hit' voiced dialog entry if not already saying
@ -645,6 +655,11 @@ namespace MWClass
armorref.mCharge = armor.get<ESM::Armor>()->mBase->mData.mHealth;
armorref.mCharge -= std::min(std::max(1, (int)damagediff),
armorref.mCharge);
// Armor broken? unequip it
if (armorref.mCharge == 0)
inv.unequipItem(armor, ptr);
switch(get(armor).getEquipmentSkill(armor))
{
case ESM::Skill::LightArmor:
@ -839,10 +854,11 @@ namespace MWClass
float moveSpeed;
if(normalizedEncumbrance >= 1.0f)
moveSpeed = 0.0f;
else if(mageffects.get(MWMechanics::EffectKey(10/*levitate*/)).mMagnitude > 0)
else if(mageffects.get(ESM::MagicEffect::Levitate).mMagnitude > 0 &&
world->isLevitationEnabled())
{
float flySpeed = 0.01f*(npcdata->mNpcStats.getAttribute(ESM::Attribute::Speed).getModified() +
mageffects.get(MWMechanics::EffectKey(10/*levitate*/)).mMagnitude);
mageffects.get(ESM::MagicEffect::Levitate).mMagnitude);
flySpeed = fMinFlySpeed->getFloat() + flySpeed*(fMaxFlySpeed->getFloat() - fMinFlySpeed->getFloat());
flySpeed *= 1.0f - fEncumberedMoveEffect->getFloat() * normalizedEncumbrance;
flySpeed = std::max(0.0f, flySpeed);
@ -853,7 +869,7 @@ namespace MWClass
float swimSpeed = walkSpeed;
if(Npc::getStance(ptr, Run, false))
swimSpeed = runSpeed;
swimSpeed *= 1.0f + 0.01f * mageffects.get(MWMechanics::EffectKey(1/*swift swim*/)).mMagnitude;
swimSpeed *= 1.0f + 0.01f * mageffects.get(ESM::MagicEffect::SwiftSwim).mMagnitude;
swimSpeed *= fSwimRunBase->getFloat() + 0.01f*npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified()*
fSwimRunAthleticsMult->getFloat();
moveSpeed = swimSpeed;
@ -887,7 +903,7 @@ namespace MWClass
float x = fJumpAcrobaticsBase->getFloat() +
std::pow(a / 15.0f, fJumpAcroMultiplier->getFloat());
x += 3.0f * b * fJumpAcroMultiplier->getFloat();
x += mageffects.get(MWMechanics::EffectKey(ESM::MagicEffect::Jump)).mMagnitude * 64;
x += mageffects.get(ESM::MagicEffect::Jump).mMagnitude * 64;
x *= encumbranceTerm;
if(Npc::getStance(ptr, Run, false))
@ -910,7 +926,7 @@ namespace MWClass
{
const float acrobaticsSkill = MWWorld::Class::get(ptr).getNpcStats (ptr).getSkill(ESM::Skill::Acrobatics).getModified();
const CustomData *npcdata = static_cast<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 fallAcroMult = gmst.find("fFallAcroMult")->getFloat();
const float fallDistanceBase = gmst.find("fFallDistanceBase")->getFloat();
@ -1015,8 +1031,8 @@ namespace MWClass
if(!stats.isWerewolf())
{
weight = getContainerStore(ptr).getWeight();
weight -= stats.getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::Feather)).mMagnitude;
weight += stats.getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::Burden)).mMagnitude;
weight -= stats.getMagicEffects().get(ESM::MagicEffect::Feather).mMagnitude;
weight += stats.getMagicEffects().get(ESM::MagicEffect::Burden).mMagnitude;
if(weight < 0.0f)
weight = 0.0f;
}

View file

@ -388,14 +388,14 @@ namespace MWClass
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);
// equip the item in the first free slot
for (std::vector<int>::const_iterator slot=slots_.first.begin();
slot!=slots_.first.end(); ++slot)
{
if(*slot == MWWorld::InventoryStore::Slot_CarriedRight)
{
if (slots_.first.empty())
return std::make_pair (0, "");
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 ||
@ -406,11 +406,9 @@ namespace MWClass
{
return std::make_pair (2, "");
}
}
return std::make_pair(1, "");
}
return std::make_pair (0, "");
}
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);
@ -262,12 +262,9 @@ namespace MWDialogue
MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow();
std::vector<const ESM::DialInfo *> infos = filter.list (dialogue, true, true);
if (!infos.empty())
const ESM::DialInfo* info = filter.search(dialogue, true);
if (info)
{
const ESM::DialInfo* info = infos[randomResponse ? std::rand() % infos.size() : 0];
parseText (info->mResponse);
std::string title;
@ -509,7 +506,7 @@ namespace MWDialogue
text = "Bribe";
}
executeTopic (text + (success ? " Success" : " Fail"), true);
executeTopic (text + (success ? " Success" : " Fail"));
}
int DialogueManager::getTemporaryDispositionChange() const

View file

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

View file

@ -5,6 +5,7 @@
#include "../mwbase/world.hpp"
#include "../mwbase/journal.hpp"
#include "../mwbase/mechanicsmanager.hpp"
#include "../mwbase/dialoguemanager.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/player.hpp"
@ -133,7 +134,8 @@ bool MWDialogue::Filter::testDisposition (const ESM::DialInfo& info, bool invert
if (isCreature)
return true;
int actorDisposition = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mActor);
int actorDisposition = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mActor)
+ MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange();
// For service refusal, the disposition check is inverted. However, a value of 0 still means "always succeed".
return invert ? (info.mData.mDisposition == 0 || actorDisposition < info.mData.mDisposition)
: (actorDisposition >= info.mData.mDisposition);

View file

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

View file

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

View file

@ -75,7 +75,7 @@ namespace MWGui
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)
{
@ -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)
mReviewDialog->setSkillValue(parSkill, value);
@ -229,8 +229,8 @@ namespace MWGui
}
{
std::map<int, MWMechanics::Stat<int> > attributes = MWBase::Environment::get().getWindowManager()->getPlayerAttributeValues();
for (std::map<int, MWMechanics::Stat<int> >::iterator it = attributes.begin();
std::map<int, MWMechanics::AttributeValue > attributes = MWBase::Environment::get().getWindowManager()->getPlayerAttributeValues();
for (std::map<int, MWMechanics::AttributeValue >::iterator it = attributes.begin();
it != attributes.end(); ++it)
{
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();
for (std::map<int, MWMechanics::Stat<float> >::iterator it = skills.begin();
std::map<int, MWMechanics::SkillValue > skills = MWBase::Environment::get().getWindowManager()->getPlayerSkillValues();
for (std::map<int, MWMechanics::SkillValue >::iterator it = skills.begin();
it != skills.end(); ++it)
{
mReviewDialog->setSkillValue(static_cast<ESM::Skill::SkillEnum> (it->first), it->second);

View file

@ -31,9 +31,9 @@ namespace MWGui
//Show a dialog
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 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 doRenderUpdate();

View file

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

View file

@ -55,6 +55,8 @@ namespace MWGui
, mWorldMouseOver(false)
, mEnemyHealthTimer(0)
, mIsDrowning(false)
, mWeaponSpellTimer(0.f)
, mDrowningFlashTheta(0.f)
{
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.
// Vanilla likely uses a hack like this since there's no other way to prevent it from
// being shown or taken.
if(item.getCellRef().mRefID == "WerewolfRobe")
if(item.getCellRef().mRefID == "werewolfrobe")
continue;
ItemStack newItem (item, this, item.getRefData().getCount());

View file

@ -163,6 +163,14 @@ namespace MWGui
MWWorld::Ptr object = item.mBase;
int count = item.mCount;
// Bound items may not be moved
if (item.mBase.getCellRef().mRefID.size() > 6
&& item.mBase.getCellRef().mRefID.substr(0,6) == "bound_")
{
MWBase::Environment::get().getWindowManager()->messageBox("#{sBarterDialog12}");
return;
}
if (item.mType == ItemStack::Type_Equipped)
{
MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr);
@ -417,7 +425,7 @@ namespace MWGui
// NOTE: Don't allow users to select WerewolfRobe objects in the inventory. Vanilla
// likely uses a hack like this since there's no other way to prevent it from being
// taken.
if(item.getCellRef().mRefID == "WerewolfRobe")
if(item.getCellRef().mRefID == "werewolfrobe")
return MWWorld::Ptr();
return item;
}

View file

@ -166,7 +166,7 @@ namespace MWGui
// increase attributes
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]));
if (attribute.getBase() >= 100)

View file

@ -103,27 +103,80 @@ namespace MWGui
void LocalMapBase::onMarkerFocused (MyGUI::Widget* w1, MyGUI::Widget* w2)
{
// Workaround to not make the marker visible if it's under fog of war
applyFogOfWar ();
}
void LocalMapBase::onMarkerUnfocused (MyGUI::Widget* w1, MyGUI::Widget* w2)
{
// Workaround to not make the marker visible if it's under fog of war
applyFogOfWar ();
}
MyGUI::IntPoint LocalMapBase::getMarkerPosition(float worldX, float worldY, MarkerPosition& markerPos)
{
MyGUI::IntPoint widgetPos;
// normalized cell coordinates
float nX,nY;
markerPos.interior = mInterior;
if (!mInterior)
{
int cellX, cellY;
MWBase::Environment::get().getWorld()->positionToIndex(worldX, worldY, cellX, cellY);
const int cellSize = 8192;
nX = (worldX - cellSize * cellX) / cellSize;
// Image space is -Y up, cells are Y up
nY = 1 - (worldY - cellSize * cellY) / cellSize;
float cellDx = cellX - mCurX;
float cellDy = cellY - mCurY;
markerPos.cellX = cellX;
markerPos.cellY = cellY;
widgetPos = MyGUI::IntPoint(nX * 512 + (1+cellDx) * 512,
nY * 512 - (cellDy-1) * 512);
}
else
{
int cellX, cellY;
Ogre::Vector2 worldPos (worldX, worldY);
MWBase::Environment::get().getWorld ()->getInteriorMapPosition (worldPos, nX, nY, cellX, cellY);
markerPos.cellX = cellX;
markerPos.cellY = cellY;
widgetPos = MyGUI::IntPoint(nX * 512 + (1+cellX-mCurX) * 512,
nY * 512 + (1+cellY-mCurY) * 512);
}
markerPos.nX = nX;
markerPos.nY = nY;
return widgetPos;
}
void LocalMapBase::setActiveCell(const int x, const int y, bool interior)
{
if (x==mCurX && y==mCurY && mInterior==interior && !mChanged) return; // don't do anything if we're still in the same cell
if (x==mCurX && y==mCurY && mInterior==interior && !mChanged)
return; // don't do anything if we're still in the same cell
mCurX = x;
mCurY = y;
mInterior = interior;
mChanged = false;
// clear all previous markers
for (unsigned int i=0; i< mLocalMap->getChildCount(); ++i)
{
if (mLocalMap->getChildAt(i)->getName ().substr (0, 6) == "Marker")
if (mLocalMap->getChildAt(i)->getName ().substr (0, 4) == "Door")
{
MyGUI::Gui::getInstance ().destroyWidget (mLocalMap->getChildAt(i));
}
}
// Update the map textures
for (int mx=0; mx<3; ++mx)
{
for (int my=0; my<3; ++my)
@ -138,78 +191,57 @@ namespace MWGui
box->setImageTexture(image);
else
box->setImageTexture("black.png");
}
}
MWBase::World* world = MWBase::Environment::get().getWorld();
// 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;
// Retrieve the door markers we want to show
std::vector<MWBase::World::DoorMarker> doors;
if (interior)
cell = MWBase::Environment::get().getWorld ()->getInterior (mPrefix);
{
MWWorld::CellStore* cell = world->getInterior (mPrefix);
world->getDoorMarkers(cell, doors);
}
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 (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;
// 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;
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, "Marker" + boost::lexical_cast<std::string>(counter));
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->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;
// Used by tooltips to not show the tooltip if marker is hidden by fog of war
markerWidget->setUserString("IsMarker", "true");
markerWidget->setUserData(markerPos);
}
updateMarkers();
}
}
mInterior = interior;
mCurX = x;
mCurY = y;
mChanged = false;
// fog of war
applyFogOfWar();
// set the compass texture again, because MyGUI determines sorting of ImageBox widgets
@ -222,6 +254,8 @@ namespace MWGui
void LocalMapBase::setPlayerPos(const float x, const float y)
{
updateMarkers();
if (x == mLastPositionX && y == mLastPositionY)
return;
@ -255,6 +289,88 @@ namespace MWGui
mLastDirectionY = y;
}
void LocalMapBase::addDetectionMarkers(int type)
{
std::vector<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)
@ -319,7 +435,7 @@ namespace MWGui
static int _counter=0;
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->setUserString("ToolTipType", "Layout");
markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine");
@ -385,7 +501,7 @@ namespace MWGui
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");
}
@ -395,6 +511,9 @@ namespace MWGui
}
void MapWindow::globalMapUpdatePlayer ()
{
// For interiors, position is set by WindowManager via setGlobalMapPlayerPosition
if (MWBase::Environment::get().getWorld ()->isCellExterior ())
{
Ogre::Vector3 pos = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedPosition ();
Ogre::Quaternion orient = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedOrientation ();
@ -405,11 +524,6 @@ namespace MWGui
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 ())
{
mPlayerArrowGlobal->setPosition(MyGUI::IntPoint(worldX - 16, worldY - 16));
MyGUI::ISubWidget* main = mPlayerArrowGlobal->getSubWidgetMain();
@ -444,4 +558,19 @@ namespace MWGui
"#{sWorld}");
}
void MapWindow::setGlobalMapPlayerPosition(float worldX, float worldY)
{
float x, y;
mGlobalMapRender->worldPosToImageSpace (worldX, worldY, x, y);
x *= mGlobalMapRender->getWidth();
y *= mGlobalMapRender->getHeight();
mPlayerArrowGlobal->setPosition(MyGUI::IntPoint(x - 16, y - 16));
// set the view offset so that player is in the center
MyGUI::IntSize viewsize = mGlobalMap->getSize();
MyGUI::IntPoint viewoffs(0.5*viewsize.width - x, 0.5*viewsize.height - y);
mGlobalMap->setViewOffset(viewoffs);
}
}

View file

@ -55,9 +55,16 @@ namespace MWGui
void onMarkerFocused(MyGUI::Widget* w1, MyGUI::Widget* w2);
void onMarkerUnfocused(MyGUI::Widget* w1, MyGUI::Widget* w2);
MyGUI::IntPoint getMarkerPosition (float worldX, float worldY, MarkerPosition& markerPos);
virtual void notifyPlayerUpdate() {}
virtual void notifyMapChanged() {}
// Update markers (Detect X effects, Mark/Recall effects)
// Note, door markers handled in setActiveCell
void updateMarkers();
void addDetectionMarkers(int type);
OEngine::GUI::Layout* mLayout;
bool mMapDragAndDrop;
@ -81,6 +88,8 @@ namespace MWGui
void addVisitedLocation(const std::string& name, int x, int y); // adds the marker to the global map
void cellExplored(int x, int y);
void setGlobalMapPlayerPosition (float worldX, float worldY);
virtual void open();
private:

View file

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

View file

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

View file

@ -40,6 +40,14 @@ namespace MWGui
for (size_t i = 0; i<mSourceModel->getItemCount(); ++i)
{
const ItemStack& item = mSourceModel->getItem(i);
// Bound items may not be stolen
if (item.mBase.getCellRef().mRefID.size() > 6
&& item.mBase.getCellRef().mRefID.substr(0,6) == "bound_")
{
continue;
}
if (std::find(mHiddenItems.begin(), mHiddenItems.end(), item) == mHiddenItems.end()
&& item.mType != ItemStack::Type_Equipped)
mItems.push_back(item);

View file

@ -65,7 +65,7 @@ namespace MWGui
getWidget(attribute, std::string("Attribute") + boost::lexical_cast<std::string>(idx));
mAttributeWidgets.insert(std::make_pair(static_cast<int>(ESM::Attribute::sAttributeIds[idx]), attribute));
attribute->setAttributeId(ESM::Attribute::sAttributeIds[idx]);
attribute->setAttributeValue(Widgets::MWAttribute::AttributeValue(0, 0));
attribute->setAttributeValue(Widgets::MWAttribute::AttributeValue());
}
// Setup skills
@ -74,7 +74,7 @@ namespace MWGui
for (int i = 0; i < ESM::Skill::Length; ++i)
{
mSkillValues.insert(std::make_pair(i, MWMechanics::Stat<float>()));
mSkillValues.insert(std::make_pair(i, MWMechanics::SkillValue()));
mSkillWidgetMap.insert(std::make_pair(i, static_cast<MyGUI::TextBox*> (0)));
}
@ -152,7 +152,7 @@ namespace MWGui
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));
if (attr == mAttributeWidgets.end())
@ -161,7 +161,7 @@ namespace MWGui
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;
MyGUI::TextBox* widget = mSkillWidgetMap[skillId];
@ -279,9 +279,9 @@ namespace MWGui
continue;
assert(skillId >= 0 && skillId < ESM::Skill::Length);
const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId];
const MWMechanics::Stat<float> &stat = mSkillValues.find(skillId)->second;
float base = stat.getBase();
float modified = stat.getModified();
const MWMechanics::SkillValue &stat = mSkillValues.find(skillId)->second;
int base = stat.getBase();
int modified = stat.getModified();
std::string state = "normal";
if (modified > base)

View file

@ -38,10 +38,10 @@ namespace MWGui
void setMagicka(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 setSkillValue(ESM::Skill::SkillEnum skillId, const MWMechanics::Stat<float>& value);
void setSkillValue(ESM::Skill::SkillEnum skillId, const MWMechanics::SkillValue& value);
virtual void open();
@ -85,7 +85,7 @@ namespace MWGui
std::map<int, Widgets::MWAttributePtr> mAttributeWidgets;
SkillList mMajorSkills, mMinorSkills, mMiscSkills;
std::map<int, MWMechanics::Stat<float> > mSkillValues;
std::map<int, MWMechanics::SkillValue > mSkillValues;
std::map<int, MyGUI::TextBox*> mSkillWidgetMap;
std::string mName, mRaceId, mBirthSignId;
ESM::Class mKlass;

View file

@ -22,7 +22,8 @@ namespace MWGui
{
void EffectSourceVisitor::visit (MWMechanics::EffectKey key,
const std::string& sourceName, float magnitude, float remainingTime)
const std::string& sourceName, const std::string& casterHandle,
float magnitude, float remainingTime)
{
MagicEffectInfo newEffectSource;
newEffectSource.mKey = key;

View file

@ -43,7 +43,8 @@ namespace MWGui
std::map <int, std::vector<MagicEffectInfo> > mEffectSources;
virtual void visit (MWMechanics::EffectKey key,
const std::string& sourceName, float magnitude, float remainingTime = -1);
const std::string& sourceName, const std::string& casterHandle,
float magnitude, float remainingTime = -1);
};
class SpellIcons

View file

@ -61,7 +61,7 @@ namespace MWGui
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));
}
@ -102,7 +102,7 @@ namespace MWGui
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[] =
{
@ -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;
MyGUI::TextBox* widget = mSkillWidgetMap[(int)parSkill];
@ -358,22 +358,20 @@ namespace MWGui
continue;
assert(skillId >= 0 && skillId < ESM::Skill::Length);
const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId];
const MWMechanics::Stat<float> &stat = mSkillValues.find(skillId)->second;
float base = stat.getBase();
float modified = stat.getModified();
int progressPercent = (modified - float(static_cast<int>(modified))) * 100;
const MWMechanics::SkillValue &stat = mSkillValues.find(skillId)->second;
int base = stat.getBase();
int modified = stat.getModified();
int progressPercent = stat.getProgress() * 100;
const MWWorld::ESMStore &esmStore =
MWBase::Environment::get().getWorld()->getStore();
const ESM::Skill* skill = esmStore.get<ESM::Skill>().find(skillId);
assert(skill);
std::string icon = "icons\\k\\" + ESM::Skill::sIconNames[skillId];
const ESM::Attribute* attr =
esmStore.get<ESM::Attribute>().find(skill->mData.mAttribute);
assert(attr);
std::string state = "normal";
if (modified > base)
@ -484,7 +482,6 @@ namespace MWGui
ESM::RankData rankData = faction->mData.mRankData[it->second+1];
const ESM::Attribute* attr1 = store.get<ESM::Attribute>().find(faction->mData.mAttribute[0]);
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)
+ ", #{" + attr2->mName + "}: " + boost::lexical_cast<std::string>(rankData.mAttribute2);

View file

@ -26,11 +26,11 @@ namespace MWGui
void setPlayerName(const std::string& playerName);
/// Set value for the given ID.
void setValue (const std::string& id, const MWMechanics::Stat<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 std::string& 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 setReputation (int reputation) { if (reputation != mReputation) mChanged = true; this->mReputation = reputation; }
@ -61,7 +61,7 @@ namespace MWGui
MyGUI::ScrollView* mSkillView;
SkillList mMajorSkills, mMinorSkills, mMiscSkills;
std::map<int, MWMechanics::Stat<float> > mSkillValues;
std::map<int, MWMechanics::SkillValue > mSkillValues;
std::map<int, MyGUI::TextBox*> mSkillWidgetMap;
std::map<std::string, MyGUI::Widget*> mFactionWidgetMap;
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))
continue;
// Bound items may not be bought
if (item.mBase.getCellRef().mRefID.size() > 6
&& item.mBase.getCellRef().mRefID.substr(0,6) == "bound_")
{
continue;
}
// don't show equipped items
if(mMerchant.getTypeName() == typeid(ESM::NPC).name())
{

View file

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

View file

@ -178,7 +178,7 @@ namespace MWGui
}
if (mAttributeValueWidget)
{
AttributeValue::Type modified = mValue.getModified(), base = mValue.getBase();
int modified = mValue.getModified(), base = mValue.getBase();
static_cast<MyGUI::TextBox*>(mAttributeValueWidget)->setCaption(boost::lexical_cast<std::string>(modified));
if (modified > base)
mAttributeValueWidget->_setWidgetState("increased");
@ -527,16 +527,11 @@ namespace MWGui
if (mBarTextWidget)
{
if (mValue >= 0 && mMax > 0)
{
std::stringstream out;
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)
{

View file

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

View file

@ -16,6 +16,7 @@
#include "../mwbase/inputmanager.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/player.hpp"
#include "console.hpp"
#include "journalwindow.hpp"
@ -174,11 +175,11 @@ namespace MWGui
MyGUI::InputManager::getInstance().eventChangeKeyFocus += MyGUI::newDelegate(this, &WindowManager::onKeyFocusChanged);
mCursorManager->setEnabled(true);
onCursorChange(MyGUI::PointerManager::getInstance().getDefaultPointer());
SDL_ShowCursor(false);
mCursorManager->setEnabled(true);
// hide mygui's pointer
MyGUI::PointerManager::getInstance().setVisible(false);
}
@ -248,12 +249,12 @@ namespace MWGui
// Setup player stats
for (int i = 0; i < ESM::Attribute::Length; ++i)
{
mPlayerAttributes.insert(std::make_pair(ESM::Attribute::sAttributeIds[i], MWMechanics::Stat<int>()));
mPlayerAttributes.insert(std::make_pair(ESM::Attribute::sAttributeIds[i], MWMechanics::AttributeValue()));
}
for (int i = 0; i < ESM::Skill::Length; ++i)
{
mPlayerSkillValues.insert(std::make_pair(ESM::Skill::sSkillIds[i], MWMechanics::Stat<float>()));
mPlayerSkillValues.insert(std::make_pair(ESM::Skill::sSkillIds[i], MWMechanics::SkillValue()));
}
// Set up visibility
@ -322,6 +323,7 @@ namespace MWGui
delete mSoulgemDialog;
delete mCursorManager;
delete mRecharge;
delete mCompanionWindow;
cleanupGarbage();
@ -542,7 +544,7 @@ namespace MWGui
}
}
void WindowManager::setValue (const std::string& id, const MWMechanics::Stat<int>& value)
void WindowManager::setValue (const std::string& id, const MWMechanics::AttributeValue& value)
{
mStatsWindow->setValue (id, value);
mCharGen->setValue(id, value);
@ -573,7 +575,7 @@ namespace MWGui
}
void WindowManager::setValue (int parSkill, const MWMechanics::Stat<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
/// allow custom skills.
@ -774,6 +776,13 @@ namespace MWGui
mHud->setCellName( cell->mCell->mName );
mMap->setCellPrefix( cell->mCell->mName );
mHud->setCellPrefix( cell->mCell->mName );
Ogre::Vector3 worldPos;
if (!MWBase::Environment::get().getWorld()->findInteriorPositionInWorldSpace(cell, worldPos))
worldPos = MWBase::Environment::get().getWorld()->getPlayer().getLastKnownExteriorPosition();
else
MWBase::Environment::get().getWorld()->getPlayer().setLastKnownExteriorPosition(worldPos);
mMap->setGlobalMapPlayerPosition(worldPos.x, worldPos.y);
}
}
@ -1169,12 +1178,12 @@ namespace MWGui
return mGuiModes.back();
}
std::map<int, MWMechanics::Stat<float> > WindowManager::getPlayerSkillValues()
std::map<int, MWMechanics::SkillValue > WindowManager::getPlayerSkillValues()
{
return mPlayerSkillValues;
}
std::map<int, MWMechanics::Stat<int> > WindowManager::getPlayerAttributeValues()
std::map<int, MWMechanics::AttributeValue > WindowManager::getPlayerAttributeValues()
{
return mPlayerAttributes;
}

View file

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

View file

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

View file

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

View file

@ -37,8 +37,8 @@ namespace MWMechanics
MWWorld::TimeStamp mTimeStamp;
std::string mDisplayName;
// TODO: To handle CASTER_LINKED flag (spell is purged when caster dies),
// we should probably store a handle to the caster here.
// Handle to the caster that that inflicted this spell on us
std::string mCasterHandle;
};
typedef std::multimap<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 effects
/// \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);
/// Remove all active effects
void purgeAll ();
/// Remove all active effects, if roll succeeds (for each effect)
void purgeAll (float chance);
bool isSpellActive (std::string id) const;
///< case insensitive

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
{
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)
{
// magic effects
@ -178,7 +278,7 @@ namespace MWMechanics
{
// the actor is sleeping, restore health and magicka
bool stunted = stats.getMagicEffects ().get(MWMechanics::EffectKey(ESM::MagicEffect::StuntedMagicka)).mMagnitude > 0;
bool stunted = stats.getMagicEffects ().get(ESM::MagicEffect::StuntedMagicka).mMagnitude > 0;
DynamicStat<float> health = stats.getHealth();
health.setCurrent (health.getCurrent() + 0.1 * endurance);
@ -217,7 +317,7 @@ namespace MWMechanics
// attributes
for(int i = 0;i < ESM::Attribute::Length;++i)
{
Stat<int> stat = creatureStats.getAttribute(i);
AttributeValue stat = creatureStats.getAttribute(i);
stat.setModifier(effects.get(EffectKey(ESM::MagicEffect::FortifyAttribute, i)).mMagnitude -
effects.get(EffectKey(ESM::MagicEffect::DrainAttribute, i)).mMagnitude -
effects.get(EffectKey(ESM::MagicEffect::AbsorbAttribute, i)).mMagnitude);
@ -229,18 +329,45 @@ namespace MWMechanics
for(int i = 0;i < 3;++i)
{
DynamicStat<float> stat = creatureStats.getDynamic(i);
stat.setModifier(effects.get(EffectKey(ESM::MagicEffect::FortifyHealth+i)).mMagnitude -
effects.get(EffectKey(ESM::MagicEffect::DrainHealth+i)).mMagnitude);
stat.setModifier(effects.get(ESM::MagicEffect::FortifyHealth+i).mMagnitude -
effects.get(ESM::MagicEffect::DrainHealth+i).mMagnitude);
float currentDiff = creatureStats.getMagicEffects().get(EffectKey(ESM::MagicEffect::RestoreHealth+i)).mMagnitude
- creatureStats.getMagicEffects().get(EffectKey(ESM::MagicEffect::DamageHealth+i)).mMagnitude
- creatureStats.getMagicEffects().get(EffectKey(ESM::MagicEffect::AbsorbHealth+i)).mMagnitude;
float currentDiff = creatureStats.getMagicEffects().get(ESM::MagicEffect::RestoreHealth+i).mMagnitude
- creatureStats.getMagicEffects().get(ESM::MagicEffect::DamageHealth+i).mMagnitude
- creatureStats.getMagicEffects().get(ESM::MagicEffect::AbsorbHealth+i).mMagnitude;
stat.setCurrent(stat.getCurrent() + currentDiff * duration);
creatureStats.setDynamic(i, stat);
}
// Apply disintegration (reduces item health)
float disintegrateWeapon = effects.get(ESM::MagicEffect::DisintegrateWeapon).mMagnitude;
if (disintegrateWeapon > 0)
disintegrateSlot(ptr, MWWorld::InventoryStore::Slot_CarriedRight, disintegrateWeapon*duration);
float disintegrateArmor = effects.get(ESM::MagicEffect::DisintegrateArmor).mMagnitude;
if (disintegrateArmor > 0)
{
// According to UESP
int priorities[] = {
MWWorld::InventoryStore::Slot_CarriedLeft,
MWWorld::InventoryStore::Slot_Cuirass,
MWWorld::InventoryStore::Slot_LeftPauldron,
MWWorld::InventoryStore::Slot_RightPauldron,
MWWorld::InventoryStore::Slot_LeftGauntlet,
MWWorld::InventoryStore::Slot_RightGauntlet,
MWWorld::InventoryStore::Slot_Helmet,
MWWorld::InventoryStore::Slot_Greaves,
MWWorld::InventoryStore::Slot_Boots
};
for (unsigned int i=0; i<sizeof(priorities)/sizeof(int); ++i)
{
if (disintegrateSlot(ptr, priorities[i], disintegrateArmor*duration))
break;
}
}
// Apply damage ticks
int damageEffects[] = {
ESM::MagicEffect::FireDamage, ESM::MagicEffect::ShockDamage, ESM::MagicEffect::FrostDamage, ESM::MagicEffect::Poison,
@ -250,7 +377,7 @@ namespace MWMechanics
DynamicStat<float> health = creatureStats.getHealth();
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)
{
@ -281,30 +408,32 @@ namespace MWMechanics
static std::map<int, std::string> boundItemsMap;
if (boundItemsMap.empty())
{
boundItemsMap[ESM::MagicEffect::BoundBattleAxe] = "battle_axe";
boundItemsMap[ESM::MagicEffect::BoundBoots] = "boots";
boundItemsMap[ESM::MagicEffect::BoundCuirass] = "cuirass";
boundItemsMap[ESM::MagicEffect::BoundDagger] = "dagger";
boundItemsMap[ESM::MagicEffect::BoundGloves] = "gauntlet"; // Note: needs both _left and _right variants, see below
boundItemsMap[ESM::MagicEffect::BoundHelm] = "helm";
boundItemsMap[ESM::MagicEffect::BoundLongbow] = "longbow";
boundItemsMap[ESM::MagicEffect::BoundLongsword] = "longsword";
boundItemsMap[ESM::MagicEffect::BoundMace] = "mace";
boundItemsMap[ESM::MagicEffect::BoundShield] = "shield";
boundItemsMap[ESM::MagicEffect::BoundSpear] = "spear";
boundItemsMap[ESM::MagicEffect::BoundBattleAxe] = "sMagicBoundBattleAxeID";
boundItemsMap[ESM::MagicEffect::BoundBoots] = "sMagicBoundBootsID";
boundItemsMap[ESM::MagicEffect::BoundCuirass] = "sMagicBoundCuirassID";
boundItemsMap[ESM::MagicEffect::BoundDagger] = "sMagicBoundDaggerID";
boundItemsMap[ESM::MagicEffect::BoundGloves] = "sMagicBoundLeftGauntletID"; // Note: needs RightGauntlet variant too (see below)
boundItemsMap[ESM::MagicEffect::BoundHelm] = "sMagicBoundHelmID";
boundItemsMap[ESM::MagicEffect::BoundLongbow] = "sMagicBoundLongbowID";
boundItemsMap[ESM::MagicEffect::BoundLongsword] = "sMagicBoundLongswordID";
boundItemsMap[ESM::MagicEffect::BoundMace] = "sMagicBoundMaceID";
boundItemsMap[ESM::MagicEffect::BoundShield] = "sMagicBoundShieldID";
boundItemsMap[ESM::MagicEffect::BoundSpear] = "sMagicBoundSpearID";
}
for (std::map<int, std::string>::iterator it = boundItemsMap.begin(); it != boundItemsMap.end(); ++it)
{
bool found = creatureStats.mBoundItems.find(it->first) != creatureStats.mBoundItems.end();
int magnitude = creatureStats.getMagicEffects().get(EffectKey(it->first)).mMagnitude;
int magnitude = creatureStats.getMagicEffects().get(it->first).mMagnitude;
if (found != (magnitude > 0))
{
std::string item = "bound_" + it->second;
std::string itemGmst = it->second;
std::string item = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
itemGmst)->getString();
if (it->first == ESM::MagicEffect::BoundGloves)
{
adjustBoundItem(item + "_left", magnitude > 0, ptr);
adjustBoundItem(item + "_right", magnitude > 0, ptr);
adjustBoundItem("sMagicBoundLeftGauntletID", magnitude > 0, ptr);
adjustBoundItem("sMagicBoundRightGauntletID", magnitude > 0, ptr);
}
else
adjustBoundItem(item, magnitude > 0, ptr);
@ -320,32 +449,34 @@ namespace MWMechanics
static std::map<int, std::string> summonMap;
if (summonMap.empty())
{
summonMap[ESM::MagicEffect::SummonAncestralGhost] = "ancestor_ghost_summon";
summonMap[ESM::MagicEffect::SummonBear] = "BM_bear_black_summon";
summonMap[ESM::MagicEffect::SummonBonelord] = "bonelord_summon";
summonMap[ESM::MagicEffect::SummonBonewalker] = "bonewalker_summon";
summonMap[ESM::MagicEffect::SummonBonewolf] = "BM_wolf_bone_summon";
summonMap[ESM::MagicEffect::SummonCenturionSphere] = "centurion_sphere_summon";
summonMap[ESM::MagicEffect::SummonClannfear] = "clannfear_summon";
summonMap[ESM::MagicEffect::SummonDaedroth] = "daedroth_summon";
summonMap[ESM::MagicEffect::SummonDremora] = "dremora_summon";
summonMap[ESM::MagicEffect::SummonFabricant] = "fabricant_summon";
summonMap[ESM::MagicEffect::SummonFlameAtronach] = "atronach_flame_summon";
summonMap[ESM::MagicEffect::SummonFrostAtronach] = "atronach_frost_summon";
summonMap[ESM::MagicEffect::SummonGoldenSaint] = "golden saint_summon";
summonMap[ESM::MagicEffect::SummonGreaterBonewalker] = "bonewalker_greater_summ";
summonMap[ESM::MagicEffect::SummonHunger] = "hunger_summon";
summonMap[ESM::MagicEffect::SummonScamp] = "scamp_summon";
summonMap[ESM::MagicEffect::SummonSkeletalMinion] = "skeleton_summon";
summonMap[ESM::MagicEffect::SummonStormAtronach] = "atronach_storm_summon";
summonMap[ESM::MagicEffect::SummonWingedTwilight] = "winged twilight_summon";
summonMap[ESM::MagicEffect::SummonWolf] = "BM_wolf_grey_summon";
summonMap[ESM::MagicEffect::SummonAncestralGhost] = "sMagicAncestralGhostID";
summonMap[ESM::MagicEffect::SummonBonelord] = "sMagicBonelordID";
summonMap[ESM::MagicEffect::SummonBonewalker] = "sMagicLeastBonewalkerID";
summonMap[ESM::MagicEffect::SummonCenturionSphere] = "sMagicCenturionSphereID";
summonMap[ESM::MagicEffect::SummonClannfear] = "sMagicClannfearID";
summonMap[ESM::MagicEffect::SummonDaedroth] = "sMagicDaedrothID";
summonMap[ESM::MagicEffect::SummonDremora] = "sMagicDremoraID";
summonMap[ESM::MagicEffect::SummonFabricant] = "sMagicFabricantID";
summonMap[ESM::MagicEffect::SummonFlameAtronach] = "sMagicFlameAtronachID";
summonMap[ESM::MagicEffect::SummonFrostAtronach] = "sMagicFrostAtronachID";
summonMap[ESM::MagicEffect::SummonGoldenSaint] = "sMagicGoldenSaintID";
summonMap[ESM::MagicEffect::SummonGreaterBonewalker] = "sMagicGreaterBonewalkerID";
summonMap[ESM::MagicEffect::SummonHunger] = "sMagicHungerID";
summonMap[ESM::MagicEffect::SummonScamp] = "sMagicScampID";
summonMap[ESM::MagicEffect::SummonSkeletalMinion] = "sMagicSkeletalMinionID";
summonMap[ESM::MagicEffect::SummonStormAtronach] = "sMagicStormAtronachID";
summonMap[ESM::MagicEffect::SummonWingedTwilight] = "sMagicWingedTwilightID";
summonMap[ESM::MagicEffect::SummonWolf] = "sMagicCreature01ID";
summonMap[ESM::MagicEffect::SummonBear] = "sMagicCreature02ID";
summonMap[ESM::MagicEffect::SummonBonewolf] = "sMagicCreature03ID";
summonMap[ESM::MagicEffect::SummonCreature04] = "sMagicCreature04ID";
summonMap[ESM::MagicEffect::SummonCreature05] = "sMagicCreature05ID";
}
for (std::map<int, std::string>::iterator it = summonMap.begin(); it != summonMap.end(); ++it)
{
bool found = creatureStats.mSummonedCreatures.find(it->first) != creatureStats.mSummonedCreatures.end();
int magnitude = creatureStats.getMagicEffects().get(EffectKey(it->first)).mMagnitude;
int magnitude = creatureStats.getMagicEffects().get(it->first).mMagnitude;
if (found != (magnitude > 0))
{
if (magnitude > 0)
@ -362,15 +493,20 @@ namespace MWMechanics
ipos.rot[1] = 0;
ipos.rot[2] = 0;
std::string creatureID =
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(it->second)->getString();
if (!creatureID.empty())
{
MWWorld::CellStore* store = ptr.getCell();
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), it->second, 1);
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), creatureID, 1);
ref.getPtr().getCellRef().mPos = ipos;
// TODO: Add AI to follow player and fight for him
creatureStats.mSummonedCreatures.insert(std::make_pair(it->first,
MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),*store,ipos).getRefData().getHandle()));
}
}
else
{
@ -396,7 +532,7 @@ namespace MWMechanics
// skills
for(int i = 0;i < ESM::Skill::Length;++i)
{
Stat<float>& skill = npcStats.getSkill(i);
SkillValue& skill = npcStats.getSkill(i);
skill.setModifier(effects.get(EffectKey(ESM::MagicEffect::FortifySkill, i)).mMagnitude -
effects.get(EffectKey(ESM::MagicEffect::DrainSkill, i)).mMagnitude -
effects.get(EffectKey(ESM::MagicEffect::AbsorbSkill, i)).mMagnitude);
@ -448,36 +584,57 @@ namespace MWMechanics
/**
* Automatically equip NPCs torches at night and unequip them at day
*/
if (!isPlayer && !MWWorld::Class::get (ptr).getCreatureStats (ptr).isHostile())
if (!isPlayer)
{
if (mTorchPtr.isEmpty())
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 (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);
}
else if (heldIter == inventoryStore.end() && !mTorchPtr.isEmpty())
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)
{
heldIter = inventoryStore.add(mTorchPtr, ptr);
inventoryStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, heldIter, ptr);
inventoryStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, torch, ptr);
}
}
}
else
{
if (heldIter != inventoryStore.end() && heldIter->getTypeName() == typeid(ESM::Light).name())
{
inventoryStore.unequipItem(*heldIter, ptr);
inventoryStore.add(*heldIter, ptr);
// At day, unequip lights and auto equip shields or other suitable items
// (Note: autoEquip will ignore lights)
inventoryStore.autoEquip(ptr);
}
}
}
heldIter = inventoryStore.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft);
//If holding a light...
if(heldIter.getType() == MWWorld::ContainerStore::Type_Light)
{
@ -516,6 +673,16 @@ namespace MWMechanics
Actors::Actors() {}
Actors::~Actors()
{
PtrControllerMap::iterator it(mActors.begin());
for (; it != mActors.end(); ++it)
{
delete it->second;
it->second = NULL;
}
}
void Actors::addActor (const MWWorld::Ptr& ptr)
{
// erase previous death events since we are currently only tracking them while in an active cell
@ -609,10 +776,23 @@ namespace MWMechanics
iter->second->kill();
// Apply soultrap
if (iter->first.getTypeName() == typeid(ESM::Creature).name())
{
SoulTrap soulTrap (iter->first);
stats.getActiveSpells().visitEffectSources(soulTrap);
}
// Reset magic effects and recalculate derived effects
// One case where we need this is to make sure bound items are removed upon death
stats.setMagicEffects(MWMechanics::MagicEffects());
calculateCreatureStatModifiers(iter->first, 0);
++mDeathCount[cls.getId(iter->first)];
if(cls.isEssential(iter->first))
MWBase::Environment::get().getWindowManager()->messageBox("#{sKilledEssential}");
}
}
@ -626,9 +806,14 @@ namespace MWMechanics
iter->second->updateContinuousVfx();
for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
{
if (iter->first.getClass().getCreatureStats(iter->first).getMagicEffects().get(
ESM::MagicEffect::Paralyze).mMagnitude > 0)
iter->second->skipAnim();
iter->second->update(duration);
}
}
}
void Actors::restoreDynamicStats()
{
for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter)

View file

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

View file

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

View file

@ -161,6 +161,7 @@ namespace MWMechanics
if(distanceBetweenResult <= mMaxDist * mMaxDist)
{
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
// TODO: use movement settings instead of rotating directly
MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false);
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1;
mMaxDist = 470;

View file

@ -97,6 +97,7 @@ namespace MWMechanics
}
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
// TODO: use movement settings instead of rotating directly
world->rotateObject(actor, 0, 0, zAngle, false);
movement.mPosition[1] = 1;

View file

@ -236,6 +236,7 @@ namespace MWMechanics
if(mWalking)
{
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
// TODO: use movement settings instead of rotating directly
world->rotateObject(actor, 0, 0, zAngle, false);
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1;

View file

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

View file

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

View file

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

View file

@ -12,6 +12,8 @@
#include "../mwworld/class.hpp"
#include "../mwworld/player.hpp"
#include "spellcasting.hpp"
namespace MWMechanics
{
void MechanicsManager::buildPlayer()
@ -123,6 +125,19 @@ namespace MWMechanics
npcStats.getSkill (index).setBase (
npcStats.getSkill (index).getBase() + bonus);
}
if (i==1)
{
// Major skill - add starting spells for this skill if existing
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
MWWorld::Store<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...
int clampedDisposition = std::max(0, std::min(getDerivedDisposition(ptr)
+ MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange(),100));
float a = std::min(playerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100.f);
float a = std::min(playerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100);
float b = std::min(0.1f * playerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f);
float c = std::min(0.2f * playerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f);
float d = std::min(sellerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100.f);
float d = std::min(sellerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100);
float e = std::min(0.1f * sellerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f);
float f = std::min(0.2f * sellerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f);

View file

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

View file

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

View file

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

View file

@ -24,21 +24,13 @@ void Repair::repair(const MWWorld::Ptr &itemToRepair)
MWWorld::LiveCellRef<ESM::Repair> *ref =
mTool.get<ESM::Repair>();
// unstack tool if required
player.getClass().getContainerStore(player).unstack(mTool, player);
// reduce number of uses left
int uses = (mTool.getCellRef().mCharge != -1) ? mTool.getCellRef().mCharge : ref->mBase->mData.mUses;
mTool.getCellRef().mCharge = uses-1;
// unstack tool if required
if (mTool.getRefData().getCount() > 1 && uses == ref->mBase->mData.mUses)
{
MWWorld::ContainerStore& store = MWWorld::Class::get(player).getContainerStore(player);
MWWorld::ContainerStoreIterator it = store.add(mTool, player);
it->getRefData().setCount(mTool.getRefData().getCount()-1);
it->getCellRef().mCharge = -1;
mTool.getRefData().setCount(1);
}
MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player);
MWMechanics::NpcStats& npcStats = MWWorld::Class::get(player).getNpcStats(player);

View file

@ -7,6 +7,8 @@
#include "../mwworld/containerstore.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/actionteleport.hpp"
#include "../mwrender/animation.hpp"
@ -66,6 +68,12 @@ namespace MWMechanics
MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find (
effectIt->mEffectID);
// If player is healing someone, show the target's HP bar
if (caster.getRefData().getHandle() == "player" && target != caster
&& effectIt->mEffectID == ESM::MagicEffect::RestoreHealth
&& target.getClass().isActor())
MWBase::Environment::get().getWindowManager()->setEnemy(target);
float magnitudeMult = 1;
if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful && target.getClass().isActor())
{
@ -133,7 +141,8 @@ namespace MWMechanics
float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * random;
magnitude *= magnitudeMult;
if (target.getClass().isActor() && !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration))
bool hasDuration = !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration);
if (target.getClass().isActor() && hasDuration)
{
ActiveSpells::Effect effect;
effect.mKey = MWMechanics::EffectKey(*effectIt);
@ -152,12 +161,23 @@ namespace MWMechanics
ActiveSpells::Effect effect_ = effect;
effect_.mMagnitude *= -1;
effects.push_back(effect_);
caster.getClass().getCreatureStats(caster).getActiveSpells().addSpell("", true, effects, mSourceName);
caster.getClass().getCreatureStats(caster).getActiveSpells().addSpell("", true,
effects, mSourceName, caster.getRefData().getHandle());
}
}
}
else
applyInstantEffect(target, effectIt->mEffectID, magnitude);
applyInstantEffect(target, EffectKey(*effectIt), magnitude);
// HACK: Damage attribute/skill actually has a duration, even though the actual effect is instant and permanent.
// This was probably just done to have the effect visible in the magic menu for a while
// to notify the player they've been damaged?
if (effectIt->mEffectID == ESM::MagicEffect::DamageAttribute
|| effectIt->mEffectID == ESM::MagicEffect::DamageSkill
|| effectIt->mEffectID == ESM::MagicEffect::RestoreAttribute
|| effectIt->mEffectID == ESM::MagicEffect::RestoreSkill
)
applyInstantEffect(target, EffectKey(*effectIt), magnitude);
if (target.getClass().isActor() || magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)
{
@ -196,11 +216,13 @@ namespace MWMechanics
inflict(caster, target, reflectedEffects, range, true);
if (appliedLastingEffects.size())
target.getClass().getCreatureStats(target).getActiveSpells().addSpell(mId, mStack, appliedLastingEffects, mSourceName);
target.getClass().getCreatureStats(target).getActiveSpells().addSpell(mId, mStack, appliedLastingEffects,
mSourceName, caster.getRefData().getHandle());
}
void CastSpell::applyInstantEffect(const MWWorld::Ptr &target, short effectId, float magnitude)
void CastSpell::applyInstantEffect(const MWWorld::Ptr &target, MWMechanics::EffectKey effect, float magnitude)
{
short effectId = effect.mId;
if (!target.getClass().isActor())
{
if (effectId == ESM::MagicEffect::Lock)
@ -223,6 +245,28 @@ namespace MWMechanics
}
else
{
if (effectId == ESM::MagicEffect::DamageAttribute || effectId == ESM::MagicEffect::RestoreAttribute)
{
int attribute = effect.mArg;
AttributeValue value = target.getClass().getCreatureStats(target).getAttribute(attribute);
if (effectId == ESM::MagicEffect::DamageAttribute)
value.damage(magnitude);
else
value.restore(magnitude);
target.getClass().getCreatureStats(target).setAttribute(attribute, value);
}
else if (effectId == ESM::MagicEffect::DamageSkill || effectId == ESM::MagicEffect::RestoreSkill)
{
if (target.getTypeName() != typeid(ESM::NPC).name())
return;
int skill = effect.mArg;
SkillValue& value = target.getClass().getNpcStats(target).getSkill(skill);
if (effectId == ESM::MagicEffect::DamageSkill)
value.damage(magnitude);
else
value.restore(magnitude);
}
if (effectId == ESM::MagicEffect::CurePoison)
target.getClass().getCreatureStats(target).getActiveSpells().purgeEffect(ESM::MagicEffect::Poison);
else if (effectId == ESM::MagicEffect::CureParalyzation)
@ -234,27 +278,45 @@ namespace MWMechanics
else if (effectId == ESM::MagicEffect::CureCorprusDisease)
target.getClass().getCreatureStats(target).getSpells().purgeCorprusDisease();
else if (effectId == ESM::MagicEffect::Dispel)
target.getClass().getCreatureStats(target).getActiveSpells().purgeAll();
target.getClass().getCreatureStats(target).getActiveSpells().purgeAll(magnitude);
else if (effectId == ESM::MagicEffect::RemoveCurse)
target.getClass().getCreatureStats(target).getSpells().purgeCurses();
else if (effectId == ESM::MagicEffect::DivineIntervention)
if (target.getRefData().getHandle() != "player")
return;
if (!MWBase::Environment::get().getWorld()->isTeleportingEnabled())
return;
Ogre::Vector3 worldPos;
if (!MWBase::Environment::get().getWorld()->findInteriorPositionInWorldSpace(target.getCell(), worldPos))
worldPos = MWBase::Environment::get().getWorld()->getPlayer().getLastKnownExteriorPosition();
if (effectId == ESM::MagicEffect::DivineIntervention)
{
// We need to be able to get the world location of an interior cell before implementing this
// or alternatively, the last known exterior location of the player, which is how vanilla does it.
MWBase::Environment::get().getWorld()->teleportToClosestMarker(target, "divinemarker", worldPos);
}
else if (effectId == ESM::MagicEffect::AlmsiviIntervention)
{
// Same as above
MWBase::Environment::get().getWorld()->teleportToClosestMarker(target, "templemarker", worldPos);
}
else if (effectId == ESM::MagicEffect::Mark)
{
// TODO
MWBase::Environment::get().getWorld()->getPlayer().markPosition(
target.getCell(), target.getRefData().getPosition());
}
else if (effectId == ESM::MagicEffect::Recall)
{
// TODO
MWWorld::CellStore* markedCell = NULL;
ESM::Position markedPosition;
MWBase::Environment::get().getWorld()->getPlayer().getMarkedPosition(markedCell, markedPosition);
if (markedCell)
{
MWWorld::ActionTeleport action(markedCell->isExterior() ? "" : markedCell->mCell->mName,
markedPosition);
action.execute(target);
}
}
}
}
@ -378,6 +440,7 @@ namespace MWMechanics
int roll = std::rand()/ (static_cast<double> (RAND_MAX) + 1) * 100; // [0, 99]
if (!fail && roll >= successChance)
{
if (mCaster.getRefData().getHandle() == "player")
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicSkillFail}");
fail = true;
}

View file

@ -203,7 +203,7 @@ namespace MWMechanics
void inflict (const MWWorld::Ptr& target, const MWWorld::Ptr& caster,
const ESM::EffectList& effects, ESM::RangeType range, bool reflected=false);
void applyInstantEffect (const MWWorld::Ptr& target, short effectId, float magnitude);
void applyInstantEffect (const MWWorld::Ptr& target, MWMechanics::EffectKey effect, float magnitude);
};
}

View file

@ -34,13 +34,14 @@ namespace MWMechanics
random.resize(spell->mEffects.mList.size());
for (unsigned int i=0; i<random.size();++i)
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)
{
TContainer::iterator iter = mSpells.find (spellId);
std::string lower = Misc::StringUtils::lowerCase(spellId);
TContainer::iterator iter = mSpells.find (lower);
if (iter!=mSpells.end())
mSpells.erase (iter);
@ -192,7 +193,7 @@ namespace MWMechanics
effectIt != list.mList.end(); ++effectIt, ++i)
{
float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * it->second[i];
visitor.visit(MWMechanics::EffectKey(*effectIt), spell->mName, magnitude);
visitor.visit(MWMechanics::EffectKey(*effectIt), spell->mName, "", magnitude);
}
}
}

View file

@ -205,6 +205,46 @@ namespace MWMechanics
{
return !(left==right);
}
class AttributeValue
{
int mBase;
int mModifier;
int mDamage;
public:
AttributeValue() : mBase(0), mModifier(0), mDamage(0) {}
int getModified() const { return std::max(0, mBase - mDamage + mModifier); }
int getBase() const { return mBase; }
int getModifier() const { return mModifier; }
void setBase(int base) { mBase = std::max(0, base); }
void setModifier(int mod) { mModifier = mod; }
void damage(int damage) { mDamage += damage; }
void restore(int amount) { mDamage -= std::min(mDamage, amount); }
int getDamage() const { return mDamage; }
};
class SkillValue : public AttributeValue
{
float mProgress;
public:
float getProgress() const { return mProgress; }
void setProgress(float progress) { mProgress = progress; }
};
inline bool operator== (const AttributeValue& left, const AttributeValue& right)
{
return left.getBase() == right.getBase()
&& left.getModifier() == right.getModifier()
&& left.getDamage() == right.getDamage();
}
inline bool operator!= (const AttributeValue& left, const AttributeValue& right)
{
return !(left == right);
}
}
#endif

View file

@ -1224,6 +1224,7 @@ void ObjectAnimation::fillBatch(Ogre::StaticGeometry *sg)
for(;iter != mObjectRoot->mEntities.rend();++iter)
{
Ogre::Node *node = (*iter)->getParentNode();
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)
: mCamera(camera),
mCameraNode(NULL),
mAnimation(NULL),
mFirstPersonView(true),
mPreviewMode(false),
mFreeLook(true),
mHeight(128.f),
mCameraDistance(300.f),
mDistanceAdjusted(false),
mAnimation(NULL),
mNearest(30.f),
mFurthest(800.f),
mIsNearest(false),
mIsFurthest(false),
mHeight(128.f),
mCameraDistance(300.f),
mDistanceAdjusted(false),
mVanityToggleQueued(false),
mViewModeToggleQueued(false)
{
mVanity.enabled = false;
mVanity.allowed = true;
mPreviewCam.pitch = 0.f;
mPreviewCam.yaw = 0.f;
mPreviewCam.offset = 400.f;
mMainCam.pitch = 0.f;
mMainCam.yaw = 0.f;
mMainCam.offset = 400.f;
}
@ -278,6 +280,11 @@ namespace MWRender
}
}
float Camera::getCameraDistance() const
{
return mCamera->getPosition().z;
}
void Camera::setCameraDistance(float dist, bool adjust, bool override)
{
if(mFirstPersonView && !mPreviewMode && !mVanity.enabled)

View file

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

View file

@ -128,7 +128,7 @@ namespace MWRender
InventoryPreview::InventoryPreview(MWWorld::Ptr character)
: CharacterPreview(character, 512, 1024, "CharacterPreview", Ogre::Vector3(0, 65, -180), Ogre::Vector3(0,65,0))
: CharacterPreview(character, 512, 1024, "CharacterPreview", Ogre::Vector3(0, 62, -200), Ogre::Vector3(0, 62, 0))
, mSelectionBuffer(NULL)
{
}

View file

@ -224,13 +224,6 @@ void LocalMap::render(const float x, const float y,
// try loading from memory
tex = TextureManager::getSingleton().getByName(texture);
if (tex.isNull())
{
// try loading from disk
//if (boost::filesystem::exists(texture+".jpg"))
//{
/// \todo
//}
//else
{
// render
tex = TextureManager::getSingleton().createManual(
@ -278,11 +271,8 @@ void LocalMap::render(const float x, const float y,
tex2->getBuffer()->unlock();
mBuffers[texture] = buffer;
}
// save to cache for next time
//rtt->writeContentsToFile("./" + texture + ".jpg");
}
}
mRenderingManager->enableLights(true);
mLight->setVisible(false);
@ -339,8 +329,6 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni
Vector3 playerdirection = mCameraRotNode->convertWorldToLocalOrientation(orientation).yAxis();
Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y);
if (!mInterior)
{
x = std::ceil(pos.x / sSize)-1;

View file

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

View file

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

View file

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

View file

@ -949,9 +949,25 @@ void VideoState::init(const std::string& resourceName)
this->format_ctx->pb = ioCtx;
// Open video file
/// \todo leak here, ffmpeg or valgrind bug ?
///
/// format_ctx->pb->buffer must be freed by hand,
/// if not, valgrind will show memleak, see:
///
/// https://trac.ffmpeg.org/ticket/1357
///
if(!this->format_ctx || avformat_open_input(&this->format_ctx, resourceName.c_str(), NULL, NULL))
{
if (this->format_ctx != NULL)
{
if (this->format_ctx->pb != NULL)
{
av_free(this->format_ctx->pb->buffer);
this->format_ctx->pb->buffer = NULL;
av_free(this->format_ctx->pb);
this->format_ctx->pb = NULL;
}
}
// "Note that a user-supplied AVFormatContext will be freed on failure."
this->format_ctx = NULL;
av_free(ioCtx);
@ -1009,9 +1025,21 @@ void VideoState::deinit()
if(this->format_ctx)
{
AVIOContext *ioContext = this->format_ctx->pb;
///
/// format_ctx->pb->buffer must be freed by hand,
/// if not, valgrind will show memleak, see:
///
/// https://trac.ffmpeg.org/ticket/1357
///
if (this->format_ctx->pb != NULL)
{
av_free(this->format_ctx->pb->buffer);
this->format_ctx->pb->buffer = NULL;
av_free(this->format_ctx->pb);
this->format_ctx->pb = NULL;;
}
avformat_close_input(&this->format_ctx);
av_free(ioContext);
}
}

View file

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

View file

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

View file

@ -127,7 +127,6 @@ op 0x200007e-0x2000084: Enable Controls
op 0x2000085-0x200008b: Disable Controls
op 0x200008c: Unlock
op 0x200008d: Unlock, explicit reference
op 0x200008e: COE
op 0x200008e-0x20000a8: GetSkill
op 0x20000a9-0x20000c3: GetSkill, explicit reference
op 0x20000c4-0x20000de: SetSkill
@ -358,5 +357,17 @@ op 0x2000222: GetLineOfSight
op 0x2000223: GetLineOfSightExplicit
op 0x2000224: ToggleAI
op 0x2000225: ToggleAIExplicit
opcodes 0x2000226-0x3ffffff unused
op 0x2000226: COE
op 0x2000227: Cast
op 0x2000228: Cast, explicit
op 0x2000229: ExplodeSpell
op 0x200022a: ExplodeSpell, explicit
op 0x200022b: RemoveSpellEffects
op 0x200022c: RemoveSpellEffects, explicit
op 0x200022d: RemoveEffects
op 0x200022e: RemoveEffects, explicit
op 0x200022f: Resurrect
op 0x2000230: Resurrect, explicit
op 0x2000231: GetSpellReadied
op 0x2000232: GetSpellReadied, explicit
opcodes 0x2000233-0x3ffffff unused

View file

@ -23,6 +23,7 @@
#include "../mwmechanics/npcstats.hpp"
#include "../mwmechanics/creaturestats.hpp"
#include "../mwmechanics/spellcasting.hpp"
#include "interpretercontext.hpp"
#include "ref.hpp"
@ -464,7 +465,20 @@ namespace MWScript
{
MWWorld::Ptr ptr = R()(runtime);
runtime.push(MWWorld::Class::get(ptr).getNpcStats (ptr).getDrawState () == MWMechanics::DrawState_Weapon);
runtime.push(ptr.getClass().getNpcStats (ptr).getDrawState () == MWMechanics::DrawState_Weapon);
}
};
template <class 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)
{
@ -739,6 +789,8 @@ namespace MWScript
interpreter.installSegment5 (Compiler::Misc::opcodeGetAttackedExplicit, new OpGetAttacked<ExplicitRef>);
interpreter.installSegment5 (Compiler::Misc::opcodeGetWeaponDrawn, new OpGetWeaponDrawn<ImplicitRef>);
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::opcodeGetSpellEffectsExplicit, new OpGetSpellEffects<ExplicitRef>);
interpreter.installSegment5 (Compiler::Misc::opcodeGetCurrentTime, new OpGetCurrentTime);
@ -761,6 +813,10 @@ namespace MWScript
interpreter.installSegment5 (Compiler::Misc::opcodeToggleGodMode, new OpToggleGodMode);
interpreter.installSegment5 (Compiler::Misc::opcodeDisableLevitation, new OpEnableLevitation<false>);
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;
runtime.pop();
MWMechanics::Stat<int> attribute = ptr.getClass().getCreatureStats(ptr).getAttribute(mIndex);
attribute.setModified (value, 0);
MWMechanics::AttributeValue attribute = ptr.getClass().getCreatureStats(ptr).getAttribute(mIndex);
attribute.setBase (value - (attribute.getModified() - attribute.getBase()));
ptr.getClass().getCreatureStats(ptr).setAttribute(mIndex, attribute);
}
};
@ -146,15 +146,11 @@ namespace MWScript
Interpreter::Type_Integer value = runtime[0].mInteger;
runtime.pop();
MWMechanics::Stat<int> attribute = MWWorld::Class::get(ptr)
MWMechanics::AttributeValue attribute = MWWorld::Class::get(ptr)
.getCreatureStats(ptr)
.getAttribute(mIndex);
value +=
attribute.getModified();
attribute
.setModified (value, 0, 100);
attribute.setBase (std::min(100, attribute.getBase() + value));
ptr.getClass().getCreatureStats(ptr).setAttribute(mIndex, attribute);
}
};
@ -346,17 +342,13 @@ namespace MWScript
const ESM::Class& class_ =
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Class>().find (ref->mBase->mClass);
float level = 0;
float progress = std::modf (stats.getSkill (mIndex).getBase(), &level);
float level = stats.getSkill(mIndex).getBase();
float progress = stats.getSkill(mIndex).getProgress();
float modifier = stats.getSkill (mIndex).getModifier();
int newLevel = static_cast<int> (value-modifier);
int newLevel = value - (stats.getSkill(mIndex).getModified() - stats.getSkill(mIndex).getBase());
if (newLevel<0)
newLevel = 0;
else if (newLevel>100)
newLevel = 100;
progress = (progress / stats.getSkillGain (mIndex, class_, -1, level))
* stats.getSkillGain (mIndex, class_, -1, newLevel);
@ -364,8 +356,8 @@ namespace MWScript
if (progress>=1)
progress = 0.999999999;
stats.getSkill (mIndex).set (newLevel + progress);
stats.getSkill (mIndex).setModifier (modifier);
stats.getSkill (mIndex).setBase (newLevel);
stats.getSkill (mIndex).setProgress(progress);
}
};
@ -385,11 +377,10 @@ namespace MWScript
Interpreter::Type_Integer value = runtime[0].mInteger;
runtime.pop();
value += MWWorld::Class::get (ptr).getNpcStats (ptr).getSkill (mIndex).
getModified();
MWMechanics::NpcStats& stats = ptr.getClass().getNpcStats(ptr);
MWWorld::Class::get (ptr).getNpcStats (ptr).getSkill (mIndex).
setModified (value, 0, 100);
stats.getSkill(mIndex).
setBase (std::min(100, stats.getSkill(mIndex).getBase() + value));
}
};
@ -468,6 +459,38 @@ namespace MWScript
}
};
template<class 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>
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)
{
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::opcodeRemoveSpellExplicit,
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::opcodeGetSpellExplicit, new OpGetSpell<ExplicitRef>);

View file

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

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);
if(!mFormatCtx->pb || avformat_open_input(&mFormatCtx, fname.c_str(), NULL, NULL) != 0)
{
if (mFormatCtx->pb != NULL)
{
if (mFormatCtx->pb->buffer != NULL)
{
av_free(mFormatCtx->pb->buffer);
mFormatCtx->pb->buffer = NULL;
}
av_free(mFormatCtx->pb);
mFormatCtx->pb = NULL;
}
avformat_free_context(mFormatCtx);
mFormatCtx = NULL;
fail("Failed to allocate input stream");
@ -195,6 +205,14 @@ void FFmpeg_Decoder::open(const std::string &fname)
}
catch(std::exception &e)
{
if (mFormatCtx->pb->buffer != NULL)
{
av_free(mFormatCtx->pb->buffer);
mFormatCtx->pb->buffer = NULL;
}
av_free(mFormatCtx->pb);
mFormatCtx->pb = NULL;
avformat_close_input(&mFormatCtx);
throw;
}
@ -211,9 +229,22 @@ void FFmpeg_Decoder::close()
if(mFormatCtx)
{
AVIOContext* context = mFormatCtx->pb;
if (mFormatCtx->pb != NULL)
{
// mFormatCtx->pb->buffer must be freed by hand,
// if not, valgrind will show memleak, see:
//
// https://trac.ffmpeg.org/ticket/1357
//
if (mFormatCtx->pb->buffer != NULL)
{
av_free(mFormatCtx->pb->buffer);
mFormatCtx->pb->buffer = NULL;
}
av_free(mFormatCtx->pb);
mFormatCtx->pb = NULL;
}
avformat_close_input(&mFormatCtx);
av_free(context);
}
mDataStream.setNull();

View file

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

View file

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

View file

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

View file

@ -4,7 +4,7 @@
#include <vector>
#include <string>
#include "refdata.hpp"
#include "ptr.hpp"
namespace ESM
{
@ -18,13 +18,13 @@ namespace MWWorld
{
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)
mHandles.push_back (handle);
data.setBaseNode(0);
ptr.getRefData().setBaseNode(0);
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)
{
std::string lowerCase = Misc::StringUtils::lowerCase(name);
if (std::binary_search (cell.mIds.begin(), cell.mIds.end(), lowerCase))
if (std::binary_search (cell.mIds.begin(), cell.mIds.end(), name))
{
cell.load (mStore, mReader);
}
@ -261,3 +259,15 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name)
// giving up
return Ptr();
}
void MWWorld::Cells::getExteriorPtrs(const std::string &name, std::vector<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);
///< \param searchInContainers Only affect loaded cells.
/// @note name must be lower case
/// @note name must be lower case
Ptr getPtr (const std::string& name);
/// Get all Ptrs referencing \a name in exterior cells
/// @note Due to the current implementation of getPtr this only supports one Ptr per cell.
/// @note name must be lower case
void getExteriorPtrs (const std::string& name, std::vector<MWWorld::Ptr>& out);
};
}

View file

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

View file

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

View file

@ -607,7 +607,7 @@ void MWWorld::InventoryStore::visitEffectSources(MWMechanics::EffectSourceVisito
const EffectParams& params = mPermanentMagicEffectMagnitudes[(**iter).getCellRef().mRefID][i];
float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * params.mRandom;
magnitude *= params.mMultiplier;
visitor.visit(MWMechanics::EffectKey(*effectIt), (**iter).getClass().getName(**iter), magnitude);
visitor.visit(MWMechanics::EffectKey(*effectIt), (**iter).getClass().getName(**iter), "", magnitude);
++i;
}

View file

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

View file

@ -577,10 +577,28 @@ namespace MWWorld
float oldHeight = iter->first.getRefData().getPosition().pos[2];
bool waterCollision = false;
if (iter->first.getClass().getCreatureStats(iter->first).getMagicEffects()
.get(ESM::MagicEffect::WaterWalking).mMagnitude
&& cell->hasWater()
&& !world->isUnderwater(iter->first.getCell(),
Ogre::Vector3(iter->first.getRefData().getPosition().pos)))
waterCollision = true;
btStaticPlaneShape planeShape(btVector3(0,0,1), waterlevel);
btCollisionObject object;
object.setCollisionShape(&planeShape);
if (waterCollision)
mEngine->dynamicsWorld->addCollisionObject(&object);
Ogre::Vector3 newpos = MovementSolver::move(iter->first, iter->second, mTimeAccum,
world->isFlying(iter->first),
waterlevel, mEngine);
if (waterCollision)
mEngine->dynamicsWorld->removeCollisionObject(&object);
float heightDiff = newpos.z - oldHeight;
if (heightDiff < 0)

View file

@ -18,8 +18,11 @@ namespace MWWorld
{
Player::Player (const ESM::NPC *player, const MWBase::World& world)
: mCellStore(0),
mLastKnownExteriorPosition(0,0,0),
mAutoMove(false),
mForwardBackward (0)
mForwardBackward (0),
mTeleported(false),
mMarkedCell(NULL)
{
mPlayer.mBase = player;
mPlayer.mRef.mRefID = "player";
@ -145,4 +148,27 @@ namespace MWWorld
MWWorld::Ptr ptr = getPlayer();
return MWWorld::Class::get(ptr).getNpcStats(ptr).getDrawState();
}
bool Player::wasTeleported() const
{
return mTeleported;
}
void Player::setTeleported(bool teleported)
{
mTeleported = teleported;
}
void Player::markPosition(CellStore *markedCell, ESM::Position markedPosition)
{
mMarkedCell = markedCell;
mMarkedPosition = markedPosition;
}
void Player::getMarkedPosition(CellStore*& markedCell, ESM::Position &markedPosition) const
{
markedCell = mMarkedCell;
if (mMarkedCell)
markedPosition = mMarkedPosition;
}
}

View file

@ -6,6 +6,8 @@
#include "../mwmechanics/drawstate.hpp"
#include <OgreVector3.h>
namespace ESM
{
struct NPC;
@ -28,13 +30,30 @@ namespace MWWorld
MWWorld::CellStore *mCellStore;
std::string mSign;
Ogre::Vector3 mLastKnownExteriorPosition;
ESM::Position mMarkedPosition;
// If no position was marked, this is NULL
CellStore* mMarkedCell;
bool mAutoMove;
int mForwardBackward;
bool mTeleported;
public:
Player(const ESM::NPC *player, const MWBase::World& world);
// For mark/recall magic effects
void markPosition (CellStore* markedCell, ESM::Position markedPosition);
void getMarkedPosition (CellStore*& markedCell, ESM::Position& markedPosition) const;
/// Interiors can not always be mapped to a world position. However
/// world position is still required for divine / almsivi magic effects
/// and the player arrow on the global map.
/// TODO: This should be stored in the savegame, too.
void setLastKnownExteriorPosition (const Ogre::Vector3& position) { mLastKnownExteriorPosition = position; }
Ogre::Vector3 getLastKnownExteriorPosition() const { return mLastKnownExteriorPosition; }
void set (const ESM::NPC *player);
void setCell (MWWorld::CellStore *cellStore);
@ -64,6 +83,9 @@ namespace MWWorld
void yaw(float yaw);
void pitch(float pitch);
void roll(float roll);
bool wasTeleported() const;
void setTeleported(bool teleported);
};
}
#endif

View file

@ -195,7 +195,7 @@ void WeatherManager::setWeather(const String& weather, bool instant)
}
mNextWeather = weather;
mRemainingTransitionTime = mWeatherSettings[mCurrentWeather].mTransitionDelta * 24.f * 3600;
mRemainingTransitionTime = mWeatherSettings[mCurrentWeather].mTransitionDelta * 24.f * 3600.f;
}
mFirstUpdate = false;
}
@ -324,7 +324,8 @@ void WeatherManager::update(float duration)
mWeatherUpdateTime -= timePassed;
const bool exterior = (MWBase::Environment::get().getWorld()->isCellExterior() || MWBase::Environment::get().getWorld()->isCellQuasiExterior());
MWBase::World* world = MWBase::Environment::get().getWorld();
const bool exterior = (world->isCellExterior() || world->isCellQuasiExterior());
if (!exterior)
{
mRendering->sunDisable(false);
@ -334,32 +335,7 @@ void WeatherManager::update(float duration)
return;
}
// Exterior
std::string regionstr = Misc::StringUtils::lowerCase(MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell()->mCell->mRegion);
if (mWeatherUpdateTime <= 0 || regionstr != mCurrentRegion)
{
mCurrentRegion = regionstr;
mWeatherUpdateTime = mHoursBetweenWeatherChanges * 3600;
std::string weatherType = "clear";
if (mRegionOverrides.find(regionstr) != mRegionOverrides.end())
weatherType = mRegionOverrides[regionstr];
else
{
// get weather probabilities for the current region
const ESM::Region *region =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Region>().search (regionstr);
if (region != 0)
{
weatherType = nextWeather(region);
}
}
setWeather(weatherType, false);
}
switchToNextWeather(false);
if (mNextWeather != "")
{
@ -708,7 +684,43 @@ float WeatherManager::getWindSpeed() const
return mWindSpeed;
}
bool WeatherManager::isNight() const
bool WeatherManager::isDark() const
{
return (mHour < mSunriseTime || mHour > mNightStart - 1);
bool exterior = (MWBase::Environment::get().getWorld()->isCellExterior()
|| MWBase::Environment::get().getWorld()->isCellQuasiExterior());
return exterior && (mHour < mSunriseTime || mHour > mNightStart - 1);
}
void WeatherManager::switchToNextWeather(bool instantly)
{
MWBase::World* world = MWBase::Environment::get().getWorld();
if (world->isCellExterior() || world->isCellQuasiExterior())
{
std::string regionstr = Misc::StringUtils::lowerCase(world->getPlayer().getPlayer().getCell()->mCell->mRegion);
if (mWeatherUpdateTime <= 0 || regionstr != mCurrentRegion)
{
mCurrentRegion = regionstr;
mWeatherUpdateTime = mHoursBetweenWeatherChanges * 3600;
std::string weatherType = "clear";
if (mRegionOverrides.find(regionstr) != mRegionOverrides.end())
{
weatherType = mRegionOverrides[regionstr];
}
else
{
// get weather probabilities for the current region
const ESM::Region *region = world->getStore().get<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
*/
void changeWeather(const std::string& region, const unsigned int id);
void switchToNextWeather(bool instantly = true);
/**
* Per-frame update
@ -152,7 +153,8 @@ namespace MWWorld
void modRegion(const std::string &regionid, const std::vector<char> &chances);
bool isNight() const;
/// @see World::isDark
bool isDark() const;
private:
float mHour;

View file

@ -39,6 +39,7 @@
#include "cellfunctors.hpp"
#include "containerstore.hpp"
#include "inventorystore.hpp"
#include "actionteleport.hpp"
#include "contentloader.hpp"
#include "esmloader.hpp"
@ -498,12 +499,14 @@ namespace MWWorld
if (!ptr.isEmpty())
return ptr;
std::string lowerCaseName = Misc::StringUtils::lowerCase(name);
// active cells
for (Scene::CellStoreCollection::const_iterator iter (mWorldScene->getActiveCells().begin());
iter!=mWorldScene->getActiveCells().end(); ++iter)
{
Ptr::CellStore* cellstore = *iter;
Ptr ptr = mCells.getPtr (name, *cellstore, true);
Ptr ptr = mCells.getPtr (lowerCaseName, *cellstore, true);
if (!ptr.isEmpty())
return ptr;
@ -511,7 +514,7 @@ namespace MWWorld
if (!activeOnly)
{
Ptr ptr = mCells.getPtr (name);
Ptr ptr = mCells.getPtr (lowerCaseName);
if (!ptr.isEmpty())
return ptr;
@ -793,32 +796,9 @@ namespace MWWorld
MWWorld::Ptr World::getFacedObject()
{
std::pair<float, std::string> result;
if (!mRendering->occlusionQuerySupported())
result = mPhysics->getFacedHandle (getMaxActivationDistance ());
else
result = std::make_pair (mFacedDistance, mFacedHandle);
if (result.second.empty())
return MWWorld::Ptr ();
MWWorld::Ptr object = searchPtrViaHandle (result.second);
if (object.isEmpty())
return object;
float ActivationDistance;
if (MWBase::Environment::get().getWindowManager()->isConsoleMode())
ActivationDistance = getObjectActivationDistance ()*50;
else if (object.getTypeName ().find("NPC") != std::string::npos)
ActivationDistance = getNpcActivationDistance ();
else
ActivationDistance = getObjectActivationDistance ();
if (result.first > ActivationDistance)
return MWWorld::Ptr ();
return object;
if (mFacedHandle.empty())
return MWWorld::Ptr();
return searchPtrViaHandle(mFacedHandle);
}
std::pair<MWWorld::Ptr,Ogre::Vector3> World::getHitContact(const MWWorld::Ptr &ptr, float distance)
@ -931,7 +911,7 @@ namespace MWWorld
ptr.getRefData().setCount(0);
}
}
if (haveToMove)
if (haveToMove && ptr.getRefData().getBaseNode())
{
mRendering->moveObject(ptr, vec);
mPhysics->moveObject (ptr);
@ -1060,7 +1040,7 @@ namespace MWWorld
void World::adjustPosition(const Ptr &ptr)
{
Ogre::Vector3 pos (ptr.getRefData().getPosition().pos[0], ptr.getRefData().getPosition().pos[1], ptr.getRefData().getPosition().pos[2]);
Ogre::Vector3 pos (ptr.getRefData().getPosition().pos);
if(!ptr.getRefData().getBaseNode())
{
@ -1287,7 +1267,7 @@ namespace MWWorld
mRendering->playVideo(mFallback.getFallbackString("Movies_New_Game"), true);
}
mWeatherManager->update (duration);
updateWeather(duration);
mWorldScene->update (duration, paused);
@ -1297,6 +1277,12 @@ namespace MWWorld
performUpdateSceneQueries ();
updateWindowManager ();
if (mPlayer->getPlayer().getCell()->isExterior())
{
ESM::Position pos = mPlayer->getPlayer().getRefData().getPosition();
mPlayer->setLastKnownExteriorPosition(Ogre::Vector3(pos.pos));
}
}
void World::updateWindowManager ()
@ -1337,6 +1323,14 @@ namespace MWWorld
void World::updateFacedHandle ()
{
float telekinesisRangeBonus =
mPlayer->getPlayer().getClass().getCreatureStats(mPlayer->getPlayer()).getMagicEffects()
.get(ESM::MagicEffect::Telekinesis).mMagnitude;
telekinesisRangeBonus = feetToGameUnits(telekinesisRangeBonus);
float activationDistance = getMaxActivationDistance() + telekinesisRangeBonus;
activationDistance += mRendering->getCameraDistance();
// send new query
// figure out which object we want to test against
std::vector < std::pair < float, std::string > > results;
@ -1344,13 +1338,13 @@ namespace MWWorld
{
float x, y;
MWBase::Environment::get().getWindowManager()->getMousePosition(x, y);
results = mPhysics->getFacedHandles(x, y, getMaxActivationDistance ());
results = mPhysics->getFacedHandles(x, y, activationDistance);
if (MWBase::Environment::get().getWindowManager()->isConsoleMode())
results = mPhysics->getFacedHandles(x, y, getMaxActivationDistance ()*50);
}
else
{
results = mPhysics->getFacedHandles(getMaxActivationDistance ());
results = mPhysics->getFacedHandles(activationDistance);
}
// ignore the player and other things we're not interested in
@ -1433,10 +1427,8 @@ namespace MWWorld
return d;
}
std::vector<World::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;
CellRefList<ESM::Door>::List& refList = doors.mList;
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.y = pos.pos[1];
result.push_back(newMarker);
out.push_back(newMarker);
}
}
return result;
}
void World::getInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y)
@ -1579,7 +1569,7 @@ namespace MWWorld
pos.rot[1] = 0;
Ogre::Vector3 orig =
Ogre::Vector3(pos.pos[0], pos.pos[1], pos.pos[2]);
Ogre::Vector3(pos.pos);
Ogre::Vector3 dir = Ogre::Vector3(0, 0, -1);
float len = (pos.pos[2] >= 0) ? pos.pos[2] : -pos.pos[2];
@ -1616,7 +1606,8 @@ namespace MWWorld
return false;
const MWMechanics::CreatureStats &stats = ptr.getClass().getCreatureStats(ptr);
if(stats.getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::Levitate)).mMagnitude > 0)
if(stats.getMagicEffects().get(ESM::MagicEffect::Levitate).mMagnitude > 0
&& isLevitationEnabled())
return true;
// TODO: Check if flying creature
@ -1635,7 +1626,7 @@ namespace MWWorld
return false;
const MWMechanics::CreatureStats &stats = ptr.getClass().getCreatureStats(ptr);
if(stats.getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::SlowFall)).mMagnitude > 0)
if(stats.getMagicEffects().get(ESM::MagicEffect::SlowFall).mMagnitude > 0)
return true;
return false;
@ -1820,9 +1811,9 @@ namespace MWWorld
{
std::vector<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)
mHandles.push_back(handle->getName());
return true;
@ -1931,17 +1922,8 @@ namespace MWWorld
int y = ext->getGridY();
indexToPosition(x, y, pos.pos[0], pos.pos[1], true);
ESM::Land* land = getStore().get<ESM::Land>().search(x, y);
if (land) {
if (!land->isDataLoaded(ESM::Land::DATA_VHGT)) {
land->loadData(ESM::Land::DATA_VHGT);
}
pos.pos[2] = land->mLandData->mHeights[ESM::Land::LAND_NUM_VERTS / 2 + 1];
}
else {
std::cerr << "Land data for cell at (" << x << ", " << y << ") not found\n";
// Note: Z pos will be adjusted by adjustPosition later
pos.pos[2] = 0;
}
return true;
}
@ -1985,11 +1967,11 @@ namespace MWWorld
{
InventoryStore &inv = actor.getClass().getInventoryStore(actor);
inv.equip(InventoryStore::Slot_Robe, inv.ContainerStore::add("WerewolfRobe", 1, actor), actor);
inv.equip(InventoryStore::Slot_Robe, inv.ContainerStore::add("werewolfrobe", 1, actor), actor);
}
else
{
actor.getClass().getContainerStore(actor).remove("WerewolfRobe", 1, actor);
actor.getClass().getContainerStore(actor).remove("werewolfrobe", 1, actor);
}
if(actor.getRefData().getHandle() == "player")
@ -2018,7 +2000,7 @@ namespace MWWorld
const Store<ESM::GameSetting> &gmst = getStore().get<ESM::GameSetting>();
MWMechanics::NpcStats &stats = Class::get(actor).getNpcStats(actor);
stats.getSkill(ESM::Skill::Acrobatics).setModified(gmst.find("fWerewolfAcrobatics")->getFloat(), 0);
stats.getSkill(ESM::Skill::Acrobatics).setBase(gmst.find("fWerewolfAcrobatics")->getFloat());
}
bool World::getGodModeState()
@ -2286,8 +2268,153 @@ namespace MWWorld
actor.getClass().getInventoryStore(actor).purgeEffect(ESM::MagicEffect::Invisibility);
}
bool World::isNight() const
bool World::isDark() const
{
return mWeatherManager->isNight();
return mWeatherManager->isDark();
}
bool World::findInteriorPositionInWorldSpace(MWWorld::CellStore* cell, Ogre::Vector3& result)
{
MWWorld::CellRefList<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