diff options
author | Paul Gilbert | 2015-02-12 23:16:20 -0500 |
---|---|---|
committer | Paul Gilbert | 2015-02-12 23:16:20 -0500 |
commit | e16ecd110b2f607621773e13df8f972c9c7e979a (patch) | |
tree | d4359937e6b4af113552305dd3756efef1b558b9 | |
parent | 2772cd33c1f62d0e0ea41507f6b809704d569254 (diff) | |
download | scummvm-rg350-e16ecd110b2f607621773e13df8f972c9c7e979a.tar.gz scummvm-rg350-e16ecd110b2f607621773e13df8f972c9c7e979a.tar.bz2 scummvm-rg350-e16ecd110b2f607621773e13df8f972c9c7e979a.zip |
XEEN: Implementing create chracter dialog
-rw-r--r-- | engines/xeen/character.h | 4 | ||||
-rw-r--r-- | engines/xeen/dialogs_party.cpp | 246 | ||||
-rw-r--r-- | engines/xeen/dialogs_party.h | 12 | ||||
-rw-r--r-- | engines/xeen/resources.cpp | 21 | ||||
-rw-r--r-- | engines/xeen/resources.h | 7 |
5 files changed, 287 insertions, 3 deletions
diff --git a/engines/xeen/character.h b/engines/xeen/character.h index 492e5e298f..9e8687dbd7 100644 --- a/engines/xeen/character.h +++ b/engines/xeen/character.h @@ -49,13 +49,13 @@ enum Race { HUMAN = 0, ELF = 1, DWARF = 2, GNOME = 3, HALF_ORC = 4 }; enum CharacterClass { CLASS_KNIGHT = 0, CLASS_PALADIN = 1, CLASS_ARCHER = 2, CLASS_CLERIC = 3, CLASS_SORCERER = 4, CLASS_ROBBER = 5, CLASS_NINJA = 6, CLASS_BARBARIAN = 7, - CLASS_DRUID = 8, CLASS_RANGER = 9, + CLASS_DRUID = 8, CLASS_RANGER = 9, TOTAL_CLASSES = 10, CLASS_12 = 12, CLASS_15 = 15, CLASS_16 = 16 }; enum Attribute { MIGHT = 0, INTELLECT = 1, PERSONALITY = 2, ENDURANCE = 3, SPEED = 4, - ACCURACY = 5, LUCK = 6 + ACCURACY = 5, LUCK = 6, TOTAL_ATTRIBUTES = 7 }; enum Skill { diff --git a/engines/xeen/dialogs_party.cpp b/engines/xeen/dialogs_party.cpp index eece1e36fe..ff59363ead 100644 --- a/engines/xeen/dialogs_party.cpp +++ b/engines/xeen/dialogs_party.cpp @@ -372,7 +372,136 @@ void PartyDialog::startingCharChanged(int firstDisplayChar) { } void PartyDialog::createChar() { - error("TODO: createChar"); + EventsManager &events = *_vm->_events; + Party &party = *_vm->_party; + Screen &screen = *_vm->_screen; + SpriteResource dice, icons; + Mode oldMode = _vm->_mode; + Common::Array<int> freeCharList; + int selectedClass = 0; + bool hasFadedIn = false; + + dice.load("dice.vga"); + icons.load("create.raw"); + + // Add buttons + saveButtons(); + addButton(Common::Rect(132, 98, 156, 118), Common::KEYCODE_r, &icons); + addButton(Common::Rect(132, 128, 156, 148), Common::KEYCODE_c, &icons); + addButton(Common::Rect(132, 158, 156, 178), Common::KEYCODE_ESCAPE, &icons); + addButton(Common::Rect(86, 98, 110, 118), Common::KEYCODE_UP, &icons); + addButton(Common::Rect(86, 120, 110, 140), Common::KEYCODE_DOWN, &icons); + addButton(Common::Rect(168, 19, 192, 39), Common::KEYCODE_n, nullptr); + addButton(Common::Rect(168, 43, 192, 63), Common::KEYCODE_i, nullptr); + addButton(Common::Rect(168, 67, 192, 87), Common::KEYCODE_p, nullptr); + addButton(Common::Rect(168, 91, 192, 111), Common::KEYCODE_e, nullptr); + addButton(Common::Rect(168, 115, 192, 135), Common::KEYCODE_s, nullptr); + addButton(Common::Rect(168, 139, 192, 159), Common::KEYCODE_a, nullptr); + addButton(Common::Rect(168, 163, 192, 183), Common::KEYCODE_l, nullptr); + addButton(Common::Rect(227, 19, 139, 29), 1000, nullptr); + addButton(Common::Rect(227, 30, 139, 40), 1001, nullptr); + addButton(Common::Rect(227, 41, 139, 51), 1002, nullptr); + addButton(Common::Rect(227, 52, 139, 62), 1003, nullptr); + addButton(Common::Rect(227, 63, 139, 73), 1004, nullptr); + addButton(Common::Rect(227, 74, 139, 84), 1005, nullptr); + addButton(Common::Rect(227, 85, 139, 95), 1006, nullptr); + addButton(Common::Rect(227, 96, 139, 106), 1007, nullptr); + addButton(Common::Rect(227, 107, 139, 117), 1008, nullptr); + addButton(Common::Rect(227, 118, 139, 128), 1009, nullptr); + + // Load the background + screen.loadBackground("create.raw"); + events.setCursor(0); + + while (!_vm->shouldQuit()) { + int classId = -1; + + // Build up list of roster slot indexes that are free + freeCharList.clear(); + for (uint idx = 0; idx < XEEN_TOTAL_CHARACTERS; ++idx) { + if (party._roster[idx]._name.empty()) + freeCharList.push_back(idx); + } + int charIndex = 0; + //bool flag9 = true; + + if (freeCharList.size() == XEEN_TOTAL_CHARACTERS) + break; + + // Get and race and sex for the given character + Race race = (Race)((freeCharList[charIndex] / 4) % 5); + Sex sex = (Sex)(freeCharList[charIndex] & 1); + + // Randomly determine attributes, and which classes they allow + uint attribs[TOTAL_ATTRIBUTES]; + bool allowedClasses[TOTAL_CLASSES]; + throwDice(attribs, allowedClasses); + + // Set up display of the rolled character details + Common::String msg; + selectedClass = newCharDetails(attribs, allowedClasses, + race, sex, classId, selectedClass, msg); + + // Draw the screen + Window &w = screen._windows[0]; + icons.draw(w, 10, Common::Point(168, 19)); + icons.draw(w, 12, Common::Point(168, 43)); + icons.draw(w, 14, Common::Point(168, 67)); + icons.draw(w, 16, Common::Point(168, 91)); + icons.draw(w, 18, Common::Point(168, 115)); + icons.draw(w, 20, Common::Point(168, 139)); + icons.draw(w, 22, Common::Point(168, 163)); + for (int idx = 0; idx < 9; ++idx) + icons.draw(w, 24 + idx * 2, Common::Point(227, 19 + 11 * idx)); + + for (int idx = 0; idx < 7; ++idx) + icons.draw(w, 50 + idx, Common::Point(195, 31 + 24 * idx)); + + icons.draw(w, 57, Common::Point(62, 148)); + icons.draw(w, 58, Common::Point(62, 158)); + icons.draw(w, 59, Common::Point(62, 168)); + icons.draw(w, 61, Common::Point(220, 19)); + icons.draw(w, 64, Common::Point(220, 155)); + icons.draw(w, 65, Common::Point(220, 170)); + + party._roster[freeCharList[charIndex]]._faceSprites->draw( + w, 0, Common::Point(27, 102)); + + icons.draw(w, 0, Common::Point(132, 98)); + icons.draw(w, 2, Common::Point(132, 128)); + icons.draw(w, 4, Common::Point(132, 158)); + icons.draw(w, 6, Common::Point(86, 98)); + icons.draw(w, 8, Common::Point(86, 120)); + + w.writeString(msg); + w.update(); + + // Draw the arrow for the selected class, if applicable + if (selectedClass != -1) + printSelectionArrow(icons, selectedClass); + + // Draw the dice + drawDice(dice); + if (!hasFadedIn) { + screen.fadeIn(4); + hasFadedIn = true; + } + + // Key handling loop + while (!_vm->shouldQuit()) { + // Animate the dice until a user action occurs + _buttonValue = 0; + while (!_vm->shouldQuit() && !_buttonValue) + drawDice(dice); + + // TODO + } + + // TODO: More + error("TODO: createChar"); + } + + _vm->_mode = oldMode; } int PartyDialog::selectCharacter(bool isDelete, int firstDisplayChar) { @@ -447,4 +576,119 @@ int PartyDialog::selectCharacter(bool isDelete, int firstDisplayChar) { return result == -1 ? 0 : result; } +/** + * Roll up some random values for the attributes, and return both them as + * well as a list of classes that the attributes meet the requirements for + */ +void PartyDialog::throwDice(uint attribs[TOTAL_ATTRIBUTES], bool allowedClasses[TOTAL_CLASSES]) { + bool repeat = true; + do { + // Default all the attributes to zero + Common::fill(&attribs[0], &attribs[TOTAL_ATTRIBUTES], 0); + + // Assign random amounts to each attribute + for (int idx1 = 0; idx1 < 3; ++idx1) { + for (int idx2 = 0; idx2 < TOTAL_ATTRIBUTES; ++idx2) { + attribs[idx1] += _vm->getRandomNumber(10, 79) / 10; + } + } + + // Check which classes are allowed based on the rolled attributes + checkClass(attribs, allowedClasses); + + // Only exit if the attributes allow for at least one class + for (int idx = 0; idx < TOTAL_CLASSES; ++idx) { + if (allowedClasses[idx]) + repeat = false; + } + } while (repeat); +} + +/** + * Set a list of flags for which classes the passed attribute set meet the + * minimum requirements of + */ +void PartyDialog::checkClass(const uint attribs[TOTAL_ATTRIBUTES], bool allowedClasses[TOTAL_CLASSES]) { + allowedClasses[CLASS_KNIGHT] = attribs[MIGHT] >= 15; + allowedClasses[CLASS_PALADIN] = attribs[MIGHT] >= 13 + && attribs[PERSONALITY] >= 13 && attribs[ENDURANCE] >= 13; + allowedClasses[CLASS_ARCHER] = attribs[INTELLECT] >= 13 && attribs[ACCURACY] >= 13; + allowedClasses[CLASS_CLERIC] = attribs[PERSONALITY] >= 13; + allowedClasses[CLASS_SORCERER] = attribs[INTELLECT] >= 13; + allowedClasses[CLASS_ROBBER] = attribs[LUCK] >= 13; + allowedClasses[CLASS_NINJA] = attribs[SPEED] >= 13 && attribs[ACCURACY] >= 13; + allowedClasses[CLASS_BARBARIAN] = attribs[ENDURANCE] >= 15; + allowedClasses[CLASS_DRUID] = attribs[INTELLECT] >= 15 && attribs[PERSONALITY] >= 15; + allowedClasses[CLASS_RANGER] = attribs[INTELLECT] >= 12 && attribs[PERSONALITY] >= 12 + && attribs[ENDURANCE] >= 12 && attribs[SPEED] >= 12; +} + +/** + * Return details of the generated character + */ +int PartyDialog::newCharDetails(const uint attribs[TOTAL_ATTRIBUTES], + bool allowedClasses[TOTAL_CLASSES], Race race, Sex sex, int classId, + int selectedClass, Common::String &msg) { + int foundClass = -1; + Common::String skillStr, classStr, raceSkillStr; + + // If a selected class is provided, set the default skill for that class + if (classId != -1 && NEW_CHAR_SKILLS[classId] != -1) { + const char *skillP = SKILL_NAMES[NEW_CHAR_SKILLS[classId]]; + skillStr = Common::String(skillP, skillP + NEW_CHAR_SKILLS_LEN[classId]); + } + + // If a class is provided, set the class name + if (classId != -1) { + classStr = Common::String::format("\t062\v168%s", CLASS_NAMES[classId]); + } + + // Set up default skill for the race, if any + if (NEW_CHAR_RACE_SKILLS[race] != -1) { + raceSkillStr = SKILL_NAMES[NEW_CHAR_RACE_SKILLS[race]]; + } + + // Set up color to use for each skill string to be displayed, based + // on whether each class is allowed or not for the given attributes + int classColors[TOTAL_CLASSES]; + Common::fill(&classColors[0], &classColors[TOTAL_CLASSES], 0); + for (int classNum = CLASS_KNIGHT; classNum <= CLASS_RANGER; ++classNum) { + if (allowedClasses[classNum]) { + if (classId == -1 && (foundClass == -1 || foundClass < classNum)) + foundClass = classNum; + classColors[classNum] = 4; + } + } + + // Return stats details and character class + msg = Common::String::format(NEW_CHAR_STATS, RACE_NAMES[race], SEX_NAMES[sex], + attribs[MIGHT], attribs[INTELLECT], attribs[PERSONALITY], + attribs[ENDURANCE], attribs[SPEED], attribs[ACCURACY], attribs[LUCK], + classColors[CLASS_KNIGHT], classColors[CLASS_PALADIN], + classColors[CLASS_ARCHER], classColors[CLASS_CLERIC], + classColors[CLASS_SORCERER], classColors[CLASS_ROBBER], + classColors[CLASS_NINJA], classColors[CLASS_BARBARIAN], + classColors[CLASS_DRUID], classColors[CLASS_RANGER], + skillStr.c_str(), raceSkillStr.c_str(), classStr.c_str() + ); + return classId == -1 ? foundClass : selectedClass; +} + +/** + * Print the selection arrow to indicate the selected class + */ +void PartyDialog::printSelectionArrow(SpriteResource &icons, int selectedClass) { + Window &w = _vm->_screen->_windows[0]; + icons.draw(w, 61, Common::Point(220, 19)); + icons.draw(w, 63, Common::Point(220, selectedClass * 11 + 21)); + w.update(); +} + +/** + * Print the dice animation + */ +void PartyDialog::drawDice(SpriteResource &dice) { + error("TODO: drawDice"); +} + } // End of namespace Xeen diff --git a/engines/xeen/dialogs_party.h b/engines/xeen/dialogs_party.h index 1510b76093..e9b06ae732 100644 --- a/engines/xeen/dialogs_party.h +++ b/engines/xeen/dialogs_party.h @@ -56,6 +56,18 @@ private: void createChar(); int selectCharacter(bool isDelete, int firstDisplayChar); + + void throwDice(uint attribs[TOTAL_ATTRIBUTES], bool allowedClasses[TOTAL_CLASSES]); + + void checkClass(const uint attribs[TOTAL_ATTRIBUTES], bool allowedClasses[TOTAL_CLASSES]); + + int newCharDetails(const uint attribs[TOTAL_ATTRIBUTES], + bool allowedClasses[TOTAL_CLASSES], Race race, Sex sex, int classId, + int selectedClass, Common::String &msg); + + void printSelectionArrow(SpriteResource &icons, int selectedClass); + + void drawDice(SpriteResource &dice); public: static void show(XeenEngine *vm); }; diff --git a/engines/xeen/resources.cpp b/engines/xeen/resources.cpp index 8f1475308d..b11db9ff82 100644 --- a/engines/xeen/resources.cpp +++ b/engines/xeen/resources.cpp @@ -1450,4 +1450,25 @@ const char *const HAS_SLAYER_SWORD = const char *const SURE_TO_DELETE_CHAR = "Are you sure you want to delete %s the %s?"; +const char *const CREATE_CHAR_DETAILS = + "\f04\x3""c\x2\t144\v119\f37R\f04oll\t144\v149\f37C\f04reate" + "\t144\v179\f37ESC\f04\x3l\x1\t195\v021\f37M\f04gt" + "\t195\v045\f37I\f04nt\t195\v069\f37P\f04er\t195\v093\f37E\f04nd" + "\t195\v116\f37S\f04pd\t195\v140\f37A\f04cy\t195\v164\f37L\f04ck%s"; + +const char *const NEW_CHAR_STATS = + "\f04\x3l\t022\v148Race\t055: %s\n" + "\t022Sex\t055: %s\n" + "\t022Class\t055:\n" + "\x3r\t215\v031%d\t215\v055%d\t215\v079%d\t215\v103%d\t215\v127%d" + "\t215\v151%d\t215\v175%d\x3l\t242\v020\f%2dKnight\t242\v031\f%2d" + "Paladin\t242\v042\f%2dArcher\t242\v053\f%2dCleric\t242\v064\f%2d" + "Sorcerer\t242\v075\f%2dRobber\t242\v086\f%2dNinja\t242\v097\f%2d" + "Barbarian\t242\v108\f%2dDruid\t242\v119\f%2dRanger\f04\x3""c" + "\t265\v142Skills\x3l\t223\v155%s\t223\v170%s%s"; + +const int NEW_CHAR_SKILLS[10] = { 1, 5, -1, -1, 4, 0, 0, -1, 6, 11 }; +const int NEW_CHAR_SKILLS_LEN[10] = { 11, 8, 0, 0, 12, 8, 8, 0, 9, 11 }; +const int NEW_CHAR_RACE_SKILLS[10] = { 14, -1, 17, 16, -1, 0, 0, 0, 0, 0 }; + } // End of namespace Xeen diff --git a/engines/xeen/resources.h b/engines/xeen/resources.h index 2ca9dbbfda..3c1ae9dbd0 100644 --- a/engines/xeen/resources.h +++ b/engines/xeen/resources.h @@ -504,6 +504,13 @@ extern const char *const YOUR_PARTY_IS_FULL; extern const char *const HAS_SLAYER_SWORD; extern const char *const SURE_TO_DELETE_CHAR; +extern const char *const CREATE_CHAR_DETAILS; + +extern const char *const NEW_CHAR_STATS; +extern const int NEW_CHAR_SKILLS[10]; +extern const int NEW_CHAR_SKILLS_LEN[10]; +extern const int NEW_CHAR_RACE_SKILLS[10]; + } // End of namespace Xeen #endif /* XEEN_RESOURCES_H */ |