diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index bc4e10501..d3698b53e 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -30,7 +30,7 @@ add_openmw_dir (mwgui formatting inventorywindow container hud countdialog tradewindow settingswindow confirmationdialog alchemywindow referenceinterface spellwindow mainmenu quickkeysmenu itemselection spellbuyingwindow loadingscreen levelupdialog waitdialog spellcreationdialog - enchantingdialog + enchantingdialog trainingwindow ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 462aef014..f4c78f5fb 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -230,6 +230,7 @@ namespace MWBase virtual void startSpellMaking(MWWorld::Ptr actor) = 0; virtual void startEnchanting(MWWorld::Ptr actor) = 0; + virtual void startTraining(MWWorld::Ptr actor) = 0; }; } diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 3a51ed2b6..063794eba 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -801,6 +801,9 @@ namespace MWDialogue if (services & ESM::NPC::Spellmaking) windowServices |= MWGui::DialogueWindow::Service_CreateSpells; + if (services & ESM::NPC::Training) + windowServices |= MWGui::DialogueWindow::Service_Training; + if (services & ESM::NPC::Enchanting) windowServices |= MWGui::DialogueWindow::Service_Enchant; diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index d03724628..d5b4ca672 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -147,6 +147,11 @@ void DialogueWindow::onSelectTopic(std::string topic) mWindowManager.pushGuiMode(GM_Enchanting); mWindowManager.startEnchanting (mPtr); } + else if (topic == MWBase::Environment::get().getWorld()->getStore().gameSettings.find("sServiceTrainingTitle")->getString()) + { + mWindowManager.pushGuiMode(GM_Training); + mWindowManager.startTraining (mPtr); + } else MWBase::Environment::get().getDialogueManager()->keywordSelected(lower_string(topic)); } @@ -181,6 +186,9 @@ void DialogueWindow::setKeywords(std::list keyWords) if (mServices & Service_Enchant) 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) mTopicsList->addSeparator(); diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index acbe75eed..1592e49ee 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -57,7 +57,8 @@ namespace MWGui Service_Trade = 0x01, Service_BuySpells = 0x02, Service_CreateSpells = 0x04, - Service_Enchant = 0x08 + Service_Enchant = 0x08, + Service_Training = 0x10 }; protected: diff --git a/apps/openmw/mwgui/mode.hpp b/apps/openmw/mwgui/mode.hpp index 7fd033f5e..e594a5d0b 100644 --- a/apps/openmw/mwgui/mode.hpp +++ b/apps/openmw/mwgui/mode.hpp @@ -24,6 +24,7 @@ namespace MWGui GM_SpellBuying, GM_SpellCreation, GM_Enchanting, + GM_Training, GM_Levelup, diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp new file mode 100644 index 000000000..536b3a3a6 --- /dev/null +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -0,0 +1,152 @@ +#include "trainingwindow.hpp" + +#include + +#include + +#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(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 > 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 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(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(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(); + + 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() *playerRef = player.get(); + 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); + } +} diff --git a/apps/openmw/mwgui/trainingwindow.hpp b/apps/openmw/mwgui/trainingwindow.hpp new file mode 100644 index 000000000..f2ef1714e --- /dev/null +++ b/apps/openmw/mwgui/trainingwindow.hpp @@ -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 diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 906bb2ca7..ea5c5b6cb 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -48,6 +48,7 @@ #include "waitdialog.hpp" #include "spellcreationdialog.hpp" #include "enchantingdialog.hpp" +#include "trainingwindow.hpp" using namespace MWGui; @@ -79,6 +80,7 @@ WindowManager::WindowManager( , mWaitDialog(NULL) , mSpellCreationDialog(NULL) , mEnchantingDialog(NULL) + , mTrainingWindow(NULL) , mPlayerClass() , mPlayerName() , mPlayerRaceId() @@ -161,6 +163,7 @@ WindowManager::WindowManager( mWaitDialog = new WaitDialog(*this); mSpellCreationDialog = new SpellCreationDialog(*this); mEnchantingDialog = new EnchantingDialog(*this); + mTrainingWindow = new TrainingWindow(*this); mLoadingScreen = new LoadingScreen(mOgre->getScene (), mOgre->getWindow (), *this); mLoadingScreen->onResChange (w,h); @@ -218,6 +221,7 @@ WindowManager::~WindowManager() delete mWaitDialog; delete mSpellCreationDialog; delete mEnchantingDialog; + delete mTrainingWindow; cleanupGarbage(); @@ -269,6 +273,7 @@ void WindowManager::updateVisible() mWaitDialog->setVisible(false); mSpellCreationDialog->setVisible(false); mEnchantingDialog->setVisible(false); + mTrainingWindow->setVisible(false); mHud->setVisible(true); @@ -375,6 +380,9 @@ void WindowManager::updateVisible() case GM_Enchanting: mEnchantingDialog->setVisible(true); break; + case GM_Training: + mTrainingWindow->setVisible(true); + break; case GM_InterMessageBox: break; case GM_Journal: @@ -574,6 +582,9 @@ void WindowManager::onFrame (float frameDuration) mHud->onFrame(frameDuration); + mTrainingWindow->onFrame (frameDuration); + + mTrainingWindow->checkReferenceAvailable(); mDialogueWindow->checkReferenceAvailable(); mTradeWindow->checkReferenceAvailable(); mSpellBuyingWindow->checkReferenceAvailable(); @@ -993,3 +1004,8 @@ void WindowManager::startEnchanting (MWWorld::Ptr actor) { mEnchantingDialog->startEnchanting (actor); } + +void WindowManager::startTraining(MWWorld::Ptr actor) +{ + mTrainingWindow->startTraining(actor); +} diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index d3890f635..8b0e744db 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -66,6 +66,7 @@ namespace MWGui class WaitDialog; class SpellCreationDialog; class EnchantingDialog; + class TrainingWindow; class WindowManager : public MWBase::WindowManager { @@ -215,6 +216,7 @@ namespace MWGui virtual void startSpellMaking(MWWorld::Ptr actor); virtual void startEnchanting(MWWorld::Ptr actor); + virtual void startTraining(MWWorld::Ptr actor); private: OEngine::GUI::MyGUIManager *mGuiManager; @@ -245,6 +247,7 @@ namespace MWGui WaitDialog* mWaitDialog; SpellCreationDialog* mSpellCreationDialog; EnchantingDialog* mEnchantingDialog; + TrainingWindow* mTrainingWindow; CharacterCreation* mCharGen; diff --git a/apps/openmw/mwsound/ffmpeg_decoder.hpp b/apps/openmw/mwsound/ffmpeg_decoder.hpp index 4344397c7..7b028e1d0 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.hpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.hpp @@ -54,6 +54,6 @@ namespace MWSound #ifndef DEFAULT_DECODER #define DEFAULT_DECODER (::MWSound::FFmpeg_Decoder) #endif -}; +} #endif diff --git a/components/esm/aipackage.hpp b/components/esm/aipackage.hpp index 8e55b6889..3128fe0c6 100644 --- a/components/esm/aipackage.hpp +++ b/components/esm/aipackage.hpp @@ -18,8 +18,6 @@ namespace ESM { // These are probabilities 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 }; // 12 bytes diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index a33d59ef6..1354271d5 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -78,6 +78,7 @@ set(MYGUI_FILES openmw_spellcreation_dialog.layout openmw_edit_effect.layout openmw_enchanting_dialog.layout + openmw_trainingwindow.layout smallbars.png VeraMono.ttf markers.png diff --git a/files/mygui/openmw_trainingwindow.layout b/files/mygui/openmw_trainingwindow.layout new file mode 100644 index 000000000..e9855a33b --- /dev/null +++ b/files/mygui/openmw_trainingwindow.layout @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +