From eec34e9f0e24a0116af2d704a7e6912b0188d49a Mon Sep 17 00:00:00 2001 From: Jan Borsodi Date: Sun, 19 Sep 2010 04:29:22 +0200 Subject: [PATCH] Added dialog for picking class from a list. --- apps/openmw/CMakeLists.txt | 2 + apps/openmw/mwgui/class.cpp | 223 ++++++++++++++++++ apps/openmw/mwgui/class.hpp | 68 ++++++ apps/openmw/mwgui/window_manager.cpp | 49 ++++ apps/openmw/mwgui/window_manager.hpp | 6 + components/esm/loadclas.hpp | 7 + extern/mygui_3.0.1/CMakeLists.txt | 1 + .../openmw_chargen_class_layout.xml | 89 +++++++ 8 files changed, 445 insertions(+) create mode 100644 apps/openmw/mwgui/class.cpp create mode 100644 apps/openmw/mwgui/class.hpp create mode 100644 extern/mygui_3.0.1/openmw_resources/openmw_chargen_class_layout.xml diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index f4c9b4361..d58e53b4b 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -37,6 +37,7 @@ set(GAMEGUI_HEADER mwgui/layouts.hpp mwgui/text_input.hpp mwgui/race.hpp + mwgui/class.hpp mwgui/window_manager.hpp mwgui/console.hpp ) @@ -46,6 +47,7 @@ set(GAMEGUI mwgui/console.cpp mwgui/text_input.cpp mwgui/race.cpp + mwgui/class.cpp ) source_group(apps\\openmw\\mwgui FILES ${GAMEGUI_HEADER} ${GAMEGUI}) diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp new file mode 100644 index 000000000..ff1f90bbb --- /dev/null +++ b/apps/openmw/mwgui/class.cpp @@ -0,0 +1,223 @@ +#include "class.hpp" +#include "../mwworld/environment.hpp" +#include "../mwworld/world.hpp" +#include "window_manager.hpp" +#include "components/esm_store/store.hpp" + +#include +#include + +#include +#include + +using namespace MWGui; + +PickClassDialog::PickClassDialog(MWWorld::Environment& environment, MyGUI::IntSize gameWindowSize) + : Layout("openmw_chargen_class_layout.xml") + , environment(environment) +{ + // Centre dialog + MyGUI::IntCoord coord = mMainWidget->getCoord(); + coord.left = (gameWindowSize.width - coord.width)/2; + coord.top = (gameWindowSize.height - coord.height)/2; + mMainWidget->setCoord(coord); + + WindowManager *wm = environment.mWindowManager; + setText("SpecializationT", wm->getGameSettingString("sChooseClassMenu1", "Specialization")); + getWidget(specializationName, "SpecializationName"); + + setText("FavoriteAttributesT", wm->getGameSettingString("sChooseClassMenu2", "Favorite Attributes:")); + getWidget(favoriteAttribute0, "FavoriteAttribute0"); + getWidget(favoriteAttribute1, "FavoriteAttribute1"); + + setText("MajorSkillT", wm->getGameSettingString("sChooseClassMenu3", "Major Skills:")); + getWidget(majorSkill0, "MajorSkill0"); + getWidget(majorSkill1, "MajorSkill1"); + getWidget(majorSkill2, "MajorSkill2"); + getWidget(majorSkill3, "MajorSkill3"); + getWidget(majorSkill4, "MajorSkill4"); + + setText("MinorSkillT", wm->getGameSettingString("sChooseClassMenu4", "Minor Skills:")); + getWidget(minorSkill0, "MinorSkill0"); + getWidget(minorSkill1, "MinorSkill1"); + getWidget(minorSkill2, "MinorSkill2"); + getWidget(minorSkill3, "MinorSkill3"); + getWidget(minorSkill4, "MinorSkill4"); + + getWidget(classList, "ClassList"); + classList->setScrollVisible(true); + classList->eventListSelectAccept = MyGUI::newDelegate(this, &PickClassDialog::onSelectClass); + classList->eventListMouseItemActivate = MyGUI::newDelegate(this, &PickClassDialog::onSelectClass); + classList->eventListChangePosition = MyGUI::newDelegate(this, &PickClassDialog::onSelectClass); + + getWidget(classImage, "ClassImage"); + + // TODO: These buttons should be managed by a Dialog class + MyGUI::ButtonPtr backButton; + getWidget(backButton, "BackButton"); + backButton->eventMouseButtonClick = MyGUI::newDelegate(this, &PickClassDialog::onBackClicked); + + MyGUI::ButtonPtr okButton; + getWidget(okButton, "OKButton"); + okButton->eventMouseButtonClick = MyGUI::newDelegate(this, &PickClassDialog::onOkClicked); + + updateClasses(); + updateStats(); +} + +void PickClassDialog::setNextButtonShow(bool shown) +{ + MyGUI::ButtonPtr backButton; + getWidget(backButton, "BackButton"); + + MyGUI::ButtonPtr okButton; + getWidget(okButton, "OKButton"); + + // TODO: All hardcoded coords for buttons are temporary, will be replaced with a dynamic system. + if (shown) + { + okButton->setCaption("Next"); + + // Adjust back button when next is shown + backButton->setCoord(MyGUI::IntCoord(382 - 18, 265, 53, 23)); + okButton->setCoord(MyGUI::IntCoord(434 - 18, 265, 42 + 18, 23)); + } + else + { + okButton->setCaption("OK"); + backButton->setCoord(MyGUI::IntCoord(382, 265, 53, 23)); + okButton->setCoord(MyGUI::IntCoord(434, 265, 42, 23)); + } +} + +void PickClassDialog::open() +{ + updateClasses(); + updateStats(); + setVisible(true); +} + + +void PickClassDialog::setClassId(const std::string &classId) +{ + currentClassId = classId; + classList->setIndexSelected(MyGUI::ITEM_NONE); + size_t count = classList->getItemCount(); + for (size_t i = 0; i < count; ++i) + { + if (boost::iequals(*classList->getItemDataAt(i), classId)) + { + classList->setIndexSelected(i); + break; + } + } + + updateStats(); +} + +// widget controls + +void PickClassDialog::onOkClicked(MyGUI::Widget* _sender) +{ + eventDone(); +} + +void PickClassDialog::onBackClicked(MyGUI::Widget* _sender) +{ + eventBack(); +} + +void PickClassDialog::onSelectClass(MyGUI::List* _sender, size_t _index) +{ + if (_index == MyGUI::ITEM_NONE) + return; + + const std::string *classId = classList->getItemDataAt(_index); + if (boost::iequals(currentClassId, *classId)) + return; + + currentClassId = *classId; + updateStats(); +} + +// update widget content + +void PickClassDialog::updateClasses() +{ + classList->removeAllItems(); + + ESMS::ESMStore &store = environment.mWorld->getStore(); + + ESMS::RecListT::MapType::const_iterator it = store.classes.list.begin(); + ESMS::RecListT::MapType::const_iterator end = store.classes.list.end(); + int index = 0; + for (; it != end; ++it) + { + const ESM::Class &klass = it->second; + bool playable = (klass.data.isPlayable != 0); + if (!playable) // Only display playable classes + continue; + + const std::string &id = it->first; + classList->addItem(klass.name, id); + if (boost::iequals(id, currentClassId)) + classList->setIndexSelected(index); + ++index; + } +} + +void PickClassDialog::updateStats() +{ + if (currentClassId.empty()) + return; + WindowManager *wm = environment.mWindowManager; + ESMS::ESMStore &store = environment.mWorld->getStore(); + const ESM::Class *klass = store.classes.find(currentClassId); + + ESM::Class::Specialization specialization = static_cast(klass->data.specialization); + + static const char *specIds[3] = { + "sSpecializationCombat", + "sSpecializationMagic", + "sSpecializationStealth" + }; + specializationName->setCaption(wm->getGameSettingString(specIds[specialization], specIds[specialization])); + static const char *attributes[8] = { + "sAttributeStrength", + "sAttributeIntelligence", + "sAttributeWillpower", + "sAttributeAgility", + "sAttributeSpeed", + "sAttributeEndurance", + "sAttributePersonality", + "sAttributeLuck" + }; + + favoriteAttribute0->setCaption(wm->getGameSettingString(attributes[klass->data.attribute[0]], "")); + favoriteAttribute1->setCaption(wm->getGameSettingString(attributes[klass->data.attribute[1]], "")); + + MyGUI::StaticTextPtr skills[2][5] = { + { + majorSkill0, + majorSkill1, + majorSkill2, + majorSkill3, + majorSkill4 + }, + { + minorSkill0, + minorSkill1, + minorSkill2, + minorSkill3, + minorSkill4 + } + }; + + for (int i = 0; i < 5; ++i) + { + skills[0][i]->setCaption(wm->getGameSettingString(ESM::Skill::sSkillNameIds[klass->data.skills[i][0]], "")); + skills[1][i]->setCaption(wm->getGameSettingString(ESM::Skill::sSkillNameIds[klass->data.skills[i][1]], "")); + } + + classImage->setImageTexture(std::string("textures\\levelup\\") + currentClassId + ".dds"); +} diff --git a/apps/openmw/mwgui/class.hpp b/apps/openmw/mwgui/class.hpp new file mode 100644 index 000000000..8a406d110 --- /dev/null +++ b/apps/openmw/mwgui/class.hpp @@ -0,0 +1,68 @@ +#ifndef MWGUI_CLASS_H +#define MWGUI_CLASS_H + +#include + +#include + +namespace MWWorld +{ + class Environment; +} + +/* + This file contains the dialogs for choosing a class. + Layout is defined by resources/mygui/openmw_chargen_class_layout.xml. + */ + +namespace MWGui +{ + using namespace MyGUI; + + class PickClassDialog : public OEngine::GUI::Layout + { + public: + PickClassDialog(MWWorld::Environment& environment, MyGUI::IntSize gameWindowSize); + + const std::string &getClassId() const { return currentClassId; } + void setClassId(const std::string &classId); + + void setNextButtonShow(bool shown); + void open(); + + // Events + typedef delegates::CDelegate0 EventHandle_Void; + + /** Event : Back button clicked.\n + signature : void method()\n + */ + EventHandle_Void eventBack; + + /** Event : Dialog finished, OK button clicked.\n + signature : void method()\n + */ + EventHandle_Void eventDone; + + protected: + void onSelectClass(MyGUI::List* _sender, size_t _index); + + void onOkClicked(MyGUI::Widget* _sender); + void onBackClicked(MyGUI::Widget* _sender); + + private: + void updateClasses(); + void updateStats(); + + MWWorld::Environment& environment; + + MyGUI::StaticImagePtr classImage; + MyGUI::ListPtr classList; + MyGUI::StaticTextPtr specializationName; + MyGUI::StaticTextPtr favoriteAttribute0, favoriteAttribute1; + MyGUI::StaticTextPtr majorSkill0, majorSkill1, majorSkill2, majorSkill3, majorSkill4; + MyGUI::StaticTextPtr minorSkill0, minorSkill1, minorSkill2, minorSkill3, minorSkill4; + + std::string currentClassId; + }; +} +#endif diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 2dae461c6..05c6a229b 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -2,6 +2,7 @@ #include "layouts.hpp" #include "text_input.hpp" #include "race.hpp" +#include "class.hpp" #include "../mwmechanics/mechanicsmanager.hpp" #include "../mwinput/inputmanager.hpp" @@ -19,6 +20,7 @@ WindowManager::WindowManager(MyGUI::Gui *_gui, MWWorld::Environment& environment : environment(environment) , nameDialog(nullptr) , raceDialog(nullptr) + , pickClassDialog(nullptr) , nameChosen(false) , raceChosen(false) , classChosen(false) @@ -63,6 +65,7 @@ WindowManager::~WindowManager() delete nameDialog; delete raceDialog; + delete pickClassDialog; } void WindowManager::updateVisible() @@ -122,6 +125,17 @@ void WindowManager::updateVisible() return; } + if (mode == GM_Class) + { + if (!pickClassDialog) + pickClassDialog = new PickClassDialog(environment, gui->getViewSize()); + pickClassDialog->setNextButtonShow(classChosen); + pickClassDialog->eventDone = MyGUI::newDelegate(this, &WindowManager::onPickClassDialogDone); + pickClassDialog->eventBack = MyGUI::newDelegate(this, &WindowManager::onPickClassDialogBack); + pickClassDialog->open(); + return; + } + if(mode == GM_Inventory) { // Ah, inventory mode. First, compute the effective set of @@ -288,3 +302,38 @@ void WindowManager::onRaceDialogBack() environment.mInputManager->setGuiMode(GM_Name); } + +void WindowManager::onPickClassDialogDone() +{ + pickClassDialog->eventDone = MWGui::PickClassDialog::EventHandle_Void(); + + bool goNext = classChosen; // Go to next dialog if class was previously chosen + classChosen = true; + if (pickClassDialog) + { + pickClassDialog->setVisible(false); + //environment.mMechanicsManager->setPlayerClass(pickClassDialog->getClassId()); + } + + updateCharacterGeneration(); + + if (reviewNext) + environment.mInputManager->setGuiMode(GM_Review); + else if (goNext) + environment.mInputManager->setGuiMode(GM_Birth); + else + environment.mInputManager->setGuiMode(GM_Game); +} + +void WindowManager::onPickClassDialogBack() +{ + if (pickClassDialog) + { + pickClassDialog->setVisible(false); + //environment.mMechanicsManager->setPlayerClass(pickClassDialog->getClassId()); + } + + updateCharacterGeneration(); + + environment.mInputManager->setGuiMode(GM_Race); +} diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index 3d8bcf6f1..f9499c5e5 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -43,6 +43,7 @@ namespace MWGui class TextInputDialog; class RaceDialog; + class PickClassDialog; class WindowManager { @@ -59,6 +60,7 @@ namespace MWGui // Character creation TextInputDialog *nameDialog; RaceDialog *raceDialog; + PickClassDialog *pickClassDialog; // Which dialogs have been shown, controls back/next/ok buttons bool nameChosen; @@ -184,6 +186,10 @@ namespace MWGui // Character generation: Race dialog void onRaceDialogDone(); void onRaceDialogBack(); + + // Character generation: Pick Class dialog + void onPickClassDialogDone(); + void onPickClassDialogBack(); }; } #endif diff --git a/components/esm/loadclas.hpp b/components/esm/loadclas.hpp index 93df3fea6..ab8de314e 100644 --- a/components/esm/loadclas.hpp +++ b/components/esm/loadclas.hpp @@ -35,6 +35,13 @@ struct Class RepairItem = 0x20000 }; + enum Specialization + { + Combat = 0, + Magic = 1, + Stealth = 2 + }; + struct CLDTstruct { int attribute[2]; // Attributes that get class bonus diff --git a/extern/mygui_3.0.1/CMakeLists.txt b/extern/mygui_3.0.1/CMakeLists.txt index b819ef033..ab4d6236b 100644 --- a/extern/mygui_3.0.1/CMakeLists.txt +++ b/extern/mygui_3.0.1/CMakeLists.txt @@ -43,6 +43,7 @@ configure_file("${SDIR}/openmw_hud_energybar.skin.xml" "${DDIR}/openmw_hud_energ configure_file("${SDIR}/openmw_hud_layout.xml" "${DDIR}/openmw_hud_layout.xml" COPYONLY) configure_file("${SDIR}/openmw_text_input_layout.xml" "${DDIR}/openmw_text_input_layout.xml" COPYONLY) configure_file("${SDIR}/openmw_chargen_race_layout.xml" "${DDIR}/openmw_chargen_race_layout.xml" COPYONLY) +configure_file("${SDIR}/openmw_chargen_class_layout.xml" "${DDIR}/openmw_chargen_class_layout.xml" COPYONLY) configure_file("${SDIR}/openmw_inventory_window_layout.xml" "${DDIR}/openmw_inventory_window_layout.xml" COPYONLY) configure_file("${SDIR}/openmw_layers.xml" "${DDIR}/openmw_layers.xml" COPYONLY) configure_file("${SDIR}/openmw_mainmenu_layout.xml" "${DDIR}/openmw_mainmenu_layout.xml" COPYONLY) diff --git a/extern/mygui_3.0.1/openmw_resources/openmw_chargen_class_layout.xml b/extern/mygui_3.0.1/openmw_resources/openmw_chargen_class_layout.xml new file mode 100644 index 000000000..3b6e8245d --- /dev/null +++ b/extern/mygui_3.0.1/openmw_resources/openmw_chargen_class_layout.xml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +