1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-03-13 07:14:31 +00:00
This commit is contained in:
scrawl 2012-10-19 20:21:34 +02:00
commit 475163bd4a
33 changed files with 1330 additions and 410 deletions

View File

@ -30,7 +30,7 @@ add_openmw_dir (mwgui
formatting inventorywindow container hud countdialog tradewindow settingswindow formatting inventorywindow container hud countdialog tradewindow settingswindow
confirmationdialog alchemywindow referenceinterface spellwindow mainmenu quickkeysmenu confirmationdialog alchemywindow referenceinterface spellwindow mainmenu quickkeysmenu
itemselection spellbuyingwindow loadingscreen levelupdialog waitdialog spellcreationdialog itemselection spellbuyingwindow loadingscreen levelupdialog waitdialog spellcreationdialog
enchantingdialog enchantingdialog trainingwindow travelwindow
) )
add_openmw_dir (mwdialogue add_openmw_dir (mwdialogue
@ -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

View File

@ -163,9 +163,8 @@ void OMW::Engine::loadBSA()
std::cout << "Data dir " << dataDirectory << std::endl; std::cout << "Data dir " << dataDirectory << std::endl;
Bsa::addDir(dataDirectory, mFSStrict); Bsa::addDir(dataDirectory, mFSStrict);
// Workaround: Mygui does not find textures in non-BSA subfolders, _unless_ they are explicitely added like this // Workaround until resource listing capabilities are added to DirArchive, we need those to list available splash screens
// For splash screens, this is OK to do, but eventually we will need an investigation why this is necessary addResourcesDirectory (dataDirectory);
Bsa::addDir(dataDirectory + "/Splash", mFSStrict);
} }
} }
@ -424,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);

View File

@ -42,6 +42,7 @@ namespace MWGui
class Console; class Console;
class SpellWindow; class SpellWindow;
class TradeWindow; class TradeWindow;
class TravelWindow;
class SpellBuyingWindow; class SpellBuyingWindow;
class ConfirmationDialog; class ConfirmationDialog;
class CountDialog; class CountDialog;
@ -108,6 +109,7 @@ namespace MWBase
virtual MWGui::ConfirmationDialog* getConfirmationDialog() = 0; virtual MWGui::ConfirmationDialog* getConfirmationDialog() = 0;
virtual MWGui::TradeWindow* getTradeWindow() = 0; virtual MWGui::TradeWindow* getTradeWindow() = 0;
virtual MWGui::SpellBuyingWindow* getSpellBuyingWindow() = 0; virtual MWGui::SpellBuyingWindow* getSpellBuyingWindow() = 0;
virtual MWGui::TravelWindow* getTravelWindow() = 0;
virtual MWGui::SpellWindow* getSpellWindow() = 0; virtual MWGui::SpellWindow* getSpellWindow() = 0;
virtual MWGui::Console* getConsole() = 0; virtual MWGui::Console* getConsole() = 0;
@ -230,6 +232,7 @@ namespace MWBase
virtual void startSpellMaking(MWWorld::Ptr actor) = 0; virtual void startSpellMaking(MWWorld::Ptr actor) = 0;
virtual void startEnchanting(MWWorld::Ptr actor) = 0; virtual void startEnchanting(MWWorld::Ptr actor) = 0;
virtual void startTraining(MWWorld::Ptr actor) = 0;
}; };
} }

View File

@ -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;

View File

@ -795,12 +795,18 @@ namespace MWDialogue
|| services & ESM::NPC::Misc) || services & ESM::NPC::Misc)
windowServices |= MWGui::DialogueWindow::Service_Trade; windowServices |= MWGui::DialogueWindow::Service_Trade;
if( !mActor.get<ESM::NPC>()->base->mTransport.empty())
windowServices |= MWGui::DialogueWindow::Service_Travel;
if (services & ESM::NPC::Spells) if (services & ESM::NPC::Spells)
windowServices |= MWGui::DialogueWindow::Service_BuySpells; windowServices |= MWGui::DialogueWindow::Service_BuySpells;
if (services & ESM::NPC::Spellmaking) if (services & ESM::NPC::Spellmaking)
windowServices |= MWGui::DialogueWindow::Service_CreateSpells; windowServices |= MWGui::DialogueWindow::Service_CreateSpells;
if (services & ESM::NPC::Training)
windowServices |= MWGui::DialogueWindow::Service_Training;
if (services & ESM::NPC::Enchanting) if (services & ESM::NPC::Enchanting)
windowServices |= MWGui::DialogueWindow::Service_Enchant; windowServices |= MWGui::DialogueWindow::Service_Enchant;

View File

@ -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);
} }
} }

View File

@ -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;
}; };
} }

View File

@ -19,6 +19,7 @@
#include "tradewindow.hpp" #include "tradewindow.hpp"
#include "spellbuyingwindow.hpp" #include "spellbuyingwindow.hpp"
#include "inventorywindow.hpp" #include "inventorywindow.hpp"
#include "travelwindow.hpp"
using namespace MWGui; using namespace MWGui;
using namespace Widgets; using namespace Widgets;
@ -137,6 +138,11 @@ void DialogueWindow::onSelectTopic(std::string topic)
mWindowManager.pushGuiMode(GM_SpellBuying); mWindowManager.pushGuiMode(GM_SpellBuying);
mWindowManager.getSpellBuyingWindow()->startSpellBuying(mPtr); mWindowManager.getSpellBuyingWindow()->startSpellBuying(mPtr);
} }
else if (topic == MWBase::Environment::get().getWorld()->getStore().gameSettings.find("sTravel")->getString())
{
mWindowManager.pushGuiMode(GM_Travel);
mWindowManager.getTravelWindow()->startTravel(mPtr);
}
else if (topic == MWBase::Environment::get().getWorld()->getStore().gameSettings.find("sSpellMakingMenuTitle")->getString()) else if (topic == MWBase::Environment::get().getWorld()->getStore().gameSettings.find("sSpellMakingMenuTitle")->getString())
{ {
mWindowManager.pushGuiMode(GM_SpellCreation); mWindowManager.pushGuiMode(GM_SpellCreation);
@ -147,6 +153,11 @@ void DialogueWindow::onSelectTopic(std::string topic)
mWindowManager.pushGuiMode(GM_Enchanting); mWindowManager.pushGuiMode(GM_Enchanting);
mWindowManager.startEnchanting (mPtr); mWindowManager.startEnchanting (mPtr);
} }
else if (topic == MWBase::Environment::get().getWorld()->getStore().gameSettings.find("sServiceTrainingTitle")->getString())
{
mWindowManager.pushGuiMode(GM_Training);
mWindowManager.startTraining (mPtr);
}
else else
MWBase::Environment::get().getDialogueManager()->keywordSelected(lower_string(topic)); MWBase::Environment::get().getDialogueManager()->keywordSelected(lower_string(topic));
} }
@ -175,12 +186,18 @@ void DialogueWindow::setKeywords(std::list<std::string> keyWords)
if (mServices & Service_BuySpells) if (mServices & Service_BuySpells)
mTopicsList->addItem(MWBase::Environment::get().getWorld()->getStore().gameSettings.find("sSpells")->getString()); mTopicsList->addItem(MWBase::Environment::get().getWorld()->getStore().gameSettings.find("sSpells")->getString());
if (mServices & Service_Travel)
mTopicsList->addItem(MWBase::Environment::get().getWorld()->getStore().gameSettings.find("sTravel")->getString());
if (mServices & Service_CreateSpells) if (mServices & Service_CreateSpells)
mTopicsList->addItem(MWBase::Environment::get().getWorld()->getStore().gameSettings.find("sSpellmakingMenuTitle")->getString()); mTopicsList->addItem(MWBase::Environment::get().getWorld()->getStore().gameSettings.find("sSpellmakingMenuTitle")->getString());
if (mServices & Service_Enchant) if (mServices & Service_Enchant)
mTopicsList->addItem(MWBase::Environment::get().getWorld()->getStore().gameSettings.find("sEnchanting")->getString()); mTopicsList->addItem(MWBase::Environment::get().getWorld()->getStore().gameSettings.find("sEnchanting")->getString());
if (mServices & Service_Training)
mTopicsList->addItem(MWBase::Environment::get().getWorld()->getStore().gameSettings.find("sServiceTrainingTitle")->getString());
if (anyService) if (anyService)
mTopicsList->addSeparator(); mTopicsList->addSeparator();

View File

@ -48,7 +48,6 @@ namespace MWGui
void askQuestion(std::string question); void askQuestion(std::string question);
void goodbye(); void goodbye();
// various service button visibilities, depending if the npc/creature talked to has these services
// make sure to call these before setKeywords() // make sure to call these before setKeywords()
void setServices(int services) { mServices = services; } void setServices(int services) { mServices = services; }
@ -57,7 +56,9 @@ namespace MWGui
Service_Trade = 0x01, Service_Trade = 0x01,
Service_BuySpells = 0x02, Service_BuySpells = 0x02,
Service_CreateSpells = 0x04, Service_CreateSpells = 0x04,
Service_Enchant = 0x08 Service_Enchant = 0x08,
Service_Training = 0x10,
Service_Travel = 0x20
}; };
protected: protected:
@ -76,10 +77,6 @@ namespace MWGui
*/ */
std::string parseText(std::string text); std::string parseText(std::string text);
// various service button visibilities, depending if the npc/creature talked to has these services
bool mShowTrade;
bool mShowSpells;
int mServices; int mServices;
bool mEnabled; bool mEnabled;

View File

@ -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);

View File

@ -6,10 +6,13 @@
#include <OgreCompositorChain.h> #include <OgreCompositorChain.h>
#include <OgreMaterial.h> #include <OgreMaterial.h>
#include <boost/algorithm/string.hpp>
#include <openengine/ogre/fader.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/inputmanager.hpp" #include "../mwbase/inputmanager.hpp"
#include "../mwbase/world.hpp"
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
@ -106,6 +109,7 @@ namespace MWGui
if (mTimer.getMilliseconds () > mLastRenderTime + (1.f/loadingScreenFps) * 1000.f) if (mTimer.getMilliseconds () > mLastRenderTime + (1.f/loadingScreenFps) * 1000.f)
{ {
float dt = mTimer.getMilliseconds () - mLastRenderTime;
mLastRenderTime = mTimer.getMilliseconds (); mLastRenderTime = mTimer.getMilliseconds ();
if (mFirstLoad && mTimer.getMilliseconds () > mLastWallpaperChangeTime + 3000*1) if (mFirstLoad && mTimer.getMilliseconds () > mLastWallpaperChangeTime + 3000*1)
@ -151,6 +155,8 @@ namespace MWGui
} }
} }
MWBase::Environment::get().getWorld ()->getFader ()->update (dt);
mWindow->update(); mWindow->update();
if (!hasCompositor) if (!hasCompositor)
@ -207,20 +213,22 @@ namespace MWGui
void LoadingScreen::changeWallpaper () void LoadingScreen::changeWallpaper ()
{ {
/// \todo use a directory listing here
std::vector<std::string> splash; std::vector<std::string> splash;
splash.push_back ("Splash_Bonelord.tga");
splash.push_back ("Splash_ClannDaddy.tga");
splash.push_back ("Splash_Clannfear.tga");
splash.push_back ("Splash_Daedroth.tga");
splash.push_back ("Splash_Hunger.tga");
splash.push_back ("Splash_KwamaWarrior.tga");
splash.push_back ("Splash_Netch.tga");
splash.push_back ("Splash_NixHound.tga");
splash.push_back ("Splash_Siltstriker.tga");
splash.push_back ("Splash_Skeleton.tga");
splash.push_back ("Splash_SphereCenturion.tga");
mBackgroundImage->setImageTexture (splash[rand() % splash.size()]); Ogre::StringVectorPtr resources = Ogre::ResourceGroupManager::getSingleton ().listResourceNames ("General", false);
for (Ogre::StringVector::const_iterator it = resources->begin(); it != resources->end(); ++it)
{
if (it->size() < 6)
continue;
std::string start = it->substr(0, 6);
boost::to_lower(start);
if (start == "splash")
splash.push_back (*it);
}
std::string randomSplash = splash[rand() % splash.size()];
Ogre::TexturePtr tex = Ogre::TextureManager::getSingleton ().load (randomSplash, "General");
mBackgroundImage->setImageTexture (randomSplash);
} }
} }

View File

@ -22,8 +22,10 @@ namespace MWGui
GM_Rest, GM_Rest,
GM_RestBed, GM_RestBed,
GM_SpellBuying, GM_SpellBuying,
GM_Travel,
GM_SpellCreation, GM_SpellCreation,
GM_Enchanting, GM_Enchanting,
GM_Training,
GM_Levelup, GM_Levelup,

View File

@ -54,7 +54,7 @@ namespace MWGui
MyGUI::Button* toAdd = MyGUI::Button* toAdd =
mSpellsView->createWidget<MyGUI::Button>( mSpellsView->createWidget<MyGUI::Button>(
(price>mWindowManager.getInventoryWindow()->getPlayerGold()) ? "SandTextGreyedOut" : "SpellText", (price>mWindowManager.getInventoryWindow()->getPlayerGold()) ? "SandTextGreyedOut" : "SandTextButton",
0, 0,
mCurrentY, mCurrentY,
200, 200,

View File

@ -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);

View File

@ -0,0 +1,159 @@
#include "trainingwindow.hpp"
#include <boost/lexical_cast.hpp>
#include <openengine/ogre/fader.hpp>
#include "../mwbase/windowmanager.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/player.hpp"
#include "../mwmechanics/npcstats.hpp"
#include "inventorywindow.hpp"
#include "tradewindow.hpp"
#include "tooltips.hpp"
namespace MWGui
{
TrainingWindow::TrainingWindow(MWBase::WindowManager &parWindowManager)
: WindowBase("openmw_trainingwindow.layout", parWindowManager)
, mFadeTimeRemaining(0)
{
getWidget(mTrainingOptions, "TrainingOptions");
getWidget(mCancelButton, "CancelButton");
getWidget(mPlayerGold, "PlayerGold");
mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TrainingWindow::onCancelButtonClicked);
}
void TrainingWindow::open()
{
center();
}
void TrainingWindow::startTraining (MWWorld::Ptr actor)
{
mPtr = actor;
mPlayerGold->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast<std::string>(mWindowManager.getInventoryWindow()->getPlayerGold()));
MWMechanics::NpcStats& npcStats = MWWorld::Class::get(actor).getNpcStats (actor);
// NPC can train you in his best 3 skills
std::vector< std::pair<int, int> > bestSkills;
bestSkills.push_back (std::make_pair(-1, -1));
bestSkills.push_back (std::make_pair(-1, -1));
bestSkills.push_back (std::make_pair(-1, -1));
for (int i=0; i<ESM::Skill::Length; ++i)
{
int value = npcStats.getSkill (i).getBase ();
for (int j=0; j<3; ++j)
{
if (value > bestSkills[j].second)
{
if (j<2)
{
bestSkills[j+1] = bestSkills[j];
}
bestSkills[j] = std::make_pair(i, value);
break;
}
}
}
MyGUI::EnumeratorWidgetPtr widgets = mTrainingOptions->getEnumerator ();
MyGUI::Gui::getInstance ().destroyWidgets (widgets);
MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer ();
MWMechanics::NpcStats& pcStats = MWWorld::Class::get(player).getNpcStats (player);
for (int i=0; i<3; ++i)
{
/// \todo mercantile skill
int price = pcStats.getSkill (bestSkills[i].first).getBase() * MWBase::Environment::get().getWorld ()->getStore ().gameSettings.find("iTrainingMod")->getInt ();
std::string skin = (price > mWindowManager.getInventoryWindow ()->getPlayerGold ()) ? "SandTextGreyedOut" : "SandTextButton";
MyGUI::Button* button = mTrainingOptions->createWidget<MyGUI::Button>(skin,
MyGUI::IntCoord(5, 5+i*18, mTrainingOptions->getWidth()-10, 18), MyGUI::Align::Default);
button->setUserData(bestSkills[i].first);
button->eventMouseButtonClick += MyGUI::newDelegate(this, &TrainingWindow::onTrainingSelected);
button->setCaptionWithReplacing("#{" + ESM::Skill::sSkillNameIds[bestSkills[i].first] + "} - " + boost::lexical_cast<std::string>(price));
button->setSize(button->getTextSize ().width+12, button->getSize().height);
ToolTips::createSkillToolTip (button, bestSkills[i].first);
}
center();
}
void TrainingWindow::onReferenceUnavailable ()
{
mWindowManager.removeGuiMode(GM_Training);
}
void TrainingWindow::onCancelButtonClicked (MyGUI::Widget *sender)
{
mWindowManager.removeGuiMode (GM_Training);
}
void TrainingWindow::onTrainingSelected (MyGUI::Widget *sender)
{
int skillId = *sender->getUserData<int>();
MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer ();
MWMechanics::NpcStats& pcStats = MWWorld::Class::get(player).getNpcStats (player);
/// \todo mercantile skill
int price = pcStats.getSkill (skillId).getBase() * MWBase::Environment::get().getWorld ()->getStore ().gameSettings.find("iTrainingMod")->getInt ();
if (mWindowManager.getInventoryWindow()->getPlayerGold()<price)
return;
MWMechanics::NpcStats& npcStats = MWWorld::Class::get(mPtr).getNpcStats (mPtr);
if (npcStats.getSkill (skillId).getBase () <= pcStats.getSkill (skillId).getBase ())
{
mWindowManager.messageBox ("#{sServiceTrainingWords}", std::vector<std::string>());
return;
}
// increase skill
MWWorld::LiveCellRef<ESM::NPC> *playerRef = player.get<ESM::NPC>();
const ESM::Class *class_ = MWBase::Environment::get().getWorld()->getStore().classes.find (
playerRef->base->mClass);
pcStats.increaseSkill (skillId, *class_, true);
// remove gold
mWindowManager.getTradeWindow()->addOrRemoveGold(-price);
// go back to game mode
mWindowManager.removeGuiMode (GM_Training);
mWindowManager.removeGuiMode (GM_Dialogue);
// advance time
MWBase::Environment::get().getWorld ()->advanceTime (2);
MWBase::Environment::get().getWorld ()->getFader()->fadeOut(0.25);
mFadeTimeRemaining = 0.5;
}
void TrainingWindow::onFrame(float dt)
{
if (mFadeTimeRemaining <= 0)
return;
mFadeTimeRemaining -= dt;
if (mFadeTimeRemaining <= 0)
MWBase::Environment::get().getWorld ()->getFader()->fadeIn(0.25);
}
}

