forked from teamnwah/openmw-tes3coop
Merge remote-tracking branch 'scrawl/alchemy'
This commit is contained in:
commit
3f6afb13f1
12 changed files with 735 additions and 375 deletions
|
@ -62,7 +62,7 @@ add_openmw_dir (mwclass
|
||||||
|
|
||||||
add_openmw_dir (mwmechanics
|
add_openmw_dir (mwmechanics
|
||||||
mechanicsmanagerimp stat creaturestats magiceffects movement actors drawstate spells
|
mechanicsmanagerimp stat creaturestats magiceffects movement actors drawstate spells
|
||||||
activespells npcstats aipackage aisequence
|
activespells npcstats aipackage aisequence alchemy
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwbase
|
add_openmw_dir (mwbase
|
||||||
|
|
|
@ -423,21 +423,10 @@ void OMW::Engine::activate()
|
||||||
if (handle.empty())
|
if (handle.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// the faced handle is not updated immediately, so on a cell change it might
|
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaHandle (handle);
|
||||||
// point to an object that doesn't exist anymore
|
|
||||||
// therefore, we are catching the "Unknown Ogre handle" exception that occurs in this case
|
|
||||||
MWWorld::Ptr ptr;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
ptr = MWBase::Environment::get().getWorld()->getPtrViaHandle (handle);
|
|
||||||
|
|
||||||
if (ptr.isEmpty())
|
if (ptr.isEmpty())
|
||||||
return;
|
|
||||||
}
|
|
||||||
catch (std::runtime_error&)
|
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
MWScript::InterpreterContext interpreterContext (&ptr.getRefData().getLocals(), ptr);
|
MWScript::InterpreterContext interpreterContext (&ptr.getRefData().getLocals(), ptr);
|
||||||
|
|
||||||
|
|
|
@ -142,6 +142,9 @@ namespace MWBase
|
||||||
virtual MWWorld::Ptr getPtrViaHandle (const std::string& handle) = 0;
|
virtual MWWorld::Ptr getPtrViaHandle (const std::string& handle) = 0;
|
||||||
///< Return a pointer to a liveCellRef with the given Ogre handle.
|
///< Return a pointer to a liveCellRef with the given Ogre handle.
|
||||||
|
|
||||||
|
virtual MWWorld::Ptr searchPtrViaHandle (const std::string& handle) = 0;
|
||||||
|
///< Return a pointer to a liveCellRef with the given Ogre handle or Ptr() if not found
|
||||||
|
|
||||||
/// \todo enable reference in the OGRE scene
|
/// \todo enable reference in the OGRE scene
|
||||||
virtual void enable (const MWWorld::Ptr& ptr) = 0;
|
virtual void enable (const MWWorld::Ptr& ptr) = 0;
|
||||||
|
|
||||||
|
|
|
@ -28,25 +28,25 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
AlchemyWindow::AlchemyWindow(MWBase::WindowManager& parWindowManager)
|
AlchemyWindow::AlchemyWindow(MWBase::WindowManager& parWindowManager)
|
||||||
: WindowBase("openmw_alchemy_window.layout", parWindowManager)
|
: WindowBase("openmw_alchemy_window.layout", parWindowManager)
|
||||||
, ContainerBase(0)
|
, ContainerBase(0), mApparatus (4), mIngredients (4)
|
||||||
{
|
{
|
||||||
getWidget(mCreateButton, "CreateButton");
|
getWidget(mCreateButton, "CreateButton");
|
||||||
getWidget(mCancelButton, "CancelButton");
|
getWidget(mCancelButton, "CancelButton");
|
||||||
getWidget(mIngredient1, "Ingredient1");
|
getWidget(mIngredients[0], "Ingredient1");
|
||||||
getWidget(mIngredient2, "Ingredient2");
|
getWidget(mIngredients[1], "Ingredient2");
|
||||||
getWidget(mIngredient3, "Ingredient3");
|
getWidget(mIngredients[2], "Ingredient3");
|
||||||
getWidget(mIngredient4, "Ingredient4");
|
getWidget(mIngredients[3], "Ingredient4");
|
||||||
getWidget(mApparatus1, "Apparatus1");
|
getWidget(mApparatus[0], "Apparatus1");
|
||||||
getWidget(mApparatus2, "Apparatus2");
|
getWidget(mApparatus[1], "Apparatus2");
|
||||||
getWidget(mApparatus3, "Apparatus3");
|
getWidget(mApparatus[2], "Apparatus3");
|
||||||
getWidget(mApparatus4, "Apparatus4");
|
getWidget(mApparatus[3], "Apparatus4");
|
||||||
getWidget(mEffectsBox, "CreatedEffects");
|
getWidget(mEffectsBox, "CreatedEffects");
|
||||||
getWidget(mNameEdit, "NameEdit");
|
getWidget(mNameEdit, "NameEdit");
|
||||||
|
|
||||||
mIngredient1->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onIngredientSelected);
|
mIngredients[0]->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onIngredientSelected);
|
||||||
mIngredient2->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onIngredientSelected);
|
mIngredients[1]->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onIngredientSelected);
|
||||||
mIngredient3->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onIngredientSelected);
|
mIngredients[2]->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onIngredientSelected);
|
||||||
mIngredient4->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onIngredientSelected);
|
mIngredients[3]->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onIngredientSelected);
|
||||||
|
|
||||||
mCreateButton->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onCreateButtonClicked);
|
mCreateButton->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onCreateButtonClicked);
|
||||||
mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onCancelButtonClicked);
|
mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onCancelButtonClicked);
|
||||||
|
@ -62,157 +62,52 @@ namespace MWGui
|
||||||
|
|
||||||
void AlchemyWindow::onCancelButtonClicked(MyGUI::Widget* _sender)
|
void AlchemyWindow::onCancelButtonClicked(MyGUI::Widget* _sender)
|
||||||
{
|
{
|
||||||
|
mAlchemy.clear();
|
||||||
|
|
||||||
mWindowManager.removeGuiMode(GM_Alchemy);
|
mWindowManager.removeGuiMode(GM_Alchemy);
|
||||||
mWindowManager.removeGuiMode(GM_Inventory);
|
mWindowManager.removeGuiMode(GM_Inventory);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AlchemyWindow::onCreateButtonClicked(MyGUI::Widget* _sender)
|
void AlchemyWindow::onCreateButtonClicked(MyGUI::Widget* _sender)
|
||||||
{
|
{
|
||||||
|
std::string name = mNameEdit->getCaption();
|
||||||
|
boost::algorithm::trim(name);
|
||||||
|
|
||||||
|
MWMechanics::Alchemy::Result result = mAlchemy.create (mNameEdit->getCaption ());
|
||||||
|
|
||||||
|
if (result == MWMechanics::Alchemy::Result_NoName)
|
||||||
|
{
|
||||||
|
mWindowManager.messageBox("#{sNotifyMessage37}", std::vector<std::string>());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// check if mortar & pestle is available (always needed)
|
// check if mortar & pestle is available (always needed)
|
||||||
/// \todo check albemic, calcinator, retort (sometimes needed)
|
if (result == MWMechanics::Alchemy::Result_NoMortarAndPestle)
|
||||||
if (!mApparatus1->isUserString("ToolTipType"))
|
|
||||||
{
|
{
|
||||||
mWindowManager.messageBox("#{sNotifyMessage45}", std::vector<std::string>());
|
mWindowManager.messageBox("#{sNotifyMessage45}", std::vector<std::string>());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure 2 or more ingredients were selected
|
// make sure 2 or more ingredients were selected
|
||||||
int numIngreds = 0;
|
if (result == MWMechanics::Alchemy::Result_LessThanTwoIngredients)
|
||||||
if (mIngredient1->isUserString("ToolTipType"))
|
|
||||||
++numIngreds;
|
|
||||||
if (mIngredient2->isUserString("ToolTipType"))
|
|
||||||
++numIngreds;
|
|
||||||
if (mIngredient3->isUserString("ToolTipType"))
|
|
||||||
++numIngreds;
|
|
||||||
if (mIngredient4->isUserString("ToolTipType"))
|
|
||||||
++numIngreds;
|
|
||||||
if (numIngreds < 2)
|
|
||||||
{
|
{
|
||||||
mWindowManager.messageBox("#{sNotifyMessage6a}", std::vector<std::string>());
|
mWindowManager.messageBox("#{sNotifyMessage6a}", std::vector<std::string>());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure a name was entered
|
if (result == MWMechanics::Alchemy::Result_NoEffects)
|
||||||
std::string name = mNameEdit->getCaption();
|
|
||||||
boost::algorithm::trim(name);
|
|
||||||
if (name == "")
|
|
||||||
{
|
|
||||||
mWindowManager.messageBox("#{sNotifyMessage37}", std::vector<std::string>());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if there are no created effects, the potion will always fail (but the ingredients won't be destroyed)
|
|
||||||
if (mEffects.empty())
|
|
||||||
{
|
{
|
||||||
mWindowManager.messageBox("#{sNotifyMessage8}", std::vector<std::string>());
|
mWindowManager.messageBox("#{sNotifyMessage8}", std::vector<std::string>());
|
||||||
MWBase::Environment::get().getSoundManager()->playSound("potion fail", 1.f, 1.f);
|
MWBase::Environment::get().getSoundManager()->playSound("potion fail", 1.f, 1.f);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rand() % 2 == 0) /// \todo
|
if (result == MWMechanics::Alchemy::Result_Success)
|
||||||
{
|
{
|
||||||
ESM::Potion newPotion;
|
|
||||||
newPotion.mName = mNameEdit->getCaption();
|
|
||||||
ESM::EffectList effects;
|
|
||||||
for (unsigned int i=0; i<4; ++i)
|
|
||||||
{
|
|
||||||
if (mEffects.size() >= i+1)
|
|
||||||
{
|
|
||||||
ESM::ENAMstruct effect;
|
|
||||||
effect.mEffectID = mEffects[i].mEffectID;
|
|
||||||
effect.mArea = 0;
|
|
||||||
effect.mRange = ESM::RT_Self;
|
|
||||||
effect.mSkill = mEffects[i].mSkill;
|
|
||||||
effect.mAttribute = mEffects[i].mAttribute;
|
|
||||||
effect.mMagnMin = 1; /// \todo
|
|
||||||
effect.mMagnMax = 10; /// \todo
|
|
||||||
effect.mDuration = 60; /// \todo
|
|
||||||
effects.mList.push_back(effect);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// UESP Wiki / Morrowind:Alchemy
|
|
||||||
// "The weight of a potion is an average of the weight of the ingredients, rounded down."
|
|
||||||
// note by scrawl: not rounding down here, I can't imagine a created potion to
|
|
||||||
// have 0 weight when using ingredients with 0.1 weight respectively
|
|
||||||
float weight = 0;
|
|
||||||
if (mIngredient1->isUserString("ToolTipType"))
|
|
||||||
weight += mIngredient1->getUserData<MWWorld::Ptr>()->get<ESM::Ingredient>()->base->mData.mWeight;
|
|
||||||
if (mIngredient2->isUserString("ToolTipType"))
|
|
||||||
weight += mIngredient2->getUserData<MWWorld::Ptr>()->get<ESM::Ingredient>()->base->mData.mWeight;
|
|
||||||
if (mIngredient3->isUserString("ToolTipType"))
|
|
||||||
weight += mIngredient3->getUserData<MWWorld::Ptr>()->get<ESM::Ingredient>()->base->mData.mWeight;
|
|
||||||
if (mIngredient4->isUserString("ToolTipType"))
|
|
||||||
weight += mIngredient4->getUserData<MWWorld::Ptr>()->get<ESM::Ingredient>()->base->mData.mWeight;
|
|
||||||
newPotion.mData.mWeight = weight / float(numIngreds);
|
|
||||||
|
|
||||||
newPotion.mData.mValue = 100; /// \todo
|
|
||||||
newPotion.mEffects = effects;
|
|
||||||
// pick a random mesh and icon
|
|
||||||
std::vector<std::string> names;
|
|
||||||
/// \todo is the mesh/icon dependent on alchemy skill?
|
|
||||||
names.push_back("standard");
|
|
||||||
names.push_back("bargain");
|
|
||||||
names.push_back("cheap");
|
|
||||||
names.push_back("fresh");
|
|
||||||
names.push_back("exclusive");
|
|
||||||
names.push_back("quality");
|
|
||||||
int random = rand() % names.size();
|
|
||||||
newPotion.mModel = "m\\misc_potion_" + names[random ] + "_01.nif";
|
|
||||||
newPotion.mIcon = "m\\tx_potion_" + names[random ] + "_01.dds";
|
|
||||||
|
|
||||||
// check if a similiar potion record exists already
|
|
||||||
bool found = false;
|
|
||||||
std::string objectId;
|
|
||||||
typedef std::map<std::string, ESM::Potion> PotionMap;
|
|
||||||
PotionMap potions = MWBase::Environment::get().getWorld()->getStore().potions.list;
|
|
||||||
for (PotionMap::const_iterator it = potions.begin(); it != potions.end(); ++it)
|
|
||||||
{
|
|
||||||
if (found) break;
|
|
||||||
|
|
||||||
if (it->second.mData.mValue == newPotion.mData.mValue
|
|
||||||
&& it->second.mData.mWeight == newPotion.mData.mWeight
|
|
||||||
&& it->second.mName == newPotion.mName
|
|
||||||
&& it->second.mEffects.mList.size() == newPotion.mEffects.mList.size())
|
|
||||||
{
|
|
||||||
// check effects
|
|
||||||
for (unsigned int i=0; i < it->second.mEffects.mList.size(); ++i)
|
|
||||||
{
|
|
||||||
const ESM::ENAMstruct& a = it->second.mEffects.mList[i];
|
|
||||||
const ESM::ENAMstruct& b = newPotion.mEffects.mList[i];
|
|
||||||
if (a.mEffectID == b.mEffectID
|
|
||||||
&& a.mArea == b.mArea
|
|
||||||
&& a.mRange == b.mRange
|
|
||||||
&& a.mSkill == b.mSkill
|
|
||||||
&& a.mAttribute == b.mAttribute
|
|
||||||
&& a.mMagnMin == b.mMagnMin
|
|
||||||
&& a.mMagnMax == b.mMagnMax
|
|
||||||
&& a.mDuration == b.mDuration)
|
|
||||||
{
|
|
||||||
found = true;
|
|
||||||
objectId = it->first;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!found)
|
|
||||||
{
|
|
||||||
std::pair<std::string, const ESM::Potion*> result = MWBase::Environment::get().getWorld()->createRecord(newPotion);
|
|
||||||
objectId = result.first;
|
|
||||||
}
|
|
||||||
|
|
||||||
// create a reference and add it to player inventory
|
|
||||||
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), objectId);
|
|
||||||
MWWorld::ContainerStore& store = MWWorld::Class::get(mPtr).getContainerStore(mPtr);
|
|
||||||
ref.getPtr().getRefData().setCount(1);
|
|
||||||
store.add(ref.getPtr());
|
|
||||||
|
|
||||||
mWindowManager.messageBox("#{sPotionSuccess}", std::vector<std::string>());
|
mWindowManager.messageBox("#{sPotionSuccess}", std::vector<std::string>());
|
||||||
MWBase::Environment::get().getSoundManager()->playSound("potion success", 1.f, 1.f);
|
MWBase::Environment::get().getSoundManager()->playSound("potion success", 1.f, 1.f);
|
||||||
}
|
}
|
||||||
else
|
else if (result == MWMechanics::Alchemy::Result_RandomFailure)
|
||||||
{
|
{
|
||||||
// potion failed
|
// potion failed
|
||||||
mWindowManager.messageBox("#{sNotifyMessage8}", std::vector<std::string>());
|
mWindowManager.messageBox("#{sNotifyMessage8}", std::vector<std::string>());
|
||||||
|
@ -220,91 +115,36 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
|
|
||||||
// reduce count of the ingredients
|
// reduce count of the ingredients
|
||||||
if (mIngredient1->isUserString("ToolTipType"))
|
for (int i=0; i<4; ++i)
|
||||||
{
|
if (mIngredients[i]->isUserString("ToolTipType"))
|
||||||
MWWorld::Ptr ingred = *mIngredient1->getUserData<MWWorld::Ptr>();
|
{
|
||||||
ingred.getRefData().setCount(ingred.getRefData().getCount()-1);
|
MWWorld::Ptr ingred = *mIngredients[i]->getUserData<MWWorld::Ptr>();
|
||||||
if (ingred.getRefData().getCount() == 0)
|
ingred.getRefData().setCount(ingred.getRefData().getCount()-1);
|
||||||
removeIngredient(mIngredient1);
|
if (ingred.getRefData().getCount() == 0)
|
||||||
}
|
removeIngredient(mIngredients[i]);
|
||||||
if (mIngredient2->isUserString("ToolTipType"))
|
|
||||||
{
|
|
||||||
MWWorld::Ptr ingred = *mIngredient2->getUserData<MWWorld::Ptr>();
|
|
||||||
ingred.getRefData().setCount(ingred.getRefData().getCount()-1);
|
|
||||||
if (ingred.getRefData().getCount() == 0)
|
|
||||||
removeIngredient(mIngredient2);
|
|
||||||
}
|
|
||||||
if (mIngredient3->isUserString("ToolTipType"))
|
|
||||||
{
|
|
||||||
MWWorld::Ptr ingred = *mIngredient3->getUserData<MWWorld::Ptr>();
|
|
||||||
ingred.getRefData().setCount(ingred.getRefData().getCount()-1);
|
|
||||||
if (ingred.getRefData().getCount() == 0)
|
|
||||||
removeIngredient(mIngredient3);
|
|
||||||
}
|
|
||||||
if (mIngredient4->isUserString("ToolTipType"))
|
|
||||||
{
|
|
||||||
MWWorld::Ptr ingred = *mIngredient4->getUserData<MWWorld::Ptr>();
|
|
||||||
ingred.getRefData().setCount(ingred.getRefData().getCount()-1);
|
|
||||||
if (ingred.getRefData().getCount() == 0)
|
|
||||||
removeIngredient(mIngredient4);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AlchemyWindow::open()
|
void AlchemyWindow::open()
|
||||||
{
|
{
|
||||||
openContainer(MWBase::Environment::get().getWorld()->getPlayer().getPlayer());
|
openContainer (MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); // this sets mPtr
|
||||||
setFilter(ContainerBase::Filter_Ingredients);
|
setFilter (ContainerBase::Filter_Ingredients);
|
||||||
|
|
||||||
// pick the best available apparatus
|
mAlchemy.setAlchemist (mPtr);
|
||||||
MWWorld::ContainerStore& store = MWWorld::Class::get(mPtr).getContainerStore(mPtr);
|
|
||||||
|
|
||||||
MWWorld::Ptr bestAlbemic;
|
int index = 0;
|
||||||
MWWorld::Ptr bestMortarPestle;
|
|
||||||
MWWorld::Ptr bestCalcinator;
|
|
||||||
MWWorld::Ptr bestRetort;
|
|
||||||
|
|
||||||
for (MWWorld::ContainerStoreIterator it(store.begin(MWWorld::ContainerStore::Type_Apparatus));
|
for (MWMechanics::Alchemy::TToolsIterator iter (mAlchemy.beginTools());
|
||||||
it != store.end(); ++it)
|
iter!=mAlchemy.endTools() && index<static_cast<int> (mApparatus.size()); ++iter, ++index)
|
||||||
{
|
{
|
||||||
MWWorld::LiveCellRef<ESM::Apparatus>* ref = it->get<ESM::Apparatus>();
|
if (!iter->isEmpty())
|
||||||
if (ref->base->mData.mType == ESM::Apparatus::Albemic
|
{
|
||||||
&& (bestAlbemic.isEmpty() || ref->base->mData.mQuality > bestAlbemic.get<ESM::Apparatus>()->base->mData.mQuality))
|
mApparatus.at (index)->setUserString ("ToolTipType", "ItemPtr");
|
||||||
bestAlbemic = *it;
|
mApparatus.at (index)->setUserData (*iter);
|
||||||
else if (ref->base->mData.mType == ESM::Apparatus::MortarPestle
|
mApparatus.at (index)->setImageTexture (getIconPath (*iter));
|
||||||
&& (bestMortarPestle.isEmpty() || ref->base->mData.mQuality > bestMortarPestle.get<ESM::Apparatus>()->base->mData.mQuality))
|
}
|
||||||
bestMortarPestle = *it;
|
|
||||||
else if (ref->base->mData.mType == ESM::Apparatus::Calcinator
|
|
||||||
&& (bestCalcinator.isEmpty() || ref->base->mData.mQuality > bestCalcinator.get<ESM::Apparatus>()->base->mData.mQuality))
|
|
||||||
bestCalcinator = *it;
|
|
||||||
else if (ref->base->mData.mType == ESM::Apparatus::Retort
|
|
||||||
&& (bestRetort.isEmpty() || ref->base->mData.mQuality > bestRetort.get<ESM::Apparatus>()->base->mData.mQuality))
|
|
||||||
bestRetort = *it;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!bestMortarPestle.isEmpty())
|
|
||||||
{
|
|
||||||
mApparatus1->setUserString("ToolTipType", "ItemPtr");
|
|
||||||
mApparatus1->setUserData(bestMortarPestle);
|
|
||||||
mApparatus1->setImageTexture(getIconPath(bestMortarPestle));
|
|
||||||
}
|
|
||||||
if (!bestAlbemic.isEmpty())
|
|
||||||
{
|
|
||||||
mApparatus2->setUserString("ToolTipType", "ItemPtr");
|
|
||||||
mApparatus2->setUserData(bestAlbemic);
|
|
||||||
mApparatus2->setImageTexture(getIconPath(bestAlbemic));
|
|
||||||
}
|
|
||||||
if (!bestCalcinator.isEmpty())
|
|
||||||
{
|
|
||||||
mApparatus3->setUserString("ToolTipType", "ItemPtr");
|
|
||||||
mApparatus3->setUserData(bestCalcinator);
|
|
||||||
mApparatus3->setImageTexture(getIconPath(bestCalcinator));
|
|
||||||
}
|
|
||||||
if (!bestRetort.isEmpty())
|
|
||||||
{
|
|
||||||
mApparatus4->setUserString("ToolTipType", "ItemPtr");
|
|
||||||
mApparatus4->setUserData(bestRetort);
|
|
||||||
mApparatus4->setImageTexture(getIconPath(bestRetort));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,45 +163,27 @@ namespace MWGui
|
||||||
// (which could happen if two similiar ingredients don't stack because of script / owner)
|
// (which could happen if two similiar ingredients don't stack because of script / owner)
|
||||||
bool alreadyAdded = false;
|
bool alreadyAdded = false;
|
||||||
std::string name = MWWorld::Class::get(item).getName(item);
|
std::string name = MWWorld::Class::get(item).getName(item);
|
||||||
if (mIngredient1->isUserString("ToolTipType"))
|
for (int i=0; i<4; ++i)
|
||||||
{
|
if (mIngredients[i]->isUserString("ToolTipType"))
|
||||||
MWWorld::Ptr item2 = *mIngredient1->getUserData<MWWorld::Ptr>();
|
{
|
||||||
std::string name2 = MWWorld::Class::get(item2).getName(item2);
|
MWWorld::Ptr item2 = *mIngredients[i]->getUserData<MWWorld::Ptr>();
|
||||||
if (name == name2)
|
std::string name2 = MWWorld::Class::get(item2).getName(item2);
|
||||||
alreadyAdded = true;
|
if (name == name2)
|
||||||
}
|
alreadyAdded = true;
|
||||||
if (mIngredient2->isUserString("ToolTipType"))
|
}
|
||||||
{
|
|
||||||
MWWorld::Ptr item2 = *mIngredient2->getUserData<MWWorld::Ptr>();
|
|
||||||
std::string name2 = MWWorld::Class::get(item2).getName(item2);
|
|
||||||
if (name == name2)
|
|
||||||
alreadyAdded = true;
|
|
||||||
}
|
|
||||||
if (mIngredient3->isUserString("ToolTipType"))
|
|
||||||
{
|
|
||||||
MWWorld::Ptr item2 = *mIngredient3->getUserData<MWWorld::Ptr>();
|
|
||||||
std::string name2 = MWWorld::Class::get(item2).getName(item2);
|
|
||||||
if (name == name2)
|
|
||||||
alreadyAdded = true;
|
|
||||||
}
|
|
||||||
if (mIngredient4->isUserString("ToolTipType"))
|
|
||||||
{
|
|
||||||
MWWorld::Ptr item2 = *mIngredient4->getUserData<MWWorld::Ptr>();
|
|
||||||
std::string name2 = MWWorld::Class::get(item2).getName(item2);
|
|
||||||
if (name == name2)
|
|
||||||
alreadyAdded = true;
|
|
||||||
}
|
|
||||||
if (alreadyAdded)
|
if (alreadyAdded)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!mIngredient1->isUserString("ToolTipType"))
|
for (int i=0; i<4; ++i)
|
||||||
add = mIngredient1;
|
if (!mIngredients[i]->isUserString("ToolTipType"))
|
||||||
if (add == NULL && !mIngredient2->isUserString("ToolTipType"))
|
{
|
||||||
add = mIngredient2;
|
add = mIngredients[i];
|
||||||
if (add == NULL && !mIngredient3->isUserString("ToolTipType"))
|
|
||||||
add = mIngredient3;
|
mAlchemy.addIngredient(item);
|
||||||
if (add == NULL && !mIngredient4->isUserString("ToolTipType"))
|
|
||||||
add = mIngredient4;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (add != NULL)
|
if (add != NULL)
|
||||||
{
|
{
|
||||||
|
@ -380,50 +202,22 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
std::vector<MWWorld::Ptr> ignore;
|
std::vector<MWWorld::Ptr> ignore;
|
||||||
// don't show ingredients that are currently selected in the "available ingredients" box.
|
// don't show ingredients that are currently selected in the "available ingredients" box.
|
||||||
if (mIngredient1->isUserString("ToolTipType"))
|
for (int i=0; i<4; ++i)
|
||||||
ignore.push_back(*mIngredient1->getUserData<MWWorld::Ptr>());
|
if (mIngredients[i]->isUserString("ToolTipType"))
|
||||||
if (mIngredient2->isUserString("ToolTipType"))
|
ignore.push_back(*mIngredients[i]->getUserData<MWWorld::Ptr>());
|
||||||
ignore.push_back(*mIngredient2->getUserData<MWWorld::Ptr>());
|
|
||||||
if (mIngredient3->isUserString("ToolTipType"))
|
|
||||||
ignore.push_back(*mIngredient3->getUserData<MWWorld::Ptr>());
|
|
||||||
if (mIngredient4->isUserString("ToolTipType"))
|
|
||||||
ignore.push_back(*mIngredient4->getUserData<MWWorld::Ptr>());
|
|
||||||
|
|
||||||
return ignore;
|
return ignore;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AlchemyWindow::update()
|
void AlchemyWindow::update()
|
||||||
{
|
{
|
||||||
Widgets::SpellEffectList effects;
|
|
||||||
|
|
||||||
for (int i=0; i<4; ++i)
|
for (int i=0; i<4; ++i)
|
||||||
{
|
{
|
||||||
MyGUI::ImageBox* ingredient;
|
MyGUI::ImageBox* ingredient = mIngredients[i];
|
||||||
if (i==0)
|
|
||||||
ingredient = mIngredient1;
|
|
||||||
else if (i==1)
|
|
||||||
ingredient = mIngredient2;
|
|
||||||
else if (i==2)
|
|
||||||
ingredient = mIngredient3;
|
|
||||||
else if (i==3)
|
|
||||||
ingredient = mIngredient4;
|
|
||||||
|
|
||||||
if (!ingredient->isUserString("ToolTipType"))
|
if (!ingredient->isUserString("ToolTipType"))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// add the effects of this ingredient to list of effects
|
|
||||||
MWWorld::LiveCellRef<ESM::Ingredient>* ref = ingredient->getUserData<MWWorld::Ptr>()->get<ESM::Ingredient>();
|
|
||||||
for (int i=0; i<4; ++i)
|
|
||||||
{
|
|
||||||
if (ref->base->mData.mEffectID[i] < 0)
|
|
||||||
continue;
|
|
||||||
MWGui::Widgets::SpellEffectParams params;
|
|
||||||
params.mEffectID = ref->base->mData.mEffectID[i];
|
|
||||||
params.mAttribute = ref->base->mData.mAttributes[i];
|
|
||||||
params.mSkill = ref->base->mData.mSkills[i];
|
|
||||||
effects.push_back(params);
|
|
||||||
}
|
|
||||||
|
|
||||||
// update ingredient count labels
|
// update ingredient count labels
|
||||||
if (ingredient->getChildCount())
|
if (ingredient->getChildCount())
|
||||||
MyGUI::Gui::getInstance().destroyWidget(ingredient->getChildAt(0));
|
MyGUI::Gui::getInstance().destroyWidget(ingredient->getChildAt(0));
|
||||||
|
@ -436,50 +230,14 @@ namespace MWGui
|
||||||
text->setCaption(getCountString(ingredient->getUserData<MWWorld::Ptr>()->getRefData().getCount()));
|
text->setCaption(getCountString(ingredient->getUserData<MWWorld::Ptr>()->getRefData().getCount()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// now remove effects that are only present once
|
std::vector<ESM::ENAMstruct> effects;
|
||||||
Widgets::SpellEffectList::iterator it = effects.begin();
|
ESM::EffectList list;
|
||||||
while (it != effects.end())
|
list.mList = effects;
|
||||||
|
for (MWMechanics::Alchemy::TEffectsIterator it = mAlchemy.beginEffects (); it != mAlchemy.endEffects (); ++it)
|
||||||
{
|
{
|
||||||
Widgets::SpellEffectList::iterator next = it;
|
list.mList.push_back(*it);
|
||||||
++next;
|
|
||||||
bool found = false;
|
|
||||||
for (; next != effects.end(); ++next)
|
|
||||||
{
|
|
||||||
if (*next == *it)
|
|
||||||
found = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!found)
|
|
||||||
it = effects.erase(it);
|
|
||||||
else
|
|
||||||
++it;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// now remove duplicates, and don't allow more than 4 effects
|
|
||||||
Widgets::SpellEffectList old = effects;
|
|
||||||
effects.clear();
|
|
||||||
int i=0;
|
|
||||||
for (Widgets::SpellEffectList::iterator it = old.begin();
|
|
||||||
it != old.end(); ++it)
|
|
||||||
{
|
|
||||||
bool found = false;
|
|
||||||
for (Widgets::SpellEffectList::iterator it2 = effects.begin();
|
|
||||||
it2 != effects.end(); ++it2)
|
|
||||||
{
|
|
||||||
// MW considers all "foritfy attribute" effects as the same effect. See the
|
|
||||||
// "Can't create multi-state boost potions" discussion on http://www.uesp.net/wiki/Morrowind_talk:Alchemy
|
|
||||||
// thus, we are only checking effectID here and not attribute or skill
|
|
||||||
if (it2->mEffectID == it->mEffectID)
|
|
||||||
found = true;
|
|
||||||
}
|
|
||||||
if (!found && i<4)
|
|
||||||
{
|
|
||||||
++i;
|
|
||||||
effects.push_back(*it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mEffects = effects;
|
|
||||||
|
|
||||||
while (mEffectsBox->getChildCount())
|
while (mEffectsBox->getChildCount())
|
||||||
MyGUI::Gui::getInstance().destroyWidget(mEffectsBox->getChildAt(0));
|
MyGUI::Gui::getInstance().destroyWidget(mEffectsBox->getChildAt(0));
|
||||||
|
|
||||||
|
@ -487,7 +245,9 @@ namespace MWGui
|
||||||
Widgets::MWEffectListPtr effectsWidget = mEffectsBox->createWidget<Widgets::MWEffectList>
|
Widgets::MWEffectListPtr effectsWidget = mEffectsBox->createWidget<Widgets::MWEffectList>
|
||||||
("MW_StatName", coord, MyGUI::Align::Left | MyGUI::Align::Top);
|
("MW_StatName", coord, MyGUI::Align::Left | MyGUI::Align::Top);
|
||||||
effectsWidget->setWindowManager(&mWindowManager);
|
effectsWidget->setWindowManager(&mWindowManager);
|
||||||
effectsWidget->setEffectList(effects);
|
|
||||||
|
Widgets::SpellEffectList _list = Widgets::MWEffectList::effectListFromESM(&list);
|
||||||
|
effectsWidget->setEffectList(_list);
|
||||||
|
|
||||||
std::vector<MyGUI::WidgetPtr> effectItems;
|
std::vector<MyGUI::WidgetPtr> effectItems;
|
||||||
effectsWidget->createEffectWidgets(effectItems, mEffectsBox, coord, false, 0);
|
effectsWidget->createEffectWidgets(effectItems, mEffectsBox, coord, false, 0);
|
||||||
|
@ -500,5 +260,9 @@ namespace MWGui
|
||||||
static_cast<MyGUI::ImageBox*>(ingredient)->setImageTexture("");
|
static_cast<MyGUI::ImageBox*>(ingredient)->setImageTexture("");
|
||||||
if (ingredient->getChildCount())
|
if (ingredient->getChildCount())
|
||||||
MyGUI::Gui::getInstance().destroyWidget(ingredient->getChildAt(0));
|
MyGUI::Gui::getInstance().destroyWidget(ingredient->getChildAt(0));
|
||||||
|
|
||||||
|
for (int i=0; i<4; ++i)
|
||||||
|
if (mIngredients[i] == ingredient)
|
||||||
|
mAlchemy.removeIngredient (i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
#ifndef MWGUI_ALCHEMY_H
|
#ifndef MWGUI_ALCHEMY_H
|
||||||
#define MWGUI_ALCHEMY_H
|
#define MWGUI_ALCHEMY_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "../mwmechanics/alchemy.hpp"
|
||||||
|
|
||||||
#include "window_base.hpp"
|
#include "window_base.hpp"
|
||||||
#include "container.hpp"
|
#include "container.hpp"
|
||||||
#include "widgets.hpp"
|
#include "widgets.hpp"
|
||||||
|
@ -18,22 +22,10 @@ namespace MWGui
|
||||||
MyGUI::Button* mCreateButton;
|
MyGUI::Button* mCreateButton;
|
||||||
MyGUI::Button* mCancelButton;
|
MyGUI::Button* mCancelButton;
|
||||||
|
|
||||||
MyGUI::ImageBox* mIngredient1;
|
|
||||||
MyGUI::ImageBox* mIngredient2;
|
|
||||||
MyGUI::ImageBox* mIngredient3;
|
|
||||||
MyGUI::ImageBox* mIngredient4;
|
|
||||||
|
|
||||||
MyGUI::ImageBox* mApparatus1;
|
|
||||||
MyGUI::ImageBox* mApparatus2;
|
|
||||||
MyGUI::ImageBox* mApparatus3;
|
|
||||||
MyGUI::ImageBox* mApparatus4;
|
|
||||||
|
|
||||||
MyGUI::Widget* mEffectsBox;
|
MyGUI::Widget* mEffectsBox;
|
||||||
|
|
||||||
MyGUI::EditBox* mNameEdit;
|
MyGUI::EditBox* mNameEdit;
|
||||||
|
|
||||||
Widgets::SpellEffectList mEffects; // effects of created potion
|
|
||||||
|
|
||||||
void onCancelButtonClicked(MyGUI::Widget* _sender);
|
void onCancelButtonClicked(MyGUI::Widget* _sender);
|
||||||
void onCreateButtonClicked(MyGUI::Widget* _sender);
|
void onCreateButtonClicked(MyGUI::Widget* _sender);
|
||||||
void onIngredientSelected(MyGUI::Widget* _sender);
|
void onIngredientSelected(MyGUI::Widget* _sender);
|
||||||
|
@ -46,6 +38,13 @@ namespace MWGui
|
||||||
virtual void onReferenceUnavailable() { ; }
|
virtual void onReferenceUnavailable() { ; }
|
||||||
|
|
||||||
void update();
|
void update();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
MWMechanics::Alchemy mAlchemy;
|
||||||
|
|
||||||
|
std::vector<MyGUI::ImageBox *> mApparatus;
|
||||||
|
std::vector<MyGUI::ImageBox *> mIngredients;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -245,15 +245,7 @@ void HUD::onWorldClicked(MyGUI::Widget* _sender)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::string handle = MWBase::Environment::get().getWorld()->getFacedHandle();
|
std::string handle = MWBase::Environment::get().getWorld()->getFacedHandle();
|
||||||
MWWorld::Ptr object;
|
MWWorld::Ptr object = MWBase::Environment::get().getWorld()->searchPtrViaHandle(handle);
|
||||||
try
|
|
||||||
{
|
|
||||||
object = MWBase::Environment::get().getWorld()->getPtrViaHandle(handle);
|
|
||||||
}
|
|
||||||
catch (std::exception& /* e */)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mode == GM_Console)
|
if (mode == GM_Console)
|
||||||
MWBase::Environment::get().getWindowManager()->getConsole()->setSelectedObject(object);
|
MWBase::Environment::get().getWindowManager()->getConsole()->setSelectedObject(object);
|
||||||
|
|
|
@ -79,14 +79,10 @@ void ToolTips::onFrame(float frameDuration)
|
||||||
|| (mWindowManager->getMode() == GM_Inventory)))
|
|| (mWindowManager->getMode() == GM_Inventory)))
|
||||||
{
|
{
|
||||||
std::string handle = MWBase::Environment::get().getWorld()->getFacedHandle();
|
std::string handle = MWBase::Environment::get().getWorld()->getFacedHandle();
|
||||||
try
|
|
||||||
{
|
mFocusObject = MWBase::Environment::get().getWorld()->searchPtrViaHandle(handle);
|
||||||
mFocusObject = MWBase::Environment::get().getWorld()->getPtrViaHandle(handle);
|
if (mFocusObject.isEmpty ())
|
||||||
}
|
|
||||||
catch (std::exception /* & e */)
|
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
MyGUI::IntSize tooltipSize = getToolTipViaPtr(true);
|
MyGUI::IntSize tooltipSize = getToolTipViaPtr(true);
|
||||||
|
|
||||||
|
|
490
apps/openmw/mwmechanics/alchemy.cpp
Normal file
490
apps/openmw/mwmechanics/alchemy.cpp
Normal file
|
@ -0,0 +1,490 @@
|
||||||
|
|
||||||
|
#include "alchemy.hpp"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include <components/esm/loadskil.hpp>
|
||||||
|
#include <components/esm/loadappa.hpp>
|
||||||
|
#include <components/esm/loadgmst.hpp>
|
||||||
|
#include <components/esm/loadmgef.hpp>
|
||||||
|
|
||||||
|
#include <components/esm_store/store.hpp>
|
||||||
|
|
||||||
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwbase/world.hpp"
|
||||||
|
|
||||||
|
#include "../mwworld/containerstore.hpp"
|
||||||
|
#include "../mwworld/class.hpp"
|
||||||
|
#include "../mwworld/cellstore.hpp"
|
||||||
|
#include "../mwworld/manualref.hpp"
|
||||||
|
|
||||||
|
#include "magiceffects.hpp"
|
||||||
|
#include "creaturestats.hpp"
|
||||||
|
#include "npcstats.hpp"
|
||||||
|
|
||||||
|
std::set<MWMechanics::EffectKey> MWMechanics::Alchemy::listEffects() const
|
||||||
|
{
|
||||||
|
std::set<EffectKey> effects;
|
||||||
|
|
||||||
|
for (TIngredientsIterator iter (mIngredients.begin()); iter!=mIngredients.end(); ++iter)
|
||||||
|
{
|
||||||
|
if (!iter->isEmpty())
|
||||||
|
{
|
||||||
|
const MWWorld::LiveCellRef<ESM::Ingredient> *ingredient = iter->get<ESM::Ingredient>();
|
||||||
|
|
||||||
|
for (int i=0; i<4; ++i)
|
||||||
|
if (ingredient->base->mData.mEffectID[i]!=-1)
|
||||||
|
effects.insert (EffectKey (
|
||||||
|
ingredient->base->mData.mEffectID[i], ingredient->base->mData.mSkills[i]!=-1 ?
|
||||||
|
ingredient->base->mData.mSkills[i] : ingredient->base->mData.mAttributes[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return effects;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MWMechanics::Alchemy::filterEffects (std::set<EffectKey>& effects) const
|
||||||
|
{
|
||||||
|
std::set<EffectKey>::iterator iter = effects.begin();
|
||||||
|
|
||||||
|
while (iter!=effects.end())
|
||||||
|
{
|
||||||
|
bool remove = false;
|
||||||
|
|
||||||
|
const EffectKey& key = *iter;
|
||||||
|
|
||||||
|
{ // dodge pointless g++ warning
|
||||||
|
for (TIngredientsIterator iter (mIngredients.begin()); iter!=mIngredients.end(); ++iter)
|
||||||
|
{
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
if (iter->isEmpty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const MWWorld::LiveCellRef<ESM::Ingredient> *ingredient = iter->get<ESM::Ingredient>();
|
||||||
|
|
||||||
|
for (int i=0; i<4; ++i)
|
||||||
|
if (key.mId==ingredient->base->mData.mEffectID[i] &&
|
||||||
|
(key.mArg==ingredient->base->mData.mSkills[i] ||
|
||||||
|
key.mArg==ingredient->base->mData.mAttributes[i]))
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
{
|
||||||
|
remove = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (remove)
|
||||||
|
effects.erase (iter++);
|
||||||
|
else
|
||||||
|
++iter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MWMechanics::Alchemy::applyTools (int flags, float& value) const
|
||||||
|
{
|
||||||
|
bool magnitude = !(flags & ESM::MagicEffect::NoMagnitude);
|
||||||
|
bool duration = !(flags & ESM::MagicEffect::NoDuration);
|
||||||
|
bool negative = flags & (ESM::MagicEffect::Negative | ESM::MagicEffect::Harmful);
|
||||||
|
|
||||||
|
int tool = negative ? ESM::Apparatus::Retort : ESM::Apparatus::Albemic;
|
||||||
|
|
||||||
|
int setup = 0;
|
||||||
|
|
||||||
|
if (!mTools[tool].isEmpty() && !mTools[ESM::Apparatus::Calcinator].isEmpty())
|
||||||
|
setup = 1;
|
||||||
|
else if (!mTools[tool].isEmpty())
|
||||||
|
setup = 2;
|
||||||
|
else if (!mTools[ESM::Apparatus::Calcinator].isEmpty())
|
||||||
|
setup = 3;
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
|
||||||
|
float toolQuality = setup==1 || setup==2 ? mTools[tool].get<ESM::Apparatus>()->base->mData.mQuality : 0;
|
||||||
|
float calcinatorQuality = setup==1 || setup==3 ?
|
||||||
|
mTools[ESM::Apparatus::Calcinator].get<ESM::Apparatus>()->base->mData.mQuality : 0;
|
||||||
|
|
||||||
|
float quality = 1;
|
||||||
|
|
||||||
|
switch (setup)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
|
||||||
|
quality = negative ? 2 * toolQuality + 3 * calcinatorQuality :
|
||||||
|
(magnitude && duration ?
|
||||||
|
2 * toolQuality + calcinatorQuality : 2/3.0 * (toolQuality + calcinatorQuality) + 0.5);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
|
||||||
|
quality = negative ? 1+toolQuality : (magnitude && duration ? toolQuality : toolQuality + 0.5);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
|
||||||
|
quality = magnitude && duration ? calcinatorQuality : calcinatorQuality + 0.5;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setup==3 || !negative)
|
||||||
|
{
|
||||||
|
value += quality;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (quality==0)
|
||||||
|
throw std::runtime_error ("invalid derived alchemy apparatus quality");
|
||||||
|
|
||||||
|
value /= quality;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MWMechanics::Alchemy::updateEffects()
|
||||||
|
{
|
||||||
|
mEffects.clear();
|
||||||
|
mValue = 0;
|
||||||
|
|
||||||
|
if (countIngredients()<2 || mAlchemist.isEmpty() || mTools[ESM::Apparatus::MortarPestle].isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// find effects
|
||||||
|
std::set<EffectKey> effects (listEffects());
|
||||||
|
filterEffects (effects);
|
||||||
|
|
||||||
|
// general alchemy factor
|
||||||
|
float x = getChance();
|
||||||
|
|
||||||
|
x *= mTools[ESM::Apparatus::MortarPestle].get<ESM::Apparatus>()->base->mData.mQuality;
|
||||||
|
x *= MWBase::Environment::get().getWorld()->getStore().gameSettings.find ("fPotionStrengthMult")->getFloat();
|
||||||
|
|
||||||
|
// value
|
||||||
|
mValue = static_cast<int> (
|
||||||
|
x * MWBase::Environment::get().getWorld()->getStore().gameSettings.find ("iAlchemyMod")->getFloat());
|
||||||
|
|
||||||
|
// build quantified effect list
|
||||||
|
for (std::set<EffectKey>::const_iterator iter (effects.begin()); iter!=effects.end(); ++iter)
|
||||||
|
{
|
||||||
|
const ESM::MagicEffect *magicEffect =
|
||||||
|
MWBase::Environment::get().getWorld()->getStore().magicEffects.find (iter->mId);
|
||||||
|
|
||||||
|
if (magicEffect->mData.mBaseCost<=0)
|
||||||
|
throw std::runtime_error ("invalid base cost for magic effect " + iter->mId);
|
||||||
|
|
||||||
|
float fPotionT1MagMul =
|
||||||
|
MWBase::Environment::get().getWorld()->getStore().gameSettings.find ("fPotionT1MagMult")->getFloat();
|
||||||
|
|
||||||
|
if (fPotionT1MagMul<=0)
|
||||||
|
throw std::runtime_error ("invalid gmst: fPotionT1MagMul");
|
||||||
|
|
||||||
|
float fPotionT1DurMult =
|
||||||
|
MWBase::Environment::get().getWorld()->getStore().gameSettings.find ("fPotionT1DurMult")->getFloat();
|
||||||
|
|
||||||
|
if (fPotionT1DurMult<=0)
|
||||||
|
throw std::runtime_error ("invalid gmst: fPotionT1DurMult");
|
||||||
|
|
||||||
|
float magnitude = magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude ?
|
||||||
|
1 : (x / fPotionT1MagMul) / magicEffect->mData.mBaseCost;
|
||||||
|
float duration = magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration ?
|
||||||
|
1 : (x / fPotionT1DurMult) / magicEffect->mData.mBaseCost;
|
||||||
|
|
||||||
|
if (!(magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude))
|
||||||
|
applyTools (magicEffect->mData.mFlags, magnitude);
|
||||||
|
|
||||||
|
if (!(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration))
|
||||||
|
applyTools (magicEffect->mData.mFlags, duration);
|
||||||
|
|
||||||
|
duration = static_cast<int> (duration+0.5);
|
||||||
|
magnitude = static_cast<int> (magnitude+0.5);
|
||||||
|
|
||||||
|
if (magnitude>0 && duration>0)
|
||||||
|
{
|
||||||
|
ESM::ENAMstruct effect;
|
||||||
|
effect.mEffectID = iter->mId;
|
||||||
|
|
||||||
|
effect.mSkill = effect.mAttribute = iter->mArg; // somewhat hack-ish, but should work
|
||||||
|
|
||||||
|
effect.mRange = 0;
|
||||||
|
effect.mArea = 0;
|
||||||
|
|
||||||
|
effect.mDuration = duration;
|
||||||
|
effect.mMagnMin = effect.mMagnMax = magnitude;
|
||||||
|
|
||||||
|
mEffects.push_back (effect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const ESM::Potion *MWMechanics::Alchemy::getRecord() const
|
||||||
|
{
|
||||||
|
for (ESMS::RecListWithIDT<ESM::Potion>::MapType::const_iterator iter (
|
||||||
|
MWBase::Environment::get().getWorld()->getStore().potions.list.begin());
|
||||||
|
iter!=MWBase::Environment::get().getWorld()->getStore().potions.list.end(); ++iter)
|
||||||
|
{
|
||||||
|
if (iter->second.mEffects.mList.size()!=mEffects.size())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
bool mismatch = false;
|
||||||
|
|
||||||
|
for (int i=0; i<static_cast<int> (iter->second.mEffects.mList.size()); ++iter)
|
||||||
|
{
|
||||||
|
const ESM::ENAMstruct& first = iter->second.mEffects.mList[i];
|
||||||
|
const ESM::ENAMstruct& second = mEffects[i];
|
||||||
|
|
||||||
|
if (first.mEffectID!=second.mEffectID ||
|
||||||
|
first.mArea!=second.mArea ||
|
||||||
|
first.mRange!=second.mRange ||
|
||||||
|
first.mSkill!=second.mSkill ||
|
||||||
|
first.mAttribute!=second.mAttribute ||
|
||||||
|
first.mMagnMin!=second.mMagnMin ||
|
||||||
|
first.mMagnMax!=second.mMagnMax ||
|
||||||
|
first.mDuration!=second.mDuration)
|
||||||
|
{
|
||||||
|
mismatch = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mismatch)
|
||||||
|
return &iter->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MWMechanics::Alchemy::removeIngredients()
|
||||||
|
{
|
||||||
|
bool needsUpdate = false;
|
||||||
|
|
||||||
|
for (TIngredientsContainer::iterator iter (mIngredients.begin()); iter!=mIngredients.end(); ++iter)
|
||||||
|
if (!iter->isEmpty())
|
||||||
|
{
|
||||||
|
iter->getRefData().setCount (iter->getRefData().getCount()-1);
|
||||||
|
if (iter->getRefData().getCount()<1)
|
||||||
|
{
|
||||||
|
needsUpdate = true;
|
||||||
|
*iter = MWWorld::Ptr();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needsUpdate)
|
||||||
|
updateEffects();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MWMechanics::Alchemy::addPotion (const std::string& name)
|
||||||
|
{
|
||||||
|
const ESM::Potion *record = getRecord();
|
||||||
|
|
||||||
|
if (!record)
|
||||||
|
{
|
||||||
|
ESM::Potion newRecord;
|
||||||
|
|
||||||
|
newRecord.mData.mWeight = 0;
|
||||||
|
|
||||||
|
for (TIngredientsIterator iter (beginIngredients()); iter!=endIngredients(); ++iter)
|
||||||
|
if (!iter->isEmpty())
|
||||||
|
newRecord.mData.mWeight += iter->get<ESM::Ingredient>()->base->mData.mWeight;
|
||||||
|
|
||||||
|
newRecord.mData.mWeight /= countIngredients();
|
||||||
|
|
||||||
|
newRecord.mData.mValue = mValue;
|
||||||
|
newRecord.mData.mAutoCalc = 0;
|
||||||
|
|
||||||
|
newRecord.mName = name;
|
||||||
|
|
||||||
|
int index = static_cast<int> (std::rand()/static_cast<double> (RAND_MAX)*6);
|
||||||
|
assert (index>=0 && index<6);
|
||||||
|
|
||||||
|
static const char *name[] = { "standard", "bargain", "cheap", "fresh", "exclusive", "quality" };
|
||||||
|
|
||||||
|
newRecord.mModel = "m\\misc_potion_" + std::string (name[index]) + "_01.nif";
|
||||||
|
newRecord.mIcon = "m\\tx_potion_" + std::string (name[index]) + "_01.dds";
|
||||||
|
|
||||||
|
newRecord.mEffects.mList = mEffects;
|
||||||
|
|
||||||
|
record = MWBase::Environment::get().getWorld()->createRecord (newRecord).second;
|
||||||
|
}
|
||||||
|
|
||||||
|
MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), record->mId);
|
||||||
|
MWWorld::Class::get (mAlchemist).getContainerStore (mAlchemist).add (ref.getPtr());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MWMechanics::Alchemy::increaseSkill()
|
||||||
|
{
|
||||||
|
MWWorld::Class::get (mAlchemist).skillUsageSucceeded (mAlchemist, ESM::Skill::Alchemy, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
float MWMechanics::Alchemy::getChance() const
|
||||||
|
{
|
||||||
|
const CreatureStats& creatureStats = MWWorld::Class::get (mAlchemist).getCreatureStats (mAlchemist);
|
||||||
|
const NpcStats& npcStats = MWWorld::Class::get (mAlchemist).getNpcStats (mAlchemist);
|
||||||
|
|
||||||
|
return
|
||||||
|
(npcStats.getSkill (ESM::Skill::Alchemy).getModified() +
|
||||||
|
0.1 * creatureStats.getAttribute (1).getModified()
|
||||||
|
+ 0.1 * creatureStats.getAttribute (7).getModified());
|
||||||
|
}
|
||||||
|
|
||||||
|
int MWMechanics::Alchemy::countIngredients() const
|
||||||
|
{
|
||||||
|
int ingredients = 0;
|
||||||
|
|
||||||
|
for (TIngredientsIterator iter (beginIngredients()); iter!=endIngredients(); ++iter)
|
||||||
|
if (!iter->isEmpty())
|
||||||
|
++ingredients;
|
||||||
|
|
||||||
|
return ingredients;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MWMechanics::Alchemy::setAlchemist (const MWWorld::Ptr& npc)
|
||||||
|
{
|
||||||
|
mAlchemist = npc;
|
||||||
|
|
||||||
|
mIngredients.resize (4);
|
||||||
|
|
||||||
|
std::fill (mIngredients.begin(), mIngredients.end(), MWWorld::Ptr());
|
||||||
|
|
||||||
|
mTools.resize (4);
|
||||||
|
|
||||||
|
std::fill (mTools.begin(), mTools.end(), MWWorld::Ptr());
|
||||||
|
|
||||||
|
mEffects.clear();
|
||||||
|
|
||||||
|
MWWorld::ContainerStore& store = MWWorld::Class::get (npc).getContainerStore (npc);
|
||||||
|
|
||||||
|
for (MWWorld::ContainerStoreIterator iter (store.begin (MWWorld::ContainerStore::Type_Apparatus));
|
||||||
|
iter!=store.end(); ++iter)
|
||||||
|
{
|
||||||
|
MWWorld::LiveCellRef<ESM::Apparatus>* ref = iter->get<ESM::Apparatus>();
|
||||||
|
|
||||||
|
int type = ref->base->mData.mType;
|
||||||
|
|
||||||
|
if (type<0 || type>=static_cast<int> (mTools.size()))
|
||||||
|
throw std::runtime_error ("invalid apparatus type");
|
||||||
|
|
||||||
|
if (!mTools[type].isEmpty())
|
||||||
|
if (ref->base->mData.mQuality<=mTools[type].get<ESM::Apparatus>()->base->mData.mQuality)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
mTools[type] = *iter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MWMechanics::Alchemy::TToolsIterator MWMechanics::Alchemy::beginTools() const
|
||||||
|
{
|
||||||
|
return mTools.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
MWMechanics::Alchemy::TToolsIterator MWMechanics::Alchemy::endTools() const
|
||||||
|
{
|
||||||
|
return mTools.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
MWMechanics::Alchemy::TIngredientsIterator MWMechanics::Alchemy::beginIngredients() const
|
||||||
|
{
|
||||||
|
return mIngredients.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
MWMechanics::Alchemy::TIngredientsIterator MWMechanics::Alchemy::endIngredients() const
|
||||||
|
{
|
||||||
|
return mIngredients.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MWMechanics::Alchemy::clear()
|
||||||
|
{
|
||||||
|
mAlchemist = MWWorld::Ptr();
|
||||||
|
mTools.clear();
|
||||||
|
mIngredients.clear();
|
||||||
|
mEffects.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
int MWMechanics::Alchemy::addIngredient (const MWWorld::Ptr& ingredient)
|
||||||
|
{
|
||||||
|
// find a free slot
|
||||||
|
int slot = -1;
|
||||||
|
|
||||||
|
for (int i=0; i<static_cast<int> (mIngredients.size()); ++i)
|
||||||
|
if (mIngredients[i].isEmpty())
|
||||||
|
{
|
||||||
|
slot = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slot==-1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (TIngredientsIterator iter (mIngredients.begin()); iter!=mIngredients.end(); ++iter)
|
||||||
|
if (!iter->isEmpty() && ingredient.get<ESM::Ingredient>()==iter->get<ESM::Ingredient>())
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
mIngredients[slot] = ingredient;
|
||||||
|
|
||||||
|
updateEffects();
|
||||||
|
|
||||||
|
return slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MWMechanics::Alchemy::removeIngredient (int index)
|
||||||
|
{
|
||||||
|
if (index>=0 && index<static_cast<int> (mIngredients.size()))
|
||||||
|
{
|
||||||
|
mIngredients[index] = MWWorld::Ptr();
|
||||||
|
updateEffects();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MWMechanics::Alchemy::TEffectsIterator MWMechanics::Alchemy::beginEffects() const
|
||||||
|
{
|
||||||
|
return mEffects.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
MWMechanics::Alchemy::TEffectsIterator MWMechanics::Alchemy::endEffects() const
|
||||||
|
{
|
||||||
|
return mEffects.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string MWMechanics::Alchemy::getPotionName() const
|
||||||
|
{
|
||||||
|
if (const ESM::Potion *potion = getRecord())
|
||||||
|
return potion->mName;
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
MWMechanics::Alchemy::Result MWMechanics::Alchemy::create (const std::string& name)
|
||||||
|
{
|
||||||
|
if (mTools[ESM::Apparatus::MortarPestle].isEmpty())
|
||||||
|
return Result_NoMortarAndPestle;
|
||||||
|
|
||||||
|
if (countIngredients()<2)
|
||||||
|
return Result_LessThanTwoIngredients;
|
||||||
|
|
||||||
|
if (name.empty() && getPotionName().empty())
|
||||||
|
return Result_NoName;
|
||||||
|
|
||||||
|
if (beginEffects()==endEffects())
|
||||||
|
return Result_NoEffects;
|
||||||
|
|
||||||
|
if (getChance()<std::rand()/static_cast<double> (RAND_MAX)*100)
|
||||||
|
{
|
||||||
|
removeIngredients();
|
||||||
|
return Result_RandomFailure;
|
||||||
|
}
|
||||||
|
|
||||||
|
addPotion (name);
|
||||||
|
|
||||||
|
removeIngredients();
|
||||||
|
|
||||||
|
increaseSkill();
|
||||||
|
|
||||||
|
return Result_Success;
|
||||||
|
}
|
121
apps/openmw/mwmechanics/alchemy.hpp
Normal file
121
apps/openmw/mwmechanics/alchemy.hpp
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
#ifndef GAME_MWMECHANICS_ALCHEMY_H
|
||||||
|
#define GAME_MWMECHANICS_ALCHEMY_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
#include <components/esm/effectlist.hpp>
|
||||||
|
|
||||||
|
#include "../mwworld/ptr.hpp"
|
||||||
|
|
||||||
|
namespace MWMechanics
|
||||||
|
{
|
||||||
|
struct EffectKey;
|
||||||
|
|
||||||
|
/// \brief Potion creation via alchemy skill
|
||||||
|
class Alchemy
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
typedef std::vector<MWWorld::Ptr> TToolsContainer;
|
||||||
|
typedef TToolsContainer::const_iterator TToolsIterator;
|
||||||
|
|
||||||
|
typedef std::vector<MWWorld::Ptr> TIngredientsContainer;
|
||||||
|
typedef TIngredientsContainer::const_iterator TIngredientsIterator;
|
||||||
|
|
||||||
|
typedef std::vector<ESM::ENAMstruct> TEffectsContainer;
|
||||||
|
typedef TEffectsContainer::const_iterator TEffectsIterator;
|
||||||
|
|
||||||
|
enum Result
|
||||||
|
{
|
||||||
|
Result_Success,
|
||||||
|
|
||||||
|
Result_NoMortarAndPestle,
|
||||||
|
Result_LessThanTwoIngredients,
|
||||||
|
Result_NoName,
|
||||||
|
Result_NoEffects,
|
||||||
|
Result_RandomFailure
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
MWWorld::Ptr mAlchemist;
|
||||||
|
TToolsContainer mTools;
|
||||||
|
TIngredientsContainer mIngredients;
|
||||||
|
TEffectsContainer mEffects;
|
||||||
|
int mValue;
|
||||||
|
|
||||||
|
std::set<EffectKey> listEffects() const;
|
||||||
|
///< List all effects of all used ingredients.
|
||||||
|
|
||||||
|
void filterEffects (std::set<EffectKey>& effects) const;
|
||||||
|
///< Filter out effects not shared by all ingredients.
|
||||||
|
|
||||||
|
void applyTools (int flags, float& value) const;
|
||||||
|
|
||||||
|
void updateEffects();
|
||||||
|
|
||||||
|
const ESM::Potion *getRecord() const;
|
||||||
|
///< Return existing recrod for created potion (may return 0)
|
||||||
|
|
||||||
|
void removeIngredients();
|
||||||
|
///< Remove selected ingredients from alchemist's inventory, cleanup selected ingredients and
|
||||||
|
/// update effect list accordingly.
|
||||||
|
|
||||||
|
void addPotion (const std::string& name);
|
||||||
|
///< Add a potion to the alchemist's inventory.
|
||||||
|
|
||||||
|
void increaseSkill();
|
||||||
|
///< Increase alchemist's skill.
|
||||||
|
|
||||||
|
float getChance() const;
|
||||||
|
///< Return chance of success.
|
||||||
|
|
||||||
|
int countIngredients() const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
void setAlchemist (const MWWorld::Ptr& npc);
|
||||||
|
///< Set alchemist and configure alchemy setup accordingly. \a npc may be empty to indicate that
|
||||||
|
/// there is no alchemist (alchemy session has ended).
|
||||||
|
|
||||||
|
TToolsIterator beginTools() const;
|
||||||
|
///< \attention Iterates over tool slots, not over tools. Some of the slots may be empty.
|
||||||
|
|
||||||
|
TToolsIterator endTools() const;
|
||||||
|
|
||||||
|
TIngredientsIterator beginIngredients() const;
|
||||||
|
///< \attention Iterates over ingredient slots, not over ingredients. Some of the slots may be empty.
|
||||||
|
|
||||||
|
TIngredientsIterator endIngredients() const;
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
///< Remove alchemist, tools and ingredients.
|
||||||
|
|
||||||
|
int addIngredient (const MWWorld::Ptr& ingredient);
|
||||||
|
///< Add ingredient into the next free slot.
|
||||||
|
///
|
||||||
|
/// \return Slot index or -1, if adding failed because of no free slot or the ingredient type being
|
||||||
|
/// listed already.
|
||||||
|
|
||||||
|
void removeIngredient (int index);
|
||||||
|
///< Remove ingredient from slot (calling this function on an empty slot is a no-op).
|
||||||
|
|
||||||
|
TEffectsIterator beginEffects() const;
|
||||||
|
|
||||||
|
TEffectsIterator endEffects() const;
|
||||||
|
|
||||||
|
std::string getPotionName() const;
|
||||||
|
///< Return the name of the potion that would be created when calling create (if a record for such
|
||||||
|
/// a potion already exists) or return an empty string.
|
||||||
|
|
||||||
|
Result create (const std::string& name);
|
||||||
|
///< Try to create a potion from the ingredients, place it in the inventory of the alchemist and
|
||||||
|
/// adjust the skills of the alchemist accordingly.
|
||||||
|
/// \param name must not be an empty string, unless there is already a potion record (
|
||||||
|
/// getPotionName() does not return an empty string).
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -326,6 +326,14 @@ namespace MWWorld
|
||||||
}
|
}
|
||||||
|
|
||||||
Ptr World::getPtrViaHandle (const std::string& handle)
|
Ptr World::getPtrViaHandle (const std::string& handle)
|
||||||
|
{
|
||||||
|
Ptr res = searchPtrViaHandle (handle);
|
||||||
|
if (res.isEmpty ())
|
||||||
|
throw std::runtime_error ("unknown Ogre handle: " + handle);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ptr World::searchPtrViaHandle (const std::string& handle)
|
||||||
{
|
{
|
||||||
if (mPlayer->getPlayer().getRefData().getHandle()==handle)
|
if (mPlayer->getPlayer().getRefData().getHandle()==handle)
|
||||||
return mPlayer->getPlayer();
|
return mPlayer->getPlayer();
|
||||||
|
@ -339,7 +347,7 @@ namespace MWWorld
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw std::runtime_error ("unknown Ogre handle: " + handle);
|
return MWWorld::Ptr();
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::enable (const Ptr& reference)
|
void World::enable (const Ptr& reference)
|
||||||
|
@ -850,12 +858,13 @@ namespace MWWorld
|
||||||
mWeatherManager->update (duration);
|
mWeatherManager->update (duration);
|
||||||
|
|
||||||
// inform the GUI about focused object
|
// inform the GUI about focused object
|
||||||
try
|
MWWorld::Ptr object = searchPtrViaHandle(mFacedHandle);
|
||||||
{
|
|
||||||
MWWorld::Ptr object = getPtrViaHandle(mFacedHandle);
|
|
||||||
MWBase::Environment::get().getWindowManager()->setFocusObject(object);
|
|
||||||
|
|
||||||
// retrieve object dimensions so we know where to place the floating label
|
MWBase::Environment::get().getWindowManager()->setFocusObject(object);
|
||||||
|
|
||||||
|
// retrieve object dimensions so we know where to place the floating label
|
||||||
|
if (!object.isEmpty ())
|
||||||
|
{
|
||||||
Ogre::SceneNode* node = object.getRefData().getBaseNode();
|
Ogre::SceneNode* node = object.getRefData().getBaseNode();
|
||||||
Ogre::AxisAlignedBox bounds;
|
Ogre::AxisAlignedBox bounds;
|
||||||
int i;
|
int i;
|
||||||
|
@ -871,11 +880,6 @@ namespace MWWorld
|
||||||
screenCoords[0], screenCoords[1], screenCoords[2], screenCoords[3]);
|
screenCoords[0], screenCoords[1], screenCoords[2], screenCoords[3]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (std::runtime_error&)
|
|
||||||
{
|
|
||||||
MWWorld::Ptr null;
|
|
||||||
MWBase::Environment::get().getWindowManager()->setFocusObject(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mRendering->occlusionQuerySupported())
|
if (!mRendering->occlusionQuerySupported())
|
||||||
{
|
{
|
||||||
|
|
|
@ -163,6 +163,9 @@ namespace MWWorld
|
||||||
virtual Ptr getPtrViaHandle (const std::string& handle);
|
virtual Ptr getPtrViaHandle (const std::string& handle);
|
||||||
///< Return a pointer to a liveCellRef with the given Ogre handle.
|
///< Return a pointer to a liveCellRef with the given Ogre handle.
|
||||||
|
|
||||||
|
virtual Ptr searchPtrViaHandle (const std::string& handle);
|
||||||
|
///< Return a pointer to a liveCellRef with the given Ogre handle or Ptr() if not found
|
||||||
|
|
||||||
virtual void enable (const Ptr& ptr);
|
virtual void enable (const Ptr& ptr);
|
||||||
|
|
||||||
virtual void disable (const Ptr& ptr);
|
virtual void disable (const Ptr& ptr);
|
||||||
|
|
|
@ -26,7 +26,6 @@ struct MagicEffect
|
||||||
NonRecastable = 0x4000, // Does not land if parent spell is already affecting target. Shows "you cannot re-cast" message for self target.
|
NonRecastable = 0x4000, // Does not land if parent spell is already affecting target. Shows "you cannot re-cast" message for self target.
|
||||||
Unreflectable = 0x10000, // Cannot be reflected, the effect always lands normally.
|
Unreflectable = 0x10000, // Cannot be reflected, the effect always lands normally.
|
||||||
CasterLinked = 0x20000, // Must quench if caster is dead, or not an NPC/creature. Not allowed in containter/door trap spells.
|
CasterLinked = 0x20000, // Must quench if caster is dead, or not an NPC/creature. Not allowed in containter/door trap spells.
|
||||||
|
|
||||||
SpellMaking = 0x0200,
|
SpellMaking = 0x0200,
|
||||||
Enchanting = 0x0400,
|
Enchanting = 0x0400,
|
||||||
Negative = 0x0800 // A harmful effect. Will determine whether
|
Negative = 0x0800 // A harmful effect. Will determine whether
|
||||||
|
|
Loading…
Reference in a new issue