scummvm/engines/xeen/dialogs_spells.cpp

417 lines
13 KiB
C++
Raw Normal View History

/* 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_query.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;
uint 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:
2015-02-07 21:17:31 -05:00
if (_vm->_mode != MODE_COMBAT) {
_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 (Confirm::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((int)topIndex - 10, 0);
break;
case Common::KEYCODE_PAGEDOWN:
case Common::KEYCODE_KP3:
topIndex = MIN(topIndex + 10, ((_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 < (_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 (uint 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[groupIndex][0];
spellId < DARK_SPELL_RANGES[groupIndex][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] !=
(int)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