diff --git a/CMakeLists.txt b/CMakeLists.txt index 54f038d79..0ad1c5a9e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -107,6 +107,8 @@ file(GLOB ESM_HEADER ${COMP_DIR}/esm/*.hpp) set(ESM ${COMP_DIR}/esm/load_impl.cpp ${COMP_DIR}/esm/skill.cpp + ${COMP_DIR}/esm/attr.cpp + ${COMP_DIR}/esm/class.cpp ) source_group(components\\esm FILES ${ESM_HEADER} ${ESM}) diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index da3e7f1b9..5e4247725 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -187,7 +187,7 @@ void BirthDialog::updateSpells() } int i = 0; - static struct{ const std::vector &spells; const char *label; } categories[3] = { + struct{ const std::vector &spells; const char *label; } categories[3] = { {abilities, "sBirthsignmenu1"}, {powers, "sPowers"}, {spells, "sBirthsignmenu2"} diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 7c56c553d..f7e567031 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -12,6 +12,62 @@ using namespace MWGui; +/* GenerateClassResultDialog */ + +GenerateClassResultDialog::GenerateClassResultDialog(MWWorld::Environment& environment) + : Layout("openmw_chargen_generate_class_result_layout.xml") + , environment(environment) +{ + // Centre dialog + MyGUI::IntSize gameWindowSize = environment.mWindowManager->getGui()->getViewSize(); + 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("ReflectT", wm->getGameSettingString("sMessageQuestionAnswer1", "")); + + getWidget(classImage, "ClassImage"); + getWidget(className, "ClassName"); + + // TODO: These buttons should be managed by a Dialog class + MyGUI::ButtonPtr backButton; + getWidget(backButton, "BackButton"); + backButton->eventMouseButtonClick = MyGUI::newDelegate(this, &GenerateClassResultDialog::onBackClicked); + + MyGUI::ButtonPtr okButton; + getWidget(okButton, "OKButton"); + okButton->eventMouseButtonClick = MyGUI::newDelegate(this, &GenerateClassResultDialog::onOkClicked); +} + +std::string GenerateClassResultDialog::getClassId() const +{ + return className->getCaption(); +} + +void GenerateClassResultDialog::setClassId(const std::string &classId) +{ + currentClassId = classId; + classImage->setImageTexture(std::string("textures\\levelup\\") + currentClassId + ".dds"); + ESMS::ESMStore &store = environment.mWorld->getStore(); + className->setCaption(store.classes.find(currentClassId)->name); +} + +// widget controls + +void GenerateClassResultDialog::onOkClicked(MyGUI::Widget* _sender) +{ + eventDone(); +} + +void GenerateClassResultDialog::onBackClicked(MyGUI::Widget* _sender) +{ + eventBack(); +} + +/* PickClassDialog */ + PickClassDialog::PickClassDialog(MWWorld::Environment& environment, MyGUI::IntSize gameWindowSize) : Layout("openmw_chargen_class_layout.xml") , environment(environment) @@ -221,3 +277,713 @@ void PickClassDialog::updateStats() classImage->setImageTexture(std::string("textures\\levelup\\") + currentClassId + ".dds"); } + +/* InfoBoxDialog */ + +void fitToText(MyGUI::StaticTextPtr widget) +{ + MyGUI::IntCoord inner = widget->getTextRegion(); + MyGUI::IntCoord outer = widget->getCoord(); + MyGUI::IntSize size = widget->getTextSize(); + size.width += outer.width - inner.width; + size.height += outer.height - inner.height; + widget->setSize(size); +} + +void layoutVertically(MyGUI::WidgetPtr widget, int margin) +{ + size_t count = widget->getChildCount(); + int pos = 0; + pos += margin; + int width = 0; + for (unsigned i = 0; i < count; ++i) + { + MyGUI::WidgetPtr child = widget->getChildAt(i); + if (!child->isVisible()) + continue; + + child->setPosition(child->getLeft(), pos); + width = std::max(width, child->getWidth()); + pos += child->getHeight() + margin; + } + width += margin*2; + widget->setSize(width, pos); +} + +InfoBoxDialog::InfoBoxDialog(MWWorld::Environment& environment) + : Layout("openmw_infobox_layout.xml") + , environment(environment) + , currentButton(-1) +{ + getWidget(textBox, "TextBox"); + getWidget(text, "Text"); + text->getSubWidgetText()->setWordWrap(true); + getWidget(buttonBar, "ButtonBar"); + + center(); +} + +void InfoBoxDialog::setText(const std::string &str) +{ + text->setCaption(str); + textBox->setVisible(!str.empty()); + fitToText(text); +} + +std::string InfoBoxDialog::getText() const +{ + return text->getCaption(); +} + +void InfoBoxDialog::setButtons(ButtonList &buttons) +{ + for (std::vector::iterator it = this->buttons.begin(); it != this->buttons.end(); ++it) + { + MyGUI::Gui::getInstance().destroyWidget(*it); + } + this->buttons.clear(); + currentButton = -1; + + // TODO: The buttons should be generated from a template in the layout file, ie. cloning an existing widget + MyGUI::ButtonPtr button; + MyGUI::IntCoord coord = MyGUI::IntCoord(0, 0, buttonBar->getWidth(), 10); + ButtonList::const_iterator end = buttons.end(); + for (ButtonList::const_iterator it = buttons.begin(); it != end; ++it) + { + const std::string &text = *it; + button = buttonBar->createWidget("MW_Button", coord, MyGUI::Align::Top | MyGUI::Align::HCenter, ""); + button->getSubWidgetText()->setWordWrap(true); + button->setCaption(text); + fitToText(button); + button->eventMouseButtonClick = MyGUI::newDelegate(this, &InfoBoxDialog::onButtonClicked); + coord.top += button->getHeight(); + this->buttons.push_back(button); + } +} + +void InfoBoxDialog::update() +{ + // Fix layout + layoutVertically(textBox, 4); + layoutVertically(buttonBar, 6); + layoutVertically(mMainWidget, 4 + 6); + + center(); +} + +int InfoBoxDialog::getChosenButton() const +{ + return currentButton; +} + +void InfoBoxDialog::onButtonClicked(MyGUI::WidgetPtr _sender) +{ + std::vector::const_iterator end = buttons.end(); + int i = 0; + for (std::vector::const_iterator it = buttons.begin(); it != end; ++it) + { + if (*it == _sender) + { + currentButton = i; + eventButtonSelected(_sender, i); + return; + } + ++i; + } +} + +void InfoBoxDialog::center() +{ + // Centre dialog + MyGUI::IntSize gameWindowSize = environment.mWindowManager->getGui()->getViewSize(); + MyGUI::IntCoord coord = mMainWidget->getCoord(); + coord.left = (gameWindowSize.width - coord.width)/2; + coord.top = (gameWindowSize.height - coord.height)/2; + mMainWidget->setCoord(coord); +} + +/* ClassChoiceDialog */ + +ClassChoiceDialog::ClassChoiceDialog(MWWorld::Environment& environment) + : InfoBoxDialog(environment) +{ + WindowManager *mw = environment.mWindowManager; + setText(""); + ButtonList buttons; + buttons.push_back(mw->getGameSettingString("sClassChoiceMenu1", "")); + buttons.push_back(mw->getGameSettingString("sClassChoiceMenu2", "")); + buttons.push_back(mw->getGameSettingString("sClassChoiceMenu3", "")); + buttons.push_back(mw->getGameSettingString("sBack", "")); + setButtons(buttons); + + update(); +} + +/* CreateClassDialog */ + +CreateClassDialog::CreateClassDialog(MWWorld::Environment& environment, MyGUI::IntSize gameWindowSize) + : Layout("openmw_chargen_create_class_layout.xml") + , environment(environment) + , specDialog(nullptr) + , attribDialog(nullptr) + , skillDialog(nullptr) + , descDialog(nullptr) +{ + // 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"); + specializationName->setCaption(wm->getGameSettingString(ESM::Class::gmstSpecializationIds[ESM::Class::Combat], "")); + specializationName->eventMouseButtonClick = MyGUI::newDelegate(this, &CreateClassDialog::onSpecializationClicked); + + setText("FavoriteAttributesT", wm->getGameSettingString("sChooseClassMenu2", "Favorite Attributes:")); + getWidget(favoriteAttribute0, "FavoriteAttribute0"); + getWidget(favoriteAttribute1, "FavoriteAttribute1"); + favoriteAttribute0->setWindowManager(wm); + favoriteAttribute1->setWindowManager(wm); + favoriteAttribute0->eventClicked = MyGUI::newDelegate(this, &CreateClassDialog::onAttributeClicked); + favoriteAttribute1->eventClicked = MyGUI::newDelegate(this, &CreateClassDialog::onAttributeClicked); + + setText("MajorSkillT", wm->getGameSettingString("sSkillClassMajor", "")); + getWidget(majorSkill0, "MajorSkill0"); + getWidget(majorSkill1, "MajorSkill1"); + getWidget(majorSkill2, "MajorSkill2"); + getWidget(majorSkill3, "MajorSkill3"); + getWidget(majorSkill4, "MajorSkill4"); + skills.push_back(majorSkill0); + skills.push_back(majorSkill1); + skills.push_back(majorSkill2); + skills.push_back(majorSkill3); + skills.push_back(majorSkill4); + + setText("MinorSkillT", wm->getGameSettingString("sSkillClassMinor", "")); + getWidget(minorSkill0, "MinorSkill0"); + getWidget(minorSkill1, "MinorSkill1"); + getWidget(minorSkill2, "MinorSkill2"); + getWidget(minorSkill3, "MinorSkill3"); + getWidget(minorSkill4, "MinorSkill4"); + skills.push_back(minorSkill0); + skills.push_back(minorSkill1); + skills.push_back(minorSkill2); + skills.push_back(minorSkill3); + skills.push_back(minorSkill4); + + std::vector::const_iterator end = skills.end(); + for (std::vector::const_iterator it = skills.begin(); it != end; ++it) + { + (*it)->setWindowManager(wm); + (*it)->eventClicked = MyGUI::newDelegate(this, &CreateClassDialog::onSkillClicked); + } + + setText("LabelT", wm->getGameSettingString("sName", "")); + getWidget(editName, "EditName"); + + // Make sure the edit box has focus + MyGUI::InputManager::getInstance().setKeyFocusWidget(editName); + + // TODO: These buttons should be managed by a Dialog class + MyGUI::ButtonPtr descriptionButton; + getWidget(descriptionButton, "DescriptionButton"); + descriptionButton->eventMouseButtonClick = MyGUI::newDelegate(this, &CreateClassDialog::onDescriptionClicked); + + MyGUI::ButtonPtr backButton; + getWidget(backButton, "BackButton"); + backButton->eventMouseButtonClick = MyGUI::newDelegate(this, &CreateClassDialog::onBackClicked); + + MyGUI::ButtonPtr okButton; + getWidget(okButton, "OKButton"); + okButton->eventMouseButtonClick = MyGUI::newDelegate(this, &CreateClassDialog::onOkClicked); + + // Set default skills, attributes + + favoriteAttribute0->setAttributeId(ESM::Attribute::Strength); + favoriteAttribute1->setAttributeId(ESM::Attribute::Agility); + + majorSkill0->setSkillId(ESM::Skill::Block); + majorSkill1->setSkillId(ESM::Skill::Armorer); + majorSkill2->setSkillId(ESM::Skill::MediumArmor); + majorSkill3->setSkillId(ESM::Skill::HeavyArmor); + majorSkill4->setSkillId(ESM::Skill::BluntWeapon); + + minorSkill0->setSkillId(ESM::Skill::LongBlade); + minorSkill1->setSkillId(ESM::Skill::Axe); + minorSkill2->setSkillId(ESM::Skill::Spear); + minorSkill3->setSkillId(ESM::Skill::Athletics); + minorSkill4->setSkillId(ESM::Skill::Enchant); +} + +CreateClassDialog::~CreateClassDialog() +{ + delete specDialog; + delete attribDialog; + delete skillDialog; + delete descDialog; +} + +std::string CreateClassDialog::getName() const +{ + return editName->getOnlyText(); +} + +std::string CreateClassDialog::getDescription() const +{ + return description; +} + +ESM::Class::Specialization CreateClassDialog::getSpecializationId() const +{ + return specializationId; +} + +std::vector CreateClassDialog::getFavoriteAttributes() const +{ + std::vector v; + v.push_back(favoriteAttribute0->getAttributeId()); + v.push_back(favoriteAttribute1->getAttributeId()); + return v; +} + +std::vector CreateClassDialog::getMajorSkills() const +{ + std::vector v; + v.push_back(majorSkill0->getSkillId()); + v.push_back(majorSkill1->getSkillId()); + v.push_back(majorSkill2->getSkillId()); + v.push_back(majorSkill3->getSkillId()); + v.push_back(majorSkill4->getSkillId()); + return v; +} + +std::vector CreateClassDialog::getMinorSkills() const +{ + std::vector v; + v.push_back(majorSkill0->getSkillId()); + v.push_back(majorSkill1->getSkillId()); + v.push_back(majorSkill2->getSkillId()); + v.push_back(majorSkill3->getSkillId()); + v.push_back(majorSkill4->getSkillId()); + return v; +} + +void CreateClassDialog::setNextButtonShow(bool shown) +{ + MyGUI::ButtonPtr descriptionButton; + getWidget(descriptionButton, "DescriptionButton"); + + 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 + descriptionButton->setCoord(MyGUI::IntCoord(207 - 18, 158, 143, 23)); + backButton->setCoord(MyGUI::IntCoord(356 - 18, 158, 53, 23)); + okButton->setCoord(MyGUI::IntCoord(417 - 18, 158, 42 + 18, 23)); + } + else + { + okButton->setCaption("OK"); + descriptionButton->setCoord(MyGUI::IntCoord(207, 158, 143, 23)); + backButton->setCoord(MyGUI::IntCoord(356, 158, 53, 23)); + okButton->setCoord(MyGUI::IntCoord(417, 158, 42, 23)); + } +} + +void CreateClassDialog::open() +{ + setVisible(true); +} + +// widget controls + +void CreateClassDialog::onDialogCancel() +{ + if (specDialog) + specDialog->setVisible(false); + if (attribDialog) + attribDialog->setVisible(false); + if (skillDialog) + skillDialog->setVisible(false); + if (descDialog) + descDialog->setVisible(false); + // TODO: Delete dialogs here +} + +void CreateClassDialog::onSpecializationClicked(MyGUI::WidgetPtr _sender) +{ + if (specDialog) + delete specDialog; + specDialog = new SelectSpecializationDialog(environment, environment.mWindowManager->getGui()->getViewSize()); + specDialog->eventCancel = MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); + specDialog->eventItemSelected = MyGUI::newDelegate(this, &CreateClassDialog::onSpecializationSelected); + specDialog->setVisible(true); +} + +void CreateClassDialog::onSpecializationSelected() +{ + specializationId = specDialog->getSpecializationId(); + specializationName->setCaption(environment.mWindowManager->getGameSettingString(ESM::Class::gmstSpecializationIds[specializationId], "")); + specDialog->setVisible(false); +} + +void CreateClassDialog::onAttributeClicked(Widgets::MWAttributePtr _sender) +{ + if (attribDialog) + delete attribDialog; + attribDialog = new SelectAttributeDialog(environment, environment.mWindowManager->getGui()->getViewSize()); + attribDialog->setAffectedWidget(_sender); + attribDialog->eventCancel = MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); + attribDialog->eventItemSelected = MyGUI::newDelegate(this, &CreateClassDialog::onAttributeSelected); + attribDialog->setVisible(true); +} + +void CreateClassDialog::onAttributeSelected() +{ + ESM::Attribute::AttributeID id = attribDialog->getAttributeId(); + Widgets::MWAttributePtr attribute = attribDialog->getAffectedWidget(); + if (attribute == favoriteAttribute0) + { + if (favoriteAttribute1->getAttributeId() == id) + favoriteAttribute1->setAttributeId(favoriteAttribute0->getAttributeId()); + } + else if (attribute == favoriteAttribute1) + { + if (favoriteAttribute0->getAttributeId() == id) + favoriteAttribute0->setAttributeId(favoriteAttribute1->getAttributeId()); + } + attribute->setAttributeId(id); + attribDialog->setVisible(false); +} + +void CreateClassDialog::onSkillClicked(Widgets::MWSkillPtr _sender) +{ + if (skillDialog) + delete skillDialog; + skillDialog = new SelectSkillDialog(environment, environment.mWindowManager->getGui()->getViewSize()); + skillDialog->setAffectedWidget(_sender); + skillDialog->eventCancel = MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); + skillDialog->eventItemSelected = MyGUI::newDelegate(this, &CreateClassDialog::onSkillSelected); + skillDialog->setVisible(true); +} + +void CreateClassDialog::onSkillSelected() +{ + ESM::Skill::SkillEnum id = skillDialog->getSkillId(); + Widgets::MWSkillPtr skill = skillDialog->getAffectedWidget(); + + // Avoid duplicate skills by swapping any skill field that matches the selected one + std::vector::const_iterator end = skills.end(); + for (std::vector::const_iterator it = skills.begin(); it != end; ++it) + { + if (*it == skill) + continue; + if ((*it)->getSkillId() == id) + { + (*it)->setSkillId(skill->getSkillId()); + break; + } + } + + skill->setSkillId(skillDialog->getSkillId()); + skillDialog->setVisible(false); +} + +void CreateClassDialog::onDescriptionClicked(MyGUI::Widget* _sender) +{ + if (descDialog) + delete descDialog; + descDialog = new DescriptionDialog(environment, environment.mWindowManager->getGui()->getViewSize()); + descDialog->setTextInput(description); + descDialog->eventDone = MyGUI::newDelegate(this, &CreateClassDialog::onDescriptionEntered); + descDialog->setVisible(true); +} + +void CreateClassDialog::onDescriptionEntered() +{ + description = descDialog->getTextInput(); + descDialog->setVisible(false); +} + +void CreateClassDialog::onOkClicked(MyGUI::Widget* _sender) +{ + eventDone(); +} + +void CreateClassDialog::onBackClicked(MyGUI::Widget* _sender) +{ + eventBack(); +} + +/* SelectSpecializationDialog */ + +SelectSpecializationDialog::SelectSpecializationDialog(MWWorld::Environment& environment, MyGUI::IntSize gameWindowSize) + : Layout("openmw_chargen_select_specialization_layout.xml") +{ + // 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("LabelT", wm->getGameSettingString("sSpecializationMenu1", "")); + + getWidget(specialization0, "Specialization0"); + getWidget(specialization1, "Specialization1"); + getWidget(specialization2, "Specialization2"); + specialization0->setCaption(wm->getGameSettingString(ESM::Class::gmstSpecializationIds[ESM::Class::Combat], "")); + specialization0->eventMouseButtonClick = MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked); + specialization1->setCaption(wm->getGameSettingString(ESM::Class::gmstSpecializationIds[ESM::Class::Magic], "")); + specialization1->eventMouseButtonClick = MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked); + specialization2->setCaption(wm->getGameSettingString(ESM::Class::gmstSpecializationIds[ESM::Class::Stealth], "")); + specialization2->eventMouseButtonClick = MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked); + specializationId = ESM::Class::Combat; + + // TODO: These buttons should be managed by a Dialog class + MyGUI::ButtonPtr cancelButton; + getWidget(cancelButton, "CancelButton"); + cancelButton->setCaption(wm->getGameSettingString("sCancel", "")); + cancelButton->eventMouseButtonClick = MyGUI::newDelegate(this, &SelectSpecializationDialog::onCancelClicked); +} + +// widget controls + +void SelectSpecializationDialog::onSpecializationClicked(MyGUI::WidgetPtr _sender) +{ + if (_sender == specialization0) + specializationId = ESM::Class::Combat; + else if (_sender == specialization1) + specializationId = ESM::Class::Magic; + else if (_sender == specialization2) + specializationId = ESM::Class::Stealth; + else + return; + + eventItemSelected(); +} + +void SelectSpecializationDialog::onCancelClicked(MyGUI::Widget* _sender) +{ + eventCancel(); +} + +/* SelectAttributeDialog */ + +SelectAttributeDialog::SelectAttributeDialog(MWWorld::Environment& environment, MyGUI::IntSize gameWindowSize) + : Layout("openmw_chargen_select_attribute_layout.xml") +{ + // 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("LabelT", wm->getGameSettingString("sAttributesMenu1", "")); + + getWidget(attribute0, "Attribute0"); + getWidget(attribute1, "Attribute1"); + getWidget(attribute2, "Attribute2"); + getWidget(attribute3, "Attribute3"); + getWidget(attribute4, "Attribute4"); + getWidget(attribute5, "Attribute5"); + getWidget(attribute6, "Attribute6"); + getWidget(attribute7, "Attribute7"); + + Widgets::MWAttributePtr attributes[8] = { + attribute0, + attribute1, + attribute2, + attribute3, + attribute4, + attribute5, + attribute6, + attribute7 + }; + + for (int i = 0; i < 8; ++i) + { + attributes[i]->setWindowManager(wm); + attributes[i]->setAttributeId(ESM::Attribute::attributeIds[i]); + attributes[i]->eventClicked = MyGUI::newDelegate(this, &SelectAttributeDialog::onAttributeClicked); + } + + // TODO: These buttons should be managed by a Dialog class + MyGUI::ButtonPtr cancelButton; + getWidget(cancelButton, "CancelButton"); + cancelButton->setCaption(wm->getGameSettingString("sCancel", "")); + cancelButton->eventMouseButtonClick = MyGUI::newDelegate(this, &SelectAttributeDialog::onCancelClicked); +} + +// widget controls + +void SelectAttributeDialog::onAttributeClicked(Widgets::MWAttributePtr _sender) +{ + // TODO: Change MWAttribute to set and get AttributeID enum instead of int + attributeId = static_cast(_sender->getAttributeId()); + eventItemSelected(); +} + +void SelectAttributeDialog::onCancelClicked(MyGUI::Widget* _sender) +{ + eventCancel(); +} + + +/* SelectSkillDialog */ + +SelectSkillDialog::SelectSkillDialog(MWWorld::Environment& environment, MyGUI::IntSize gameWindowSize) + : Layout("openmw_chargen_select_skill_layout.xml") +{ + // 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("LabelT", wm->getGameSettingString("sSkillsMenu1", "")); + setText("CombatLabelT", wm->getGameSettingString("sSpecializationCombat", "")); + setText("MagicLabelT", wm->getGameSettingString("sSpecializationMagic", "")); + setText("StealthLabelT", wm->getGameSettingString("sSpecializationStealth", "")); + + getWidget(combatSkill0, "CombatSkill0"); + getWidget(combatSkill1, "CombatSkill1"); + getWidget(combatSkill2, "CombatSkill2"); + getWidget(combatSkill3, "CombatSkill3"); + getWidget(combatSkill4, "CombatSkill4"); + getWidget(combatSkill5, "CombatSkill5"); + getWidget(combatSkill6, "CombatSkill6"); + getWidget(combatSkill7, "CombatSkill7"); + getWidget(combatSkill8, "CombatSkill8"); + + getWidget(magicSkill0, "MagicSkill0"); + getWidget(magicSkill1, "MagicSkill1"); + getWidget(magicSkill2, "MagicSkill2"); + getWidget(magicSkill3, "MagicSkill3"); + getWidget(magicSkill4, "MagicSkill4"); + getWidget(magicSkill5, "MagicSkill5"); + getWidget(magicSkill6, "MagicSkill6"); + getWidget(magicSkill7, "MagicSkill7"); + getWidget(magicSkill8, "MagicSkill8"); + + getWidget(stealthSkill0, "StealthSkill0"); + getWidget(stealthSkill1, "StealthSkill1"); + getWidget(stealthSkill2, "StealthSkill2"); + getWidget(stealthSkill3, "StealthSkill3"); + getWidget(stealthSkill4, "StealthSkill4"); + getWidget(stealthSkill5, "StealthSkill5"); + getWidget(stealthSkill6, "StealthSkill6"); + getWidget(stealthSkill7, "StealthSkill7"); + getWidget(stealthSkill8, "StealthSkill8"); + + struct {Widgets::MWSkillPtr widget; ESM::Skill::SkillEnum skillId;} skills[3][9] = { + { + {combatSkill0, ESM::Skill::Block}, + {combatSkill1, ESM::Skill::Armorer}, + {combatSkill2, ESM::Skill::MediumArmor}, + {combatSkill3, ESM::Skill::HeavyArmor}, + {combatSkill4, ESM::Skill::BluntWeapon}, + {combatSkill5, ESM::Skill::LongBlade}, + {combatSkill6, ESM::Skill::Axe}, + {combatSkill7, ESM::Skill::Spear}, + {combatSkill8, ESM::Skill::Athletics} + }, + { + {magicSkill0, ESM::Skill::Enchant}, + {magicSkill1, ESM::Skill::Destruction}, + {magicSkill2, ESM::Skill::Alteration}, + {magicSkill3, ESM::Skill::Illusion}, + {magicSkill4, ESM::Skill::Conjuration}, + {magicSkill5, ESM::Skill::Mysticism}, + {magicSkill6, ESM::Skill::Restoration}, + {magicSkill7, ESM::Skill::Alchemy}, + {magicSkill8, ESM::Skill::Unarmored} + }, + { + {stealthSkill0, ESM::Skill::Security}, + {stealthSkill1, ESM::Skill::Sneak}, + {stealthSkill2, ESM::Skill::Acrobatics}, + {stealthSkill3, ESM::Skill::LightArmor}, + {stealthSkill4, ESM::Skill::ShortBlade}, + {stealthSkill5 ,ESM::Skill::Marksman}, + {stealthSkill6 ,ESM::Skill::Mercantile}, + {stealthSkill7 ,ESM::Skill::Speechcraft}, + {stealthSkill8 ,ESM::Skill::HandToHand} + } + }; + + for (int spec = 0; spec < 3; ++spec) + { + for (int i = 0; i < 9; ++i) + { + skills[spec][i].widget->setWindowManager(wm); + skills[spec][i].widget->setSkillId(skills[spec][i].skillId); + skills[spec][i].widget->eventClicked = MyGUI::newDelegate(this, &SelectSkillDialog::onSkillClicked); + } + } + + // TODO: These buttons should be managed by a Dialog class + MyGUI::ButtonPtr cancelButton; + getWidget(cancelButton, "CancelButton"); + cancelButton->setCaption(wm->getGameSettingString("sCancel", "")); + cancelButton->eventMouseButtonClick = MyGUI::newDelegate(this, &SelectSkillDialog::onCancelClicked); +} + +// widget controls + +void SelectSkillDialog::onSkillClicked(Widgets::MWSkillPtr _sender) +{ + skillId = _sender->getSkillId(); + eventItemSelected(); +} + +void SelectSkillDialog::onCancelClicked(MyGUI::Widget* _sender) +{ + eventCancel(); +} + +/* DescriptionDialog */ + +DescriptionDialog::DescriptionDialog(MWWorld::Environment& environment, MyGUI::IntSize gameWindowSize) + : Layout("openmw_chargen_class_description_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); + + getWidget(textEdit, "TextEdit"); + + // TODO: These buttons should be managed by a Dialog class + MyGUI::ButtonPtr okButton; + getWidget(okButton, "OKButton"); + okButton->eventMouseButtonClick = MyGUI::newDelegate(this, &DescriptionDialog::onOkClicked); + okButton->setCaption(environment.mWindowManager->getGameSettingString("sInputMenu1", "")); + + // Make sure the edit box has focus + MyGUI::InputManager::getInstance().setKeyFocusWidget(textEdit); +} + +// widget controls + +void DescriptionDialog::onOkClicked(MyGUI::Widget* _sender) +{ + eventDone(); +} diff --git a/apps/openmw/mwgui/class.hpp b/apps/openmw/mwgui/class.hpp index 35b18f63f..7f50a8b3e 100644 --- a/apps/openmw/mwgui/class.hpp +++ b/apps/openmw/mwgui/class.hpp @@ -23,6 +23,92 @@ namespace MWGui { using namespace MyGUI; + class InfoBoxDialog : public OEngine::GUI::Layout + { + public: + InfoBoxDialog(MWWorld::Environment& environment); + + typedef std::vector ButtonList; + + void setText(const std::string &str); + std::string getText() const; + void setButtons(ButtonList &buttons); + + void update(); + int getChosenButton() const; + + // Events + typedef delegates::CDelegate2 EventHandle_WidgetInt; + + /** Event : Button was clicked.\n + signature : void method(MyGUI::WidgetPtr widget, int index)\n + */ + EventHandle_WidgetInt eventButtonSelected; + + protected: + void onButtonClicked(MyGUI::WidgetPtr _sender); + + private: + void center(); + + MWWorld::Environment& environment; + + int currentButton; + MyGUI::WidgetPtr textBox; + MyGUI::StaticTextPtr text; + MyGUI::WidgetPtr buttonBar; + std::vector buttons; + }; + + // Lets the player choose between 3 ways of creating a class + class ClassChoiceDialog : public InfoBoxDialog + { + public: + // Corresponds to the buttons that can be clicked + enum ClassChoice + { + Class_Generate = 0, + Class_Pick = 1, + Class_Create = 2, + Class_Back = 3 + }; + ClassChoiceDialog(MWWorld::Environment& environment); + }; + + class GenerateClassResultDialog : public OEngine::GUI::Layout + { + public: + GenerateClassResultDialog(MWWorld::Environment& environment); + + std::string getClassId() const; + void setClassId(const std::string &classId); + + // 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 onOkClicked(MyGUI::Widget* _sender); + void onBackClicked(MyGUI::Widget* _sender); + + private: + MWWorld::Environment& environment; + + MyGUI::StaticImagePtr classImage; + MyGUI::StaticTextPtr className; + + std::string currentClassId; + }; + class PickClassDialog : public OEngine::GUI::Layout { public: @@ -68,5 +154,194 @@ namespace MWGui std::string currentClassId; }; + + class SelectSpecializationDialog : public OEngine::GUI::Layout + { + public: + SelectSpecializationDialog(MWWorld::Environment& environment, MyGUI::IntSize gameWindowSize); + + ESM::Class::Specialization getSpecializationId() const { return specializationId; } + + // Events + typedef delegates::CDelegate0 EventHandle_Void; + + /** Event : Cancel button clicked.\n + signature : void method()\n + */ + EventHandle_Void eventCancel; + + /** Event : Dialog finished, specialization selected.\n + signature : void method()\n + */ + EventHandle_Void eventItemSelected; + + protected: + void onSpecializationClicked(MyGUI::Widget* _sender); + void onCancelClicked(MyGUI::Widget* _sender); + + private: + MyGUI::WidgetPtr specialization0, specialization1, specialization2; + + ESM::Class::Specialization specializationId; + }; + + class SelectAttributeDialog : public OEngine::GUI::Layout + { + public: + SelectAttributeDialog(MWWorld::Environment& environment, MyGUI::IntSize gameWindowSize); + + ESM::Attribute::AttributeID getAttributeId() const { return attributeId; } + Widgets::MWAttributePtr getAffectedWidget() const { return affectedWidget; } + void setAffectedWidget(Widgets::MWAttributePtr widget) { affectedWidget = widget; } + + // Events + typedef delegates::CDelegate0 EventHandle_Void; + + /** Event : Cancel button clicked.\n + signature : void method()\n + */ + EventHandle_Void eventCancel; + + /** Event : Dialog finished, attribute selected.\n + signature : void method()\n + */ + EventHandle_Void eventItemSelected; + + protected: + void onAttributeClicked(Widgets::MWAttributePtr _sender); + void onCancelClicked(MyGUI::Widget* _sender); + + private: + Widgets::MWAttributePtr attribute0, attribute1, attribute2, attribute3, + attribute4, attribute5, attribute6, attribute7; + Widgets::MWAttributePtr affectedWidget; + + ESM::Attribute::AttributeID attributeId; + }; + + class SelectSkillDialog : public OEngine::GUI::Layout + { + public: + SelectSkillDialog(MWWorld::Environment& environment, MyGUI::IntSize gameWindowSize); + + ESM::Skill::SkillEnum getSkillId() const { return skillId; } + Widgets::MWSkillPtr getAffectedWidget() const { return affectedWidget; } + void setAffectedWidget(Widgets::MWSkillPtr widget) { affectedWidget = widget; } + + // Events + typedef delegates::CDelegate0 EventHandle_Void; + + /** Event : Cancel button clicked.\n + signature : void method()\n + */ + EventHandle_Void eventCancel; + + /** Event : Dialog finished, skill selected.\n + signature : void method()\n + */ + EventHandle_Void eventItemSelected; + + protected: + void onSkillClicked(Widgets::MWSkillPtr _sender); + void onCancelClicked(MyGUI::Widget* _sender); + + private: + Widgets::MWSkillPtr combatSkill0, combatSkill1, combatSkill2, combatSkill3, combatSkill4, + combatSkill5, combatSkill6, combatSkill7, combatSkill8; + Widgets::MWSkillPtr magicSkill0, magicSkill1, magicSkill2, magicSkill3, magicSkill4, + magicSkill5, magicSkill6, magicSkill7, magicSkill8; + Widgets::MWSkillPtr stealthSkill0, stealthSkill1, stealthSkill2, stealthSkill3, stealthSkill4, + stealthSkill5, stealthSkill6, stealthSkill7, stealthSkill8; + Widgets::MWSkillPtr affectedWidget; + + ESM::Skill::SkillEnum skillId; + }; + + class DescriptionDialog : public OEngine::GUI::Layout + { + public: + DescriptionDialog(MWWorld::Environment& environment, MyGUI::IntSize gameWindowSize); + + std::string getTextInput() const { return textEdit ? textEdit->getOnlyText() : ""; } + void setTextInput(const std::string &text) { if (textEdit) textEdit->setOnlyText(text); } + + // Events + typedef delegates::CDelegate0 EventHandle_Void; + + /** Event : Dialog finished, OK button clicked.\n + signature : void method()\n + */ + EventHandle_Void eventDone; + + protected: + void onOkClicked(MyGUI::Widget* _sender); + + private: + MWWorld::Environment& environment; + + MyGUI::EditPtr textEdit; + }; + + class CreateClassDialog : public OEngine::GUI::Layout + { + public: + CreateClassDialog(MWWorld::Environment& environment, MyGUI::IntSize gameWindowSize); + virtual ~CreateClassDialog(); + + std::string getName() const; + std::string getDescription() const; + ESM::Class::Specialization getSpecializationId() const; + std::vector getFavoriteAttributes() const; + std::vector getMajorSkills() const; + std::vector getMinorSkills() const; + + 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 onOkClicked(MyGUI::Widget* _sender); + void onBackClicked(MyGUI::Widget* _sender); + + void onSpecializationClicked(MyGUI::WidgetPtr _sender); + void onSpecializationSelected(); + void onAttributeClicked(Widgets::MWAttributePtr _sender); + void onAttributeSelected(); + void onSkillClicked(Widgets::MWSkillPtr _sender); + void onSkillSelected(); + void onDescriptionClicked(MyGUI::Widget* _sender); + void onDescriptionEntered(); + void onDialogCancel(); + + private: + MWWorld::Environment& environment; + + MyGUI::EditPtr editName; + MyGUI::WidgetPtr specializationName; + Widgets::MWAttributePtr favoriteAttribute0, favoriteAttribute1; + Widgets::MWSkillPtr majorSkill0, majorSkill1, majorSkill2, majorSkill3, majorSkill4; + Widgets::MWSkillPtr minorSkill0, minorSkill1, minorSkill2, minorSkill3, minorSkill4; + std::vector skills; + std::string description; + + SelectSpecializationDialog *specDialog; + SelectAttributeDialog *attribDialog; + SelectSkillDialog *skillDialog; + DescriptionDialog *descDialog; + + ESM::Class::Specialization specializationId; + }; } #endif diff --git a/apps/openmw/mwgui/mode.hpp b/apps/openmw/mwgui/mode.hpp index b18dd9f95..313b097cf 100644 --- a/apps/openmw/mwgui/mode.hpp +++ b/apps/openmw/mwgui/mode.hpp @@ -23,6 +23,9 @@ namespace MWGui GM_Race, GM_Birth, GM_Class, + GM_ClassGenerate, + GM_ClassPick, + GM_ClassCreate, GM_Review }; diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index e8b127591..f23a884a2 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -82,6 +82,11 @@ void MWSkill::updateWidgets() } } +void MWSkill::onClicked(MyGUI::Widget* _sender) +{ + eventClicked(this); +} + void MWSkill::_initialise(WidgetStyle _style, const IntCoord& _coord, Align _align, ResourceSkin* _info, Widget* _parent, ICroppedRectangle * _croppedParent, IWidgetCreator * _creator, const std::string& _name) { Base::_initialise(_style, _coord, _align, _info, _parent, _croppedParent, _creator, _name); @@ -116,6 +121,20 @@ void MWSkill::initialiseWidgetSkin(ResourceSkin* _info) MYGUI_DEBUG_ASSERT( ! skillValueWidget, "widget already assigned"); skillValueWidget = (*iter)->castType(); } + else if (name == "StatNameButton") + { + MYGUI_DEBUG_ASSERT( ! skillNameWidget, "widget already assigned"); + MyGUI::ButtonPtr button = (*iter)->castType