#include "charactercreation.hpp" #include #include #include #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/actorutil.hpp" #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/player.hpp" /* Start of tes3mp addition Include additional headers for multiplayer purposes */ #include "../mwmp/Main.hpp" #include "../mwmp/LocalPlayer.hpp" /* End of tes3mp addition */ #include "textinput.hpp" #include "race.hpp" #include "class.hpp" #include "birth.hpp" #include "review.hpp" #include "inventorywindow.hpp" namespace { struct Response { const std::string mText; const ESM::Class::Specialization mSpecialization; }; struct Step { const std::string mText; const Response mResponses[3]; const std::string mSound; }; Step sGenerateClassSteps(int number) { number++; std::string question = Fallback::Map::getString("Question_" + MyGUI::utility::toString(number) + "_Question"); std::string answer0 = Fallback::Map::getString("Question_" + MyGUI::utility::toString(number) + "_AnswerOne"); std::string answer1 = Fallback::Map::getString("Question_" + MyGUI::utility::toString(number) + "_AnswerTwo"); std::string answer2 = Fallback::Map::getString("Question_" + MyGUI::utility::toString(number) + "_AnswerThree"); std::string sound = "vo\\misc\\chargen qa" + MyGUI::utility::toString(number) + ".wav"; Response r0 = {answer0, ESM::Class::Combat}; Response r1 = {answer1, ESM::Class::Magic}; Response r2 = {answer2, ESM::Class::Stealth}; // randomize order in which responses are displayed int order = Misc::Rng::rollDice(6); switch (order) { case 0: return {question, {r0, r1, r2}, sound}; case 1: return {question, {r0, r2, r1}, sound}; case 2: return {question, {r1, r0, r2}, sound}; case 3: return {question, {r1, r2, r0}, sound}; case 4: return {question, {r2, r0, r1}, sound}; default: return {question, {r2, r1, r0}, sound}; } } void updatePlayerHealth() { MWWorld::Ptr player = MWMechanics::getPlayer(); MWMechanics::NpcStats& npcStats = player.getClass().getNpcStats(player); npcStats.updateHealth(); } } namespace MWGui { CharacterCreation::CharacterCreation(osg::Group* parent, Resource::ResourceSystem* resourceSystem) : mParent(parent) , mResourceSystem(resourceSystem) , mNameDialog(nullptr) , mRaceDialog(nullptr) , mClassChoiceDialog(nullptr) , mGenerateClassQuestionDialog(nullptr) , mGenerateClassResultDialog(nullptr) , mPickClassDialog(nullptr) , mCreateClassDialog(nullptr) , mBirthSignDialog(nullptr) , mReviewDialog(nullptr) , mGenerateClassStep(0) { mCreationStage = CSE_NotStarted; mGenerateClassResponses[0] = ESM::Class::Combat; mGenerateClassResponses[1] = ESM::Class::Magic; mGenerateClassResponses[2] = ESM::Class::Stealth; mGenerateClassSpecializations[0] = 0; mGenerateClassSpecializations[1] = 0; mGenerateClassSpecializations[2] = 0; // Setup player stats for (int i = 0; i < ESM::Attribute::Length; ++i) mPlayerAttributes.emplace(ESM::Attribute::sAttributeIds[i], MWMechanics::AttributeValue()); for (int i = 0; i < ESM::Skill::Length; ++i) mPlayerSkillValues.emplace(ESM::Skill::sSkillIds[i], MWMechanics::SkillValue()); } void CharacterCreation::setValue (const std::string& id, const MWMechanics::AttributeValue& value) { static const char *ids[] = { "AttribVal1", "AttribVal2", "AttribVal3", "AttribVal4", "AttribVal5", "AttribVal6", "AttribVal7", "AttribVal8", 0 }; for (int i=0; ids[i]; ++i) { if (ids[i]==id) { mPlayerAttributes[static_cast(i)] = value; if (mReviewDialog) mReviewDialog->setAttribute(static_cast(i), value); break; } } } void CharacterCreation::setValue (const std::string& id, const MWMechanics::DynamicStat& value) { if (mReviewDialog) { if (id == "HBar") { mReviewDialog->setHealth (value); } else if (id == "MBar") { mReviewDialog->setMagicka (value); } else if (id == "FBar") { mReviewDialog->setFatigue (value); } } } void CharacterCreation::setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value) { mPlayerSkillValues[parSkill] = value; if (mReviewDialog) mReviewDialog->setSkillValue(parSkill, value); } void CharacterCreation::configureSkills (const SkillList& major, const SkillList& minor) { if (mReviewDialog) mReviewDialog->configureSkills(major, minor); mPlayerMajorSkills = major; mPlayerMinorSkills = minor; } void CharacterCreation::onFrame(float duration) { if (mReviewDialog) mReviewDialog->onFrame(duration); } void CharacterCreation::spawnDialog(const char id) { try { switch (id) { case GM_Name: MWBase::Environment::get().getWindowManager()->removeDialog(mNameDialog); mNameDialog = nullptr; mNameDialog = new TextInputDialog(); mNameDialog->setTextLabel(MWBase::Environment::get().getWindowManager()->getGameSettingString("sName", "Name")); mNameDialog->setTextInput(mPlayerName); mNameDialog->setNextButtonShow(mCreationStage >= CSE_NameChosen); mNameDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onNameDialogDone); mNameDialog->setVisible(true); break; case GM_Race: MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); mRaceDialog = nullptr; mRaceDialog = new RaceDialog(mParent, mResourceSystem); mRaceDialog->setNextButtonShow(mCreationStage >= CSE_RaceChosen); mRaceDialog->setRaceId(mPlayerRaceId); mRaceDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogDone); mRaceDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogBack); mRaceDialog->setVisible(true); if (mCreationStage < CSE_NameChosen) mCreationStage = CSE_NameChosen; break; case GM_Class: MWBase::Environment::get().getWindowManager()->removeDialog(mClassChoiceDialog); mClassChoiceDialog = nullptr; mClassChoiceDialog = new ClassChoiceDialog(); mClassChoiceDialog->eventButtonSelected += MyGUI::newDelegate(this, &CharacterCreation::onClassChoice); mClassChoiceDialog->setVisible(true); if (mCreationStage < CSE_RaceChosen) mCreationStage = CSE_RaceChosen; break; case GM_ClassPick: MWBase::Environment::get().getWindowManager()->removeDialog(mPickClassDialog); mPickClassDialog = nullptr; mPickClassDialog = new PickClassDialog(); mPickClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen); mPickClassDialog->setClassId(mPlayerClass.mId); mPickClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogDone); mPickClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogBack); mPickClassDialog->setVisible(true); if (mCreationStage < CSE_RaceChosen) mCreationStage = CSE_RaceChosen; break; case GM_Birth: MWBase::Environment::get().getWindowManager()->removeDialog(mBirthSignDialog); mBirthSignDialog = nullptr; mBirthSignDialog = new BirthDialog(); mBirthSignDialog->setNextButtonShow(mCreationStage >= CSE_BirthSignChosen); mBirthSignDialog->setBirthId(mPlayerBirthSignId); mBirthSignDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogDone); mBirthSignDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogBack); mBirthSignDialog->setVisible(true); if (mCreationStage < CSE_ClassChosen) mCreationStage = CSE_ClassChosen; break; case GM_ClassCreate: if (!mCreateClassDialog) { mCreateClassDialog = new CreateClassDialog(); mCreateClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogDone); mCreateClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogBack); } mCreateClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen); mCreateClassDialog->setVisible(true); if (mCreationStage < CSE_RaceChosen) mCreationStage = CSE_RaceChosen; break; case GM_ClassGenerate: mGenerateClassStep = 0; mGenerateClass = ""; mGenerateClassSpecializations[0] = 0; mGenerateClassSpecializations[1] = 0; mGenerateClassSpecializations[2] = 0; showClassQuestionDialog(); if (mCreationStage < CSE_RaceChosen) mCreationStage = CSE_RaceChosen; break; case GM_Review: MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); mReviewDialog = nullptr; mReviewDialog = new ReviewDialog(); MWBase::World *world = MWBase::Environment::get().getWorld(); const ESM::NPC *playerNpc = world->getPlayerPtr().get()->mBase; const MWWorld::Player player = world->getPlayer(); const ESM::Class *playerClass = world->getStore().get().find(playerNpc->mClass); mReviewDialog->setPlayerName(playerNpc->mName); mReviewDialog->setRace(playerNpc->mRace); mReviewDialog->setClass(*playerClass); mReviewDialog->setBirthSign(player.getBirthSign()); MWWorld::Ptr playerPtr = MWMechanics::getPlayer(); const MWMechanics::CreatureStats& stats = playerPtr.getClass().getCreatureStats(playerPtr); mReviewDialog->setHealth(stats.getHealth()); mReviewDialog->setMagicka(stats.getMagicka()); mReviewDialog->setFatigue(stats.getFatigue()); for (auto& attributePair : mPlayerAttributes) { mReviewDialog->setAttribute(static_cast (attributePair.first), attributePair.second); } for (auto& skillPair : mPlayerSkillValues) { mReviewDialog->setSkillValue(static_cast (skillPair.first), skillPair.second); } mReviewDialog->configureSkills(mPlayerMajorSkills, mPlayerMinorSkills); mReviewDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogDone); mReviewDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogBack); mReviewDialog->eventActivateDialog += MyGUI::newDelegate(this, &CharacterCreation::onReviewActivateDialog); mReviewDialog->setVisible(true); if (mCreationStage < CSE_BirthSignChosen) mCreationStage = CSE_BirthSignChosen; break; } } catch (std::exception& e) { Log(Debug::Error) << "Error: Failed to create chargen window: " << e.what(); } } void CharacterCreation::onReviewDialogDone(WindowBase* parWindow) { MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); mReviewDialog = nullptr; MWBase::Environment::get().getWindowManager()->popGuiMode(); } void CharacterCreation::onReviewDialogBack() { MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); mReviewDialog = nullptr; mCreationStage = CSE_ReviewBack; MWBase::Environment::get().getWindowManager()->popGuiMode(); MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); /* Start of tes3mp addition Decrease the character generation stage tracked for the LocalPlayer */ mwmp::Main::get().getLocalPlayer()->charGenState.currentStage--; /* End of tes3mp addition */ } void CharacterCreation::onReviewActivateDialog(int parDialog) { MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); mReviewDialog = nullptr; mCreationStage = CSE_ReviewNext; MWBase::Environment::get().getWindowManager()->popGuiMode(); switch(parDialog) { case ReviewDialog::NAME_DIALOG: MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Name); break; case ReviewDialog::RACE_DIALOG: MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Race); break; case ReviewDialog::CLASS_DIALOG: MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); break; case ReviewDialog::BIRTHSIGN_DIALOG: MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); }; } void CharacterCreation::selectPickedClass() { if (mPickClassDialog) { const std::string &classId = mPickClassDialog->getClassId(); if (!classId.empty()) MWBase::Environment::get().getMechanicsManager()->setPlayerClass(classId); const ESM::Class *klass = MWBase::Environment::get().getWorld()->getStore().get().find(classId); if (klass) { mPlayerClass = *klass; } MWBase::Environment::get().getWindowManager()->removeDialog(mPickClassDialog); mPickClassDialog = nullptr; } updatePlayerHealth(); } void CharacterCreation::onPickClassDialogDone(WindowBase* parWindow) { selectPickedClass(); handleDialogDone(CSE_ClassChosen, GM_Birth); /* Start of tes3mp addition Increase the character generation stage tracked for the LocalPlayer */ mwmp::Main::get().getLocalPlayer()->charGenState.currentStage++; /* End of tes3mp addition */ } void CharacterCreation::onPickClassDialogBack() { selectPickedClass(); MWBase::Environment::get().getWindowManager()->popGuiMode(); MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); } void CharacterCreation::onClassChoice(int _index) { MWBase::Environment::get().getWindowManager()->removeDialog(mClassChoiceDialog); mClassChoiceDialog = nullptr; MWBase::Environment::get().getWindowManager()->popGuiMode(); switch(_index) { case ClassChoiceDialog::Class_Generate: MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_ClassGenerate); break; case ClassChoiceDialog::Class_Pick: MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_ClassPick); break; case ClassChoiceDialog::Class_Create: MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_ClassCreate); break; case ClassChoiceDialog::Class_Back: MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Race); /* Start of tes3mp addition Decrease the character generation stage tracked for the LocalPlayer */ mwmp::Main::get().getLocalPlayer()->charGenState.currentStage--; /* End of tes3mp addition */ break; }; } void CharacterCreation::onNameDialogDone(WindowBase* parWindow) { if (mNameDialog) { mPlayerName = mNameDialog->getTextInput(); /* Start of tes3mp change (major) Ensure names are not longer than the original game's 31 character maximum */ if (mPlayerName.length() > 31) mPlayerName = mPlayerName.substr(0, 31); /* End of tes3mp change (major) */ MWBase::Environment::get().getMechanicsManager()->setPlayerName(mPlayerName); MWBase::Environment::get().getWindowManager()->removeDialog(mNameDialog); mNameDialog = nullptr; } handleDialogDone(CSE_NameChosen, GM_Race); /* Start of tes3mp addition Increase the character generation stage tracked for the LocalPlayer */ mwmp::Main::get().getLocalPlayer()->charGenState.currentStage++; /* End of tes3mp addition */ } void CharacterCreation::selectRace() { if (mRaceDialog) { const ESM::NPC &data = mRaceDialog->getResult(); mPlayerRaceId = data.mRace; if (!mPlayerRaceId.empty()) { MWBase::Environment::get().getMechanicsManager()->setPlayerRace( data.mRace, data.isMale(), data.mHead, data.mHair ); } MWBase::Environment::get().getWindowManager()->getInventoryWindow()->rebuildAvatar(); MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); mRaceDialog = nullptr; } updatePlayerHealth(); } void CharacterCreation::onRaceDialogBack() { selectRace(); MWBase::Environment::get().getWindowManager()->popGuiMode(); MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Name); } void CharacterCreation::onRaceDialogDone(WindowBase* parWindow) { selectRace(); handleDialogDone(CSE_RaceChosen, GM_Class); /* Start of tes3mp addition Increase the character generation stage tracked for the LocalPlayer */ mwmp::Main::get().getLocalPlayer()->charGenState.currentStage++; /* End of tes3mp addition */ } void CharacterCreation::selectBirthSign() { if (mBirthSignDialog) { mPlayerBirthSignId = mBirthSignDialog->getBirthId(); if (!mPlayerBirthSignId.empty()) MWBase::Environment::get().getMechanicsManager()->setPlayerBirthsign(mPlayerBirthSignId); MWBase::Environment::get().getWindowManager()->removeDialog(mBirthSignDialog); mBirthSignDialog = nullptr; } updatePlayerHealth(); } void CharacterCreation::onBirthSignDialogDone(WindowBase* parWindow) { selectBirthSign(); handleDialogDone(CSE_BirthSignChosen, GM_Review); /* Start of tes3mp addition Increase the character generation stage tracked for the LocalPlayer */ mwmp::Main::get().getLocalPlayer()->charGenState.currentStage++; /* End of tes3mp addition */ } void CharacterCreation::onBirthSignDialogBack() { selectBirthSign(); MWBase::Environment::get().getWindowManager()->popGuiMode(); MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); /* Start of tes3mp addition Decrease the character generation stage tracked for the LocalPlayer */ mwmp::Main::get().getLocalPlayer()->charGenState.currentStage--; /* End of tes3mp addition */ } void CharacterCreation::selectCreatedClass() { if (mCreateClassDialog) { ESM::Class klass; klass.mName = mCreateClassDialog->getName(); klass.mDescription = mCreateClassDialog->getDescription(); klass.mData.mSpecialization = mCreateClassDialog->getSpecializationId(); klass.mData.mIsPlayable = 0x1; std::vector attributes = mCreateClassDialog->getFavoriteAttributes(); assert(attributes.size() == 2); klass.mData.mAttribute[0] = attributes[0]; klass.mData.mAttribute[1] = attributes[1]; std::vector majorSkills = mCreateClassDialog->getMajorSkills(); std::vector minorSkills = mCreateClassDialog->getMinorSkills(); assert(majorSkills.size() >= sizeof(klass.mData.mSkills)/sizeof(klass.mData.mSkills[0])); assert(minorSkills.size() >= sizeof(klass.mData.mSkills)/sizeof(klass.mData.mSkills[0])); for (size_t i = 0; i < sizeof(klass.mData.mSkills)/sizeof(klass.mData.mSkills[0]); ++i) { klass.mData.mSkills[i][1] = majorSkills[i]; klass.mData.mSkills[i][0] = minorSkills[i]; } MWBase::Environment::get().getMechanicsManager()->setPlayerClass(klass); mPlayerClass = klass; // Do not delete dialog, so that choices are remembered in case we want to go back and adjust them later mCreateClassDialog->setVisible(false); } updatePlayerHealth(); } void CharacterCreation::onCreateClassDialogDone(WindowBase* parWindow) { selectCreatedClass(); handleDialogDone(CSE_ClassChosen, GM_Birth); /* Start of tes3mp addition Increase the character generation stage tracked for the LocalPlayer */ mwmp::Main::get().getLocalPlayer()->charGenState.currentStage++; /* End of tes3mp addition */ } void CharacterCreation::onCreateClassDialogBack() { // not done in MW, but we do it for consistency with the other dialogs selectCreatedClass(); MWBase::Environment::get().getWindowManager()->popGuiMode(); MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); /* Start of tes3mp addition Decrease the character generation stage tracked for the LocalPlayer */ mwmp::Main::get().getLocalPlayer()->charGenState.currentStage--; /* End of tes3mp addition */ } void CharacterCreation::onClassQuestionChosen(int _index) { MWBase::Environment::get().getSoundManager()->stopSay(); MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassQuestionDialog); mGenerateClassQuestionDialog = nullptr; if (_index < 0 || _index >= 3) { MWBase::Environment::get().getWindowManager()->popGuiMode(); MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); return; } ESM::Class::Specialization specialization = mGenerateClassResponses[_index]; if (specialization == ESM::Class::Combat) ++mGenerateClassSpecializations[0]; else if (specialization == ESM::Class::Magic) ++mGenerateClassSpecializations[1]; else if (specialization == ESM::Class::Stealth) ++mGenerateClassSpecializations[2]; ++mGenerateClassStep; showClassQuestionDialog(); } void CharacterCreation::showClassQuestionDialog() { if (mGenerateClassStep == 10) { unsigned combat = mGenerateClassSpecializations[0]; unsigned magic = mGenerateClassSpecializations[1]; unsigned stealth = mGenerateClassSpecializations[2]; if (combat > 7) { mGenerateClass = "Warrior"; } else if (magic > 7) { mGenerateClass = "Mage"; } else if (stealth > 7) { mGenerateClass = "Thief"; } else { switch (combat) { case 4: mGenerateClass = "Rogue"; break; case 5: if (stealth == 3) mGenerateClass = "Scout"; else mGenerateClass = "Archer"; break; case 6: if (stealth == 1) mGenerateClass = "Barbarian"; else if (stealth == 3) mGenerateClass = "Crusader"; else mGenerateClass = "Knight"; break; case 7: mGenerateClass = "Warrior"; break; default: switch (magic) { case 4: mGenerateClass = "Spellsword"; break; case 5: mGenerateClass = "Witchhunter"; break; case 6: if (combat == 2) mGenerateClass = "Sorcerer"; else if (combat == 3) mGenerateClass = "Healer"; else mGenerateClass = "Battlemage"; break; case 7: mGenerateClass = "Mage"; break; default: switch (stealth) { case 3: if (magic == 3) mGenerateClass = "Bard"; // unreachable else mGenerateClass = "Warrior"; break; case 5: if (magic == 3) mGenerateClass = "Monk"; else mGenerateClass = "Pilgrim"; break; case 6: if (magic == 1) mGenerateClass = "Agent"; else if (magic == 3) mGenerateClass = "Assassin"; else mGenerateClass = "Acrobat"; break; case 7: mGenerateClass = "Thief"; break; default: mGenerateClass = "Warrior"; } } } } MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassResultDialog); mGenerateClassResultDialog = nullptr; mGenerateClassResultDialog = new GenerateClassResultDialog(); mGenerateClassResultDialog->setClassId(mGenerateClass); mGenerateClassResultDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onGenerateClassBack); mGenerateClassResultDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onGenerateClassDone); mGenerateClassResultDialog->setVisible(true); return; } if (mGenerateClassStep > 10) { MWBase::Environment::get().getWindowManager()->popGuiMode(); MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); return; } MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassQuestionDialog); mGenerateClassQuestionDialog = nullptr; mGenerateClassQuestionDialog = new InfoBoxDialog(); Step step = sGenerateClassSteps(mGenerateClassStep); mGenerateClassResponses[0] = step.mResponses[0].mSpecialization; mGenerateClassResponses[1] = step.mResponses[1].mSpecialization; mGenerateClassResponses[2] = step.mResponses[2].mSpecialization; InfoBoxDialog::ButtonList buttons; mGenerateClassQuestionDialog->setText(step.mText); buttons.push_back(step.mResponses[0].mText); buttons.push_back(step.mResponses[1].mText); buttons.push_back(step.mResponses[2].mText); mGenerateClassQuestionDialog->setButtons(buttons); mGenerateClassQuestionDialog->eventButtonSelected += MyGUI::newDelegate(this, &CharacterCreation::onClassQuestionChosen); mGenerateClassQuestionDialog->setVisible(true); MWBase::Environment::get().getSoundManager()->say(step.mSound); } void CharacterCreation::selectGeneratedClass() { MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassResultDialog); mGenerateClassResultDialog = nullptr; MWBase::Environment::get().getMechanicsManager()->setPlayerClass(mGenerateClass); const ESM::Class *klass = MWBase::Environment::get().getWorld()->getStore().get().find(mGenerateClass); mPlayerClass = *klass; updatePlayerHealth(); } void CharacterCreation::onGenerateClassBack() { selectGeneratedClass(); MWBase::Environment::get().getWindowManager()->popGuiMode(); MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); } void CharacterCreation::onGenerateClassDone(WindowBase* parWindow) { selectGeneratedClass(); handleDialogDone(CSE_ClassChosen, GM_Birth); /* Start of tes3mp addition Increase the character generation stage tracked for the LocalPlayer */ mwmp::Main::get().getLocalPlayer()->charGenState.currentStage++; /* End of tes3mp addition */ } CharacterCreation::~CharacterCreation() { delete mNameDialog; delete mRaceDialog; delete mClassChoiceDialog; delete mGenerateClassQuestionDialog; delete mGenerateClassResultDialog; delete mPickClassDialog; delete mCreateClassDialog; delete mBirthSignDialog; delete mReviewDialog; } void CharacterCreation::handleDialogDone(CSE currentStage, int nextMode) { MWBase::Environment::get().getWindowManager()->popGuiMode(); if (mCreationStage == CSE_ReviewNext) { MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); } /* Start of tes3mp change (major) Servers have control over character generation in multiplayer, which is why the automatic transition to the next character generation menu has been commented out here */ /* else if (mCreationStage >= currentStage) { MWBase::Environment::get().getWindowManager()->pushGuiMode((GuiMode)nextMode); } */ /* End of tes3mp change (major) */ else { mCreationStage = currentStage; } } }