View File

@ -0,0 +1,36 @@
#ifndef MWGUI_TRAININGWINDOW_H
#define MWGUI_TRAININGWINDOW_H
#include "window_base.hpp"
#include "referenceinterface.hpp"
namespace MWGui
{
class TrainingWindow : public WindowBase, public ReferenceInterface
{
public:
TrainingWindow(MWBase::WindowManager& parWindowManager);
virtual void open();
void startTraining(MWWorld::Ptr actor);
void onFrame(float dt);
protected:
virtual void onReferenceUnavailable ();
void onCancelButtonClicked (MyGUI::Widget* sender);
void onTrainingSelected(MyGUI::Widget* sender);
MyGUI::Widget* mTrainingOptions;
MyGUI::Button* mCancelButton;
MyGUI::TextBox* mPlayerGold;
float mFadeTimeRemaining;
};
}
#endif

View File

@ -0,0 +1,187 @@
#include "travelwindow.hpp"
#include <algorithm>
#include <boost/lexical_cast.hpp>
#include <libs/openengine/ogre/fader.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwbase/soundmanager.hpp"
#include "../mwbase/windowmanager.hpp"
#include "../mwbase/mechanicsmanager.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/manualref.hpp"
#include "../mwmechanics/spells.hpp"
#include "../mwmechanics/creaturestats.hpp"
#include "inventorywindow.hpp"
#include "tradewindow.hpp"
namespace MWGui
{
const int TravelWindow::sLineHeight = 18;
TravelWindow::TravelWindow(MWBase::WindowManager& parWindowManager) :
WindowBase("openmw_travel_window.layout", parWindowManager)
, mCurrentY(0)
, mLastPos(0)
{
setCoord(0, 0, 450, 300);
getWidget(mCancelButton, "CancelButton");
getWidget(mPlayerGold, "PlayerGold");
getWidget(mSelect, "Select");
getWidget(mDestinations, "Travel");
getWidget(mDestinationsView, "DestinationsView");
mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TravelWindow::onCancelButtonClicked);
mDestinations->setCoord(450/2-mDestinations->getTextSize().width/2,
mDestinations->getTop(),
mDestinations->getTextSize().width,
mDestinations->getHeight());
mSelect->setCoord(8,
mSelect->getTop(),
mSelect->getTextSize().width,
mSelect->getHeight());
}
void TravelWindow::addDestination(const std::string& travelId,ESM::Position pos,bool interior)
{
int price = 0;
if(interior)
{
price = MWBase::Environment::get().getWorld()->getStore().gameSettings.find("fMagesGuildTravel")->getFloat();
}
else
{
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
ESM::Position PlayerPos = player.getRefData().getPosition();
float d = sqrt( pow(pos.pos[0] - PlayerPos.pos[0],2) + pow(pos.pos[1] - PlayerPos.pos[1],2) + pow(pos.pos[2] - PlayerPos.pos[2],2) );
price = d/MWBase::Environment::get().getWorld()->getStore().gameSettings.find("fTravelMult")->getFloat();
}
MyGUI::Button* toAdd = mDestinationsView->createWidget<MyGUI::Button>((price>mWindowManager.getInventoryWindow()->getPlayerGold()) ? "SandTextGreyedOut" : "SandTextButton", 0, mCurrentY, 200, sLineHeight, MyGUI::Align::Default);
mCurrentY += sLineHeight;
/// \todo price adjustment depending on merchantile skill
if(interior)
toAdd->setUserString("interior","y");
else
toAdd->setUserString("interior","n");
std::ostringstream oss;
oss << price;
toAdd->setUserString("price",oss.str());
toAdd->setCaptionWithReplacing(travelId+" - "+boost::lexical_cast<std::string>(price)+"#{sgp}");
toAdd->setSize(toAdd->getTextSize().width,sLineHeight);
toAdd->eventMouseWheel += MyGUI::newDelegate(this, &TravelWindow::onMouseWheel);
toAdd->setUserString("Destination", travelId);
toAdd->setUserData(pos);
toAdd->eventMouseButtonClick += MyGUI::newDelegate(this, &TravelWindow::onTravelButtonClick);
mDestinationsWidgetMap.insert(std::make_pair (toAdd, travelId));
}
void TravelWindow::clearDestinations()
{
mDestinationsView->setViewOffset(MyGUI::IntPoint(0,0));
mCurrentY = 0;
while (mDestinationsView->getChildCount())
MyGUI::Gui::getInstance().destroyWidget(mDestinationsView->getChildAt(0));
mDestinationsWidgetMap.clear();
}
void TravelWindow::startTravel(const MWWorld::Ptr& actor)
{
center();
mPtr = actor;
clearDestinations();
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
for(unsigned int i = 0;i<mPtr.get<ESM::NPC>()->base->mTransport.size();i++)
{
std::string cellname = mPtr.get<ESM::NPC>()->base->mTransport[i].mCellName;
bool interior = true;
int x,y;
MWBase::Environment::get().getWorld()->positionToIndex(mPtr.get<ESM::NPC>()->base->mTransport[i].mPos.pos[0],
mPtr.get<ESM::NPC>()->base->mTransport[i].mPos.pos[1],x,y);
if(cellname == "") {cellname = MWBase::Environment::get().getWorld()->getExterior(x,y)->cell->mName; interior= false;}
addDestination(cellname,mPtr.get<ESM::NPC>()->base->mTransport[i].mPos,interior);
}
updateLabels();
mDestinationsView->setCanvasSize (MyGUI::IntSize(mDestinationsView->getWidth(), std::max(mDestinationsView->getHeight(), mCurrentY)));
}
void TravelWindow::onTravelButtonClick(MyGUI::Widget* _sender)
{
std::istringstream iss(_sender->getUserString("price"));
int price;
iss >> price;
if (mWindowManager.getInventoryWindow()->getPlayerGold()<price)
return;
MWBase::Environment::get().getWorld ()->getFader ()->fadeOut(1);
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
ESM::Position pos = *_sender->getUserData<ESM::Position>();
std::string cellname = _sender->getUserString("Destination");
int x,y;
bool interior = _sender->getUserString("interior") == "y";
MWBase::Environment::get().getWorld()->positionToIndex(pos.pos[0],pos.pos[1],x,y);
MWWorld::CellStore* cell;
if(interior) cell = MWBase::Environment::get().getWorld()->getInterior(cellname);
else
{
cell = MWBase::Environment::get().getWorld()->getExterior(x,y);
ESM::Position PlayerPos = player.getRefData().getPosition();
float d = sqrt( pow(pos.pos[0] - PlayerPos.pos[0],2) + pow(pos.pos[1] - PlayerPos.pos[1],2) + pow(pos.pos[2] - PlayerPos.pos[2],2) );
int time = int(d /MWBase::Environment::get().getWorld()->getStore().gameSettings.find("fTravelTimeMult")->getFloat());
for(int i = 0;i < time;i++)
{
MWBase::Environment::get().getMechanicsManager ()->restoreDynamicStats ();
}
MWBase::Environment::get().getWorld()->advanceTime(time);
}
MWBase::Environment::get().getWorld()->moveObject(player,*cell,pos.pos[0],pos.pos[1],pos.pos[2]);
mWindowManager.removeGuiMode(GM_Travel);
mWindowManager.removeGuiMode(GM_Dialogue);
MWBase::Environment::get().getWorld ()->getFader ()->fadeOut(0);
MWBase::Environment::get().getWorld ()->getFader ()->fadeIn(1);
}
void TravelWindow::onCancelButtonClicked(MyGUI::Widget* _sender)
{
mWindowManager.removeGuiMode(GM_Travel);
}
void TravelWindow::updateLabels()
{
mPlayerGold->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast<std::string>(mWindowManager.getInventoryWindow()->getPlayerGold()));
mPlayerGold->setCoord(8,
mPlayerGold->getTop(),
mPlayerGold->getTextSize().width,
mPlayerGold->getHeight());
}
void TravelWindow::onReferenceUnavailable()
{
mWindowManager.removeGuiMode(GM_Travel);
mWindowManager.removeGuiMode(GM_Dialogue);
}
void TravelWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel)
{
if (mDestinationsView->getViewOffset().top + _rel*0.3 > 0)
mDestinationsView->setViewOffset(MyGUI::IntPoint(0, 0));
else
mDestinationsView->setViewOffset(MyGUI::IntPoint(0, mDestinationsView->getViewOffset().top + _rel*0.3));
}
}

