From 29753a29a4b82d8cac78223232dc84c003d8f210 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Fri, 30 Jan 2015 19:18:43 -0500 Subject: XEEN: Implemented SpellsDialog and ConfirmDialog classes --- engines/xeen/dialogs_confirm.cpp | 85 ++++++++ engines/xeen/dialogs_confirm.h | 43 ++++ engines/xeen/dialogs_spells.cpp | 416 +++++++++++++++++++++++++++++++++++++++ engines/xeen/dialogs_spells.h | 61 ++++++ engines/xeen/dialogs_yesno.cpp | 4 +- engines/xeen/module.mk | 1 + engines/xeen/party.cpp | 66 +++++++ engines/xeen/party.h | 5 + engines/xeen/resources.cpp | 47 ++++- engines/xeen/resources.h | 20 +- engines/xeen/spells.cpp | 2 + engines/xeen/spells.h | 1 + engines/xeen/town.cpp | 86 +------- engines/xeen/town.h | 4 - 14 files changed, 755 insertions(+), 86 deletions(-) create mode 100644 engines/xeen/dialogs_confirm.cpp create mode 100644 engines/xeen/dialogs_confirm.h create mode 100644 engines/xeen/dialogs_spells.cpp create mode 100644 engines/xeen/dialogs_spells.h diff --git a/engines/xeen/dialogs_confirm.cpp b/engines/xeen/dialogs_confirm.cpp new file mode 100644 index 0000000000..13a41e76ca --- /dev/null +++ b/engines/xeen/dialogs_confirm.cpp @@ -0,0 +1,85 @@ +/* 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_confirm.h" +#include "xeen/xeen.h" + +namespace Xeen { + +bool ConfirmDialog::show(XeenEngine *vm, const Common::String &msg, int v2) { + ConfirmDialog *dlg = new ConfirmDialog(vm); + bool result = dlg->execute(msg, v2); + delete dlg; + + return result; +} + +bool ConfirmDialog::execute(const Common::String &msg, int v2) { + Screen &screen = *_vm->_screen; + EventsManager &events = *_vm->_events; + SpriteResource confirmSprites; + confirmSprites.load("confirm.icn"); + + addButton(Common::Rect(129, 112, 153, 132), Common::KEYCODE_y, &confirmSprites); + addButton(Common::Rect(185, 112, 209, 132), Common::KEYCODE_n, &confirmSprites); + + Window &w = screen._windows[v2 ? 21 : 22]; + w.open(); + + if (v2) { + confirmSprites.draw(screen._windows[21], 0, Common::Point(129, 112)); + confirmSprites.draw(screen._windows[21], 2, Common::Point(185, 112)); + + _buttons[0]._bounds.moveTo(129, 112); + _buttons[1]._bounds.moveTo(185, 112); + } else if (v2 & 0x80) { + clearButtons(); + } else { + confirmSprites.draw(screen._windows[22], 0, Common::Point(120, 133)); + confirmSprites.draw(screen._windows[22], 2, Common::Point(176, 133)); + + _buttons[0]._bounds.moveTo(120, 133); + _buttons[1]._bounds.moveTo(176, 133); + } + + w.writeString(msg); + w.update(); + + bool result = false; + while (!_vm->shouldQuit()) { + while (!events.isKeyMousePressed()) + events.pollEventsAndWait(); + + if ((v2 & 0x80) || _buttonValue == Common::KEYCODE_ESCAPE || + _buttonValue == Common::KEYCODE_y) + break; + else if (_buttonValue == Common::KEYCODE_y) { + result = true; + break; + } + } + + w.close(); + return result; +} + +} // End of namespace Xeen diff --git a/engines/xeen/dialogs_confirm.h b/engines/xeen/dialogs_confirm.h new file mode 100644 index 0000000000..825be5e764 --- /dev/null +++ b/engines/xeen/dialogs_confirm.h @@ -0,0 +1,43 @@ +/* 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. + * + */ + +#ifndef XEEN_DIALOGS_CONFIRM_H +#define XEEN_DIALOGS_CONFIRM_H + +#include "xeen/dialogs.h" + +namespace Xeen { + +class ConfirmDialog : public ButtonContainer { +private: + XeenEngine *_vm; + + ConfirmDialog(XeenEngine *vm) : ButtonContainer(), _vm(vm) {} + + bool execute(const Common::String &msg, int v2); +public: + static bool show(XeenEngine *vm, const Common::String &msg, int v2); +}; + +} // End of namespace Xeen + +#endif /* XEEN_DIALOGS_CONFIRM_H */ diff --git a/engines/xeen/dialogs_spells.cpp b/engines/xeen/dialogs_spells.cpp new file mode 100644 index 0000000000..7ae5e7ad90 --- /dev/null +++ b/engines/xeen/dialogs_spells.cpp @@ -0,0 +1,416 @@ +/* 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_spells.h" +#include "xeen/dialogs_confirm.h" +#include "xeen/resources.h" +#include "xeen/spells.h" +#include "xeen/sprites.h" +#include "xeen/xeen.h" + +namespace Xeen { + +Character *SpellsScroll::show(XeenEngine *vm, Character *c, int v2) { + SpellsScroll *dlg = new SpellsScroll(vm); + Character *result = dlg->execute(c, v2); + delete dlg; + + return result; +} + +Character *SpellsScroll::execute(Character *c, int v2) { + EventsManager &events = *_vm->_events; + Interface &intf = *_vm->_interface; + Party &party = *_vm->_party; + Screen &screen = *_vm->_screen; + SoundManager &sound = *_vm->_sound; + Spells &spells = *_vm->_spells; + bool isDarkCc = _vm->_files->_isDarkCc; + loadButtons(); + + int v2Copy = v2; + v2 &= 0x7f; + int selection = -1; + int topIndex = 0; + int newSelection; + screen._windows[25].open(); + + while (!_vm->shouldQuit()) { + if (!v2) { + if (!c->guildMember()) { + sound.playSample(nullptr, 0); + intf._overallFrame = 5; + File f(isDarkCc ? "skull1.voc" : "guild11.voc"); + sound.playSample(&f, 1); + break; + } + + Common::String title = Common::String::format(BUY_SPELLS, c->_name.c_str()); + Common::String msg = Common::String::format(GUILD_OPTIONS, + title.c_str(), XeenEngine::printMil(party._gold)); + screen._windows[10].writeString(msg); + + warning("TODO: Sprite draw using previously used button sprites"); + } + + _spells.clear(); + const char *errorMsg = setSpellText(c, v2Copy); + screen._windows[25].writeString(Common::String::format(SPELLS_FOR, + errorMsg == nullptr ? SPELL_LINES_0_TO_9 : nullptr)); + + screen._windows[37].writeString(Common::String::format(SPELLS_DIALOG_SPELLS, + (topIndex + 0) < _spells.size() ? _spells[topIndex + 0]._name.c_str() : nullptr, + (topIndex + 1) < _spells.size() ? _spells[topIndex + 1]._name.c_str() : nullptr, + (topIndex + 2) < _spells.size() ? _spells[topIndex + 2]._name.c_str() : nullptr, + (topIndex + 3) < _spells.size() ? _spells[topIndex + 3]._name.c_str() : nullptr, + (topIndex + 4) < _spells.size() ? _spells[topIndex + 4]._name.c_str() : nullptr, + (topIndex + 5) < _spells.size() ? _spells[topIndex + 5]._name.c_str() : nullptr, + (topIndex + 6) < _spells.size() ? _spells[topIndex + 6]._name.c_str() : nullptr, + (topIndex + 7) < _spells.size() ? _spells[topIndex + 7]._name.c_str() : nullptr, + (topIndex + 8) < _spells.size() ? _spells[topIndex + 8]._name.c_str() : nullptr, + (topIndex + 9) < _spells.size() ? _spells[topIndex + 9]._name.c_str() : nullptr, + v2 ? SPELL_PTS : GOLD, + v2 ? c->_currentSp : party._gold + )); + + _iconSprites.draw(screen, 4, Common::Point(39, 26)); + _iconSprites.draw(screen, 0, Common::Point(187, 26)); + _iconSprites.draw(screen, 2, Common::Point(187, 111)); + if (v2) + _iconSprites.draw(screen._windows[25], 5, Common::Point(132, 123)); + + screen._windows[25].update(); + + while (!_vm->shouldQuit() && !events.isKeyMousePressed()) + events.pollEventsAndWait(); + if (_vm->shouldQuit()) + break; + checkEvents(_vm); + + switch (_buttonValue) { + case Common::KEYCODE_F1: + case Common::KEYCODE_F6: + if (_vm->_mode != MODE_2) { + _buttonValue -= Common::KEYCODE_F1; + if (_buttonValue < party._partyCount) { + c = &party._activeParty[_buttonValue]; + spells._lastCaster = _buttonValue; + intf.highlightChar(_buttonValue); + + if (_vm->_mode == MODE_17) { + screen._windows[10].writeString(Common::String::format(GUILD_OPTIONS, + XeenEngine::printMil(party._gold).c_str(), GUILD_TEXT, c->_name.c_str())); + } else { + int category; + switch (c->_class) { + case CLASS_ARCHER: + case CLASS_SORCERER: + category = 1; + break; + case CLASS_DRUID: + case CLASS_RANGER: + category = 2; + break; + default: + category = 0; + break; + } + + int spellIndex = (c->_currentSp == -1) ? 39 : c->_currentSpell; + int spellId = SPELLS_ALLOWED[category][spellIndex]; + screen._windows[10].writeString(Common::String::format(SPELL_DETAILS, + spells._spellNames[spellId].c_str(), + spells.calcSpellPoints(spellId, c->getCurrentLevel()), + SPELL_GEM_COST[spellId], c->_currentSp)); + } + + drawButtons(&screen); + screen._windows[10].update(); + } + } + break; + + case Common::KEYCODE_RETURN: + case Common::KEYCODE_KP_ENTER: + case Common::KEYCODE_s: + if (selection != -1) + _buttonValue = Common::KEYCODE_ESCAPE; + break; + + case Common::KEYCODE_ESCAPE: + selection = -1; + _buttonValue = Common::KEYCODE_ESCAPE; + break; + + case Common::KEYCODE_0: + 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: + newSelection = topIndex + (_buttonValue == Common::KEYCODE_0) ? 9 : + (_buttonValue - Common::KEYCODE_1); + + if (newSelection < (int)_spells.size()) { + int expenseFactor = 0; + int category = 0; + + switch (c->_class) { + case CLASS_PALADIN: + expenseFactor = 1; + category = 0; + break; + case CLASS_ARCHER: + expenseFactor = 1; + category = 1; + break; + case CLASS_CLERIC: + category = 0; + break; + case CLASS_SORCERER: + category = 1; + break; + case CLASS_DRUID: + category = 2; + break; + case CLASS_RANGER: + expenseFactor = 1; + category = 2; + break; + default: + break; + } + + int spellId = _spells[newSelection]._spellId; + int spellIndex = _spells[newSelection]._spellIndex; + int spellCost = spells.calcSpellCost(spellId, expenseFactor); + if (v2) { + // TODO: Confirm this refactoring against against original + selection = _buttonValue; + } else { + Common::String spellName = _spells[_buttonValue]._name; + Common::String msg = (v2Copy & 0x80) ? + Common::String::format(SPELLS_PRESS_A_KEY, msg.c_str()) : + Common::String::format(SPELLS_PURCHASE, msg.c_str(), spellCost); + + if (ConfirmDialog::show(_vm, msg, v2Copy + 1)) { + if (party.subtract(0, spellCost, 0, WT_FREEZE_WAIT)) { + ++c->_spells[spellIndex]; + sound.playSample(nullptr, 0); + intf._overallFrame = 0; + File f(isDarkCc ? "guild12.voc" : "parrot2.voc"); + sound.playSample(&f, 1); + } else { + sound.playFX(21); + } + } + } + } + break; + + case Common::KEYCODE_PAGEUP: + case Common::KEYCODE_KP9: + topIndex = MAX(topIndex - 10, 0); + break; + + case Common::KEYCODE_PAGEDOWN: + case Common::KEYCODE_KP3: + topIndex = MIN(topIndex + 10, (((int)_spells.size() - 1) / 10) * 10); + break; + + case Common::KEYCODE_UP: + case Common::KEYCODE_KP8: + if (topIndex > 0) + --topIndex; + break; + + case Common::KEYCODE_DOWN: + case Common::KEYCODE_KP2: + if (topIndex < ((int)_spells.size() - 10)) + ++topIndex; + break; + } + } + + screen._windows[25].close(); + if (v2 && selection != -1) + c->_currentSpell = _spells[selection]._spellIndex; + + return c; +} + +void SpellsScroll::loadButtons() { + _iconSprites.load("main.icn"); + _scrollSprites.load("scroll.icn"); + addButton(Common::Rect(187, 26, 198, 36), Common::KEYCODE_UP, &_scrollSprites, true); + addButton(Common::Rect(187, 111, 198, 121), Common::KEYCODE_DOWN, &_scrollSprites, true); + addButton(Common::Rect(40, 28, 187, 36), Common::KEYCODE_1, &_scrollSprites, false); + addButton(Common::Rect(40, 37, 187, 45), Common::KEYCODE_2, &_scrollSprites, false); + addButton(Common::Rect(40, 46, 187, 54), Common::KEYCODE_3, &_scrollSprites, false); + addButton(Common::Rect(40, 55, 187, 63), Common::KEYCODE_4, &_scrollSprites, false); + addButton(Common::Rect(40, 64, 187, 72), Common::KEYCODE_5, &_scrollSprites, false); + addButton(Common::Rect(40, 73, 187, 81), Common::KEYCODE_6, &_scrollSprites, false); + addButton(Common::Rect(40, 82, 187, 90), Common::KEYCODE_7, &_scrollSprites, false); + addButton(Common::Rect(40, 91, 187, 99), Common::KEYCODE_8, &_scrollSprites, false); + addButton(Common::Rect(40, 100, 187, 108), Common::KEYCODE_9, &_scrollSprites, false); + addButton(Common::Rect(40, 109, 187, 117), Common::KEYCODE_0, &_scrollSprites, false); + addButton(Common::Rect(174, 123, 198, 133), Common::KEYCODE_ESCAPE, &_scrollSprites, false); + addButton(Common::Rect(187, 35, 198, 73), Common::KEYCODE_PAGEUP, &_scrollSprites, false); + addButton(Common::Rect(187, 74, 198, 112), Common::KEYCODE_PAGEDOWN, &_scrollSprites, false); + addButton(Common::Rect(132, 123, 168, 133), Common::KEYCODE_s, &_scrollSprites, false); +} + +const char *SpellsScroll::setSpellText(Character *c, int v2) { + Party &party = *_vm->_party; + Spells &spells = *_vm->_spells; + bool isDarkCc = _vm->_files->_isDarkCc; + int expenseFactor = 0; + int currLevel = c->getCurrentLevel(); + int category; + + if ((v2 & 0x7f) == 0) { + switch (c->_class) { + case CLASS_PALADIN: + expenseFactor = 1; + category = 0; + break; + case CLASS_ARCHER: + expenseFactor = 1; + category = 1; + break; + case CLASS_CLERIC: + category = 0; + break; + case CLASS_SORCERER: + category = 1; + break; + case CLASS_DRUID: + category = 2; + break; + case CLASS_RANGER: + expenseFactor = 1; + category = 2; + break; + default: + category = -1; + break; + } + + if (category != -1) { + if (party._mazeId == 49 || party._mazeId == 37) { + for (int spellId = 0; spellId < 76; ++spellId) { + int idx = 0; + while (idx < MAX_SPELLS_PER_CLASS && SPELLS_ALLOWED[category][idx] == spellId) + ++idx; + + // Handling if the spell is appropriate for the character's class + if (idx < MAX_SPELLS_PER_CLASS) { + if (!c->_spells[idx] || (v2 & 0x80)) { + int cost = spells.calcSpellCost(SPELLS_ALLOWED[category][idx], expenseFactor); + _spells.push_back(SpellEntry(Common::String::format("\x3l%s\x3r\x9""000%u", + spells._spellNames[SPELLS_ALLOWED[category][idx]], cost), + idx, spellId)); + } + } + } + } else if (isDarkCc) { + int groupIndex = (party._mazeId - 29) / 2; + for (int spellId = DARK_SPELL_RANGES[category][0]; + spellId < DARK_SPELL_RANGES[category][1]; ++spellId) { + int idx = 0; + while (idx < 40 && SPELLS_ALLOWED[category][idx] == + DARK_SPELL_OFFSETS[category][spellId]); + + if (idx < 40) { + if (!c->_spells[idx] || (v2 & 0x80)) { + int cost = spells.calcSpellCost(SPELLS_ALLOWED[category][idx], expenseFactor); + _spells.push_back(SpellEntry(Common::String::format("\x3l%s\x3r\x9""000%u", + spells._spellNames[SPELLS_ALLOWED[category][idx]], cost), + idx, spellId)); + } + } + } + } else { + for (int spellId = 0; spellId < 20; ++spellId) { + int idx = 0; + while (CLOUDS_SPELL_OFFSETS[party._mazeId - 29][spellId] != + SPELLS_ALLOWED[category][idx] && idx < 40) ; + + if (idx < 40) { + if (!c->_spells[idx] || (v2 & 0x80)) { + int cost = spells.calcSpellCost(SPELLS_ALLOWED[category][idx], expenseFactor); + _spells.push_back(SpellEntry(Common::String::format("\x3l%s\x3r\x9""000%u", + spells._spellNames[SPELLS_ALLOWED[category][idx]], cost), + idx, spellId)); + } + } + } + } + } + + if (c->getMaxSP() == 0) + return NOT_A_SPELL_CASTER; + + } else if ((v2 & 0x7f) == 1) { + switch (c->_class) { + case 0: + case 12: + category = 0; + break; + case 1: + case 3: + category = 1; + break; + case 7: + case 8: + category = 2; + break; + default: + category = 0; + break; + } + + if (c->getMaxSP() == 0) { + return NOT_A_SPELL_CASTER; + } else { + for (int spellIndex = 0; spellIndex < (MAX_SPELLS_PER_CLASS - 1); ++spellIndex) { + if (c->_spells[spellIndex]) { + int spellId = SPELLS_ALLOWED[category][spellIndex]; + int gemCost = SPELL_GEM_COST[spellId]; + int spCost = spells.calcSpellPoints(spellId, currLevel); + + Common::String msg = Common::String::format("\x3l%s\x3r\x9""000%u/%u", + spells._spellNames[spellId].c_str(), spCost, gemCost); + _spells.push_back(SpellEntry(msg, spellIndex, spellId)); + } + } + } + } + + return nullptr; +} + +} // End of namespace Xeen diff --git a/engines/xeen/dialogs_spells.h b/engines/xeen/dialogs_spells.h new file mode 100644 index 0000000000..69e339fa79 --- /dev/null +++ b/engines/xeen/dialogs_spells.h @@ -0,0 +1,61 @@ +/* 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. + * + */ + +#ifndef XEEN_DIALOGS_SPELLS_H +#define XEEN_DIALOGS_SPELLS_H + +#include "common/array.h" +#include "xeen/dialogs.h" +#include "xeen/party.h" + +namespace Xeen { + +struct SpellEntry { + Common::String _name; + int _spellIndex; + int _spellId; + + SpellEntry(const Common::String &name, int spellIndex, int spellId) : + _name(name), _spellIndex(spellIndex), _spellId(spellId) {} +}; + +class SpellsScroll : public ButtonContainer { +private: + XeenEngine *_vm; + SpriteResource _iconSprites; + SpriteResource _scrollSprites; + Common::Array _spells; + + SpellsScroll(XeenEngine *vm) : ButtonContainer(), _vm(vm) {} + + Character *execute(Character *c, int v2); + + void loadButtons(); + + const char *setSpellText(Character *c, int v2); +public: + static Character *show(XeenEngine *vm, Character *c, int v2); +}; + +} // End of namespace Xeen + +#endif /* XEEN_DIALOGS_SPELLS_H */ diff --git a/engines/xeen/dialogs_yesno.cpp b/engines/xeen/dialogs_yesno.cpp index 8ea27ebd6c..17ca9a0c3e 100644 --- a/engines/xeen/dialogs_yesno.cpp +++ b/engines/xeen/dialogs_yesno.cpp @@ -25,9 +25,9 @@ namespace Xeen { -bool YesNo::show(XeenEngine *vm, bool type, bool v2) { +bool YesNo::show(XeenEngine *vm, bool type, bool townFlag) { YesNo *dlg = new YesNo(vm); - bool result = dlg->execute(type, v2); + bool result = dlg->execute(type, townFlag); delete dlg; return result; diff --git a/engines/xeen/module.mk b/engines/xeen/module.mk index 9d252b14c2..be951239d3 100644 --- a/engines/xeen/module.mk +++ b/engines/xeen/module.mk @@ -8,6 +8,7 @@ MODULE_OBJS := \ debugger.o \ detection.o \ dialogs.o \ + dialogs_confirm.o \ dialogs_error.o \ dialogs_options.o \ dialogs_input.o \ diff --git a/engines/xeen/party.cpp b/engines/xeen/party.cpp index 2138ca6154..66078b67e8 100644 --- a/engines/xeen/party.cpp +++ b/engines/xeen/party.cpp @@ -1218,4 +1218,70 @@ void Party::handleLight() { (map.mazeData()._mazeFlags2 & FLAG_IS_DARK) == 0 ? 4 : 0; } +int Party::subtract(int mode, uint amount, int whereId, ErrorWaitType wait) { + switch (mode) { + case 0: + // Gold + if (whereId) { + if (amount <= _bankGold) { + _bankGold -= amount; + } else { + notEnough(0, whereId, false, wait); + return false; + } + } + else { + if (amount <= _gold) { + _gold -= amount; + } else { + notEnough(0, whereId, false, wait); + return false; + } + } + break; + + case 1: + // Gems + if (whereId) { + if (amount <= _bankGems) { + _bankGems -= amount; + } else { + notEnough(0, whereId, false, wait); + return false; + } + } + else { + if (amount <= _gems) { + _gems -= amount; + } else { + notEnough(0, whereId, false, wait); + return false; + } + } + break; + + case 2: + // Food + if (amount > _food) { + _food -= amount; + } else { + notEnough(5, 0, 0, wait); + return false; + } + break; + + default: + break; + } + + return true; +} + +void Party::notEnough(int consumableId, int whereId, bool mode, ErrorWaitType wait) { + Common::String msg = Common::String::format( + mode ? NO_X_IN_THE_Y : NOT_ENOUGH_X_IN_THE_Y, + CONSUMABLE_NAMES[consumableId], WHERE_NAMES[whereId]); + ErrorScroll::show(_vm, msg, wait); +} + } // End of namespace Xeen diff --git a/engines/xeen/party.h b/engines/xeen/party.h index 035e76c098..e00b42476a 100644 --- a/engines/xeen/party.h +++ b/engines/xeen/party.h @@ -28,6 +28,7 @@ #include "common/rect.h" #include "common/serializer.h" #include "xeen/combat.h" +#include "xeen/dialogs_error.h" #include "xeen/items.h" namespace Xeen { @@ -274,6 +275,10 @@ public: void resetTemps(); void handleLight(); + + int subtract(int mode, uint amount, int whereId, ErrorWaitType wait); + + void notEnough(int consumableId, int whereId, bool mode, ErrorWaitType wait); }; } // End of namespace Xeen diff --git a/engines/xeen/resources.cpp b/engines/xeen/resources.cpp index 57e16d74d0..ed304dc9e1 100644 --- a/engines/xeen/resources.cpp +++ b/engines/xeen/resources.cpp @@ -492,7 +492,7 @@ const int MONSTER_EFFECT_FLAGS[15][8] = { { 0x108, 0x108, 0x108, 0x108, 0x108, 0x108, 0x108, 0x108 } }; -const uint SPELLS_ALLOWED[3][40] = { +const int SPELLS_ALLOWED[3][40] = { { 0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 12, 14, 16, 23, 26, 27, 28, 30, 31, 32, @@ -781,6 +781,49 @@ const int SPELL_GEM_COST[77] = { 5, 0, 0, 0, 0, 5, 1, 2, 0, 2, 0 }; -extern const char *NOT_A_SPELL_CASTER = "Not a spell caster..."; +const char *const NOT_A_SPELL_CASTER = "Not a spell caster..."; + +const char *const SPELLS_FOR = "\xD\xC""d%s\x2\x3""c\x9""000\xB""002Spells for %s"; + +const char *const SPELL_LINES_0_TO_9 = + "\x2\x3l\xB""015\x9""0011\n2\n3\n4\n5\n6\n7\n8\n9\n0"; + +const char *const SPELLS_DIALOG_SPELLS = "\x3l\xB""015" + "\x9""010\xC""%2u%s\xC""d\x3l\n" + "\x9""010\xC""%2u%s\xC""d\x3l\n" + "\x9""010\xC""%2u%s\xC""d\x3l\n" + "\x9""010\xC""%2u%s\xC""d\x3l\n" + "\x9""010\xC""%2u%s\xC""d\x3l\n" + "\x9""010\xC""%2u%s\xC""d\x3l\n" + "\x9""010\xC""%2u%s\xC""d\x3l\n" + "\x9""010\xC""%2u%s\xC""d\x3l\n" + "\x9""010\xC""%2u%s\xC""d\x3l\n" + "\x9""010\xC""%2u%s\xC""d\x3l" + "\x9""004\xB""110%s - %lu\x1"; + +const char *const SPELL_PTS = "Spell Pts"; + +const char *const GOLD = "Gold"; + +const char *const SPELLS_PRESS_A_KEY = + "\x3""c\xC""09%s\xC""d\x3l\n" + "\n" + "%s\x3""c\x9""000\xB""100Press a Key!"; + +const char *const SPELLS_PURCHASE = + "\x3l\xB""000\x9""000\xC""d%s Do you wish to purchase " + "\xC""09%s\xC""d for %u?"; + +const char *const SPELL_DETAILS = +"\xD\x2\x3""c\xB""122\x9""013\xC""37C\xC""dast" +"\x9""040\xC""37N\xC""dew\x9""067ESC\x1""000\xB""000\x3""cCast Spell\n" +"\n" +"%s\x3l\n" +"\n" +"Spell Ready:\x3""c\n" +"\n" +"\xC""09%s\xC""d\x2\x3l\n" +"\xB""082Cost\x3r\x9""000%u/%u\x3l\n" +"Cur SP\x3r\x9""000%u\x1"; } // End of namespace Xeen diff --git a/engines/xeen/resources.h b/engines/xeen/resources.h index 60f4848c00..37afb2cc76 100644 --- a/engines/xeen/resources.h +++ b/engines/xeen/resources.h @@ -124,7 +124,7 @@ extern const int COMBAT_FLOAT_Y[8]; extern const int MONSTER_EFFECT_FLAGS[15][8]; -extern const uint SPELLS_ALLOWED[3][40]; +extern const int SPELLS_ALLOWED[3][40]; extern const int BASE_HP_BY_CLASS[10]; @@ -226,7 +226,23 @@ extern const int SPELL_LEVEL_OFFSETS[3][39]; extern const int SPELL_GEM_COST[77]; -extern const char *NOT_A_SPELL_CASTER; +extern const char *const NOT_A_SPELL_CASTER; + +extern const char *const SPELLS_FOR; + +extern const char *const SPELL_LINES_0_TO_9; + +extern const char *const SPELLS_DIALOG_SPELLS; + +extern const char *const SPELL_PTS; + +extern const char *const GOLD; + +extern const char *const SPELLS_PRESS_A_KEY; + +extern const char *const SPELLS_PURCHASE; + +extern const char *const SPELL_DETAILS; } // End of namespace Xeen diff --git a/engines/xeen/spells.cpp b/engines/xeen/spells.cpp index 922f6fcb84..588fa1b510 100644 --- a/engines/xeen/spells.cpp +++ b/engines/xeen/spells.cpp @@ -28,6 +28,8 @@ namespace Xeen { Spells::Spells(XeenEngine *vm) : _vm(vm) { + _lastCaster = 0; + load(); } diff --git a/engines/xeen/spells.h b/engines/xeen/spells.h index 97e3c80bba..96f491684e 100644 --- a/engines/xeen/spells.h +++ b/engines/xeen/spells.h @@ -40,6 +40,7 @@ private: public: Common::StringArray _spellNames; Common::StringArray _maeNames; + int _lastCaster; public: Spells(XeenEngine *vm); diff --git a/engines/xeen/town.cpp b/engines/xeen/town.cpp index d773f6d4f2..2f31113146 100644 --- a/engines/xeen/town.cpp +++ b/engines/xeen/town.cpp @@ -606,7 +606,7 @@ Character *Town::doTavernOptions(Character *c) { case Common::KEYCODE_d: // Drink if (!c->noActions()) { - if (subtract(0, 1, 0, WT_2)) { + if (party.subtract(0, 1, 0, WT_2)) { sound.playSample(nullptr, 0); File f("gulp.voc"); sound.playSample(&f, 0); @@ -664,7 +664,7 @@ Character *Town::doTavernOptions(Character *c) { if (YesNo::show(_vm, false, true)) { if (party._food >= _v22) { ErrorScroll::show(_vm, FOOD_PACKS_FULL, WT_2); - } else if (subtract(0, _v23, 0, WT_2)) { + } else if (party.subtract(0, _v23, 0, WT_2)) { party._food = _v22; sound.playSample(nullptr, 0); File f(isDarkCc ? "thanks2.voc" : "thankyou.voc"); @@ -744,7 +744,7 @@ Character *Town::doTavernOptions(Character *c) { drawButtons(&screen); screen._windows[10].update(); townWait(); - } else if (subtract(0, 1, 0, WT_2)) { + } else if (party.subtract(0, 1, 0, WT_2)) { sound.playSample(nullptr, 0); File f(isDarkCc ? "thanks2.voc" : "thankyou.voc"); sound.playSample(&f, 1); @@ -805,7 +805,7 @@ Character *Town::doTempleOptions(Character *c) { break; case Common::KEYCODE_d: - if (_donation && subtract(0, _donation, 0, WT_2)) { + if (_donation && party.subtract(0, _donation, 0, WT_2)) { sound.playSample(nullptr, 0); File f("coina.voc"); sound.playSample(&f, 1); @@ -832,7 +832,7 @@ Character *Town::doTempleOptions(Character *c) { break; case Common::KEYCODE_h: - if (_healCost && subtract(0, _healCost, 0, WT_2)) { + if (_healCost && party.subtract(0, _healCost, 0, WT_2)) { c->_magicResistence._temporary = 0; c->_energyResistence._temporary = 0; c->_poisonResistence._temporary = 0; @@ -860,7 +860,7 @@ Character *Town::doTempleOptions(Character *c) { break; case Common::KEYCODE_u: - if (_uncurseCost && subtract(0, _uncurseCost, 0, WT_2)) { + if (_uncurseCost && party.subtract(0, _uncurseCost, 0, WT_2)) { for (int idx = 0; idx < 9; ++idx) { c->_weapons[idx]._bonusFlags &= ~FLAG_CURSED; c->_armor[idx]._bonusFlags &= ~FLAG_CURSED; @@ -921,7 +921,7 @@ Character *Town::doTrainingOptions(Character *c) { sound.playSample(&f); } else if (!c->noActions()) { - if (subtract(0, (c->_level._permanent * c->_level._permanent) * 10, 0, WT_2)) { + if (party.subtract(0, (c->_level._permanent * c->_level._permanent) * 10, 0, WT_2)) { _drawFrameIndex = 0; sound.playSample(nullptr, 0); File f(isDarkCc ? "prtygd.voc" : "trainin2.voc"); @@ -1003,14 +1003,14 @@ void Town::depositWithdrawl(int choice) { (choice && !party._bankGold && !flag) || (!choice && !party._gems && flag) || (!choice && !party._gold && !flag)) { - notEnough(flag, choice, 1, WT_2); + party.notEnough(flag, choice, 1, WT_2); } else { screen._windows[35].writeString(AMOUNT); int amount = NumericInput::show(_vm, 35, 10, 77); if (amount) { if (flag) { - if (subtract(true, amount, choice, WT_2)) { + if (party.subtract(true, amount, choice, WT_2)) { if (choice) { party._gems += amount; } else { @@ -1018,7 +1018,7 @@ void Town::depositWithdrawl(int choice) { } } } else { - if (subtract(false, amount, choice, WT_2)) { + if (party.subtract(false, amount, choice, WT_2)) { if (choice) { party._gold += amount; } else { @@ -1053,72 +1053,6 @@ void Town::depositWithdrawl(int choice) { _buttons[2]._value = Common::KEYCODE_ESCAPE; } -void Town::notEnough(int consumableId, int whereId, bool mode, ErrorWaitType wait) { - Common::String msg = Common::String::format( - mode ? NO_X_IN_THE_Y : NOT_ENOUGH_X_IN_THE_Y, - CONSUMABLE_NAMES[consumableId], WHERE_NAMES[whereId]); - ErrorScroll::show(_vm, msg, wait); -} - -int Town::subtract(int mode, uint amount, int whereId, ErrorWaitType wait) { - Party &party = *_vm->_party; - - switch (mode) { - case 0: - // Gold - if (whereId) { - if (amount <= party._bankGold) { - party._bankGold -= amount; - } else { - notEnough(0, whereId, false, wait); - return false; - } - } else { - if (amount <= party._gold) { - party._gold -= amount; - } else { - notEnough(0, whereId, false, wait); - return false; - } - } - break; - - case 1: - // Gems - if (whereId) { - if (amount <= party._bankGems) { - party._bankGems -= amount; - } else { - notEnough(0, whereId, false, wait); - return false; - } - } else { - if (amount <= party._gems) { - party._gems -= amount; - } else { - notEnough(0, whereId, false, wait); - return false; - } - } - break; - - case 2: - // Food - if (amount > party._food) { - party._food -= amount; - } else { - notEnough(5, 0, 0, wait); - return false; - } - break; - - default: - break; - } - - return true; -} - void Town::drawTownAnim(bool flag) { Interface &intf = *_vm->_interface; Screen &screen = *_vm->_screen; diff --git a/engines/xeen/town.h b/engines/xeen/town.h index 27b1fe2121..8237f8102e 100644 --- a/engines/xeen/town.h +++ b/engines/xeen/town.h @@ -96,10 +96,6 @@ private: void depositWithdrawl(int choice); - void notEnough(int consumableId, int whereId, bool mode, ErrorWaitType wait); - - int subtract(int mode, uint amount, int whereId, ErrorWaitType wait); - Character *showItems(Character *c, int v2); public: Town(XeenEngine *vm); -- cgit v1.2.3