Memorization now lists all spells in all carried books (minus spells which are already memorized or which can never be memorized because of the player's species), sorted by easy of memorization.
Miscast effects from failing to memorize from out of the Necronomicon, the book of Demonology and the book of Annihilations is commented out, pending figuring out how to do it with the new interface.
Spells which can't be memorized because of the player's species are highlighted as light red when reading a spell book, and a note is added when describing the spell.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@9883 c06c8d41-db1a-0410-9941-cceddc491573
4NNN5LKBZLDXMDN2322PBG7WFHF4TWOEMVODSO7BXXCM3AZKQN4QC
FSKFHQL6PYT4TTQEA2HQDRZVQFID32TLX25JNJAMB32LNJP3DPTAC
ZCSO4HPSQOVAOPCF3QBRAFHHS6QP65LVRZ4WE3E4IMCGGDTDIOOQC
A43NYENITQ3BRLUMCFT3T5CM2NFXCIDRX7OCMEAXXGNTJIDDS6YQC
4QE4GYRBDR2URCA7UE7TSRBYYMWM3ZBD4PSZGOVTTHC2GON52V3QC
GCQMZPKM43XL26VMLDG4CSCEGQCCPOS3VG6VVMBVWBWRQX45EISQC
FCL7KOWXA5O3GLMDR22JCGMTHMZ57C4WQIJKBIIUQV3LI2CI3X7AC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
DWQDVEHZSTDVFS2GU24ZLIGJDA3M4767TB734JAQEAUVOOCLZ75AC
76XAPPSY2BXXT7AC45TNI7DL7AP6242DXC45CDIZ6T3RN4ZI3R4AC
JCWJWGMQIKQGSSFJUQRKNIWW3HBOJSHYDTOPPE5BWOJTIJTDYUTAC
SVY2PTCLXR3KNPQAWXVXTTGCC5DR334HOAKHYO3VDDRWM2BWMALAC
BFCFMN2BXNLXJCYYCL2V2XTDQQNM3PJPSRB6CU76FM3332NC7GMAC
FOQJ5S5WR7P7YMEWQ5Q4O7LTGLQ7LFVM4I2SG2Q7MIVC4PB2JHTQC
TRZAZJJA5VQBJ65SO5H5DNSILIZEJHIZCBYEBHEATCT6ZSMWIFKQC
FWNNTOEERPUKXPE4OC52UABFZLKIU3O5GRNNLDK4QI4HR2IOU36QC
S34LKQDIQJLIWVIPASOJBBZ6ZCXDHP5KPS7TRBZJSCDRVNCLK6UAC
SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
KNO4TZR76DMOYJCF24PSVQW7FUZOTMOJTL7I7J74SM4IHOGDX6TAC
25VJTGR3AWZJ7OHKYWS53VJ6TVMMU6UT7BA6V3QVVWDGI6FYKD7QC
UEI5JAVCMN7Y2SACTEZPZSNFJWOJTC55G24Q6LKQCT4XNDH5ZQIAC
YCL3W2PFE6ILTGBFODCSXNPDIA46KVSZP2TI7HDMYAOEJT65RIEAC
LG6R5CQGJY6FYJC4F7NY7MJYJMVXDZ4BFZZ6N4P5JA5EOK72JWZQC
BWAQ3FHBBM6G3K3KYP75CRTR343RDQZJRYX5ZGYUEXYBAC3APDLAC
KZIHM6RUX43HHKXG6HGJHVEEYUPVVNBFIWMT4SKPD2GAH5ZMA3KAC
KNCEMOC5TMWHTKCWF7CMYNHLGCXOLGMTXLEIHMEFBGM5FR26GRXAC
ASLW3Z5PAVZSWJEMMMVZT226P44EKSAD47QS72JIFJESAI3RPN3AC
Z6XF4AIERIW4U4AR3HU2ILYFZ54IK4K4ORQ6JKCEWRO5LZODWDDAC
7VCVH6XKT4L4PSCBF6XRYV3WQQDVGDMA73RHPV6IOWMQ2S7B5XAQC
SR63JKG2P3RFZPY4CCMS4M6RZWUPKOQ4KAQN2JD6WKZLF3S6V3GAC
R7TUO3AXCHGFSVHHXDNGAAXLWSNY7L4T5D7LOPQILBHGFDA3KFNAC
I2B33Z7NZGC33AMDSSK446AZZYWKPHWLAGULVHKKZU4MVB4BNJOAC
46MRRHVYJ3BS74R2BEVUWEWJCI4FCRBSLZ3NWMQCE6FUCNE5P73QC
IU2CR2KXWJ6QGCVGNCXUWKK2HDUYYVR5IU4D65WVPLV7KWS6PASAC
OLMTUY4KVSPRWQKIOLSIYRAUEVJLRDJV7CCXJRW7IKWGUHSNRZTAC
HY573GOUSHODH7XGW32XONKRBHSDKL7AC2DENXQDQS7TYNEPUR2AC
S6ADNAPM545WP3FRHCU6UWKX5VEMY5TPSIZYSZ3XE76VCBTVIN5QC
OBWENTR55T5IGFMLKDJUJ6QEL3R6TGPBY7DF36YAWU2W6UHZ5TZAC
FEKRY3DYIDLWVBLAZN7W2WFNEKZPCAHABXOSM6K5RLTH5WY2NODQC
bool already = false;
for (int i = 0; i <= SPTYP_LAST_EXPONENT; ++i)
{
if (spell_typematch(spell, (1<<i)))
{
if (already)
desc << '/';
desc << spelltype_name(1 << i);
already = true;
}
}
desc << spell_schools_string(spell);
std::string spell_schools_string(spell_type spell)
{
std::string desc;
bool already = false;
for (int i = 0; i <= SPTYP_LAST_EXPONENT; ++i)
{
if (spell_typematch(spell, (1<<i)))
{
if (already)
desc += "/";
desc += spelltype_name(1 << i);
already = true;
}
}
return (desc);
}
break;
case RBOOK_MEMORISE:
out.cprintf( "Select a spell to memorise (%d level%s available)." EOL,
spell_levels, (spell_levels == 1) ? "" : "s" );
static int _which_spellbook( void )
{
int book = -1;
const int avail_levels = player_spell_levels();
// Knowing delayed fireball will allow Fireball to be learned for free -bwr
if (avail_levels < 1 && !player_has_spell(SPELL_DELAYED_FIREBALL))
{
mpr("You can't memorise any more spells yet.");
return (-1);
}
else if (inv_count() < 1)
{
canned_msg(MSG_NOTHING_CARRIED);
return (-1);
}
mprf("You can memorise %d more level%s of spells.",
avail_levels, (avail_levels > 1) ? "s" : "" );
book = prompt_invent_item("Memorise from which spellbook?", MT_INVLIST,
OSEL_MEMORISE );
if (prompt_failed(book))
return (-1);
if (you.inv[book].base_type != OBJ_BOOKS
|| you.inv[book].sub_type == BOOK_MANUAL)
{
mpr("That isn't a spellbook!");
return (-1);
}
if (you.inv[book].sub_type == BOOK_DESTRUCTION)
{
tome_of_power( book );
return (-1);
}
return (book);
}
if (player_in_bat_form())
std::set<spell_type> all_spells;
std::vector<spell_type> mem_spells;
bool book_errors = false;
int num_books = 0;
int num_unreadable = 0;
// Collect the list of all spells in all available spellbooks.
for (int i = 0; i < ENDOFPACK; i++)
if (j == 0)
int spells_in_book = 0;
for (int j = 0; j < SPELLBOOK_SIZE; j++)
{
if (!is_valid_spell_in_book(book, j))
continue;
all_spells.insert(which_spell_in_book(book, j));
spells_in_book++;
}
if (spells_in_book == 0)
{
mprf(MSGCH_ERROR, "Spellbook \"%s\" contains no spells! Please "
"file a bug report.", book.name(DESC_PLAIN).c_str());
book_errors = true;
}
}
if (book_errors)
more();
if (num_books == 0)
mpr("You can't use spell magic! I'm afraid it's scrolls only for now.");
return (false);
mpr("You aren't carrying any spellbooks.", MSGCH_PROMPT);
return (mem_spells);
}
else if (num_unreadable == num_books)
{
mpr("All of the spellbooks you're carrying are beyond your "
"current level of comprehension.", MSGCH_PROMPT);
return (mem_spells);
}
else if (all_spells.size() == 0)
{
mpr("None of the spellbooks you are carrying contain any spells.",
MSGCH_PROMPT);
return (mem_spells);
if (you.confused())
unsigned int num_known = 0;
unsigned int num_race = 0;
unsigned int num_low_xl = 0;
unsigned int num_low_levels = 0;
unsigned int num_memable = 0;
bool amnesia = false;
for (std::set<spell_type>::iterator i = all_spells.begin();
i != all_spells.end(); ++i)
mpr("You are too confused!");
return (false);
const spell_type spell = *i;
if (player_knows_spell(spell))
num_known++;
else if (you_cannot_memorise(spell))
num_race++;
else
{
mem_spells.push_back(spell);
if (spell_difficulty(spell) > you.experience_level)
num_low_xl++;
else if (player_spell_levels() < spell_levels_required(spell))
num_low_levels++;
else
{
if (spell == SPELL_SELECTIVE_AMNESIA)
amnesia = true;
num_memable++;
}
}
if (book < 0)
book = _which_spellbook();
if (num_memable)
return (mem_spells);
// No spells to be memorized is indicated by an empty list.
mem_spells.clear();
// None of the spells can be memorized, tell the player why.
std::string prefix =
make_stringf("You cannot memorize any new spells. Out of %u "
"available spells ", all_spells.size());
std::vector<std::string> causes;
if (num_known)
causes.push_back(make_stringf("you already known %u of them",
num_known));
if (num_race)
causes.push_back(make_stringf("%u cannot be memorized because of "
"your race", num_race));
if (num_low_xl)
causes.push_back(make_stringf("%u cannot be memorized because of "
"your low experinece level",
num_low_xl));
if (num_low_levels)
causes.push_back(make_stringf("%u cannot be memorized because you "
"don't have enough free spell levels",
num_low_levels));
unsigned int total = num_known + num_race + num_low_xl + num_low_levels;
if (total < all_spells.size())
causes.push_back(make_stringf("%u cannot be accounted for (please "
"file a bug report)",
all_spells.size() - total));
mpr_comma_separated_list(prefix, causes, ", and ", ", ", MSGCH_PROMPT);
if (book < 0) // still -1?
return (false);
if (num_unreadable)
mprf(MSGCH_PROMPT, "Additionally, %d of your spellbooks are beyond "
"your current level of understanding, and thus none of the "
"spells in them are avaible to you.");
return (mem_spells);
}
static bool _sort_mem_spells(spell_type a, spell_type b)
{
if (spell_fail(a) != spell_fail(b))
return (spell_fail(a) < spell_fail(b));
if (spell_difficulty(a) != spell_difficulty(b))
return (spell_difficulty(a) < spell_difficulty(b));
canned_msg( MSG_HUH );
return (false);
const spell_type spell = spells[i];
const bool grey = spell_difficulty(spell) > you.experience_level
|| player_spell_levels() < spell_levels_required(spell);
std::ostringstream desc;
if (grey)
desc << "<darkgrey>";
desc << std::left;
desc << std::setw(30) << spell_title(spell);
desc << spell_schools_string(spell);
int so_far = desc.str().length() - (grey ? 10 : 0);
if (so_far < 60)
desc << std::string(60 - so_far, ' ');
desc << std::setw(12) << failure_rate_to_string(spell_fail(spell))
<< spell_difficulty(spell);
if (grey)
desc << "</darkgrey>";
MenuEntry* me = new MenuEntry(desc.str(), MEL_ITEM, 1,
index_to_letter(i % 52));
me->data = (void*) i;
spell_menu.add_entry(me);
if (index >= SPELLBOOK_SIZE
|| !is_valid_spell_in_book( you.inv[book], index ))
if (!crawl_state.doing_prev_cmd_again)
redraw_screen();
if (sel.empty())
return (SPELL_NO_SPELL);
ASSERT(sel.size() == 1);
const spell_type spell = spells[(int) sel[0]->data];
ASSERT(is_valid_spell(spell));
return (spell);
}
}
bool learn_spell()
{
if (player_in_bat_form())
if (you_cannot_memorise(specspell))
{
mpr("You cannot use this spell.");
std::vector<spell_type> spell_list = _get_mem_list();
if (spell_list.empty())
OSEL_MEMORISE = -5,
OSEL_RECHARGE = -6,
OSEL_ENCH_ARM = -7,
OSEL_VAMP_EAT = -8,
OSEL_DRAW_DECK = -9,
OSEL_THROWABLE = -10,
OSEL_BUTCHERY = -11,
OSEL_EVOKABLE = -12,
OSEL_WORN_ARMOUR = -13
OSEL_RECHARGE = -5,
OSEL_ENCH_ARM = -6,
OSEL_VAMP_EAT = -7,
OSEL_DRAW_DECK = -8,
OSEL_THROWABLE = -9,
OSEL_BUTCHERY = -10,
OSEL_EVOKABLE = -11,
OSEL_WORN_ARMOUR = -12