View File

@ -0,0 +1,55 @@
#ifndef MWGUI_TravelWINDOW_H
#define MWGUI_TravelWINDOW_H
#include "container.hpp"
#include "window_base.hpp"
#include "../mwworld/ptr.hpp"
namespace MyGUI
{
class Gui;
class Widget;
}
namespace MWGui
{
class WindowManager;
}
namespace MWGui
{
class TravelWindow : public ReferenceInterface, public WindowBase
{
public:
TravelWindow(MWBase::WindowManager& parWindowManager);
void startTravel(const MWWorld::Ptr& actor);
protected:
MyGUI::Button* mCancelButton;
MyGUI::TextBox* mPlayerGold;
MyGUI::TextBox* mDestinations;
MyGUI::TextBox* mSelect;
MyGUI::ScrollView* mDestinationsView;
std::map<MyGUI::Widget*, std::string> mDestinationsWidgetMap;
void onCancelButtonClicked(MyGUI::Widget* _sender);
void onTravelButtonClick(MyGUI::Widget* _sender);
void onMouseWheel(MyGUI::Widget* _sender, int _rel);
void addDestination(const std::string& destinationID,ESM::Position pos,bool interior);
void clearDestinations();
int mLastPos,mCurrentY;
static const int sLineHeight;
void updateLabels();
virtual void onReferenceUnavailable();
};
}
#endif

View File

