aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Gilbert2015-02-12 23:16:20 -0500
committerPaul Gilbert2015-02-12 23:16:20 -0500
commite16ecd110b2f607621773e13df8f972c9c7e979a (patch)
treed4359937e6b4af113552305dd3756efef1b558b9
parent2772cd33c1f62d0e0ea41507f6b809704d569254 (diff)
downloadscummvm-rg350-e16ecd110b2f607621773e13df8f972c9c7e979a.tar.gz
scummvm-rg350-e16ecd110b2f607621773e13df8f972c9c7e979a.tar.bz2
scummvm-rg350-e16ecd110b2f607621773e13df8f972c9c7e979a.zip
XEEN: Implementing create chracter dialog
-rw-r--r--engines/xeen/character.h4
-rw-r--r--engines/xeen/dialogs_party.cpp246
-rw-r--r--engines/xeen/dialogs_party.h12
-rw-r--r--engines/xeen/resources.cpp21
-rw-r--r--engines/xeen/resources.h7
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 */