aboutsummaryrefslogtreecommitdiff
path: root/engines/xeen/dialogs/dialogs_items.cpp
diff options
context:
space:
mode:
authorPaul Gilbert2018-03-04 18:12:09 -0500
committerPaul Gilbert2018-03-04 22:40:42 -0500
commitf2b574d64762d23a83cc682da0e622be99080688 (patch)
tree1ccbabbda83e70911dae0d4042223ee81a006d1d /engines/xeen/dialogs/dialogs_items.cpp
parent50630efde6d0f42f4d5f371d6818afac64ba86f5 (diff)
downloadscummvm-rg350-f2b574d64762d23a83cc682da0e622be99080688.tar.gz
scummvm-rg350-f2b574d64762d23a83cc682da0e622be99080688.tar.bz2
scummvm-rg350-f2b574d64762d23a83cc682da0e622be99080688.zip
XEEN: Move all the dialog classes to their own sub-folder
Diffstat (limited to 'engines/xeen/dialogs/dialogs_items.cpp')
-rw-r--r--engines/xeen/dialogs/dialogs_items.cpp1066
1 files changed, 1066 insertions, 0 deletions
diff --git a/engines/xeen/dialogs/dialogs_items.cpp b/engines/xeen/dialogs/dialogs_items.cpp
new file mode 100644
index 0000000000..0ca0fd2267
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs_items.cpp
@@ -0,0 +1,1066 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "xeen/dialogs/dialogs_items.h"
+#include "xeen/dialogs/dialogs_query.h"
+#include "xeen/dialogs/dialogs_quests.h"
+#include "xeen/resources.h"
+#include "xeen/xeen.h"
+
+namespace Xeen {
+
+Character *ItemsDialog::show(XeenEngine *vm, Character *c, ItemsMode mode) {
+ ItemsDialog *dlg = new ItemsDialog(vm);
+ Character *result = dlg->execute(c, mode);
+ delete dlg;
+
+ return result;
+}
+
+Character *ItemsDialog::execute(Character *c, ItemsMode mode) {
+ Combat &combat = *_vm->_combat;
+ EventsManager &events = *_vm->_events;
+ Interface &intf = *_vm->_interface;
+ Party &party = *_vm->_party;
+ Windows &windows = *_vm->_windows;
+
+ Character *startingChar = c;
+ ItemCategory category = mode == ITEMMODE_RECHARGE || mode == ITEMMODE_COMBAT ?
+ CATEGORY_MISC : CATEGORY_WEAPON;
+ int varA = mode == ITEMMODE_COMBAT ? 1 : 0;
+ if (varA != 0)
+ mode = ITEMMODE_CHAR_INFO;
+ bool updateStock = mode == ITEMMODE_BLACKSMITH;
+ int itemIndex = -1;
+ Common::StringArray lines;
+ uint arr[40];
+ int actionIndex = -1;
+
+ events.setCursor(0);
+ loadButtons(mode, c);
+
+ windows[29].open();
+ windows[30].open();
+
+ enum { REDRAW_NONE, REDRAW_TEXT, REDRAW_FULL } redrawFlag = REDRAW_FULL;
+ for (;;) {
+ if (redrawFlag == REDRAW_FULL) {
+ if ((mode != ITEMMODE_CHAR_INFO || category != CATEGORY_MISC) && mode != ITEMMODE_ENCHANT
+ && mode != ITEMMODE_RECHARGE && mode != ITEMMODE_TO_GOLD) {
+ _buttons[4]._bounds.moveTo(148, _buttons[4]._bounds.top);
+ _buttons[9]._draw = false;
+ } else if (mode == ITEMMODE_RECHARGE) {
+ _buttons[4]._value = Common::KEYCODE_r;
+ } else if (mode == ITEMMODE_ENCHANT) {
+ _buttons[4]._value = Common::KEYCODE_e;
+ } else if (mode == ITEMMODE_TO_GOLD) {
+ _buttons[4]._value = Common::KEYCODE_g;
+ } else {
+ _buttons[4]._bounds.moveTo(0, _buttons[4]._bounds.top);
+ _buttons[9]._draw = true;
+ _buttons[9]._value = Common::KEYCODE_u;
+ }
+
+ // Write text for the dialog
+ Common::String msg;
+ if (mode != ITEMMODE_CHAR_INFO && mode != ITEMMODE_8 && mode != ITEMMODE_ENCHANT
+ && mode != ITEMMODE_RECHARGE && mode != ITEMMODE_TO_GOLD) {
+ msg = Common::String::format(Res.ITEMS_DIALOG_TEXT1,
+ Res.BTN_BUY, Res.BTN_SELL, Res.BTN_IDENTIFY, Res.BTN_FIX);
+ } else if (mode != ITEMMODE_ENCHANT && mode != ITEMMODE_RECHARGE && mode != ITEMMODE_TO_GOLD) {
+ msg = Common::String::format(Res.ITEMS_DIALOG_TEXT1,
+ category == 3 ? Res.BTN_USE : Res.BTN_EQUIP,
+ Res.BTN_REMOVE, Res.BTN_DISCARD, Res.BTN_QUEST);
+ } else if (mode == ITEMMODE_ENCHANT) {
+ msg = Common::String::format(Res.ITEMS_DIALOG_TEXT2, Res.BTN_ENCHANT);
+ } else if (mode == ITEMMODE_RECHARGE) {
+ msg = Common::String::format(Res.ITEMS_DIALOG_TEXT2, Res.BTN_RECHARGE);
+ } else {
+ msg = Common::String::format(Res.ITEMS_DIALOG_TEXT2, Res.BTN_GOLD);
+ }
+
+ windows[29].writeString(msg);
+ drawButtons(&windows[0]);
+
+ Common::fill(&arr[0], &arr[40], 0);
+ itemIndex = -1;
+ }
+
+ if (redrawFlag == REDRAW_TEXT || redrawFlag == REDRAW_FULL) {
+ lines.clear();
+
+ if (mode == ITEMMODE_CHAR_INFO || category != 3) {
+ _iconSprites.draw(0, 8, Common::Point(148, 109));
+ }
+ if (mode != ITEMMODE_ENCHANT && mode != ITEMMODE_RECHARGE && mode != ITEMMODE_TO_GOLD) {
+ _iconSprites.draw(0, 10, Common::Point(182, 109));
+ _iconSprites.draw(0, 12, Common::Point(216, 109));
+ _iconSprites.draw(0, 14, Common::Point(250, 109));
+ }
+
+ switch (mode) {
+ case ITEMMODE_CHAR_INFO:
+ _iconSprites.draw(0, 9, Common::Point(148, 109));
+ break;
+ case ITEMMODE_BLACKSMITH:
+ _iconSprites.draw(0, 11, Common::Point(182, 109));
+ break;
+ case ITEMMODE_REPAIR:
+ _iconSprites.draw(0, 15, Common::Point(250, 109));
+ break;
+ case ITEMMODE_IDENTIFY:
+ _iconSprites.draw(0, 13, Common::Point(216, 109));
+ break;
+ default:
+ break;
+ }
+
+ for (int idx = 0; idx < INV_ITEMS_TOTAL; ++idx) {
+ DrawStruct &ds = _itemsDrawList[idx];
+ XeenItem &i = c->_items[category][idx];
+
+ ds._sprites = nullptr;
+ ds._x = 8;
+ ds._y = 18 + idx * 9;
+
+ switch (category) {
+ case CATEGORY_WEAPON:
+ case CATEGORY_ARMOR:
+ case CATEGORY_ACCESSORY:
+ if (i._id) {
+ if (mode == ITEMMODE_CHAR_INFO || mode == ITEMMODE_8
+ || mode == ITEMMODE_ENCHANT || mode == ITEMMODE_RECHARGE) {
+ lines.push_back(Common::String::format(Res.ITEMS_DIALOG_LINE1,
+ arr[idx], idx + 1,
+ c->_items[category].getFullDescription(idx, arr[idx]).c_str()));
+ } else {
+ lines.push_back(Common::String::format(Res.ITEMS_DIALOG_LINE2,
+ arr[idx], idx + 1,
+ c->_items[category].getFullDescription(idx, arr[idx]).c_str(),
+ calcItemCost(c, idx, mode,
+ mode == ITEMMODE_TO_GOLD ? 1 : startingChar->_skills[MERCHANT],
+ category)
+ ));
+ }
+
+ ds._sprites = &_equipSprites;
+ if (c->_weapons.passRestrictions(i._id, true))
+ ds._frame = i._frame;
+ else
+ ds._frame = 14;
+ } else if (ds._sprites == nullptr && idx == 0) {
+ lines.push_back(Res.NO_ITEMS_AVAILABLE);
+ }
+ break;
+
+ case CATEGORY_MISC:
+ if (i._material == 0) {
+ // No item
+ if (idx == 0) {
+ lines.push_back(Res.NO_ITEMS_AVAILABLE);
+ }
+ } else {
+ ItemsMode tempMode = mode;
+ int skill = startingChar->_skills[MERCHANT];
+
+ if (mode == ITEMMODE_CHAR_INFO || mode == ITEMMODE_8
+ || mode == ITEMMODE_ENCHANT || mode == ITEMMODE_RECHARGE) {
+ tempMode = ITEMMODE_ENCHANT;
+ } else if (mode == ITEMMODE_TO_GOLD) {
+ skill = 1;
+ }
+
+ lines.push_back(Common::String::format(Res.ITEMS_DIALOG_LINE2,
+ arr[idx], idx + 1,
+ c->_items[category].getFullDescription(idx, arr[idx]).c_str(),
+ calcItemCost(c, idx, tempMode, skill, category)
+ ));
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ while (lines.size() < INV_ITEMS_TOTAL)
+ lines.push_back("");
+
+ // Draw out overall text and the list of items
+ switch (mode) {
+ case ITEMMODE_CHAR_INFO:
+ case ITEMMODE_8:
+ windows[30].writeString(Common::String::format(Res.X_FOR_THE_Y,
+ category == CATEGORY_MISC ? "\x3l" : "\x3c",
+ Res.CATEGORY_NAMES[category], c->_name.c_str(), Res.CLASS_NAMES[c->_class],
+ category == CATEGORY_MISC ? Res.FMT_CHARGES : " ",
+ 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()
+ ));
+ break;
+
+ case ITEMMODE_BLACKSMITH:
+ windows[30].writeString(Common::String::format(Res.AVAILABLE_GOLD_COST,
+ Res.CATEGORY_NAMES[category], party._gold,
+ 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()
+ ));
+ break;
+
+ case ITEMMODE_2:
+ case ITEMMODE_RECHARGE:
+ case ITEMMODE_ENCHANT:
+ case ITEMMODE_REPAIR:
+ case ITEMMODE_IDENTIFY:
+ case ITEMMODE_TO_GOLD:
+ windows[30].writeString(Common::String::format(Res.X_FOR_Y,
+ Res.CATEGORY_NAMES[category], startingChar->_name.c_str(),
+ (mode == ITEMMODE_RECHARGE || mode == ITEMMODE_ENCHANT) ? Res.CHARGES : Res.COST,
+ 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()
+ ));
+ break;
+
+ case ITEMMODE_3:
+ case ITEMMODE_5:
+ windows[30].writeString(Common::String::format(Res.X_FOR_Y_GOLD,
+ Res.CATEGORY_NAMES[category], c->_name.c_str(), party._gold, Res.CHARGES,
+ 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()
+ ));
+ break;
+
+ default:
+ break;
+ }
+
+ // Draw the glyphs for the items
+ windows[0].drawList(_itemsDrawList, INV_ITEMS_TOTAL);
+ windows[0].update();
+ }
+
+ redrawFlag = REDRAW_NONE;
+
+ if (itemIndex != -1) {
+ switch (mode) {
+ case ITEMMODE_BLACKSMITH:
+ actionIndex = 0;
+ break;
+ case ITEMMODE_2:
+ actionIndex = 1;
+ break;
+ case ITEMMODE_REPAIR:
+ actionIndex = 3;
+ break;
+ case ITEMMODE_IDENTIFY:
+ actionIndex = 2;
+ break;
+ default:
+ break;
+ }
+ }
+
+ // If it's time to do an item action, take care of it
+ if (actionIndex >= 0) {
+ int result = doItemOptions(*c, actionIndex, itemIndex, category, mode);
+ if (result == 1) {
+ // Finish dialog with no selected character
+ c = nullptr;
+ break;
+ } else if (result == 2) {
+ // Close dialogs and finish dialog with original starting character
+ windows[30].close();
+ windows[29].close();
+ c = startingChar;
+ break;
+ }
+
+ // Otherwise, result and continue showing dialog
+ actionIndex = -1;
+ }
+
+ // Wait for a selection
+ _buttonValue = 0;
+ while (!_vm->shouldExit() && !_buttonValue) {
+ events.pollEventsAndWait();
+ checkEvents(_vm);
+ }
+ if (_vm->shouldExit())
+ return nullptr;
+
+ // Handle escaping out of dialog
+ if (_buttonValue == Common::KEYCODE_ESCAPE) {
+ if (mode == ITEMMODE_8)
+ continue;
+ c = startingChar;
+ break;
+ }
+
+ // Handle other selections
+ switch (_buttonValue) {
+ case Common::KEYCODE_F1:
+ case Common::KEYCODE_F2:
+ case Common::KEYCODE_F3:
+ case Common::KEYCODE_F4:
+ case Common::KEYCODE_F5:
+ case Common::KEYCODE_F6:
+ if (!varA && mode != ITEMMODE_3 && mode != ITEMMODE_ENCHANT
+ && mode != ITEMMODE_RECHARGE && mode != ITEMMODE_TO_GOLD
+ && party._mazeId != 0) {
+ _buttonValue -= Common::KEYCODE_F1;
+
+ if (_buttonValue < (int)(_vm->_mode == MODE_COMBAT ?
+ combat._combatParty.size() : party._activeParty.size())) {
+ // Character number is valid
+ redrawFlag = REDRAW_TEXT;
+ Character *newChar = _vm->_mode == MODE_COMBAT ?
+ combat._combatParty[_buttonValue] : &party._activeParty[_buttonValue];
+
+ if (mode == ITEMMODE_BLACKSMITH) {
+ _oldCharacter = newChar;
+ startingChar = newChar;
+ c = &_itemsCharacter;
+ } else if (mode != ITEMMODE_2 && mode != ITEMMODE_REPAIR
+ && mode != ITEMMODE_IDENTIFY && itemIndex != -1) {
+ InventoryItems &destItems = newChar->_items[category];
+ XeenItem &destItem = destItems[INV_ITEMS_TOTAL - 1];
+ InventoryItems &srcItems = c->_items[category];
+ XeenItem &srcItem = srcItems[itemIndex];
+
+ if (srcItem._bonusFlags & ITEMFLAG_CURSED)
+ ErrorScroll::show(_vm, Res.CANNOT_REMOVE_CURSED_ITEM);
+ else if (destItems[INV_ITEMS_TOTAL - 1]._id)
+ ErrorScroll::show(_vm, Common::String::format(
+ Res.CATEGORY_BACKPACK_IS_FULL[category], c->_name.c_str()));
+ else {
+ destItem = srcItem;
+ srcItem.clear();
+ destItem._frame = 0;
+
+ srcItems.sort();
+ destItems.sort();
+ }
+
+ continue;
+ }
+
+ c = newChar;
+ startingChar = newChar;
+ intf.highlightChar(_buttonValue);
+ }
+ }
+ break;
+
+ case Common::KEYCODE_1:
+ case Common::KEYCODE_2:
+ case Common::KEYCODE_3:
+ case Common::KEYCODE_4:
+ case Common::KEYCODE_5:
+ case Common::KEYCODE_6:
+ case Common::KEYCODE_7:
+ case Common::KEYCODE_8:
+ case Common::KEYCODE_9:
+ // Select an item
+ if (mode == ITEMMODE_3)
+ break;
+
+ _buttonValue -= Common::KEYCODE_1;
+ if (_buttonValue != itemIndex) {
+ // Check whether the new selection has an associated item
+ if (!c->_items[category][_buttonValue].empty()) {
+ itemIndex = _buttonValue;
+ Common::fill(&arr[0], &arr[40], 0);
+ arr[itemIndex] = 15;
+ }
+
+ redrawFlag = REDRAW_TEXT;
+ }
+ break;
+
+ case Common::KEYCODE_a:
+ // Armor category
+ category = CATEGORY_ARMOR;
+ redrawFlag = REDRAW_FULL;
+ break;
+
+ case Common::KEYCODE_b:
+ // Buy
+ if (mode != ITEMMODE_CHAR_INFO && mode != ITEMMODE_RECHARGE &&
+ mode != ITEMMODE_ENCHANT && mode != ITEMMODE_TO_GOLD) {
+ mode = ITEMMODE_BLACKSMITH;
+ c = &_itemsCharacter;
+ redrawFlag = REDRAW_FULL;
+ }
+ break;
+
+ case Common::KEYCODE_c:
+ // Accessories category
+ category = CATEGORY_ACCESSORY;
+ redrawFlag = REDRAW_FULL;
+ break;
+
+ case Common::KEYCODE_d:
+ if (mode == ITEMMODE_CHAR_INFO)
+ actionIndex = 3;
+ break;
+
+ case Common::KEYCODE_e:
+ if (mode == ITEMMODE_CHAR_INFO || mode == ITEMMODE_ENCHANT ||
+ mode == ITEMMODE_TO_GOLD) {
+ if (category != CATEGORY_MISC) {
+ actionIndex = mode == ITEMMODE_ENCHANT ? 4 : 0;
+ }
+ }
+ break;
+
+ case Common::KEYCODE_f:
+ if (mode != ITEMMODE_CHAR_INFO && mode != ITEMMODE_RECHARGE &&
+ mode != ITEMMODE_ENCHANT && mode != ITEMMODE_TO_GOLD) {
+ mode = ITEMMODE_REPAIR;
+ c = startingChar;
+ redrawFlag = REDRAW_TEXT;
+ }
+ break;
+
+ case Common::KEYCODE_g:
+ if (mode == ITEMMODE_TO_GOLD)
+ actionIndex = 6;
+ break;
+
+ case Common::KEYCODE_i:
+ if (mode != ITEMMODE_CHAR_INFO && mode != ITEMMODE_RECHARGE &&
+ mode != ITEMMODE_ENCHANT && mode != ITEMMODE_TO_GOLD) {
+ mode = ITEMMODE_IDENTIFY;
+ c = startingChar;
+ redrawFlag = REDRAW_TEXT;
+ }
+ break;
+
+ case Common::KEYCODE_m:
+ // Misc
+ category = CATEGORY_MISC;
+ redrawFlag = REDRAW_TEXT;
+ break;
+
+ case Common::KEYCODE_q:
+ // Quests
+ if (mode == ITEMMODE_CHAR_INFO) {
+ Quests::show(_vm);
+ redrawFlag = REDRAW_FULL;
+ }
+ break;
+
+ case Common::KEYCODE_r:
+ if (mode == ITEMMODE_CHAR_INFO)
+ actionIndex = 1;
+ else if (mode == ITEMMODE_RECHARGE)
+ actionIndex = 5;
+ break;
+
+ case Common::KEYCODE_s:
+ if (mode != ITEMMODE_CHAR_INFO && mode != ITEMMODE_RECHARGE &&
+ mode != ITEMMODE_ENCHANT && mode != ITEMMODE_TO_GOLD) {
+ mode = ITEMMODE_2;
+ c = startingChar;
+ redrawFlag = REDRAW_TEXT;
+ }
+ break;
+
+ case Common::KEYCODE_u:
+ if (mode == ITEMMODE_CHAR_INFO && category == CATEGORY_MISC)
+ actionIndex = 2;
+ break;
+
+ case Common::KEYCODE_w:
+ // Weapons category
+ category = CATEGORY_WEAPON;
+ redrawFlag = REDRAW_TEXT;
+ break;
+ }
+ }
+
+ windows[30].close();
+ windows[29].close();
+
+ intf.drawParty(true);
+ if (updateStock)
+ charData2BlackData();
+
+ return c;
+}
+
+void ItemsDialog::loadButtons(ItemsMode mode, Character *&c) {
+ _iconSprites.load(Common::String::format("%s.icn",
+ (mode == ITEMMODE_CHAR_INFO) ? "items" : "buy"));
+ _equipSprites.load("equip.icn");
+
+ if (mode == ITEMMODE_ENCHANT || mode == ITEMMODE_RECHARGE || mode == ITEMMODE_TO_GOLD) {
+ // Enchant button list
+ addButton(Common::Rect(12, 109, 36, 129), Common::KEYCODE_w, &_iconSprites);
+ addButton(Common::Rect(46, 109, 70, 129), Common::KEYCODE_a, &_iconSprites);
+ addButton(Common::Rect(80, 109, 104, 129), Common::KEYCODE_c, &_iconSprites);
+ addButton(Common::Rect(114, 109, 138, 129), Common::KEYCODE_m, &_iconSprites);
+ addButton(Common::Rect(148, 109, 172, 129), Common::KEYCODE_e, &_iconSprites);
+ addButton(Common::Rect(284, 109, 308, 129), Common::KEYCODE_ESCAPE, &_iconSprites);
+ addButton(Common::Rect(148, 109, 172, 129), Common::KEYCODE_u, &_iconSprites);
+ addButton(Common::Rect(8, 20, 263, 28), Common::KEYCODE_1);
+ addButton(Common::Rect(8, 29, 263, 37), Common::KEYCODE_2);
+ addButton(Common::Rect(8, 38, 263, 46), Common::KEYCODE_3);
+ addButton(Common::Rect(8, 47, 263, 55), Common::KEYCODE_4);
+ addButton(Common::Rect(8, 56, 263, 64), Common::KEYCODE_5);
+ addButton(Common::Rect(8, 65, 263, 73), Common::KEYCODE_6);
+ addButton(Common::Rect(8, 74, 263, 82), Common::KEYCODE_7);
+ addButton(Common::Rect(8, 83, 263, 91), Common::KEYCODE_8);
+ addButton(Common::Rect(8, 92, 263, 100), Common::KEYCODE_9);
+ } else {
+ addButton(Common::Rect(12, 109, 36, 129), Common::KEYCODE_w, &_iconSprites);
+ addButton(Common::Rect(46, 109, 70, 129), Common::KEYCODE_a, &_iconSprites);
+ addButton(Common::Rect(80, 109, 104, 129), Common::KEYCODE_c, &_iconSprites);
+ addButton(Common::Rect(114, 109, 138, 129), Common::KEYCODE_m, &_iconSprites);
+ addButton(Common::Rect(148, 109, 172, 129), Common::KEYCODE_e, &_iconSprites);
+ addButton(Common::Rect(182, 109, 206, 129), Common::KEYCODE_r, &_iconSprites);
+ addButton(Common::Rect(216, 109, 240, 129), Common::KEYCODE_d, &_iconSprites);
+ addButton(Common::Rect(250, 109, 274, 129), Common::KEYCODE_q, &_iconSprites);
+ addButton(Common::Rect(284, 109, 308, 129), Common::KEYCODE_ESCAPE, &_iconSprites);
+ addButton(Common::Rect(8, 20, 263, 28), Common::KEYCODE_1);
+ addButton(Common::Rect(8, 29, 263, 37), Common::KEYCODE_2);
+ addButton(Common::Rect(8, 38, 263, 46), Common::KEYCODE_3);
+ addButton(Common::Rect(8, 47, 263, 55), Common::KEYCODE_4);
+ addButton(Common::Rect(8, 56, 263, 64), Common::KEYCODE_5);
+ addButton(Common::Rect(8, 65, 263, 73), Common::KEYCODE_6);
+ addButton(Common::Rect(8, 74, 263, 82), Common::KEYCODE_7);
+ addButton(Common::Rect(8, 83, 263, 91), Common::KEYCODE_8);
+ addButton(Common::Rect(8, 92, 263, 100), Common::KEYCODE_9);
+ addPartyButtons(_vm);
+ }
+
+ if (mode == ITEMMODE_BLACKSMITH) {
+ _oldCharacter = c;
+ c = &_itemsCharacter;
+ blackData2CharData();
+
+ _buttons[4]._value = Common::KEYCODE_b;
+ _buttons[5]._value = Common::KEYCODE_s;
+ _buttons[6]._value = Common::KEYCODE_i;
+ _buttons[7]._value = Common::KEYCODE_f;
+
+ setEquipmentIcons();
+ } else {
+ _buttons[4]._value = Common::KEYCODE_e;
+ _buttons[5]._value = Common::KEYCODE_r;
+ _buttons[6]._value = Common::KEYCODE_d;
+ _buttons[7]._value = Common::KEYCODE_q;
+ }
+}
+
+void ItemsDialog::blackData2CharData() {
+ Party &party = *_vm->_party;
+ bool isDarkCc = _vm->_files->_isDarkCc;
+ int slotIndex = 0;
+ while (slotIndex < 4 && party._mazeId != (int)Res.BLACKSMITH_MAP_IDS[isDarkCc][slotIndex])
+ ++slotIndex;
+ if (slotIndex == 4)
+ slotIndex = 0;
+
+ for (int idx = 0; idx < INV_ITEMS_TOTAL; ++idx) {
+ _itemsCharacter._weapons[idx] = party._blacksmithWeapons[isDarkCc][idx];
+ _itemsCharacter._armor[idx] = party._blacksmithArmor[isDarkCc][idx];
+ _itemsCharacter._accessories[idx] = party._blacksmithAccessories[isDarkCc][idx];
+ _itemsCharacter._misc[idx] = party._blacksmithMisc[isDarkCc][idx];
+ }
+}
+
+void ItemsDialog::charData2BlackData() {
+ Party &party = *_vm->_party;
+ bool isDarkCc = _vm->_files->_isDarkCc;
+ int slotIndex = 0;
+ while (slotIndex < 4 && party._mazeId != (int)Res.BLACKSMITH_MAP_IDS[isDarkCc][slotIndex])
+ ++slotIndex;
+ if (slotIndex == 4)
+ slotIndex = 0;
+
+ for (int idx = 0; idx < INV_ITEMS_TOTAL; ++idx) {
+ party._blacksmithWeapons[isDarkCc][idx] = _itemsCharacter._weapons[idx];
+ party._blacksmithArmor[isDarkCc][idx] = _itemsCharacter._armor[idx];
+ party._blacksmithAccessories[isDarkCc][idx] = _itemsCharacter._accessories[idx];
+ party._blacksmithMisc[isDarkCc][idx] = _itemsCharacter._misc[idx];
+ }
+}
+
+void ItemsDialog::setEquipmentIcons() {
+ for (int typeIndex = 0; typeIndex < 4; ++typeIndex) {
+ for (int idx = 0; idx < INV_ITEMS_TOTAL; ++idx) {
+ switch (typeIndex) {
+ case CATEGORY_WEAPON: {
+ XeenItem &i = _itemsCharacter._weapons[idx];
+ if (i._id <= 17)
+ i._frame = 1;
+ else if (i._id <= 29 || i._id > 33)
+ i._frame = 13;
+ else
+ i._frame = 4;
+ break;
+ }
+
+ case CATEGORY_ARMOR: {
+ XeenItem &i = _itemsCharacter._armor[idx];
+ if (i._id <= 7)
+ i._frame = 3;
+ else if (i._id == 9)
+ i._frame = 5;
+ else if (i._id == 10)
+ i._frame = 9;
+ else if (i._id <= 12)
+ i._frame = 10;
+ else
+ i._frame = 6;
+ break;
+ }
+
+ case CATEGORY_ACCESSORY: {
+ XeenItem &i = _itemsCharacter._accessories[idx];
+ if (i._id == 1)
+ i._id = 8;
+ else if (i._id == 2)
+ i._frame = 12;
+ else if (i._id <= 7)
+ i._frame = 7;
+ else
+ i._frame = 11;
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+ }
+}
+
+int ItemsDialog::calcItemCost(Character *c, int itemIndex, ItemsMode mode,
+ int skillLevel, ItemCategory category) {
+ int amount1 = 0, amount2 = 0, amount3 = 0, amount4 = 0;
+ int result = 0;
+ int level = skillLevel & 0x7f;
+
+ InventoryItems *invGroups[4] = {
+ &c->_weapons, &c->_armor, &c->_accessories, &c->_misc
+ };
+ const int *BASE_COSTS[4] = {
+ Res.WEAPON_BASE_COSTS, Res.ARMOR_BASE_COSTS, Res.ACCESSORY_BASE_COSTS, Res.MISC_BASE_COSTS
+ };
+
+ switch (mode) {
+ case ITEMMODE_BLACKSMITH:
+ level = 0;
+ break;
+ case ITEMMODE_2:
+ case ITEMMODE_TO_GOLD:
+ level = level == 0 ? 1 : 0;
+ break;
+ case ITEMMODE_IDENTIFY:
+ level = 2;
+ break;
+ case ITEMMODE_REPAIR:
+ level = 3;
+ break;
+ default:
+ break;
+ }
+
+ switch (category) {
+ case CATEGORY_WEAPON:
+ case CATEGORY_ARMOR:
+ case CATEGORY_ACCESSORY: {
+ XeenItem &i = (*invGroups[category])[itemIndex];
+ amount1 = (BASE_COSTS[category])[i._id];
+
+ if (i._material > 36 && i._material < 59) {
+ switch (i._material) {
+ case 37:
+ amount1 /= 10;
+ break;
+ case 38:
+ amount1 /= 4;
+ break;
+ case 39:
+ amount1 /= 2;
+ break;
+ case 40:
+ amount1 /= 4;
+ break;
+ default:
+ amount1 *= Res.METAL_BASE_MULTIPLIERS[i._material - 37];
+ break;
+ }
+ }
+
+ if (i._material < 37)
+ amount2 = Res.ELEMENTAL_DAMAGE[i._material] * 100;
+ else if (i._material > 58)
+ amount3 = Res.ELEMENTAL_DAMAGE[i._material - 59 + 7] * 100;
+
+ switch (mode) {
+ case ITEMMODE_BLACKSMITH:
+ case ITEMMODE_2:
+ case ITEMMODE_REPAIR:
+ case ITEMMODE_IDENTIFY:
+ case ITEMMODE_TO_GOLD:
+ result = (amount1 + amount2 + amount3 + amount4) / Res.ITEM_SKILL_DIVISORS[level];
+ if (!result)
+ result = 1;
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+
+ case CATEGORY_MISC: {
+ // Misc
+ XeenItem &i = c->_misc[itemIndex];
+ amount1 = Res.MISC_MATERIAL_COSTS[i._material];
+ amount4 = Res.MISC_BASE_COSTS[i._id];
+
+ switch (mode) {
+ case ITEMMODE_BLACKSMITH:
+ case ITEMMODE_2:
+ case ITEMMODE_REPAIR:
+ case ITEMMODE_IDENTIFY:
+ case ITEMMODE_TO_GOLD:
+ result = (amount1 + amount2 + amount3 + amount4) / Res.ITEM_SKILL_DIVISORS[level];
+ if (!result)
+ result = 1;
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ return (mode == ITEMMODE_CHAR_INFO) ? 0 : result;
+}
+
+int ItemsDialog::doItemOptions(Character &c, int actionIndex, int itemIndex, ItemCategory category,
+ ItemsMode mode) {
+ Combat &combat = *_vm->_combat;
+ EventsManager &events = *_vm->_events;
+ Interface &intf = *_vm->_interface;
+ Party &party = *_vm->_party;
+ Sound &sound = *_vm->_sound;
+ Spells &spells = *_vm->_spells;
+ Windows &windows = *_vm->_windows;
+ bool isDarkCc = _vm->_files->_isDarkCc;
+
+ XeenItem *itemCategories[4] = { &c._weapons[0], &c._armor[0], &c._accessories[0], &c._misc[0] };
+ XeenItem *items = itemCategories[category];
+ if (!items[0]._id)
+ // Inventory is empty
+ return category == CATEGORY_MISC ? 0 : 2;
+
+ Window &w = windows[11];
+ SpriteResource escSprites;
+ if (itemIndex < 0 || itemIndex > 8) {
+ saveButtons();
+
+ escSprites.load("esc.icn");
+ addButton(Common::Rect(235, 111, 259, 131), Common::KEYCODE_ESCAPE, &escSprites);
+ addButton(Common::Rect(8, 20, 263, 28), Common::KEYCODE_1);
+ addButton(Common::Rect(8, 29, 263, 37), Common::KEYCODE_2);
+ addButton(Common::Rect(8, 38, 263, 46), Common::KEYCODE_3);
+ addButton(Common::Rect(8, 47, 263, 55), Common::KEYCODE_4);
+ addButton(Common::Rect(8, 56, 263, 64), Common::KEYCODE_5);
+ addButton(Common::Rect(8, 65, 263, 73), Common::KEYCODE_6);
+ addButton(Common::Rect(8, 74, 263, 82), Common::KEYCODE_7);
+ addButton(Common::Rect(8, 83, 263, 91), Common::KEYCODE_8);
+ addButton(Common::Rect(8, 92, 263, 100), Common::KEYCODE_9);
+
+ w.open();
+ w.writeString(Common::String::format(Res.WHICH_ITEM, Res.ITEM_ACTIONS[actionIndex]));
+ _iconSprites.draw(0, 0, Common::Point(235, 111));
+ w.update();
+
+ while (!_vm->shouldExit()) {
+ while (!_buttonValue) {
+ events.pollEventsAndWait();
+ checkEvents(_vm);
+ if (_vm->shouldExit())
+ return false;
+ }
+
+ if (_buttonValue == Common::KEYCODE_ESCAPE) {
+ itemIndex = -1;
+ break;
+ } else if (_buttonValue >= Common::KEYCODE_1 && _buttonValue <= Common::KEYCODE_9) {
+ // Check whether there's an item at the selected index
+ int selectedIndex = _buttonValue - Common::KEYCODE_1;
+ if (!items[selectedIndex]._id)
+ continue;
+
+ itemIndex = selectedIndex;
+ break;
+ }
+ }
+
+ w.close();
+ restoreButtons();
+ }
+
+ if (itemIndex != -1) {
+ XeenItem &item = c._items[category][itemIndex];
+
+ switch (mode) {
+ case ITEMMODE_CHAR_INFO:
+ case ITEMMODE_8:
+ switch (actionIndex) {
+ case 0:
+ c._items[category].equipItem(itemIndex);
+ break;
+ case 1:
+ c._items[category].removeItem(itemIndex);
+ break;
+ case 2:
+ if (!party._mazeId) {
+ ErrorScroll::show(_vm, Res.WHATS_YOUR_HURRY);
+ } else {
+ XeenItem &i = c._misc[itemIndex];
+
+ Condition condition = c.worstCondition();
+ switch (condition) {
+ case ASLEEP:
+ case PARALYZED:
+ case UNCONSCIOUS:
+ case DEAD:
+ case STONED:
+ case ERADICATED:
+ ErrorScroll::show(_vm, Common::String::format(Res.IN_NO_CONDITION, c._name.c_str()));
+ break;
+ default:
+ if (combat._itemFlag) {
+ ErrorScroll::show(_vm, Res.USE_ITEM_IN_COMBAT);
+ } else if (i._id && (i._bonusFlags & ITEMFLAG_BONUS_MASK)
+ && !(i._bonusFlags & (ITEMFLAG_BROKEN | ITEMFLAG_CURSED))) {
+ int charges = (i._bonusFlags & ITEMFLAG_BONUS_MASK) - 1;
+ i._bonusFlags = charges;
+ _oldCharacter = &c;
+
+ windows[30].close();
+ windows[29].close();
+ windows[24].close();
+ spells.castItemSpell(i._id);
+
+ if (!charges) {
+ // Ran out of charges, so make item disappear
+ c._items[category][itemIndex].clear();
+ c._items[category].sort();
+ }
+ } else {
+ ErrorScroll::show(_vm, Common::String::format(Res.NO_SPECIAL_ABILITIES,
+ c._items[category].getFullDescription(itemIndex).c_str()
+ ));
+ }
+ }
+ }
+ break;
+ case 3:
+ c._items[category].discardItem(itemIndex);
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case ITEMMODE_BLACKSMITH: {
+ InventoryItems &invItems = _oldCharacter->_items[category];
+ if (invItems[INV_ITEMS_TOTAL - 1]._id) {
+ // If the last slot is in use, it means the list is full
+ ErrorScroll::show(_vm, Common::String::format(Res.BACKPACK_IS_FULL,
+ _oldCharacter->_name.c_str()));
+ } else {
+ int cost = calcItemCost(_oldCharacter, itemIndex, mode, 0, category);
+ Common::String desc = c._items[category].getFullDescription(itemIndex);
+ if (Confirm::show(_vm, Common::String::format(Res.BUY_X_FOR_Y_GOLD,
+ desc.c_str(), cost))) {
+ if (party.subtract(CONS_GOLD, cost, WHERE_PARTY, WT_FREEZE_WAIT)) {
+ if (isDarkCc) {
+ sound.stopSound();
+ sound.playSound("choice2.voc");
+ }
+
+ // Add entry to the end of the list
+ _oldCharacter->_items[category][8] = c._items[category][itemIndex];
+ _oldCharacter->_items[category][8]._frame = 0;
+ c._items[category].clear();
+ c._items[category].sort();
+ _oldCharacter->_items[category].sort();
+ }
+ }
+ }
+ return 0;
+ }
+
+ case ITEMMODE_2: {
+ bool noNeed;
+ switch (category) {
+ case CATEGORY_WEAPON:
+ noNeed = (item._bonusFlags & ITEMFLAG_CURSED) || item._id == 34;
+ break;
+ default:
+ noNeed = item._bonusFlags & ITEMFLAG_CURSED;
+ break;
+ }
+
+ if (noNeed) {
+ ErrorScroll::show(_vm, Common::String::format(Res.NO_NEED_OF_THIS,
+ c._items[category].getFullDescription(itemIndex).c_str()));
+ } else {
+ int cost = calcItemCost(&c, itemIndex, mode, c._skills[MERCHANT], category);
+ Common::String desc = c._items[category].getFullDescription(itemIndex);
+ Common::String msg = Common::String::format(Res.SELL_X_FOR_Y_GOLD,
+ desc.c_str(), cost);
+
+ if (Confirm::show(_vm, msg)) {
+ // Remove the sold item and add gold to the party's total
+ item.clear();
+ c._items[category].sort();
+
+ party._gold += cost;
+ }
+ }
+ return 0;
+ }
+
+ case ITEMMODE_RECHARGE:
+ if (category != CATEGORY_MISC || c._misc[itemIndex]._material > 9
+ || c._misc[itemIndex]._id == 53 || c._misc[itemIndex]._id == 0) {
+ sound.playFX(21);
+ ErrorScroll::show(_vm, Common::String::format(Res.NOT_RECHARGABLE, Res.SPELL_FAILED));
+ } else {
+ int charges = MIN(63, _vm->getRandomNumber(1, 6) +
+ (c._misc[itemIndex]._bonusFlags & ITEMFLAG_BONUS_MASK));
+ sound.playFX(20);
+
+ c._misc[itemIndex]._bonusFlags = (c._misc[itemIndex]._bonusFlags
+ & ~ITEMFLAG_BONUS_MASK) | charges;
+ }
+ return 2;
+
+ case ITEMMODE_ENCHANT: {
+ int amount = _vm->getRandomNumber(1, _oldCharacter->getCurrentLevel() / 5 + 1);
+ amount = MIN(amount, 5);
+ _oldCharacter->_items[category].enchantItem(itemIndex, amount);
+ break;
+ }
+
+ case ITEMMODE_REPAIR:
+ if (!(item._bonusFlags & ITEMFLAG_BROKEN)) {
+ ErrorScroll::show(_vm, Res.ITEM_NOT_BROKEN);
+ } else {
+ int cost = calcItemCost(&c, itemIndex, mode, actionIndex, category);
+ Common::String msg = Common::String::format(Res.FIX_IDENTIFY_GOLD,
+ Res.FIX_IDENTIFY[0],
+ c._items[category].getFullDescription(itemIndex).c_str(),
+ cost);
+
+ if (Confirm::show(_vm, msg) && party.subtract(CONS_GOLD, cost, WHERE_PARTY)) {
+ item._bonusFlags &= ~ITEMFLAG_BROKEN;
+ }
+ }
+ break;
+
+ case ITEMMODE_IDENTIFY: {
+ int cost = calcItemCost(&c, itemIndex, mode, actionIndex, category);
+ Common::String msg = Common::String::format(Res.FIX_IDENTIFY_GOLD,
+ Res.FIX_IDENTIFY[1],
+ c._items[category].getFullDescription(itemIndex).c_str(),
+ cost);
+
+ if (Confirm::show(_vm, msg) && party.subtract(CONS_GOLD, cost, WHERE_PARTY)) {
+ Common::String details = c._items[category].getIdentifiedDetails(itemIndex);
+ Common::String desc = c._items[category].getFullDescription(itemIndex);
+ Common::String str = Common::String::format(Res.IDENTIFY_ITEM_MSG,
+ desc.c_str(), details.c_str());
+
+ Window &win = windows[14];
+ win.open();
+ win.writeString(str);
+ win.update();
+
+ saveButtons();
+ clearButtons();
+
+ while (!_vm->shouldExit() && !events.isKeyMousePressed())
+ events.pollEventsAndWait();
+ events.clearEvents();
+
+ restoreButtons();
+ win.close();
+ }
+ break;
+ }
+
+ case ITEMMODE_TO_GOLD:
+ // Convert item in inventory to gold
+ itemToGold(c, itemIndex, category, mode);
+ return 2;
+
+ default:
+ break;
+ }
+ }
+
+ intf._charsShooting = false;
+ combat.moveMonsters();
+ combat._whosTurn = -1;
+ return true;
+}
+
+void ItemsDialog::itemToGold(Character &c, int itemIndex, ItemCategory category,
+ ItemsMode mode) {
+ XeenItem &item = c._items[category][itemIndex];
+ Party &party = *_vm->_party;
+ Sound &sound = *_vm->_sound;
+
+ if (category == CATEGORY_WEAPON && item._id == 34) {
+ sound.playFX(21);
+ ErrorScroll::show(_vm, Common::String::format("\v012\t000\x03""c%s",
+ Res.SPELL_FAILED));
+ } else if (item._id != 0) {
+ // There is a valid item present
+ // Calculate cost of item and add it to the party's total
+ int cost = calcItemCost(&c, itemIndex, mode, 1, category);
+ party._gold += cost;
+
+ // Remove the item from the inventory
+ item.clear();
+ c._items[category].sort();
+ }
+}
+
+} // End of namespace Xeen