@ -38,6 +38,7 @@
#include "countdialog.hpp" #include "countdialog.hpp"
#include "tradewindow.hpp" #include "tradewindow.hpp"
#include "spellbuyingwindow.hpp" #include "spellbuyingwindow.hpp"
#include "travelwindow.hpp"
#include "settingswindow.hpp" #include "settingswindow.hpp"
#include "confirmationdialog.hpp" #include "confirmationdialog.hpp"
#include "alchemywindow.hpp" #include "alchemywindow.hpp"
@ -48,6 +49,7 @@
#include "waitdialog.hpp" #include "waitdialog.hpp"
#include "spellcreationdialog.hpp" #include "spellcreationdialog.hpp"
#include "enchantingdialog.hpp" #include "enchantingdialog.hpp"
#include "trainingwindow.hpp"
using namespace MWGui; using namespace MWGui;
@ -69,6 +71,7 @@ WindowManager::WindowManager(
, mCountDialog(NULL) , mCountDialog(NULL)
, mTradeWindow(NULL) , mTradeWindow(NULL)
, mSpellBuyingWindow(NULL) , mSpellBuyingWindow(NULL)
, mTravelWindow(NULL)
, mSettingsWindow(NULL) , mSettingsWindow(NULL)
, mConfirmationDialog(NULL) , mConfirmationDialog(NULL)
, mAlchemyWindow(NULL) , mAlchemyWindow(NULL)
@ -79,6 +82,7 @@ WindowManager::WindowManager(
, mWaitDialog(NULL) , mWaitDialog(NULL)
, mSpellCreationDialog(NULL) , mSpellCreationDialog(NULL)
, mEnchantingDialog(NULL) , mEnchantingDialog(NULL)
, mTrainingWindow(NULL)
, mPlayerClass() , mPlayerClass()
, mPlayerName() , mPlayerName()
, mPlayerRaceId() , mPlayerRaceId()
@ -145,6 +149,7 @@ WindowManager::WindowManager(
mInventoryWindow = new InventoryWindow(*this,mDragAndDrop); mInventoryWindow = new InventoryWindow(*this,mDragAndDrop);
mTradeWindow = new TradeWindow(*this); mTradeWindow = new TradeWindow(*this);
mSpellBuyingWindow = new SpellBuyingWindow(*this); mSpellBuyingWindow = new SpellBuyingWindow(*this);
mTravelWindow = new TravelWindow(*this);
mDialogueWindow = new DialogueWindow(*this); mDialogueWindow = new DialogueWindow(*this);
mContainerWindow = new ContainerWindow(*this,mDragAndDrop); mContainerWindow = new ContainerWindow(*this,mDragAndDrop);
mHud = new HUD(w,h, mShowFPSLevel, mDragAndDrop); mHud = new HUD(w,h, mShowFPSLevel, mDragAndDrop);
@ -161,6 +166,7 @@ WindowManager::WindowManager(
mWaitDialog = new WaitDialog(*this); mWaitDialog = new WaitDialog(*this);
mSpellCreationDialog = new SpellCreationDialog(*this); mSpellCreationDialog = new SpellCreationDialog(*this);
mEnchantingDialog = new EnchantingDialog(*this); mEnchantingDialog = new EnchantingDialog(*this);
mTrainingWindow = new TrainingWindow(*this);
mLoadingScreen = new LoadingScreen(mOgre->getScene (), mOgre->getWindow (), *this); mLoadingScreen = new LoadingScreen(mOgre->getScene (), mOgre->getWindow (), *this);
mLoadingScreen->onResChange (w,h); mLoadingScreen->onResChange (w,h);
@ -209,6 +215,7 @@ WindowManager::~WindowManager()
delete mScrollWindow; delete mScrollWindow;
delete mTradeWindow; delete mTradeWindow;
delete mSpellBuyingWindow; delete mSpellBuyingWindow;
delete mTravelWindow;
delete mSettingsWindow; delete mSettingsWindow;
delete mConfirmationDialog; delete mConfirmationDialog;
delete mAlchemyWindow; delete mAlchemyWindow;
@ -218,6 +225,7 @@ WindowManager::~WindowManager()
delete mWaitDialog; delete mWaitDialog;
delete mSpellCreationDialog; delete mSpellCreationDialog;
delete mEnchantingDialog; delete mEnchantingDialog;
delete mTrainingWindow;
cleanupGarbage(); cleanupGarbage();
@ -261,6 +269,7 @@ void WindowManager::updateVisible()
mBookWindow->setVisible(false); mBookWindow->setVisible(false);
mTradeWindow->setVisible(false); mTradeWindow->setVisible(false);
mSpellBuyingWindow->setVisible(false); mSpellBuyingWindow->setVisible(false);
mTravelWindow->setVisible(false);
mSettingsWindow->setVisible(false); mSettingsWindow->setVisible(false);
mAlchemyWindow->setVisible(false); mAlchemyWindow->setVisible(false);
mSpellWindow->setVisible(false); mSpellWindow->setVisible(false);
@ -269,6 +278,7 @@ void WindowManager::updateVisible()
mWaitDialog->setVisible(false); mWaitDialog->setVisible(false);
mSpellCreationDialog->setVisible(false); mSpellCreationDialog->setVisible(false);
mEnchantingDialog->setVisible(false); mEnchantingDialog->setVisible(false);
mTrainingWindow->setVisible(false);
mHud->setVisible(true); mHud->setVisible(true);
@ -369,12 +379,18 @@ void WindowManager::updateVisible()
case GM_SpellBuying: case GM_SpellBuying:
mSpellBuyingWindow->setVisible(true); mSpellBuyingWindow->setVisible(true);
break; break;
case GM_Travel:
mTravelWindow->setVisible(true);
break;
case GM_SpellCreation: case GM_SpellCreation:
mSpellCreationDialog->setVisible(true); mSpellCreationDialog->setVisible(true);
break; break;
case GM_Enchanting: case GM_Enchanting:
mEnchantingDialog->setVisible(true); mEnchantingDialog->setVisible(true);
break; break;
case GM_Training:
mTrainingWindow->setVisible(true);
break;
case GM_InterMessageBox: case GM_InterMessageBox:
break; break;
case GM_Journal: case GM_Journal:
@ -574,6 +590,9 @@ void WindowManager::onFrame (float frameDuration)
mHud->onFrame(frameDuration); mHud->onFrame(frameDuration);
mTrainingWindow->onFrame (frameDuration);
mTrainingWindow->checkReferenceAvailable();
mDialogueWindow->checkReferenceAvailable(); mDialogueWindow->checkReferenceAvailable();
mTradeWindow->checkReferenceAvailable(); mTradeWindow->checkReferenceAvailable();
mSpellBuyingWindow->checkReferenceAvailable(); mSpellBuyingWindow->checkReferenceAvailable();
@ -862,6 +881,7 @@ MWGui::CountDialog* WindowManager::getCountDialog() { return mCountDialog; }
MWGui::ConfirmationDialog* WindowManager::getConfirmationDialog() { return mConfirmationDialog; } MWGui::ConfirmationDialog* WindowManager::getConfirmationDialog() { return mConfirmationDialog; }
MWGui::TradeWindow* WindowManager::getTradeWindow() { return mTradeWindow; } MWGui::TradeWindow* WindowManager::getTradeWindow() { return mTradeWindow; }
MWGui::SpellBuyingWindow* WindowManager::getSpellBuyingWindow() { return mSpellBuyingWindow; } MWGui::SpellBuyingWindow* WindowManager::getSpellBuyingWindow() { return mSpellBuyingWindow; }
MWGui::TravelWindow* WindowManager::getTravelWindow() { return mTravelWindow; }
MWGui::SpellWindow* WindowManager::getSpellWindow() { return mSpellWindow; } MWGui::SpellWindow* WindowManager::getSpellWindow() { return mSpellWindow; }
MWGui::Console* WindowManager::getConsole() { return mConsole; } MWGui::Console* WindowManager::getConsole() { return mConsole; }
@ -993,3 +1013,8 @@ void WindowManager::startEnchanting (MWWorld::Ptr actor)
{ {
mEnchantingDialog->startEnchanting (actor); mEnchantingDialog->startEnchanting (actor);
} }
void WindowManager::startTraining(MWWorld::Ptr actor)
{
mTrainingWindow->startTraining(actor);
}

View File

@ -66,6 +66,7 @@ namespace MWGui
class WaitDialog; class WaitDialog;
class SpellCreationDialog; class SpellCreationDialog;
class EnchantingDialog; class EnchantingDialog;
class TrainingWindow;
class WindowManager : public MWBase::WindowManager class WindowManager : public MWBase::WindowManager
{ {
@ -113,6 +114,7 @@ namespace MWGui
virtual MWGui::ConfirmationDialog* getConfirmationDialog(); virtual MWGui::ConfirmationDialog* getConfirmationDialog();
virtual MWGui::TradeWindow* getTradeWindow(); virtual MWGui::TradeWindow* getTradeWindow();
virtual MWGui::SpellBuyingWindow* getSpellBuyingWindow(); virtual MWGui::SpellBuyingWindow* getSpellBuyingWindow();
virtual MWGui::TravelWindow* getTravelWindow();
virtual MWGui::SpellWindow* getSpellWindow(); virtual MWGui::SpellWindow* getSpellWindow();
virtual MWGui::Console* getConsole(); virtual MWGui::Console* getConsole();
@ -215,6 +217,7 @@ namespace MWGui
virtual void startSpellMaking(MWWorld::Ptr actor); virtual void startSpellMaking(MWWorld::Ptr actor);
virtual void startEnchanting(MWWorld::Ptr actor); virtual void startEnchanting(MWWorld::Ptr actor);
virtual void startTraining(MWWorld::Ptr actor);
private: private:
OEngine::GUI::MyGUIManager *mGuiManager; OEngine::GUI::MyGUIManager *mGuiManager;
@ -235,6 +238,7 @@ namespace MWGui
CountDialog* mCountDialog; CountDialog* mCountDialog;
TradeWindow* mTradeWindow; TradeWindow* mTradeWindow;
SpellBuyingWindow* mSpellBuyingWindow; SpellBuyingWindow* mSpellBuyingWindow;
TravelWindow* mTravelWindow;
SettingsWindow* mSettingsWindow; SettingsWindow* mSettingsWindow;
ConfirmationDialog* mConfirmationDialog; ConfirmationDialog* mConfirmationDialog;
AlchemyWindow* mAlchemyWindow; AlchemyWindow* mAlchemyWindow;
@ -245,6 +249,7 @@ namespace MWGui
WaitDialog* mWaitDialog; WaitDialog* mWaitDialog;
SpellCreationDialog* mSpellCreationDialog; SpellCreationDialog* mSpellCreationDialog;
EnchantingDialog* mEnchantingDialog; EnchantingDialog* mEnchantingDialog;
TrainingWindow* mTrainingWindow;
CharacterCreation* mCharGen; CharacterCreation* mCharGen;

View File

@ -118,18 +118,14 @@ namespace MWMechanics
+ fRestMagicMult * stats.getAttribute(ESM::Attribute::Intelligence).getModified ()); + fRestMagicMult * stats.getAttribute(ESM::Attribute::Intelligence).getModified ());
} }
} }
} }
void Actors::calculateCreatureStatModifiers (const MWWorld::Ptr& ptr) void Actors::calculateCreatureStatModifiers (const MWWorld::Ptr& ptr)
{ {
CreatureStats& creatureStats = MWWorld::Class::get (ptr).getCreatureStats (ptr); CreatureStats& creatureStats = MWWorld::Class::get (ptr).getCreatureStats (ptr);
// attributes // attributes
for (int i=0; i<5; ++i) for (int i=0; i<8; ++i)
{ {
int modifier = int modifier =
creatureStats.getMagicEffects().get (EffectKey (79, i)).mMagnitude; creatureStats.getMagicEffects().get (EffectKey (79, i)).mMagnitude;

View 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;
}

View 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

View File

@ -54,6 +54,6 @@ namespace MWSound
#ifndef DEFAULT_DECODER #ifndef DEFAULT_DECODER
#define DEFAULT_DECODER (::MWSound::FFmpeg_Decoder) #define DEFAULT_DECODER (::MWSound::FFmpeg_Decoder)
#endif #endif
}; }
#endif #endif

View File

@ -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())
{ {

View File

@ -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);

View File

@ -375,7 +375,7 @@ void addBSA(const std::string& name, const std::string& group)
{ {
insertBSAFactory(); insertBSAFactory();
ResourceGroupManager::getSingleton(). ResourceGroupManager::getSingleton().
addResourceLocation(name, "BSA", group); addResourceLocation(name, "BSA", group, true);
} }
void addDir(const std::string& name, const bool& fs, const std::string& group) void addDir(const std::string& name, const bool& fs, const std::string& group)
@ -384,7 +384,7 @@ void addDir(const std::string& name, const bool& fs, const std::string& group)
insertDirFactory(); insertDirFactory();
ResourceGroupManager::getSingleton(). ResourceGroupManager::getSingleton().
addResourceLocation(name, "Dir", group); addResourceLocation(name, "Dir", group, true);
} }
} }

