From d225bc4cb3364b2cc8fc0fcab96347cc91e93866 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Fri, 13 Feb 2015 23:20:23 -0500 Subject: XEEN: Implemented saveCharacter --- engines/xeen/dialogs.cpp | 12 +- engines/xeen/dialogs_input.cpp | 9 + engines/xeen/dialogs_input.h | 3 + engines/xeen/dialogs_party.cpp | 417 +++++++++++++++++++++++++++++++++-------- engines/xeen/dialogs_party.h | 5 + engines/xeen/resources.cpp | 23 +++ engines/xeen/resources.h | 10 + engines/xeen/xeen.h | 3 +- 8 files changed, 401 insertions(+), 81 deletions(-) (limited to 'engines') diff --git a/engines/xeen/dialogs.cpp b/engines/xeen/dialogs.cpp index a2535fdf02..8bb0af0833 100644 --- a/engines/xeen/dialogs.cpp +++ b/engines/xeen/dialogs.cpp @@ -52,8 +52,6 @@ void ButtonContainer::addButton(const Common::Rect &bounds, int val, SpriteResou } void ButtonContainer::addPartyButtons(XeenEngine *vm) { - Party &party = *vm->_party; - for (uint idx = 0; idx < MAX_ACTIVE_PARTY; ++idx) { addButton(Common::Rect(CHAR_FACES_X[idx], 150, CHAR_FACES_X[idx] + 32, 182), Common::KEYCODE_F1 + idx, nullptr, false); @@ -80,7 +78,15 @@ bool ButtonContainer::checkEvents(XeenEngine *vm) { Common::KeyState keyState; events.getKey(keyState); - _buttonValue = keyState.keycode | (keyState.flags << 8); + _buttonValue = keyState.keycode; + if (_buttonValue == Common::KEYCODE_KP8) + _buttonValue = Common::KEYCODE_UP; + else if (_buttonValue == Common::KEYCODE_KP2) + _buttonValue = Common::KEYCODE_DOWN; + else if (_buttonValue == Common::KEYCODE_KP_ENTER) + _buttonValue = Common::KEYCODE_RETURN; + + _buttonValue |= (keyState.flags << 8); if (_buttonValue) return true; } diff --git a/engines/xeen/dialogs_input.cpp b/engines/xeen/dialogs_input.cpp index 1394379910..042fabf102 100644 --- a/engines/xeen/dialogs_input.cpp +++ b/engines/xeen/dialogs_input.cpp @@ -26,6 +26,15 @@ namespace Xeen { +int Input::show(XeenEngine *vm, Window *window, Common::String &line, + uint maxLen, int maxWidth, bool isNumeric) { + Input *dlg = new Input(vm, window); + int result = dlg->getString(line, maxLen, maxWidth, isNumeric); + delete dlg; + + return result; +} + /** * Allows the user to enter a string */ diff --git a/engines/xeen/dialogs_input.h b/engines/xeen/dialogs_input.h index c6d832ce6b..30e4cb2854 100644 --- a/engines/xeen/dialogs_input.h +++ b/engines/xeen/dialogs_input.h @@ -39,6 +39,9 @@ protected: int getString(Common::String &line, uint maxLen, int maxWidth, bool isNumeric); Input(XeenEngine *vm, Window *window) : _vm(vm), _window(window) {} +public: + static int show(XeenEngine *vm, Window *window, Common::String &line, + uint maxLen, int maxWidth, bool isNumeric = false); }; class StringInput : public Input { diff --git a/engines/xeen/dialogs_party.cpp b/engines/xeen/dialogs_party.cpp index ff59363ead..058ead4edc 100644 --- a/engines/xeen/dialogs_party.cpp +++ b/engines/xeen/dialogs_party.cpp @@ -23,6 +23,7 @@ #include "common/scummsys.h" #include "xeen/dialogs_char_info.h" #include "xeen/dialogs_party.h" +#include "xeen/dialogs_input.h" #include "xeen/dialogs_query.h" #include "xeen/character.h" #include "xeen/events.h" @@ -375,12 +376,22 @@ void PartyDialog::createChar() { EventsManager &events = *_vm->_events; Party &party = *_vm->_party; Screen &screen = *_vm->_screen; + Window &w = screen._windows[0]; SpriteResource dice, icons; - Mode oldMode = _vm->_mode; Common::Array freeCharList; + int classId; int selectedClass = 0; bool hasFadedIn = false; + bool restartFlag = true; + uint attribs[TOTAL_ATTRIBUTES]; + bool allowedClasses[TOTAL_CLASSES]; + Race race; + Sex sex; + Common::String msg; + int charIndex; + Mode oldMode = _vm->_mode; + _vm->_mode = MODE_4; dice.load("dice.vga"); icons.load("create.raw"); @@ -414,93 +425,261 @@ void PartyDialog::createChar() { 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; + classId = -1; + + if (restartFlag) { + // 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); + } + charIndex = 0; + //bool flag9 = true; - // 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)); + if (freeCharList.size() == XEEN_TOTAL_CHARACTERS) + break; + + // Get and race and sex for the given character + race = (Race)((freeCharList[charIndex] / 4) % 5); + sex = (Sex)(freeCharList[charIndex] & 1); + + // Randomly determine attributes, and which classes they allow + throwDice(attribs, allowedClasses); + + // Set up display of the rolled character details + selectedClass = newCharDetails(attribs, allowedClasses, + race, sex, classId, selectedClass, msg); + + // Draw the screen + 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; + } + + restartFlag = false; + } + + // Animate the dice until a user action occurs + _buttonValue = 0; + while (!_vm->shouldQuit() && !_buttonValue) + drawDice(dice); + + // Handling for different actions + switch (_buttonValue) { + case Common::KEYCODE_UP: + if (charIndex == 0) + continue; + + race = (Race)((freeCharList[charIndex] / 4) % 5); + sex = (Sex)(freeCharList[charIndex] & 1); + break; - 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)); + case Common::KEYCODE_DOWN: + if (++charIndex == (int)freeCharList.size()) { + --charIndex; + continue; + } else { + race = (Race)((freeCharList[charIndex] / 4) % 5); + sex = (Sex)(freeCharList[charIndex] & 1); + } + break; - w.writeString(msg); - w.update(); + case Common::KEYCODE_PAGEUP: + for (int tempClass = selectedClass - 1; tempClass >= 0; --tempClass) { + if (allowedClasses[tempClass]) { + selectedClass = tempClass; + break; + } + } - // Draw the arrow for the selected class, if applicable - if (selectedClass != -1) printSelectionArrow(icons, selectedClass); + continue; - // Draw the dice - drawDice(dice); - if (!hasFadedIn) { - screen.fadeIn(4); - hasFadedIn = true; + case Common::KEYCODE_PAGEDOWN: + break; + + case Common::KEYCODE_m: + case Common::KEYCODE_i: + case Common::KEYCODE_p: + case Common::KEYCODE_e: + case Common::KEYCODE_s: + case Common::KEYCODE_a: + case Common::KEYCODE_l: { + Attribute srcAttrib, destAttrib; + if (_buttonValue == Common::KEYCODE_m) + srcAttrib = MIGHT; + else if (_buttonValue == Common::KEYCODE_i) + srcAttrib = INTELLECT; + else if (_buttonValue == Common::KEYCODE_p) + srcAttrib = PERSONALITY; + else if (_buttonValue == Common::KEYCODE_e) + srcAttrib = ENDURANCE; + else if (_buttonValue == Common::KEYCODE_s) + srcAttrib = SPEED; + else if (_buttonValue == Common::KEYCODE_a) + srcAttrib = ACCURACY; + else + srcAttrib = LUCK; + + _vm->_mode = MODE_86; + icons.draw(w, srcAttrib * 2 + 11, Common::Point( + _buttons[srcAttrib + 5]._bounds.left, _buttons[srcAttrib + 5]._bounds.top)); + w.update(); + + int destAttribVal = exchangeAttribute(srcAttrib + 1); + if (destAttribVal) { + destAttrib = (Attribute)(destAttribVal - 1); + icons.draw(w, destAttrib * 2 + 11, Common::Point( + _buttons[destAttrib + 10]._bounds.left, + _buttons[destAttrib + 10]._bounds.top)); + w.update(); + + SWAP(attribs[srcAttrib], attribs[destAttrib]); + checkClass(attribs, allowedClasses); + classId = -1; + selectedClass = newCharDetails(attribs, allowedClasses, + race, sex, classId, selectedClass, msg); + } else { + icons.draw(w, srcAttrib * 2 + 10, Common::Point( + _buttons[srcAttrib + 5]._bounds.left, + _buttons[srcAttrib + 5]._bounds.top)); + w.update(); + _vm->_mode = MODE_SLEEPING; + continue; + } + break; } - // Key handling loop - while (!_vm->shouldQuit()) { - // Animate the dice until a user action occurs - _buttonValue = 0; - while (!_vm->shouldQuit() && !_buttonValue) - drawDice(dice); + case 1000: + case 1001: + case 1002: + case 1003: + case 1004: + case 1005: + case 1006: + case 1007: + case 1008: + case 1009: + if (allowedClasses[_buttonValue - 1000]) { + selectedClass = classId = _buttonValue - 1000; + } + break; + + case Common::KEYCODE_c: { + _vm->_mode = MODE_FF; + bool result = saveCharacter(party._roster[freeCharList[charIndex]], + (CharacterClass)classId, race, sex, attribs); + _vm->_mode = MODE_4; - // TODO + if (result) + restartFlag = true; + continue; } - - // TODO: More - error("TODO: createChar"); - } + case Common::KEYCODE_RETURN: + classId = selectedClass; + break; + + case Common::KEYCODE_SPACE: + case Common::KEYCODE_r: + // Re-roll the attributes + throwDice(attribs, allowedClasses); + classId = -1; + break; + + default: + // For all other keypresses, skip the code below the switch + // statement, and go to wait for the next key + continue; + } + + if (_buttonValue != Common::KEYCODE_PAGEDOWN) { + selectedClass = newCharDetails(attribs, allowedClasses, + race, sex, classId, selectedClass, msg); + + for (int idx = 0; idx < 7; ++idx) + icons.draw(w, 10 + idx * 2, Common::Point(168, 19 + idx * 24)); + for (int idx = 0; idx < 10; ++idx) + icons.draw(w, 24 + idx * 2, Common::Point(227, 19 + idx * 11)); + for (int idx = 0; idx < 8; ++idx) + icons.draw(w, 50 + idx, Common::Point(195, 31 + idx * 24)); + + 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(); + + if (selectedClass != -1) { + printSelectionArrow(icons, selectedClass); + continue; + } + } + + // Move to next available class, or if the code block above resulted in + // selectedClass being -1, move to select the first available class + for (int tempClass = selectedClass + 1; tempClass <= CLASS_RANGER; ++tempClass) { + if (allowedClasses[tempClass]) { + selectedClass = tempClass; + break; + } + } + + printSelectionArrow(icons, selectedClass); + } while (!_vm->shouldQuit() && _buttonValue != Common::KEYCODE_ESCAPE); + _vm->_mode = oldMode; } @@ -691,4 +870,88 @@ void PartyDialog::drawDice(SpriteResource &dice) { error("TODO: drawDice"); } +/** + * Exchanging two attributes for the character being rolled + */ +int PartyDialog::exchangeAttribute(int srcAttr) { + error("TODO: exchangeAttribute"); +} + +bool PartyDialog::saveCharacter(Character &c, CharacterClass classId, + Race race, Sex sex, uint attribs[TOTAL_ATTRIBUTES]) { + if (classId == -1) { + ErrorScroll::show(_vm, SELECT_CLASS_BEFORE_SAVING); + return false; + } + + Map &map = *_vm->_map; + Party &party = *_vm->_party; + Screen &screen = *_vm->_screen; + Window &w = screen._windows[6]; + Common::String name; + int result; + bool isDarkCc = _vm->_files->_isDarkCc; + + saveButtons(); + w.writeString(NAME_FOR_NEW_CHARACTER); + + result = Input::show(_vm, &w, name, 10, 200); + w.close(); + restoreButtons(); + if (!result) + return false; + + // Save new character details + c.clear(); + c._name = name; + c._savedMazeId = party._priorMazeId; + c._xeenSide = map._loadDarkSide; + c._sex = sex; + c._race = race; + c._class = classId; + c._level._permanent = isDarkCc ? 5 : 1; + + c._might._permanent = attribs[MIGHT]; + c._intellect._permanent = attribs[INTELLECT]; + c._personality._permanent = attribs[PERSONALITY]; + c._endurance._permanent = attribs[ENDURANCE]; + c._speed._permanent = attribs[SPEED]; + c._accuracy._permanent = attribs[ACCURACY]; + c._luck._permanent = attribs[LUCK]; + + c._magicResistence._permanent = RACE_MAGIC_RESISTENCES[race]; + c._fireResistence._permanent = RACE_FIRE_RESISTENCES[race]; + c._electricityResistence._permanent = RACE_ELECTRIC_RESISTENCES[race]; + c._coldResistence._permanent = RACE_COLD_RESISTENCES[race]; + c._energyResistence._permanent = RACE_ENERGY_RESISTENCES[race]; + c._poisonResistence._permanent = RACE_POISON_RESISTENCES[race]; + + c._birthYear = party._year - 18; + c._birthDay = party._day; + c._hasSpells = false; + c._currentSpell = -1; + + // Set up any default spells for the character's class + for (int idx = 0; idx < 4; ++idx) { + if (NEW_CHARACTER_SPELLS[c._class][idx] != -1) { + c._hasSpells = true; + c._currentSpell = NEW_CHARACTER_SPELLS[c._class][idx]; + c._spells[c._currentSpell] = 1; + } + } + + int classSkill = NEW_CHAR_SKILLS[c._class]; + if (classSkill != -1) + c._skills[classSkill] = 1; + + int raceSkill = NEW_CHAR_RACE_SKILLS[c._race]; + if (raceSkill != -1) + c._skills[raceSkill] = 1; + + c._currentHp = c.getMaxHP(); + c._currentSp = c.getMaxSP(); + return true; +} + + } // End of namespace Xeen diff --git a/engines/xeen/dialogs_party.h b/engines/xeen/dialogs_party.h index e9b06ae732..178a5c4991 100644 --- a/engines/xeen/dialogs_party.h +++ b/engines/xeen/dialogs_party.h @@ -68,6 +68,11 @@ private: void printSelectionArrow(SpriteResource &icons, int selectedClass); void drawDice(SpriteResource &dice); + + int exchangeAttribute(int srcAttr); + + bool saveCharacter(Character &c, CharacterClass classId, Race race, + Sex sex, uint attribs[TOTAL_ATTRIBUTES]); public: static void show(XeenEngine *vm); }; diff --git a/engines/xeen/resources.cpp b/engines/xeen/resources.cpp index b11db9ff82..c9c377d3a6 100644 --- a/engines/xeen/resources.cpp +++ b/engines/xeen/resources.cpp @@ -1467,8 +1467,31 @@ const char *const NEW_CHAR_STATS = "Barbarian\t242\v108\f%2dDruid\t242\v119\f%2dRanger\f04\x3""c" "\t265\v142Skills\x3l\t223\v155%s\t223\v170%s%s"; +const char *const NAME_FOR_NEW_CHARACTER = + "\x3""cEnter a Name for this Character"; +const char *const SELECT_CLASS_BEFORE_SAVING = + "\v006\x3""cSelect a Class before saving.\x3l"; 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 }; +const int RACE_MAGIC_RESISTENCES[5] = { 7, 5, 20, 0, 0 }; +const int RACE_FIRE_RESISTENCES[5] = { 7, 0, 2, 5, 10 }; +const int RACE_ELECTRIC_RESISTENCES[5] = { 7, 0, 2, 5, 10 }; +const int RACE_COLD_RESISTENCES[5] = { 7, 0, 2, 5, 10 }; +const int RACE_ENERGY_RESISTENCES[5] = { 7, 5, 2, 5, 0 }; +const int RACE_POISON_RESISTENCES[5] = { 7, 0, 2, 20, 0 }; +const int NEW_CHARACTER_SPELLS[10][4] = { + { -1, -1, -1, -1 }, + { 21, -1, -1, -1 }, + { 22, -1, -1, -1 }, + { 21, 1, 14, -1 }, + { 22, 0, 25, -1 }, + { -1, -1, -1, -1 }, + { -1, -1, -1, -1 }, + { -1, -1, -1, -1 }, + { 20, 1, 11, 23 }, + { 20, 1, -1, -1 } +}; + } // End of namespace Xeen diff --git a/engines/xeen/resources.h b/engines/xeen/resources.h index 3c1ae9dbd0..3c6df78a8f 100644 --- a/engines/xeen/resources.h +++ b/engines/xeen/resources.h @@ -507,10 +507,20 @@ extern const char *const SURE_TO_DELETE_CHAR; extern const char *const CREATE_CHAR_DETAILS; extern const char *const NEW_CHAR_STATS; +extern const char *const NAME_FOR_NEW_CHARACTER; +extern const char *const SELECT_CLASS_BEFORE_SAVING; extern const int NEW_CHAR_SKILLS[10]; extern const int NEW_CHAR_SKILLS_LEN[10]; extern const int NEW_CHAR_RACE_SKILLS[10]; +extern const int RACE_MAGIC_RESISTENCES[5]; +extern const int RACE_FIRE_RESISTENCES[5]; +extern const int RACE_ELECTRIC_RESISTENCES[5]; +extern const int RACE_COLD_RESISTENCES[5]; +extern const int RACE_ENERGY_RESISTENCES[5]; +extern const int RACE_POISON_RESISTENCES[5]; +extern const int NEW_CHARACTER_SPELLS[10][4]; + } // End of namespace Xeen #endif /* XEEN_RESOURCES_H */ diff --git a/engines/xeen/xeen.h b/engines/xeen/xeen.h index c4f826d508..2d85335ced 100644 --- a/engines/xeen/xeen.h +++ b/engines/xeen/xeen.h @@ -88,7 +88,8 @@ enum Mode { MODE_9 = 9, MODE_CHARACTER_INFO = 10, MODE_12 = 12, - MODE_17 = 17 + MODE_17 = 17, + MODE_86 = 86 }; struct XeenGameDescription; -- cgit v1.2.3