/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "mm/xeen/dialogs/dialogs_awards.h" #include "mm/xeen/dialogs/dialogs_char_info.h" #include "mm/xeen/dialogs/dialogs_exchange.h" #include "mm/xeen/dialogs/dialogs_items.h" #include "mm/xeen/dialogs/dialogs_quick_ref.h" #include "mm/xeen/resources.h" #include "mm/xeen/xeen.h" namespace MM { namespace Xeen { #ifdef USE_TTS static const uint8 kCharacterInfoInformationCount = 20; static const uint8 kCharacterInfoSideButtonCount = 4; static const uint8 kCharacterInfoPartyGoldIndex = 7; static const uint8 kCharacterInfoRowCount = 5; static const uint8 kCharacterInfoColumnCount = 4; #endif enum CharacterInfoButtonTTSTextIndex { kCharacterInfoItem = 0, kCharacterInfoQuickRef = 1, kCharacterInfoExchange = 2, kCharacterInfoExit = 3, kCharacterInfoMight = 4, kCharacterInfoAccuracy = 5, kCharacterInfoHP = 6, kCharacterInfoExperience = 7, kCharacterInfoIntellect = 8, kCharacterInfoLuck = 9, kCharacterInfoSP = 10, kCharacterInfoPartyGold = 11, kCharacterInfoPersonality = 12, kCharacterInfoAge = 13, kCharacterInfoResistances = 14, kCharacterInfoPartyGems = 15, kCharacterInfoEndurance = 16, kCharacterInfoLevel = 17, kCharacterInfoSkills = 18, kCharacterInfoPartyFood = 19, kCharacterInfoSpeed = 20, kCharacterInfoAC = 21, kCharacterInfoAwards = 22, kCharacterInfoCondition = 23 }; void CharacterInfo::show(XeenEngine *vm, int charIndex) { CharacterInfo *dlg = new CharacterInfo(vm); dlg->execute(charIndex); delete dlg; } void CharacterInfo::execute(int charIndex) { Combat &combat = *_vm->_combat; EventsManager &events = *_vm->_events; Interface &intf = *_vm->_interface; Party &party = *_vm->_party; Windows &windows = *_vm->_windows; bool redrawFlag = true; Mode oldMode = _vm->_mode; _vm->_mode = MODE_CHARACTER_INFO; loadDrawStructs(); addButtons(); Character *c = (oldMode != MODE_COMBAT) ? &party._activeParty[charIndex] : combat._combatParty[charIndex]; intf.highlightChar(charIndex); Window &w = windows[24]; w.open(); do { if (redrawFlag) { Common::String charDetails = loadCharacterDetails(*c); Common::String ttsMessage; w.writeString(Common::String::format(Res.CHARACTER_TEMPLATE, charDetails.c_str()), false, &ttsMessage); #ifdef USE_TTS speakText(ttsMessage); #endif w.drawList(_drawList, 24); w.update(); redrawFlag = false; } // Wait for keypress, showing a blinking cursor events.updateGameCounter(); bool cursorFlag = false; _buttonValue = 0; while (!_vm->shouldExit() && !_buttonValue) { events.pollEventsAndWait(); if (events.timeElapsed() > 4) { cursorFlag = !cursorFlag; events.updateGameCounter(); } showCursor(cursorFlag); w.update(); checkEvents(_vm); } events.clearEvents(); if (Common::KEYCODE_F1 == _buttonValue || Common::KEYCODE_F2 == _buttonValue || Common::KEYCODE_F3 == _buttonValue || Common::KEYCODE_F4 == _buttonValue || Common::KEYCODE_F5 == _buttonValue || Common::KEYCODE_F6 == _buttonValue) { _buttonValue -= Common::KEYCODE_F1; if (_buttonValue < (int)(oldMode == MODE_COMBAT ? combat._combatParty.size() : party._activeParty.size())) { charIndex = _buttonValue; c = (oldMode != MODE_COMBAT) ? &party._activeParty[charIndex] : combat._combatParty[charIndex]; intf.highlightChar(_buttonValue); redrawFlag = true; } else { _vm->_mode = MODE_CHARACTER_INFO; } } else if (Common::KEYCODE_UP == _buttonValue || Common::KEYCODE_KP8 == _buttonValue) { if (_cursorCell > 0) { showCursor(false); --_cursorCell; showCursor(true); #ifdef USE_TTS _vm->sayText(_buttonTexts[_buttons[_cursorCell]._ttsIndex], Common::TextToSpeechManager::INTERRUPT); #endif } w.update(); } else if (Common::KEYCODE_DOWN == _buttonValue || Common::KEYCODE_KP2 == _buttonValue) { if (_cursorCell < 20) { showCursor(false); ++_cursorCell; showCursor(true); #ifdef USE_TTS _vm->sayText(_buttonTexts[_buttons[_cursorCell]._ttsIndex], Common::TextToSpeechManager::INTERRUPT); #endif } w.update(); } else if (Common::KEYCODE_LEFT == _buttonValue || Common::KEYCODE_KP4 == _buttonValue) { if (_cursorCell >= 5) { showCursor(false); _cursorCell -= 5; showCursor(true); #ifdef USE_TTS _vm->sayText(_buttonTexts[_buttons[_cursorCell]._ttsIndex], Common::TextToSpeechManager::INTERRUPT); #endif } w.update(); } else if (Common::KEYCODE_RIGHT == _buttonValue || Common::KEYCODE_KP6 == _buttonValue) { if (_cursorCell <= 15) { showCursor(false); _cursorCell += 5; showCursor(true); #ifdef USE_TTS _vm->sayText(_buttonTexts[_buttons[_cursorCell]._ttsIndex], Common::TextToSpeechManager::INTERRUPT); #endif } w.update(); } else if (1001 == _buttonValue || 1002 == _buttonValue || 1003 == _buttonValue || 1004 == _buttonValue || 1005 == _buttonValue || 1006 == _buttonValue || 1007 == _buttonValue || 1008 == _buttonValue || 1009 == _buttonValue || 1010 == _buttonValue || 1011 == _buttonValue || 1012 == _buttonValue || 1013 == _buttonValue || 1014 == _buttonValue || 1015 == _buttonValue || 1016 == _buttonValue || 1017 == _buttonValue || 1018 == _buttonValue || 1019 == _buttonValue || 1020 == _buttonValue) { showCursor(false); _cursorCell = _buttonValue - 1001; showCursor(true); w.update(); bool result = expandStat(_cursorCell, *c); _vm->_mode = MODE_COMBAT; if (result) redrawFlag = true; } else if (Common::KEYCODE_RETURN == _buttonValue || Common::KEYCODE_KP_ENTER == _buttonValue) { bool result = expandStat(_cursorCell, *c); _vm->_mode = MODE_COMBAT; if (result) redrawFlag = true; } else if (Res.KeyConstants.DialogsCharInfo.KEY_EXCHANGE == _buttonValue) { if (oldMode == MODE_COMBAT) { ErrorScroll::show(_vm, Res.EXCHANGING_IN_COMBAT, WT_FREEZE_WAIT); } else { _vm->_mode = oldMode; ExchangeDialog::show(_vm, c, charIndex); _vm->_mode = MODE_CHARACTER_INFO; redrawFlag = true; } } else if (Res.KeyConstants.DialogsCharInfo.KEY_ITEM == _buttonValue) { _vm->_mode = oldMode; _vm->_combat->_itemFlag = _vm->_mode == MODE_COMBAT; c = ItemsDialog::show(_vm, c, ITEMMODE_CHAR_INFO); if (!c) { party._stepped = true; goto exit; } _vm->_mode = MODE_CHARACTER_INFO; redrawFlag = true; } else if (Res.KeyConstants.DialogsCharInfo.KEY_QUICK == _buttonValue) { QuickReferenceDialog::show(_vm); redrawFlag = true; } else if (Common::KEYCODE_ESCAPE == _buttonValue) { goto exit; } } while (!_vm->shouldExit()); exit: w.close(); intf.unhighlightChar(); _vm->_mode = oldMode; _vm->_combat->_itemFlag = false; } void CharacterInfo::loadDrawStructs() { _drawList[0] = DrawStruct(0, 2, 16); _drawList[1] = DrawStruct(2, 2, 39); _drawList[2] = DrawStruct(4, 2, 62); _drawList[3] = DrawStruct(6, 2, 85); _drawList[4] = DrawStruct(8, 2, 108); _drawList[5] = DrawStruct(10, 53, 16); _drawList[6] = DrawStruct(12, 53, 39); _drawList[7] = DrawStruct(14, 53, 62); _drawList[8] = DrawStruct(16, 53, 85); _drawList[9] = DrawStruct(18, 53, 108); _drawList[10] = DrawStruct(20, 104, 16); _drawList[11] = DrawStruct(22, 104, 39); _drawList[12] = DrawStruct(24, 104, 62); _drawList[13] = DrawStruct(26, 104, 85); _drawList[14] = DrawStruct(28, 104, 108); _drawList[15] = DrawStruct(30, 169, 16); _drawList[16] = DrawStruct(32, 169, 39); _drawList[17] = DrawStruct(34, 169, 62); _drawList[18] = DrawStruct(36, 169, 85); _drawList[19] = DrawStruct(38, 169, 108); _drawList[20] = DrawStruct(40, 277, 3); _drawList[21] = DrawStruct(42, 277, 35); _drawList[22] = DrawStruct(44, 277, 67); _drawList[23] = DrawStruct(46, 277, 99); _iconSprites.load("view.icn"); for (int idx = 0; idx < 24; ++idx) _drawList[idx]._sprites = &_iconSprites; } void CharacterInfo::addButtons() { addButton(Common::Rect(10, 24, 34, 44), 1001, &_iconSprites, kCharacterInfoMight); addButton(Common::Rect(10, 47, 34, 67), 1002, &_iconSprites, kCharacterInfoIntellect); addButton(Common::Rect(10, 70, 34, 90), 1003, &_iconSprites, kCharacterInfoPersonality); addButton(Common::Rect(10, 93, 34, 113), 1004, &_iconSprites, kCharacterInfoEndurance); addButton(Common::Rect(10, 116, 34, 136), 1005, &_iconSprites, kCharacterInfoSpeed); addButton(Common::Rect(61, 24, 85, 44), 1006, &_iconSprites, kCharacterInfoAccuracy); addButton(Common::Rect(61, 47, 85, 67), 1007, &_iconSprites, kCharacterInfoLuck); addButton(Common::Rect(61, 70, 85, 90), 1008, &_iconSprites, kCharacterInfoAge); addButton(Common::Rect(61, 93, 85, 113), 1009, &_iconSprites, kCharacterInfoLevel); addButton(Common::Rect(61, 116, 85, 136), 1010, &_iconSprites, kCharacterInfoAC); addButton(Common::Rect(112, 24, 136, 44), 1011, &_iconSprites, kCharacterInfoHP); addButton(Common::Rect(112, 47, 136, 67), 1012, &_iconSprites, kCharacterInfoSP); addButton(Common::Rect(112, 70, 136, 90), 1013, &_iconSprites, kCharacterInfoResistances); addButton(Common::Rect(112, 93, 136, 113), 1014, &_iconSprites, kCharacterInfoSkills); addButton(Common::Rect(112, 116, 136, 136), 1015, &_iconSprites, kCharacterInfoAwards); addButton(Common::Rect(177, 24, 201, 44), 1016, &_iconSprites, kCharacterInfoExperience); addButton(Common::Rect(177, 47, 201, 67), 1017, &_iconSprites, kCharacterInfoPartyGold); addButton(Common::Rect(177, 70, 201, 90), 1018, &_iconSprites, kCharacterInfoPartyGems); addButton(Common::Rect(177, 93, 201, 113), 1019, &_iconSprites, kCharacterInfoPartyFood); addButton(Common::Rect(177, 116, 201, 136), 1020, &_iconSprites, kCharacterInfoCondition); addButton(Common::Rect(285, 11, 309, 31), Res.KeyConstants.DialogsCharInfo.KEY_ITEM, &_iconSprites, kCharacterInfoItem); addButton(Common::Rect(285, 43, 309, 63), Res.KeyConstants.DialogsCharInfo.KEY_QUICK, &_iconSprites, kCharacterInfoQuickRef); addButton(Common::Rect(285, 75, 309, 95), Res.KeyConstants.DialogsCharInfo.KEY_EXCHANGE, &_iconSprites, kCharacterInfoExchange); addButton(Common::Rect(285, 107, 309, 127), Common::KEYCODE_ESCAPE, &_iconSprites, kCharacterInfoExit); addPartyButtons(_vm); } const char *CharacterInfo::getDaysPlurals(int val) { if (Common::RU_RUS == g_vm->getLanguage()) { int i = val % 100; if (i < 5 || i > 20) switch (val % 10) { case 1: return Res.DAYS[0]; case 2: case 3: case 4: return Res.DAYS[1]; } return Res.DAYS[2]; } else { return Res.DAYS[val == 1 ? 0 : 1]; } } Common::String CharacterInfo::loadCharacterDetails(const Character &c) { Condition condition = c.worstCondition(); Party &party = *_vm->_party; int foodVal = party._food / party._activeParty.size() / 3; int totalResist = c._fireResistance._permanent + c.itemScan(11) + c._fireResistance._temporary + c._coldResistance._permanent + c.itemScan(13) + c._coldResistance._temporary + c._electricityResistance._permanent + c.itemScan(12) + c._electricityResistance._temporary + c._poisonResistance._permanent + c.itemScan(14) + c._poisonResistance._temporary + c._energyResistance._permanent + c.itemScan(15) + c._energyResistance._temporary + c._magicResistance._permanent + c.itemScan(16) + c._magicResistance._temporary; const char **_tmpConditions = c._sex == FEMALE ? (const char **)Res.CONDITION_NAMES_F : (const char **)Res.CONDITION_NAMES_M; return Common::String::format(Res.CHARACTER_DETAILS, Res.PARTY_GOLD, c._name.c_str(), Res.SEX_NAMES[c._sex], Res.RACE_NAMES[c._race], Res.CLASS_NAMES[c._class], c.statColor(c.getStat(MIGHT), c.getStat(MIGHT, true)), c.getStat(MIGHT), c.statColor(c.getStat(ACCURACY), c.getStat(ACCURACY, true)), c.getStat(ACCURACY), c.statColor(c._currentHp, c.getMaxHP()), c._currentHp, c.getCurrentExperience(), c.statColor(c.getStat(INTELLECT), c.getStat(INTELLECT, true)), c.getStat(INTELLECT), c.statColor(c.getStat(LUCK), c.getStat(LUCK, true)), c.getStat(LUCK), c.statColor(c._currentSp, c.getMaxSP()), c._currentSp, party._gold, c.statColor(c.getStat(PERSONALITY), c.getStat(PERSONALITY, true)), c.getStat(PERSONALITY), c.statColor(c.getAge(), c.getAge(true)), c.getAge(), totalResist, party._gems, c.statColor(c.getStat(ENDURANCE), c.getStat(ENDURANCE, true)), c.getStat(ENDURANCE), c.statColor(c.getCurrentLevel(), c._level._permanent), c.getCurrentLevel(), c.getNumSkills(), foodVal, getDaysPlurals(foodVal), c.statColor(c.getStat(SPEED), c.getStat(SPEED, true)), c.getStat(SPEED), c.statColor(c.getArmorClass(), c.getArmorClass(true)), c.getArmorClass(), c.getNumAwards(), Res.CONDITION_COLORS[condition], _tmpConditions[condition], condition == NO_CONDITION && party._blessed ? Res.PLUS_14 : "", condition == NO_CONDITION && party._powerShield ? Res.PLUS_14 : "", condition == NO_CONDITION && party._holyBonus ? Res.PLUS_14 : "", condition == NO_CONDITION && party._heroism ? Res.PLUS_14 : ""); } void CharacterInfo::showCursor(bool flag) { const int CURSOR_X[5] = { 9, 60, 111, 176, 0 }; const int CURSOR_Y[5] = { 23, 46, 69, 92, 115 }; if (_cursorCell < 20) { _iconSprites.draw(0, flag ? 49 : 48, Common::Point(CURSOR_X[_cursorCell / 5], CURSOR_Y[_cursorCell % 5])); } } const char *CharacterInfo::getBornForm(const Character &c) { if (Common::RU_RUS == g_vm->getLanguage()) { switch (c._sex) { case MALE: return Res.BORN[0]; case FEMALE: return Res.BORN[1]; case YES_PLEASE: break; } } return Res.BORN[0]; } const char *CharacterInfo::getFoodOnHandPlurals(int food) { if (Common::RU_RUS == g_vm->getLanguage()) { int i = food % 100; if (i < 5 || i > 20) switch (food % 10) { case 1: return Res.FOOD_ON_HAND[0]; case 2: case 3: case 4: return Res.FOOD_ON_HAND[1]; } return Res.FOOD_ON_HAND[2]; } return Res.FOOD_ON_HAND[0]; } #ifdef USE_TTS void CharacterInfo::speakText(const Common::String &text) { uint index = 0; uint statNameIndex = 0; // Get the header for each piece of information Common::String informationHeaders[kCharacterInfoInformationCount]; for (uint i = 0; i < kCharacterInfoInformationCount; ++i) { if (i != kCharacterInfoPartyGoldIndex) { // Items in the rightmost column already have their full names, not abbreviations if ((i + 1) % kCharacterInfoColumnCount != 0) { // Replace abbreviations with their full versions informationHeaders[i] = Res.STAT_NAMES[statNameIndex]; getNextTextSection(text, index); } else { informationHeaders[i] = getNextTextSection(text, index); } } // The text is displayed in order from left to right, while the stat names in the STAT_NAMES array are ordered // from top to bottom. Therefore, we need to set the stat name index to correspond to the STAT_NAMES array statNameIndex += kCharacterInfoRowCount; if (statNameIndex >= kCharacterInfoInformationCount) { statNameIndex -= kCharacterInfoInformationCount - 1; } } // Get the text for the side buttons Common::String sideButtonsText = addNextTextToButtons(text, index, kCharacterInfoSideButtonCount); // Party gold label (but not the value) sorts out of order and not with the rest of the information, // so we need to move it to its correct place informationHeaders[kCharacterInfoPartyGoldIndex] = getNextTextSection(text, index); // Character name _vm->sayText(getNextTextSection(text, index), Common::TextToSpeechManager::INTERRUPT); // Each attribute for (uint i = 0; i < kCharacterInfoInformationCount; ++i) { Common::String buttonText = informationHeaders[i] + ": " + getNextTextSection(text, index); _vm->sayText(buttonText); _buttonTexts.push_back(buttonText); } _vm->sayText(sideButtonsText); } #endif bool CharacterInfo::expandStat(int attrib, const Character &c) { const int STAT_POS[2][20] = { { 61, 61, 61, 61, 61, 112, 112, 112, 112, 112, 177, 177, 177, 177, 177, 34, 34, 34, 34, 34 }, { 24, 47, 70, 93, 116, 24, 47, 70, 93, 116, 24, 47, 70, 93, 116, 24, 47, 70, 93, 116 } }; assert(attrib < 20); Common::Rect bounds(STAT_POS[0][attrib], STAT_POS[1][attrib], STAT_POS[0][attrib] + 143, STAT_POS[1][attrib] + 52); Party &party = *_vm->_party; Windows &windows = *_vm->_windows; uint stat1, stat2; uint idx; Common::String msg; switch (attrib) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: // Basic attributes stat1 = c.getStat((Attribute)attrib, false); stat2 = c.getStat((Attribute)attrib, true); for (idx = 0; idx < ARRAYSIZE(Res.STAT_VALUES) - 1; ++idx) if (Res.STAT_VALUES[idx] > (int)stat1) break; msg = Common::String::format(Res.CURRENT_MAXIMUM_RATING_TEXT, Res.STAT_NAMES[attrib], stat1, stat2, Res.RATING_TEXT[idx]); break; case 7: // Age stat1 = c.getAge(false); stat2 = c.getAge(true); msg = Common::String::format(Res.AGE_TEXT, Res.STAT_NAMES[attrib], stat1, stat2, getBornForm(c), c._birthDay, c._birthYear); break; case 8: { // Level const int CLASS_ATTACK_GAINS[10] = { 5, 6, 6, 7, 8, 6, 5, 4, 7, 6 }; idx = c.getCurrentLevel() / CLASS_ATTACK_GAINS[c._class] + 1; msg = Common::String::format(Res.LEVEL_TEXT, Res.STAT_NAMES[attrib], c.getCurrentLevel(), c._level._permanent, idx, idx > 1 ? "s" : "", c._level._permanent); break; } case 9: // Armor Class stat1 = c.getArmorClass(false); stat2 = c.getArmorClass(true); msg = Common::String::format(Res.CURRENT_MAXIMUM_TEXT, Res.STAT_NAMES[attrib], stat1, stat2); bounds.setHeight(42); break; case 10: { // Hit Points Common::String fmt(Res.CURRENT_MAXIMUM_TEXT); const char *p; while ((p = strstr(fmt.c_str(), "%u")) != nullptr) fmt.setChar('d', p - fmt.c_str() + 1); msg = Common::String::format(fmt.c_str(), Res.STAT_NAMES[attrib], c._currentHp, c.getMaxHP()); bounds.setHeight(42); break; } case 11: // Spell Points stat1 = c._currentSp; stat2 = c.getMaxSP(); msg = Common::String::format(Res.CURRENT_MAXIMUM_TEXT, Res.STAT_NAMES[attrib], stat1, stat2); bounds.setHeight(42); break; case 12: // Resistances msg = Common::String::format(Res.RESISTANCES_TEXT, Res.STAT_NAMES[attrib], c._fireResistance._permanent + c.itemScan(11) + c._fireResistance._temporary, c._coldResistance._permanent + c.itemScan(13) + c._coldResistance._temporary, c._electricityResistance._permanent + c.itemScan(12) + c._electricityResistance._temporary, c._poisonResistance._permanent + c.itemScan(14) + c._poisonResistance._temporary, c._energyResistance._permanent + c.itemScan(15) + c._energyResistance._temporary, c._magicResistance._permanent + c.itemScan(16) + c._magicResistance._temporary); bounds.setHeight(80); break; case 13: { // Skills Common::String lines[20]; int numLines = c.getNumSkills(); if (numLines > 0) { for (int skill = THIEVERY; skill <= DANGER_SENSE; ++skill) { if (c._skills[skill]) { if (skill == THIEVERY) { lines[0] = Common::String::format("\n\t020%s%u", Res.SKILL_NAMES[THIEVERY], c.getThievery()); } else { lines[skill] = Common::String::format("\n\t020%s", Res.SKILL_NAMES[skill]); } } } } else { lines[0] = Res.NONE; numLines = 1; } msg = Common::String::format("\x2\x3""c%s\x3l%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", Res.STAT_NAMES[attrib], lines[0].c_str(), lines[1].c_str(), lines[2].c_str(), lines[3].c_str(), lines[4].c_str(), lines[5].c_str(), lines[17].c_str(), lines[6].c_str(), lines[7].c_str(), lines[8].c_str(), lines[9].c_str(), lines[10].c_str(), lines[11].c_str(), lines[12].c_str(), lines[13].c_str(), lines[16].c_str(), lines[14].c_str(), lines[15].c_str()); bounds.top -= (numLines / 2) * 8; bounds.setHeight(numLines * 9 + 26); if (bounds.bottom >= SCREEN_HEIGHT) bounds.moveTo(bounds.left, SCREEN_HEIGHT - bounds.height() - 1); break; } case 14: // Awards Awards::show(_vm, &c); return false; case 15: // Experience stat1 = c.getCurrentExperience(); stat2 = c.experienceToNextLevel(); msg = Common::String::format(Res.EXPERIENCE_TEXT, Res.STAT_NAMES[attrib], stat1, stat2 == 0 ? Res.ELIGIBLE : Common::String::format("%d", stat2).c_str() ); bounds.setHeight(43); break; case 16: // Gold msg = Common::String::format(Res.IN_PARTY_IN_BANK, Res.CONSUMABLE_NAMES[0], party._gold, party._bankGold); bounds.setHeight(43); break; case 17: // Gems msg = Common::String::format(Res.IN_PARTY_IN_BANK, Res.CONSUMABLE_NAMES[1], party._gems, party._bankGems); bounds.setHeight(43); break; case 18: { // Food int food = (party._food / party._activeParty.size()) / 3; msg = Common::String::format(Res.FOOD_TEXT, Res.CONSUMABLE_NAMES[2], party._food, getFoodOnHandPlurals(food), food, getDaysPlurals(food)); break; } case 19: { // Conditions Common::String lines[20]; const char **_tmpConditions = c._sex == FEMALE ? (const char **)Res.CONDITION_NAMES_F : (const char **)Res.CONDITION_NAMES_M; int total = 0; for (int condition = CURSED; condition <= ERADICATED; ++condition) { if (c._conditions[condition]) { if (condition >= UNCONSCIOUS) { lines[condition] = Common::String::format("\n\t020%s", _tmpConditions[condition]); } else { lines[condition] = Common::String::format("\n\t020%s\t095-%d", _tmpConditions[condition], c._conditions[condition]); } ++total; } } Condition condition = c.worstCondition(); if (condition == NO_CONDITION) { lines[0] = Common::String::format("\n\t020%s", Res.GOOD); ++total; } if (party._blessed) { lines[16] = Common::String::format(Res.BLESSED, party._blessed); ++total; } if (party._powerShield) { lines[17] = Common::String::format(Res.POWER_SHIELD, party._powerShield); ++total; } if (party._holyBonus) { lines[18] = Common::String::format(Res.HOLY_BONUS, party._holyBonus); ++total; } if (party._heroism) { lines[19] = Common::String::format(Res.HEROISM, party._heroism); ++total; } msg = Common::String::format("\x2\x3""c%s\x3l%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\x1", Res.CONSUMABLE_NAMES[3], lines[0].c_str(), lines[1].c_str(), lines[2].c_str(), lines[3].c_str(), lines[4].c_str(), lines[5].c_str(), lines[6].c_str(), lines[7].c_str(), lines[8].c_str(), lines[9].c_str(), lines[10].c_str(), lines[11].c_str(), lines[12].c_str(), lines[13].c_str(), lines[14].c_str(), lines[15].c_str(), lines[16].c_str(), lines[17].c_str(), lines[18].c_str(), lines[19].c_str() ); bounds.top -= ((total - 1) / 2) * 8; bounds.setHeight(total * 9 + 26); if (bounds.bottom >= SCREEN_HEIGHT) bounds.moveTo(bounds.left, SCREEN_HEIGHT - bounds.height() - 1); break; } default: break; } // Write the data for the stat display Window &w = windows[28]; w.setBounds(bounds); w.open(); w.writeString(msg); w.update(); // Wait for a user key/click EventsManager &events = *_vm->_events; while (!_vm->shouldExit() && !events.isKeyMousePressed()) events.pollEventsAndWait(); events.clearEvents(); #ifdef USE_TTS _vm->stopTextToSpeech(); #endif w.close(); return false; } } // End of namespace Xeen } // End of namespace MM