View File

@ -18,8 +18,6 @@ namespace ESM
{ {
// These are probabilities // These are probabilities
char mHello, mU1, mFight, mFlee, mAlarm, mU2, mU3, mU4; char mHello, mU1, mFight, mFlee, mAlarm, mU2, mU3, mU4;
// The last u's might be the skills that this NPC can train you
// in?
int mServices; // See the Services enum int mServices; // See the Services enum
}; // 12 bytes }; // 12 bytes

View File

@ -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

View File

@ -78,6 +78,8 @@ set(MYGUI_FILES
openmw_spellcreation_dialog.layout openmw_spellcreation_dialog.layout
openmw_edit_effect.layout openmw_edit_effect.layout
openmw_enchanting_dialog.layout openmw_enchanting_dialog.layout
openmw_trainingwindow.layout
openmw_travel_window.layout
smallbars.png smallbars.png
VeraMono.ttf VeraMono.ttf
markers.png markers.png

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<MyGUI type="Layout">
<Widget type="Window" skin="MW_Dialog" layer="Windows" position="0 0 319 200" name="_Main">
<Widget type="TextBox" skin="NormalText" position="0 5 319 24" name="Select" align="Right Top">
<Property key="TextAlign" value="Center"/>
<Property key="Caption" value="#{sServiceTrainingTitle}"/>
</Widget>
<Widget type="TextBox" skin="SandText" position="5 30 319 24" name="Travel" align="Right Top">
<Property key="TextAlign" value="Left"/>
<Property key="Caption" value="#{sTrainingServiceTitle}"/>
</Widget>
<Widget type="Widget" skin="MW_Box" position="6 54 299 100" align="Left Top" name="TrainingOptions">
</Widget>
<Widget type="TextBox" skin="SandText" position="8 161 200 24" name="PlayerGold" align="Right Top">
<Property key="TextAlign" value="Left"/>
</Widget>
<Widget type="AutoSizedButton" skin="MW_Button" position="244 161 60 24" name="CancelButton" align="Right Top">
<Property key="ExpandDirection" value="Left"/>
<Property key="Caption" value="#{sCancel}"/>
</Widget>
</Widget>
</MyGUI>

View File

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<MyGUI type="Layout">
<Widget type="Window" skin="MW_Dialog" layer="Windows" position="0 0 450 300" name="_Main">
<Property key="Visible" value="false"/>
<Widget type="TextBox" skin="SandText" position="8 10 24 24" name="Select" align="Right Top">
<Property key="TextAlign" value="Right"/>
<Property key="Caption" value="#{sTravelServiceTitle}"/>
</Widget>
<Widget type="TextBox" skin="SandText" position="0 0 24 24" name="Travel" align="Right Top">
<Property key="TextAlign" value="Right"/>
<Property key="Caption" value="#D8C09A#{sTravel}"/>
</Widget>
<Widget type="Widget" skin="MW_Box" position="6 31 430 225" align="ALIGN_LEFT ALIGN_STRETCH">
<Widget type="ScrollView" skin="MW_ScrollView" position="4 4 422 217" align="ALIGN_LEFT ALIGN_TOP ALIGN_STRETCH" name="DestinationsView">
<Property key="CanvasAlign" value="Left"/>
</Widget>
</Widget>
<Widget type="TextBox" skin="SandText" position="8 255 24 24" name="PlayerGold" align="Right Top">
<Property key="TextAlign" value="Right"/>
</Widget>
<Widget type="AutoSizedButton" skin="MW_Button" position="375 260 60 24" name="CancelButton" align="Right Top">
<Property key="ExpandDirection" value="Left"/>
<Property key="Caption" value="#{sOK}"/>
</Widget>
</Widget>
</MyGUI>

View File

@ -40,7 +40,7 @@ Fader::Fader(Ogre::SceneManager* sceneMgr)
Ogre::SceneNode* node = mSceneMgr->getRootSceneNode()->createChildSceneNode(); Ogre::SceneNode* node = mSceneMgr->getRootSceneNode()->createChildSceneNode();
node->attachObject(mRectangle); node->attachObject(mRectangle);
mRectangle->setVisible(false); mRectangle->setVisible(false);
mRectangle->setVisibilityFlags (0x01); mRectangle->setVisibilityFlags (2048);
} }
Fader::~Fader() Fader::~Fader()