Revert "Track who destroys an item; incur Nemelex penance for deck destruction."
[crawl.git] / crawl-ref / source / spl-book.cc
1 /**
2  * @file
3  * @brief Spellbook/rod contents array and management functions
4 **/
5
6 #include "AppHdr.h"
7
8 #include "spl-book.h"
9
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <algorithm>
14 #include <iomanip>
15
16 #include "artefact.h"
17 #include "cio.h"
18 #include "colour.h"
19 #include "database.h"
20 #include "delay.h"
21 #include "describe.h"
22 #include "effects.h"
23 #include "externs.h"
24 #include "food.h"
25 #include "format.h"
26 #include "godconduct.h"
27 #include "goditem.h"
28 #include "hints.h"
29 #include "invent.h"
30 #include "itemname.h"
31 #include "itemprop.h"
32 #include "items.h"
33 #include "libutil.h"
34 #include "macro.h"
35 #include "message.h"
36 #include "player.h"
37 #include "religion.h"
38 #include "species.h"
39 #include "spl-cast.h"
40 #include "spl-miscast.h"
41 #include "spl-util.h"
42 #include "state.h"
43 #include "stuff.h"
44 #ifdef USE_TILE
45  #include "tilepick.h"
46 #endif
47 #include "transform.h"
48
49 #define SPELL_LIST_KEY "spell_list"
50
51 #define RANDART_BOOK_TYPE_KEY  "randart_book_type"
52 #define RANDART_BOOK_LEVEL_KEY "randart_book_level"
53
54 #define RANDART_BOOK_TYPE_LEVEL "level"
55 #define RANDART_BOOK_TYPE_THEME "theme"
56
57 // The list of spells in spellbooks:
58 static spell_type spellbook_template_array[][SPELLBOOK_SIZE] =
59 {
60 #   include "book-data.h"
61 };
62
63 spell_type which_spell_in_book(const item_def &book, int spl)
64 {
65     ASSERT(book.base_type == OBJ_BOOKS || book.base_type == OBJ_RODS);
66
67     const CrawlHashTable &props = book.props;
68     if (!props.exists(SPELL_LIST_KEY))
69         return which_spell_in_book(book.book_number(), spl);
70
71     const CrawlVector &spells = props[SPELL_LIST_KEY].get_vector();
72
73     ASSERT(spells.get_type() == SV_INT);
74     ASSERT(spells.size() == SPELLBOOK_SIZE);
75
76     return static_cast<spell_type>(spells[spl].get_int());
77 }
78
79 spell_type which_spell_in_book(int sbook_type, int spl)
80 {
81     ASSERT_RANGE(sbook_type, 0, (int)ARRAYSZ(spellbook_template_array));
82     return spellbook_template_array[sbook_type][spl];
83 }
84
85 // If fs is not NULL, updates will be to the formatted_string instead of
86 // the display.
87 int spellbook_contents(item_def &book, read_book_action_type action,
88                         formatted_string *fs)
89 {
90     int spelcount = 0;
91     int i, j;
92     bool update_screen = !fs;
93
94     const int spell_levels = player_spell_levels();
95
96     formatted_string out;
97     out.textcolor(LIGHTGREY);
98
99     out.cprintf("%s", book.name(DESC_THE).c_str());
100
101     out.cprintf("\n\n Spells                             Type                      Level\n");
102
103     for (j = 0; j < SPELLBOOK_SIZE; j++)
104     {
105         spell_type stype = which_spell_in_book(book, j);
106         if (stype == SPELL_NO_SPELL)
107             continue;
108
109         out.cprintf(" ");
110
111         const int level_diff = spell_difficulty(stype);
112         const int levels_req = spell_levels_required(stype);
113
114         int colour = DARKGREY;
115         if (action == RBOOK_USE_ROD)
116         {
117             ASSERT(book.base_type == OBJ_RODS);
118             if (book.plus >= level_diff * ROD_CHARGE_MULT)
119                 colour = spell_highlight_by_utility(stype, COL_UNKNOWN, false, true);
120             else
121                 colour = COL_USELESS;
122         }
123         else
124         {
125             if (you.has_spell(stype))
126                 colour = COL_MEMORIZED;
127             else if (you_cannot_memorise(stype)
128                 || you.experience_level < level_diff
129                 || spell_levels < levels_req
130                 || book.base_type == OBJ_BOOKS
131                    && !player_can_memorise_from_spellbook(book))
132             {
133                 colour = COL_USELESS;
134             }
135             else if (!you.has_spell(stype))
136                 colour = COL_UNMEMORIZED;
137             else
138                 colour = spell_highlight_by_utility(stype);
139         }
140
141         out.textcolor(colour);
142
143         char strng[2];
144         strng[0] = index_to_letter(spelcount);
145         strng[1] = 0;
146
147         out.cprintf("%s", strng);
148         out.cprintf(" - ");
149
150         out.cprintf("%s", chop_string(spell_title(stype), 29).c_str());
151
152         string schools;
153         if (action == RBOOK_USE_ROD)
154             schools = "Evocations";
155         else
156         {
157             bool first = true;
158             for (i = 0; i <= SPTYP_LAST_EXPONENT; i++)
159             {
160                 if (spell_typematch(stype, 1 << i))
161                 {
162                     if (!first)
163                         schools += "/";
164                     schools += spelltype_long_name(1 << i);
165                     first = false;
166                 }
167             }
168         }
169         out.cprintf("%s%d\n", chop_string(schools, 30).c_str(), level_diff);
170         spelcount++;
171     }
172
173     out.textcolor(LIGHTGREY);
174     out.cprintf("\n");
175
176     switch (action)
177     {
178     case RBOOK_USE_ROD:
179         out.cprintf("Select a spell to cast.\n");
180         break;
181
182     case RBOOK_READ_SPELL:
183         if (book.base_type == OBJ_BOOKS && in_inventory(book)
184             && item_type_known(book)
185             && player_can_memorise_from_spellbook(book))
186         {
187             out.cprintf("Select a spell to read its description, to "
188                          "memorise it or to forget it.\n");
189         }
190         else
191             out.cprintf("Select a spell to read its description.\n");
192         break;
193
194     default:
195         break;
196     }
197
198     if (fs)
199         *fs = out;
200
201     int keyn = 0;
202     if (update_screen && !crawl_state.is_replaying_keys())
203     {
204         cursor_control coff(false);
205         clrscr();
206
207         out.display();
208     }
209
210     if (update_screen)
211         keyn = toalower(getchm(KMC_MENU));
212
213     return keyn;     // either ignored or spell letter
214 }
215
216 // Rarity 100 is reserved for unused books.
217 int book_rarity(uint8_t which_book)
218 {
219     switch (which_book)
220     {
221     case BOOK_MINOR_MAGIC:
222     case BOOK_HINDERANCE:
223     case BOOK_CANTRIPS:
224         return 1;
225
226     case BOOK_CHANGES:
227     case BOOK_MALEDICT:
228         return 2;
229
230     case BOOK_CONJURATIONS:
231     case BOOK_NECROMANCY:
232     case BOOK_CALLINGS:
233     case BOOK_WIZARDRY:
234         return 3;
235
236     case BOOK_FLAMES:
237     case BOOK_FROST:
238     case BOOK_AIR:
239     case BOOK_GEOMANCY:
240         return 4;
241
242     case BOOK_YOUNG_POISONERS:
243     case BOOK_WAR_CHANTS:
244     case BOOK_DEBILITATION:
245         return 5;
246
247     case BOOK_CLOUDS:
248     case BOOK_POWER:
249         return 6;
250
251     case BOOK_ENCHANTMENTS:
252     case BOOK_PARTY_TRICKS:
253         return 7;
254
255     case BOOK_TRANSFIGURATIONS:
256     case BOOK_BEASTS:
257         return 8;
258
259     case BOOK_FIRE:
260     case BOOK_ICE:
261     case BOOK_SKY:
262     case BOOK_EARTH:
263     case BOOK_UNLIFE:
264     case BOOK_CONTROL:
265     case BOOK_SPATIAL_TRANSLOCATIONS:
266         return 10;
267
268     case BOOK_TEMPESTS:
269     case BOOK_DEATH:
270         return 11;
271
272     case BOOK_BURGLARY:
273     case BOOK_ALCHEMY:
274     case BOOK_DREAMS:
275         return 12;
276
277     case BOOK_ENVENOMATIONS:
278     case BOOK_WARP:
279     case BOOK_DRAGON:
280         return 15;
281
282     case BOOK_SUMMONINGS:
283         return 18;
284
285     case BOOK_ANNIHILATIONS:
286     case BOOK_GRAND_GRIMOIRE:
287     case BOOK_NECRONOMICON:  // Kikubaaqudgha special
288     case BOOK_MANUAL:
289         return 20;
290
291     case BOOK_DESTRUCTION:
292         return 30;
293
294 #if TAG_MAJOR_VERSION == 34
295     case BOOK_STALKING:
296     case BOOK_MUTATIONS:
297         return 100;
298 #endif
299
300     default:
301         return 1;
302     }
303 }
304
305 static uint8_t _lowest_rarity[NUM_SPELLS];
306
307 void init_spell_rarities()
308 {
309     for (int i = 0; i < NUM_SPELLS; ++i)
310         _lowest_rarity[i] = 255;
311
312     for (int i = 0; i < NUM_FIXED_BOOKS; ++i)
313     {
314         // Manuals and books of destruction are not even part of this loop.
315         if (i >= MIN_RARE_BOOK && i <= MAX_RARE_BOOK)
316             continue;
317
318         for (int j = 0; j < SPELLBOOK_SIZE; ++j)
319         {
320             spell_type spell = which_spell_in_book(i, j);
321             if (spell == SPELL_NO_SPELL)
322                 continue;
323
324 #ifdef DEBUG
325             unsigned int flags = get_spell_flags(spell);
326
327             if (flags & (SPFLAG_MONSTER | SPFLAG_TESTING))
328             {
329                 item_def item;
330                 item.base_type = OBJ_BOOKS;
331                 item.sub_type  = i;
332
333                 end(1, false, "Spellbook '%s' contains invalid spell "
334                              "'%s'",
335                     item.name(DESC_PLAIN, false, true).c_str(),
336                     spell_title(spell));
337             }
338 #endif
339
340             const int rarity = book_rarity(i);
341             if (rarity < _lowest_rarity[spell])
342                 _lowest_rarity[spell] = rarity;
343         }
344     }
345 }
346
347 bool is_player_spell(spell_type which_spell)
348 {
349     for (int i = 0; i < NUM_FIXED_BOOKS; ++i)
350     {
351         for (int j = 0; j < SPELLBOOK_SIZE; ++j)
352         {
353             if (which_spell_in_book(i, j) == which_spell)
354                 return true;
355         }
356     }
357     return false;
358 }
359
360 int spell_rarity(spell_type which_spell)
361 {
362     const int rarity = _lowest_rarity[which_spell];
363
364     if (rarity == 255)
365         return -1;
366
367     return rarity;
368 }
369
370 static bool _is_valid_spell_in_book(const item_def &book, int spell)
371 {
372     return which_spell_in_book(book, spell) != SPELL_NO_SPELL;
373 }
374
375 // Returns false if the player cannot memorise from the book,
376 // and true otherwise. -- bwr
377 bool player_can_memorise_from_spellbook(const item_def &book)
378 {
379     if (book.base_type != OBJ_BOOKS)
380         return true;
381
382     if (book.props.exists(SPELL_LIST_KEY))
383         return true;
384
385     if ((book.sub_type == BOOK_ANNIHILATIONS
386          && (you.skill(SK_CONJURATIONS) < 10
387              || you.skill(SK_SPELLCASTING) < 6))
388         || (book.sub_type == BOOK_GRAND_GRIMOIRE
389             && (you.skill(SK_SUMMONINGS) < 10
390                 || you.skill(SK_SPELLCASTING) < 6))
391         || (book.sub_type == BOOK_NECRONOMICON
392             && you.religion != GOD_KIKUBAAQUDGHA
393             && (you.skill(SK_NECROMANCY) < 10
394                 || you.skill(SK_SPELLCASTING) < 6)))
395     {
396         return false;
397     }
398
399     return true;
400 }
401
402 void mark_had_book(const item_def &book)
403 {
404     ASSERT(book.base_type == OBJ_BOOKS);
405
406     if (!item_is_spellbook(book))
407         return;
408
409     for (int i = 0; i < SPELLBOOK_SIZE; i++)
410     {
411         spell_type stype = which_spell_in_book(book, i);
412         if (stype == SPELL_NO_SPELL)
413             continue;
414
415         you.seen_spell.set(stype);
416     }
417
418     if (book.sub_type == BOOK_RANDART_LEVEL)
419         ASSERT_RANGE(book.plus, 1, 10); // book's level
420
421     if (!book.props.exists(SPELL_LIST_KEY))
422         mark_had_book(book.book_number());
423 }
424
425 void mark_had_book(int booktype)
426 {
427     ASSERT_RANGE(booktype, 0, MAX_FIXED_BOOK + 1);
428
429     you.had_book.set(booktype);
430 }
431
432 void inscribe_book_highlevel(item_def &book)
433 {
434     if (!item_type_known(book)
435         && book.inscription.find("highlevel") == string::npos)
436     {
437         add_inscription(book, "highlevel");
438     }
439 }
440
441 /**
442  * Identify a held book/rod, if appropriate.
443  * @return whether we can see its spells
444  */
445 bool maybe_id_book(item_def &book, bool silent)
446 {
447     if (book.base_type != OBJ_BOOKS && book.base_type != OBJ_RODS)
448         return false;
449
450     if (book.base_type == OBJ_BOOKS && book.sub_type == BOOK_DESTRUCTION)
451     {
452         ASSERT(fully_identified(book));
453         return false;
454     }
455
456     if (book.base_type == OBJ_BOOKS && book.sub_type == BOOK_MANUAL)
457     {
458         set_ident_flags(book, ISFLAG_IDENT_MASK);
459         return false;
460     }
461
462     if (book.base_type == OBJ_BOOKS && !item_type_known(book)
463         && !player_can_memorise_from_spellbook(book))
464     {
465         if (!silent)
466         {
467             mpr("This book is beyond your current level of understanding.");
468             more();
469         }
470
471         inscribe_book_highlevel(book);
472         return false;
473     }
474
475     set_ident_flags(book, ISFLAG_IDENT_MASK);
476
477     if (book.base_type == OBJ_BOOKS)
478         mark_had_book(book);
479
480     return true;
481 }
482
483 int read_book(item_def &book, read_book_action_type action)
484 {
485     if (!maybe_id_book(book))
486         return 0;
487
488 #ifdef USE_TILE_WEB
489     tiles_crt_control show_as_menu(CRT_MENU, "read_book");
490 #endif
491
492     // Remember that this function is called for rods as well.
493     const int keyin = spellbook_contents(book, action);
494
495     if (!crawl_state.is_replaying_keys())
496         redraw_screen();
497
498     return keyin;
499 }
500
501 bool you_cannot_memorise(spell_type spell)
502 {
503     bool temp;
504     return you_cannot_memorise(spell, temp);
505 }
506
507 // undead is set to true if being undead prevents us from memorising the spell.
508 bool you_cannot_memorise(spell_type spell, bool &undead)
509 {
510     bool rc = false;
511
512     if (you.form == TRAN_WISP)
513     {
514         undead = false;
515         return true;
516     }
517
518     switch (you.is_undead)
519     {
520     case US_HUNGRY_DEAD: // Ghouls
521         switch (spell)
522         {
523         case SPELL_BEASTLY_APPENDAGE:
524         case SPELL_BLADE_HANDS:
525         case SPELL_BORGNJORS_REVIVIFICATION:
526         case SPELL_CURE_POISON:
527         case SPELL_DEATHS_DOOR:
528         case SPELL_DRAGON_FORM:
529         case SPELL_ICE_FORM:
530         case SPELL_NECROMUTATION:
531         case SPELL_SPIDER_FORM:
532         case SPELL_STATUE_FORM:
533         case SPELL_STONESKIN:
534             rc = true;
535             break;
536         default:
537             break;
538         }
539         break;
540
541     case US_SEMI_UNDEAD: // Vampires
542         switch (spell)
543         {
544         case SPELL_BORGNJORS_REVIVIFICATION:
545         case SPELL_DEATHS_DOOR:
546         case SPELL_NECROMUTATION:
547             // In addition, the above US_HUNGRY_DEAD spells are not castable
548             // when satiated or worse.
549             rc = true;
550             break;
551         default:
552             break;
553         }
554         break;
555
556     case US_UNDEAD: // Mummies
557         switch (spell)
558         {
559         case SPELL_BEASTLY_APPENDAGE:
560         case SPELL_BLADE_HANDS:
561         case SPELL_BORGNJORS_REVIVIFICATION:
562         case SPELL_CURE_POISON:
563         case SPELL_DEATHS_DOOR:
564         case SPELL_DRAGON_FORM:
565         case SPELL_ICE_FORM:
566         case SPELL_INTOXICATE:
567         case SPELL_NECROMUTATION:
568         case SPELL_REGENERATION:
569         case SPELL_SPIDER_FORM:
570         case SPELL_STATUE_FORM:
571         case SPELL_STONESKIN:
572             rc = true;
573             break;
574         default:
575             break;
576         }
577         break;
578
579     case US_ALIVE:
580         break;
581     }
582
583     // If rc has been set to true before now, that was because we
584     // are (possibly temporarily) undead.
585     if (rc == true)
586         undead = true;
587
588     if (you.species == SP_DEEP_DWARF && spell == SPELL_REGENERATION)
589         rc = true, undead = false;
590
591     if (you.species == SP_FELID
592         && (spell == SPELL_PORTAL_PROJECTILE
593          // weapon branding is useless
594          || spell == SPELL_FIRE_BRAND
595          || spell == SPELL_FREEZING_AURA
596          || spell == SPELL_LETHAL_INFUSION
597          || spell == SPELL_WARP_BRAND
598          || spell == SPELL_EXCRUCIATING_WOUNDS
599          || spell == SPELL_POISON_WEAPON
600          || spell == SPELL_SURE_BLADE
601          // could be useful if it didn't require wielding
602          || spell == SPELL_TUKIMAS_DANCE))
603     {
604         rc = true, undead = false;
605     }
606
607     if (you.species == SP_DJINNI
608         && (spell == SPELL_ICE_FORM
609          || spell == SPELL_OZOCUBUS_ARMOUR
610          || spell == SPELL_DEATHS_DOOR))
611     {
612         rc = true, undead = false;
613     }
614
615     if (you.species == SP_LAVA_ORC && spell == SPELL_STONESKIN)
616         rc = true, undead = false;
617
618     return rc;
619 }
620
621 bool player_can_memorise(const item_def &book)
622 {
623     if (!item_is_spellbook(book) || !player_spell_levels())
624         return false;
625
626     for (int j = 0; j < SPELLBOOK_SIZE; j++)
627     {
628         const spell_type stype = which_spell_in_book(book, j);
629
630         if (stype == SPELL_NO_SPELL)
631             continue;
632
633         // Easiest spell already too difficult?
634         if (spell_difficulty(stype) > you.experience_level
635             || player_spell_levels() < spell_levels_required(stype))
636         {
637             return false;
638         }
639
640         bool knows_spell = false;
641         for (int i = 0; i < MAX_KNOWN_SPELLS && !knows_spell; i++)
642             knows_spell = (you.spells[i] == stype);
643
644         // You don't already know this spell.
645         if (!knows_spell)
646             return true;
647     }
648     return false;
649 }
650
651 typedef vector<spell_type>   spell_list;
652 typedef map<spell_type, int> spells_to_books;
653
654 static void _index_book(item_def& book, spells_to_books &book_hash,
655                         unsigned int &num_unreadable, bool &book_errors)
656 {
657     if (!player_can_memorise_from_spellbook(book))
658     {
659         inscribe_book_highlevel(book);
660         num_unreadable++;
661         return;
662     }
663
664     mark_had_book(book);
665     set_ident_flags(book, ISFLAG_KNOW_TYPE);
666     set_ident_flags(book, ISFLAG_IDENT_MASK);
667
668     int spells_in_book = 0;
669     for (int j = 0; j < SPELLBOOK_SIZE; j++)
670     {
671         if (!_is_valid_spell_in_book(book, j))
672             continue;
673
674         const spell_type spell = which_spell_in_book(book, j);
675
676         spells_in_book++;
677
678         spells_to_books::iterator it = book_hash.find(spell);
679         if (it == book_hash.end())
680             book_hash[spell] = book.sub_type;
681     }
682
683     if (spells_in_book == 0)
684     {
685         mprf(MSGCH_ERROR, "Spellbook \"%s\" contains no spells! Please "
686              "file a bug report.", book.name(DESC_PLAIN).c_str());
687         book_errors = true;
688     }
689 }
690
691 static bool _get_mem_list(spell_list &mem_spells,
692                           spells_to_books &book_hash,
693                           unsigned int &num_unreadable,
694                           unsigned int &num_race,
695                           bool just_check = false,
696                           spell_type current_spell = SPELL_NO_SPELL)
697 {
698     if (you.form == TRAN_WISP)
699     {
700         if (!just_check)
701             mpr("You can't handle any books in this form.", MSGCH_PROMPT);
702         return false;
703     }
704
705     bool          book_errors    = false;
706     unsigned int  num_on_ground  = 0;
707     unsigned int  num_books      = 0;
708     unsigned int  num_unknown    = 0;
709                   num_unreadable = 0;
710
711     // Collect the list of all spells in all available spellbooks.
712     for (int i = 0; i < ENDOFPACK; i++)
713     {
714         item_def& book(you.inv[i]);
715
716         if (!item_is_spellbook(book))
717             continue;
718
719         num_books++;
720         _index_book(book, book_hash, num_unreadable, book_errors);
721     }
722
723     // We also check the ground
724     vector<const item_def*> items;
725     item_list_on_square(items, you.visible_igrd(you.pos()));
726
727     for (unsigned int i = 0; i < items.size(); ++i)
728     {
729         item_def book(*items[i]);
730         if (!item_is_spellbook(book))
731             continue;
732
733         if (!item_type_known(book))
734         {
735             num_unknown++;
736             continue;
737         }
738
739         num_books++;
740         num_on_ground++;
741         _index_book(book, book_hash, num_unreadable, book_errors);
742     }
743
744     // Handle Vehumet gifts
745     set<spell_type>::iterator gift_iterator = you.vehumet_gifts.begin();
746     if (gift_iterator != you.vehumet_gifts.end())
747     {
748         num_books++;
749         while (gift_iterator != you.vehumet_gifts.end())
750             book_hash[*gift_iterator++] = NUM_BOOKS;
751     }
752
753     if (book_errors)
754         more();
755
756     if (num_books == 0)
757     {
758         if (!just_check)
759         {
760             if (num_unknown > 1)
761             {
762                 mpr("You must pick up those books before reading them.",
763                     MSGCH_PROMPT);
764             }
765             else if (num_unknown == 1)
766             {
767                 mpr("You must pick up this book before reading it.",
768                     MSGCH_PROMPT);
769             }
770             else
771             {
772                 mpr("You aren't carrying or standing over any spellbooks.",
773                     MSGCH_PROMPT);
774             }
775         }
776         return false;
777     }
778     else if (num_unreadable == num_books)
779     {
780         if (!just_check)
781         {
782             mprf(MSGCH_PROMPT, "All of the spellbooks%s are beyond your "
783                  "current level of comprehension.",
784                  num_on_ground == 0 ? " you're carrying" : "");
785         }
786         return false;
787     }
788     else if (book_hash.empty())
789     {
790         if (!just_check)
791         {
792             mpr("None of the spellbooks you are carrying contain any spells.",
793                 MSGCH_PROMPT);
794         }
795         return false;
796     }
797
798     unsigned int num_known      = 0;
799                  num_race       = 0;
800     unsigned int num_low_xl     = 0;
801     unsigned int num_low_levels = 0;
802     unsigned int num_memable    = 0;
803
804     for (spells_to_books::iterator i = book_hash.begin();
805          i != book_hash.end(); ++i)
806     {
807         const spell_type spell = i->first;
808
809         if (spell == current_spell || you.has_spell(spell))
810             num_known++;
811         else if (you_cannot_memorise(spell))
812             num_race++;
813         else
814         {
815             mem_spells.push_back(spell);
816
817             int avail_slots = player_spell_levels();
818             if (current_spell != SPELL_NO_SPELL)
819                 avail_slots -= spell_levels_required(current_spell);
820
821             if (spell_difficulty(spell) > you.experience_level)
822                 num_low_xl++;
823             else if (avail_slots < spell_levels_required(spell))
824                 num_low_levels++;
825             else
826                 num_memable++;
827         }
828     }
829
830     if (num_memable > 0 && you.spell_no >= MAX_KNOWN_SPELLS)
831     {
832         if (!just_check)
833             mpr("Your head is already too full of spells!");
834         return false;
835     }
836
837     if (num_memable)
838         return true;
839
840     // Return true even if there are only spells we can't memorise _yet_.
841     if (just_check)
842         return (num_low_levels > 0 || num_low_xl > 0);
843
844     unsigned int total = num_known + num_race + num_low_xl + num_low_levels;
845
846     if (num_known == total)
847         mpr("You already know all available spells.", MSGCH_PROMPT);
848     else if (num_race == total || (num_known + num_race) == total)
849     {
850         const bool lichform = (you.form == TRAN_LICH);
851         const string species = "a " + species_name(you.species);
852         mprf(MSGCH_PROMPT,
853              "You cannot memorise any of the available spells because you "
854              "are %s.", lichform ? "in Lich form"
855                                  : lowercase_string(species).c_str());
856     }
857     else if (num_low_levels > 0 || num_low_xl > 0)
858     {
859         // Just because we can't memorise them doesn't mean we don't want to
860         // see what we have available. See FR #235. {due}
861         return true;
862     }
863     else
864     {
865         mpr("You can't memorise any new spells for an unknown reason; "
866             "please file a bug report.", MSGCH_PROMPT);
867     }
868
869     if (num_unreadable)
870     {
871         mprf(MSGCH_PROMPT, "Additionally, %u of your spellbooks are beyond "
872              "your current level of understanding, and thus none of the "
873              "spells in them are available to you.", num_unreadable);
874     }
875
876     return false;
877 }
878
879 // If current_spell is a valid spell, returns whether you'll be able to
880 // memorise any further spells once this one is committed to memory.
881 bool has_spells_to_memorise(bool silent, int current_spell)
882 {
883     spell_list      mem_spells;
884     spells_to_books book_hash;
885     unsigned int    num_unreadable;
886     unsigned int    num_race;
887
888     return _get_mem_list(mem_spells, book_hash, num_unreadable, num_race,
889                          silent, (spell_type) current_spell);
890 }
891
892 static bool _sort_mem_spells(spell_type a, spell_type b)
893 {
894     // List the Vehumet gifts at the very top.
895     bool offering_a = vehumet_is_offering(a);
896     bool offering_b = vehumet_is_offering(b);
897     if (offering_a != offering_b)
898         return offering_a;
899
900     // List spells we can memorize right away first.
901     if (player_spell_levels() >= spell_levels_required(a)
902         && player_spell_levels() < spell_levels_required(b))
903     {
904         return true;
905     }
906     else if (player_spell_levels() < spell_levels_required(a)
907              && player_spell_levels() >= spell_levels_required(b))
908     {
909         return false;
910     }
911
912     // Don't sort by failure rate beyond what the player can see in the
913     // success descriptions.
914     const int fail_rate_a = failure_rate_to_int(spell_fail(a));
915     const int fail_rate_b = failure_rate_to_int(spell_fail(b));
916     if (fail_rate_a != fail_rate_b)
917         return (fail_rate_a < fail_rate_b);
918
919     if (spell_difficulty(a) != spell_difficulty(b))
920         return (spell_difficulty(a) < spell_difficulty(b));
921
922     return (strcasecmp(spell_title(a), spell_title(b)) < 0);
923 }
924
925 vector<spell_type> get_mem_spell_list(vector<int> &books)
926 {
927     vector<spell_type> spells;
928
929     spell_list      mem_spells;
930     spells_to_books book_hash;
931     unsigned int    num_unreadable;
932     unsigned int    num_race;
933
934     if (!_get_mem_list(mem_spells, book_hash, num_unreadable, num_race))
935         return spells;
936
937     sort(mem_spells.begin(), mem_spells.end(), _sort_mem_spells);
938
939     for (unsigned int i = 0; i < mem_spells.size(); i++)
940     {
941         spell_type spell = mem_spells[i];
942         spells.push_back(spell);
943
944         spells_to_books::iterator it = book_hash.find(spell);
945         books.push_back(it->second);
946     }
947
948     return spells;
949 }
950
951 static spell_type _choose_mem_spell(spell_list &spells,
952                                     spells_to_books &book_hash,
953                                     unsigned int num_unreadable,
954                                     unsigned int num_race)
955 {
956     sort(spells.begin(), spells.end(), _sort_mem_spells);
957
958 #ifdef USE_TILE_LOCAL
959     const bool text_only = false;
960 #else
961     const bool text_only = true;
962 #endif
963
964     ToggleableMenu spell_menu(MF_SINGLESELECT | MF_ANYPRINTABLE
965                     | MF_ALWAYS_SHOW_MORE | MF_ALLOW_FORMATTING,
966                     text_only);
967 #ifdef USE_TILE_LOCAL
968     // [enne] Hack.  Use a separate title, so the column headers are aligned.
969     spell_menu.set_title(
970         new MenuEntry(" Your Spells - Memorisation  (toggle to descriptions with '!')",
971             MEL_TITLE));
972
973     spell_menu.set_title(
974         new MenuEntry(" Your Spells - Descriptions  (toggle to memorisation with '!')",
975             MEL_TITLE), false);
976
977     {
978         MenuEntry* me =
979             new MenuEntry("     Spells                        Type          "
980                           "                Failure  Level",
981                 MEL_ITEM);
982         me->colour = BLUE;
983         spell_menu.add_entry(me);
984     }
985 #else
986     spell_menu.set_title(
987         new MenuEntry("     Spells (Memorisation)         Type          "
988                       "                Failure  Level",
989             MEL_TITLE));
990
991     spell_menu.set_title(
992         new MenuEntry("     Spells (Description)          Type          "
993                       "                Failure  Level",
994             MEL_TITLE), false);
995 #endif
996
997     spell_menu.set_highlighter(NULL);
998     spell_menu.set_tag("spell");
999
1000     spell_menu.action_cycle = Menu::CYCLE_TOGGLE;
1001     spell_menu.menu_action  = Menu::ACT_EXECUTE;
1002
1003     string more_str = make_stringf("<lightgreen>%d spell level%s left"
1004                                    "<lightgreen>",
1005                                    player_spell_levels(),
1006                                    (player_spell_levels() > 1
1007                                     || player_spell_levels() == 0) ? "s" : "");
1008
1009     if (num_unreadable > 0)
1010     {
1011         more_str += make_stringf(", <lightmagenta>%u overly difficult "
1012                                  "spellbook%s</lightmagenta>",
1013                                  num_unreadable,
1014                                  num_unreadable > 1 ? "s" : "");
1015     }
1016
1017     if (num_race > 0)
1018     {
1019         more_str += make_stringf(", <lightred>%u spell%s unmemorisable"
1020                                  "</lightred>",
1021                                  num_race,
1022                                  num_race > 1 ? "s" : "");
1023     }
1024
1025 #ifndef USE_TILE_LOCAL
1026     // Tiles menus get this information in the title.
1027     more_str += "   Toggle display with '<w>!</w>'";
1028 #endif
1029
1030     spell_menu.set_more(formatted_string::parse_string(more_str));
1031
1032     // Don't make a menu so tall that we recycle hotkeys on the same page.
1033     if (spells.size() > 52
1034         && (spell_menu.maxpagesize() > 52 || spell_menu.maxpagesize() == 0))
1035     {
1036         spell_menu.set_maxpagesize(52);
1037     }
1038
1039
1040     for (unsigned int i = 0; i < spells.size(); i++)
1041     {
1042         const spell_type spell = spells[i];
1043
1044         ostringstream desc;
1045
1046         int colour = LIGHTGRAY;
1047         if (vehumet_is_offering(spell))
1048             colour = LIGHTBLUE;
1049         // Grey out spells for which you lack experience or spell levels.
1050         else if (spell_difficulty(spell) > you.experience_level
1051                  || player_spell_levels() < spell_levels_required(spell))
1052             colour = DARKGRAY;
1053         else
1054             colour = spell_highlight_by_utility(spell);
1055
1056         desc << "<" << colour_to_str(colour) << ">";
1057
1058         desc << left;
1059         desc << chop_string(spell_title(spell), 30);
1060         desc << spell_schools_string(spell);
1061
1062         int so_far = strwidth(desc.str()) - (colour_to_str(colour).length()+2);
1063         if (so_far < 60)
1064             desc << string(60 - so_far, ' ');
1065         desc << "</" << colour_to_str(colour) << ">";
1066
1067         colour = failure_rate_colour(spell);
1068         desc << "<" << colour_to_str(colour) << ">";
1069         char* failure = failure_rate_to_string(spell_fail(spell));
1070         desc << chop_string(failure, 12);
1071         free(failure);
1072         desc << "</" << colour_to_str(colour) << ">";
1073         desc << spell_difficulty(spell);
1074
1075         MenuEntry* me =
1076             new MenuEntry(desc.str(), MEL_ITEM, 1,
1077                           index_to_letter(i % 52));
1078
1079 #ifdef USE_TILE
1080         me->add_tile(tile_def(tileidx_spell(spell), TEX_GUI));
1081 #endif
1082
1083         me->data = &spells[i];
1084         spell_menu.add_entry(me);
1085     }
1086
1087     while (true)
1088     {
1089         vector<MenuEntry*> sel = spell_menu.show();
1090
1091         if (!crawl_state.doing_prev_cmd_again)
1092             redraw_screen();
1093
1094         if (sel.empty())
1095             return SPELL_NO_SPELL;
1096
1097         ASSERT(sel.size() == 1);
1098
1099         const spell_type spell = *static_cast<spell_type*>(sel[0]->data);
1100         ASSERT(is_valid_spell(spell));
1101
1102         if (spell_menu.menu_action == Menu::ACT_EXAMINE)
1103             describe_spell(spell);
1104         else
1105             return spell;
1106     }
1107 }
1108
1109 bool can_learn_spell(bool silent)
1110 {
1111     if (you.form == TRAN_BAT)
1112     {
1113         if (!silent)
1114             canned_msg(MSG_PRESENT_FORM);
1115         return false;
1116     }
1117
1118     if (you.stat_zero[STAT_INT])
1119     {
1120         if (!silent)
1121             mpr("Your brain is not functional enough to learn spells.");
1122         return false;
1123     }
1124
1125     if (you.confused())
1126     {
1127         if (!silent)
1128             canned_msg(MSG_TOO_CONFUSED);
1129         return false;
1130     }
1131
1132     if (you.berserk())
1133     {
1134         if (!silent)
1135             canned_msg(MSG_TOO_BERSERK);
1136         return false;
1137     }
1138
1139     return true;
1140 }
1141
1142 bool learn_spell()
1143 {
1144     if (!can_learn_spell())
1145         return false;
1146
1147     spell_list      mem_spells;
1148     spells_to_books book_hash;
1149
1150     unsigned int num_unreadable, num_race;
1151
1152     if (!_get_mem_list(mem_spells, book_hash, num_unreadable, num_race))
1153         return false;
1154
1155     spell_type specspell = _choose_mem_spell(mem_spells, book_hash,
1156                                              num_unreadable, num_race);
1157
1158     if (specspell == SPELL_NO_SPELL)
1159     {
1160         canned_msg(MSG_OK);
1161         return false;
1162     }
1163
1164     return learn_spell(specspell);
1165 }
1166
1167 // Returns a string about why an undead character can't memorise a spell.
1168 string desc_cannot_memorise_reason(bool undead)
1169 {
1170     if (undead)
1171         ASSERT(you.is_undead);
1172
1173     string desc = "You cannot ";
1174     if (you.form == TRAN_LICH || you.form == TRAN_WISP)
1175         desc += "currently ";
1176     desc += "memorise or cast this spell because you are ";
1177
1178     if (you.form == TRAN_LICH)
1179         desc += "in Lich form";
1180     else if (you.form == TRAN_WISP)
1181         desc += "in Wisp form";
1182     else
1183         desc += "a " + lowercase_string(species_name(you.species));
1184
1185     desc += ".";
1186
1187     return desc;
1188 }
1189
1190 static bool _learn_spell_checks(spell_type specspell)
1191 {
1192     if (!can_learn_spell())
1193         return false;
1194
1195     if (already_learning_spell((int) specspell))
1196         return false;
1197
1198     bool undead = false;
1199     if (you_cannot_memorise(specspell, undead))
1200     {
1201         mpr(desc_cannot_memorise_reason(undead).c_str());
1202         return false;
1203     }
1204
1205     if (you.has_spell(specspell))
1206     {
1207         mpr("You already know that spell!");
1208         return false;
1209     }
1210
1211     if (you.spell_no >= MAX_KNOWN_SPELLS)
1212     {
1213         mpr("Your head is already too full of spells!");
1214         return false;
1215     }
1216
1217     if (you.experience_level < spell_difficulty(specspell))
1218     {
1219         mpr("You're too inexperienced to learn that spell!");
1220         return false;
1221     }
1222
1223     if (player_spell_levels() < spell_levels_required(specspell))
1224     {
1225         mpr("You can't memorise that many levels of magic yet!");
1226         return false;
1227     }
1228
1229     if (spell_fail(specspell) >= 100 && !vehumet_is_offering(specspell))
1230     {
1231         mpr("This spell is too difficult to memorise!");
1232         return false;
1233     }
1234
1235     return true;
1236 }
1237
1238 bool learn_spell(spell_type specspell)
1239 {
1240     if (!_learn_spell_checks(specspell))
1241         return false;
1242
1243     double chance = get_miscast_chance(specspell);
1244
1245     if (chance >= 0.025)
1246         mpr("This spell is very dangerous to cast!", MSGCH_WARN);
1247     else if (chance >= 0.005)
1248         mpr("This spell is quite dangerous to cast!", MSGCH_WARN);
1249     else if (chance >= 0.001)
1250         mpr("This spell is slightly dangerous to cast.");
1251
1252     snprintf(info, INFO_SIZE,
1253              "Memorise %s, consuming %d spell level%s and leaving %d?",
1254              spell_title(specspell), spell_levels_required(specspell),
1255              spell_levels_required(specspell) != 1 ? "s" : "",
1256              player_spell_levels() - spell_levels_required(specspell));
1257
1258     // Deactivate choice from tile inventory.
1259     mouse_control mc(MOUSE_MODE_MORE);
1260     if (!yesno(info, true, 'n', false))
1261     {
1262         canned_msg(MSG_OK);
1263         return false;
1264     }
1265
1266     start_delay(DELAY_MEMORISE, spell_difficulty(specspell), specspell);
1267     you.turn_is_over = true;
1268
1269     did_god_conduct(DID_SPELL_CASTING, 2 + random2(5));
1270
1271     return true;
1272 }
1273
1274 bool forget_spell_from_book(spell_type spell, const item_def* book)
1275 {
1276     string prompt;
1277
1278     prompt += make_stringf("Forgetting %s from %s will destroy the book! "
1279                            "Are you sure?",
1280                            spell_title(spell),
1281                            book->name(DESC_THE).c_str());
1282
1283     // Deactivate choice from tile inventory.
1284     mouse_control mc(MOUSE_MODE_MORE);
1285     if (!yesno(prompt.c_str(), false, 'n'))
1286     {
1287         canned_msg(MSG_OK);
1288         return false;
1289     }
1290     mprf("As you tear out the page describing %s, the book crumbles to dust.",
1291         spell_title(spell));
1292
1293     if (del_spell_from_memory(spell))
1294     {
1295         item_was_destroyed(*book);
1296         destroy_spellbook(*book);
1297         dec_inv_item_quantity(book->link, 1);
1298         you.turn_is_over = true;
1299         return true;
1300     }
1301     else
1302     {
1303         // This shouldn't happen.
1304         mprf("A bug prevents you from forgetting %s.", spell_title(spell));
1305         return false;
1306     }
1307 }
1308
1309 int count_rod_spells(const item_def &item, bool need_id)
1310 {
1311     if (item.base_type != OBJ_RODS)
1312         return -1;
1313
1314     if (need_id && !item_type_known(item))
1315         return 0;
1316
1317     const int type = item.book_number();
1318     if (type == -1)
1319         return 0;
1320
1321     int nspel = 0;
1322     while (nspel < SPELLBOOK_SIZE && _is_valid_spell_in_book(item, nspel))
1323         ++nspel;
1324
1325     return nspel;
1326 }
1327
1328 int rod_spell(int rod)
1329 {
1330     item_def& irod(you.inv[rod]);
1331
1332     if (irod.base_type != OBJ_RODS)
1333     {
1334         canned_msg(MSG_NOTHING_HAPPENS);
1335         return -1;
1336     }
1337
1338     // ID code got moved to item_use::wield_effects. {due}
1339
1340     const int num_spells = count_rod_spells(irod, false);
1341
1342     int keyin = 0;
1343     if (num_spells == 0)
1344     {
1345         canned_msg(MSG_NOTHING_HAPPENS);  // shouldn't happen
1346         return 0;
1347     }
1348     else if (num_spells == 1)
1349         keyin = 'a';  // automatically selected if it's the only option
1350     else
1351     {
1352         mprf(MSGCH_PROMPT,
1353              "Evoke which spell from the rod ([a-%c] spell [?*] list)? ",
1354              'a' + num_spells - 1);
1355
1356         // Note that auto_list is ignored here.
1357         keyin = get_ch();
1358
1359         if (keyin == '?' || keyin == '*')
1360         {
1361             keyin = read_book(you.inv[rod], RBOOK_USE_ROD);
1362             // [ds] read_book sets turn_is_over.
1363             you.turn_is_over = false;
1364         }
1365     }
1366
1367     if (key_is_escape(keyin) || keyin == ' ' || keyin == '\r' || keyin == '\n')
1368     {
1369         canned_msg(MSG_OK);
1370         return -1;
1371     }
1372
1373     if (!isaalpha(keyin))
1374     {
1375         canned_msg(MSG_HUH);
1376         return -1;
1377     }
1378
1379     const int idx = letter_to_index(keyin);
1380
1381     if ((idx >= SPELLBOOK_SIZE) || !_is_valid_spell_in_book(irod, idx))
1382     {
1383         canned_msg(MSG_HUH);
1384         return -1;
1385     }
1386
1387     const spell_type spell = which_spell_in_book(irod, idx);
1388     int mana = spell_mana(spell) * ROD_CHARGE_MULT;
1389     int power = calc_spell_power(spell, false, false, true, true);
1390
1391     int food = spell_hunger(spell, true);
1392
1393     if (you.is_undead == US_UNDEAD)
1394         food = 0;
1395
1396     if (food && (you.hunger_state == HS_STARVING || you.hunger <= food)
1397         && !you.is_undead)
1398     {
1399         canned_msg(MSG_NO_ENERGY);
1400         crawl_state.zero_turns_taken();
1401         return -1;
1402     }
1403
1404     if (spell == SPELL_THUNDERBOLT && you.props.exists("thunderbolt_last")
1405         && you.props["thunderbolt_last"].get_int() + 1 == you.num_turns)
1406     {
1407         // Starting it up takes 2 mana, continuing any amount up to 5.
1408         // You don't get to expend less (other than stopping the zap completely).
1409         mana = min(5 * ROD_CHARGE_MULT, (int)irod.plus);
1410         // Never allow using less than a whole point of charge.
1411         mana = max(mana, ROD_CHARGE_MULT);
1412         you.props["thunderbolt_mana"].get_int() = mana;
1413     }
1414
1415     if (irod.plus < mana)
1416     {
1417         mpr("The rod doesn't have enough magic points.");
1418         crawl_state.zero_turns_taken();
1419         // Don't lose a turn for trying to evoke without enough MP - that's
1420         // needlessly cruel for an honest error.
1421         return -1;
1422     }
1423
1424     // All checks passed, we can cast the spell.
1425     if (you.confused())
1426         random_uselessness();
1427     else if (your_spells(spell, power, false, false)
1428                 == SPRET_ABORT)
1429     {
1430         crawl_state.zero_turns_taken();
1431         return -1;
1432     }
1433
1434     make_hungry(food, true, true);
1435     irod.plus -= mana;
1436     you.wield_change = true;
1437     you.turn_is_over = true;
1438
1439     return (roll_dice(1, 1 + spell_difficulty(spell) / 2));
1440 }
1441
1442 static bool _compare_spells(spell_type a, spell_type b)
1443 {
1444     if (a == SPELL_NO_SPELL && b == SPELL_NO_SPELL)
1445         return false;
1446     else if (a != SPELL_NO_SPELL && b == SPELL_NO_SPELL)
1447         return true;
1448     else if (a == SPELL_NO_SPELL && b != SPELL_NO_SPELL)
1449         return false;
1450
1451     int level_a = spell_difficulty(a);
1452     int level_b = spell_difficulty(b);
1453
1454     if (level_a != level_b)
1455         return (level_a < level_b);
1456
1457     unsigned int schools_a = get_spell_disciplines(a);
1458     unsigned int schools_b = get_spell_disciplines(b);
1459
1460     if (schools_a != schools_b && schools_a != 0 && schools_b != 0)
1461     {
1462         const char* a_type = NULL;
1463         const char* b_type = NULL;
1464
1465         // Find lowest/earliest school for each spell.
1466         for (int i = 0; i <= SPTYP_LAST_EXPONENT; i++)
1467         {
1468             int mask = 1 << i;
1469             if (a_type == NULL && (schools_a & mask))
1470                 a_type = spelltype_long_name(mask);
1471             if (b_type == NULL && (schools_b & mask))
1472                 b_type = spelltype_long_name(mask);
1473         }
1474         ASSERT(a_type != NULL);
1475         ASSERT(b_type != NULL);
1476         return (strcmp(a_type, b_type) < 0);
1477     }
1478
1479     return (strcmp(spell_title(a), spell_title(b)) < 0);
1480 }
1481
1482 bool is_memorised(spell_type spell)
1483 {
1484     for (int i = 0; i < MAX_KNOWN_SPELLS; i++)
1485         if (you.spells[i] == spell)
1486             return true;
1487
1488     return false;
1489 }
1490
1491 static void _get_spell_list(vector<spell_type> &spells, int level,
1492                             unsigned int disc1, unsigned int disc2,
1493                             god_type god, bool avoid_uncastable,
1494                             int &god_discard, int &uncastable_discard,
1495                             bool avoid_known = false)
1496 {
1497     // For randarts handed out by Sif Muna, spells contained in the
1498     // special books are fair game.
1499     // We store them in an extra vector that (once sorted) can later
1500     // be checked for each spell with a rarity -1 (i.e. not normally
1501     // appearing randomly).
1502     vector<spell_type> special_spells;
1503     if (god == GOD_SIF_MUNA)
1504     {
1505         for (int i = MIN_RARE_BOOK; i <= MAX_RARE_BOOK; ++i)
1506             for (int j = 0; j < SPELLBOOK_SIZE; ++j)
1507             {
1508                 spell_type spell = which_spell_in_book(i, j);
1509                 if (spell == SPELL_NO_SPELL)
1510                     continue;
1511
1512                 if (spell_rarity(spell) != -1)
1513                     continue;
1514
1515                 special_spells.push_back(spell);
1516             }
1517
1518         sort(special_spells.begin(), special_spells.end());
1519     }
1520
1521     int specnum = 0;
1522     for (int i = 0; i < NUM_SPELLS; ++i)
1523     {
1524         const spell_type spell = (spell_type) i;
1525
1526         if (!is_valid_spell(spell))
1527             continue;
1528
1529         // Only use spells available in books you might find lying about
1530         // the dungeon.
1531         if (spell_rarity(spell) == -1)
1532         {
1533             bool skip_spell = true;
1534             while ((unsigned int) specnum < special_spells.size()
1535                    && spell == special_spells[specnum])
1536             {
1537                 specnum++;
1538                 skip_spell = false;
1539             }
1540
1541             if (skip_spell)
1542                 continue;
1543         }
1544
1545         if (avoid_known && you.seen_spell[spell])
1546             continue;
1547
1548         if (level != -1)
1549         {
1550             // fixed level randart: only include spells of the given level
1551             if (spell_difficulty(spell) != level)
1552                 continue;
1553         }
1554         else
1555         {
1556             // themed randart: only include spells of the given disciplines
1557             const unsigned int disciplines = get_spell_disciplines(spell);
1558             if ((!(disciplines & disc1) && !(disciplines & disc2))
1559                  || disciplines_conflict(disc1, disciplines)
1560                  || disciplines_conflict(disc2, disciplines))
1561             {
1562                 continue;
1563             }
1564         }
1565
1566         if (avoid_uncastable && you_cannot_memorise(spell))
1567         {
1568             uncastable_discard++;
1569             continue;
1570         }
1571
1572         if (god_dislikes_spell_type(spell, god))
1573         {
1574             god_discard++;
1575             continue;
1576         }
1577
1578         // Passed all tests.
1579         spells.push_back(spell);
1580     }
1581 }
1582
1583 static void _get_spell_list(vector<spell_type> &spells,
1584                             unsigned int disc1, unsigned int disc2,
1585                             god_type god, bool avoid_uncastable,
1586                             int &god_discard, int &uncastable_discard,
1587                             bool avoid_known = false)
1588 {
1589     _get_spell_list(spells, -1, disc1, disc2,
1590                     god, avoid_uncastable, god_discard, uncastable_discard,
1591                     avoid_known);
1592 }
1593
1594 static void _get_spell_list(vector<spell_type> &spells, int level,
1595                             god_type god, bool avoid_uncastable,
1596                             int &god_discard, int &uncastable_discard,
1597                             bool avoid_known = false)
1598 {
1599     _get_spell_list(spells, level, SPTYP_NONE, SPTYP_NONE,
1600                     god, avoid_uncastable, god_discard, uncastable_discard,
1601                     avoid_known);
1602 }
1603
1604 static void _make_book_randart(item_def &book)
1605 {
1606     if (!is_artefact(book))
1607     {
1608         book.flags |= ISFLAG_RANDART;
1609         if (!book.props.exists(ARTEFACT_APPEAR_KEY))
1610         {
1611             book.props[ARTEFACT_APPEAR_KEY].get_string() =
1612                 make_artefact_name(book, true);
1613         }
1614     }
1615 }
1616
1617 bool make_book_level_randart(item_def &book, int level, int num_spells,
1618                              string owner)
1619 {
1620     ASSERT(book.base_type == OBJ_BOOKS);
1621
1622     god_type god;
1623     (void) origin_is_god_gift(book, &god);
1624
1625     const bool completely_random =
1626         god == GOD_XOM || (god == GOD_NO_GOD && !origin_is_acquirement(book));
1627
1628     if (level == -1)
1629     {
1630         int max_level =
1631             (completely_random ? 9
1632                                : min(9, you.get_experience_level()));
1633
1634         level = random_range(1, max_level);
1635     }
1636     ASSERT_RANGE(level, 0 + 1, 9 + 1);
1637
1638     if (num_spells == -1)
1639     {
1640         //555666421
1641         num_spells = min(5 + (level - 1)/3, 18 - 2*level);
1642         num_spells = max(1, num_spells);
1643     }
1644     ASSERT_RANGE(num_spells, 0 + 1, SPELLBOOK_SIZE + 1);
1645
1646     book.plus  = level;
1647     book.plus2 = num_spells;
1648
1649     book.sub_type = BOOK_RANDART_LEVEL;
1650     _make_book_randart(book);
1651
1652     int god_discard        = 0;
1653     int uncastable_discard = 0;
1654
1655     vector<spell_type> spells;
1656     _get_spell_list(spells, level, god, !completely_random,
1657                     god_discard, uncastable_discard);
1658
1659     if (spells.empty())
1660     {
1661         if (level > 1)
1662             return make_book_level_randart(book, level - 1);
1663         char buf[80];
1664
1665         if (god_discard > 0 && uncastable_discard == 0)
1666         {
1667             snprintf(buf, sizeof(buf), "%s disliked all level %d spells",
1668                     god_name(god).c_str(), level);
1669         }
1670         else if (god_discard == 0 && uncastable_discard > 0)
1671             sprintf(buf, "No level %d spells can be cast by you", level);
1672         else if (god_discard > 0 && uncastable_discard > 0)
1673         {
1674             snprintf(buf, sizeof(buf),
1675                          "All level %d spells are either disliked by %s "
1676                          "or cannot be cast by you.",
1677                     level, god_name(god).c_str());
1678         }
1679         else
1680             sprintf(buf, "No level %d spells?!?!?!", level);
1681
1682         mprf(MSGCH_ERROR, "Could not create fixed level randart spellbook: %s",
1683              buf);
1684
1685         return false;
1686     }
1687     random_shuffle(spells.begin(), spells.end());
1688
1689     if (num_spells > (int) spells.size())
1690     {
1691         num_spells = spells.size();
1692 #if defined(DEBUG) || defined(DEBUG_DIAGNOSTICS)
1693         mprf(MSGCH_WARN, "More spells requested for fixed level (%d) "
1694                          "randart spellbook than there are valid spells.",
1695              level);
1696         mprf(MSGCH_WARN, "Discarded %d spells due to being uncastable and "
1697                          "%d spells due to being disliked by %s.",
1698              uncastable_discard, god_discard, god_name(god).c_str());
1699 #endif
1700     }
1701
1702     vector<bool> spell_used(spells.size(), false);
1703     vector<bool> avoid_memorised(spells.size(), !completely_random);
1704     vector<bool> avoid_seen(spells.size(), !completely_random);
1705
1706     spell_type chosen_spells[SPELLBOOK_SIZE];
1707     for (int i = 0; i < SPELLBOOK_SIZE; i++)
1708         chosen_spells[i] = SPELL_NO_SPELL;
1709
1710     int book_pos = 0;
1711     while (book_pos < num_spells)
1712     {
1713         int spell_pos = random2(spells.size());
1714
1715         if (spell_used[spell_pos])
1716             continue;
1717
1718         spell_type spell = spells[spell_pos];
1719         ASSERT(spell != SPELL_NO_SPELL);
1720
1721         if (avoid_memorised[spell_pos] && is_memorised(spell))
1722         {
1723             // Only once.
1724             avoid_memorised[spell_pos] = false;
1725             continue;
1726         }
1727
1728         if (avoid_seen[spell_pos] && you.seen_spell[spell] && coinflip())
1729         {
1730             // Only once.
1731             avoid_seen[spell_pos] = false;
1732             continue;
1733         }
1734
1735         spell_used[spell_pos]     = true;
1736         chosen_spells[book_pos++] = spell;
1737     }
1738     sort(chosen_spells, chosen_spells + SPELLBOOK_SIZE, _compare_spells);
1739     ASSERT(chosen_spells[0] != SPELL_NO_SPELL);
1740
1741     CrawlHashTable &props = book.props;
1742     props.erase(SPELL_LIST_KEY);
1743     props[SPELL_LIST_KEY].new_vector(SV_INT).resize(SPELLBOOK_SIZE);
1744
1745     CrawlVector &spell_vec = props[SPELL_LIST_KEY].get_vector();
1746     spell_vec.set_max_size(SPELLBOOK_SIZE);
1747
1748     for (int i = 0; i < SPELLBOOK_SIZE; i++)
1749         spell_vec[i].get_int() = chosen_spells[i];
1750
1751     bool has_owner = true;
1752     string name = "";
1753     if (!owner.empty())
1754         name = owner;
1755     else if (god != GOD_NO_GOD)
1756         name = god_name(god, false);
1757     else if (one_chance_in(30))
1758         name = god_name(GOD_SIF_MUNA, false);
1759     else if (one_chance_in(3))
1760         name = make_name(random_int(), false);
1761     else
1762         has_owner = false;
1763
1764     if (has_owner)
1765         name = apostrophise(name) + " ";
1766
1767     // None of these books need a definite article prepended.
1768     book.props["is_named"].get_bool() = true;
1769
1770     string bookname;
1771     if (god == GOD_XOM && coinflip())
1772     {
1773         bookname = getRandNameString("book_noun") + " of "
1774                    + getRandNameString("Xom_book_title");
1775         bookname = replace_name_parts(bookname, book);
1776     }
1777     else
1778     {
1779         string lookup;
1780         if (level == 1)
1781             lookup = "starting";
1782         else if (level <= 3 || level == 4 && coinflip())
1783             lookup = "easy";
1784         else if (level <= 6)
1785             lookup = "moderate";
1786         else
1787             lookup = "difficult";
1788
1789         lookup += " level book";
1790
1791         // First try for names respecting the book's previous owner/author
1792         // (if one exists), then check for general difficulty.
1793         if (has_owner)
1794             bookname = getRandNameString(lookup + " owner");
1795
1796         if (!has_owner || bookname.empty())
1797             bookname = getRandNameString(lookup);
1798
1799         bookname = uppercase_first(bookname);
1800         if (has_owner)
1801         {
1802             if (bookname.substr(0, 4) == "The ")
1803                 bookname = bookname.substr(4);
1804             else if (bookname.substr(0, 2) == "A ")
1805                 bookname = bookname.substr(2);
1806             else if (bookname.substr(0, 3) == "An ")
1807                 bookname = bookname.substr(3);
1808         }
1809
1810         if (bookname.find("@level@", 0) != string::npos)
1811         {
1812             string number;
1813             switch (level)
1814             {
1815             case 1: number = "One"; break;
1816             case 2: number = "Two"; break;
1817             case 3: number = "Three"; break;
1818             case 4: number = "Four"; break;
1819             case 5: number = "Five"; break;
1820             case 6: number = "Six"; break;
1821             case 7: number = "Seven"; break;
1822             case 8: number = "Eight"; break;
1823             case 9: number = "Nine"; break;
1824             default:
1825                 number = ""; break;
1826             }
1827             bookname = replace_all(bookname, "@level@", number);
1828         }
1829     }
1830
1831     if (bookname.empty())
1832         bookname = getRandNameString("book");
1833
1834     name += bookname;
1835
1836     set_artefact_name(book, name);
1837
1838     return true;
1839 }
1840
1841 static bool _get_weighted_discs(bool completely_random, god_type god,
1842                                 int &disc1, int &disc2)
1843 {
1844     // Eliminate disciplines that the god dislikes or from which all
1845     // spells are discarded.
1846     vector<int> ok_discs;
1847     vector<skill_type> skills;
1848     vector<int> spellcount;
1849     for (int i = 0; i <= SPTYP_LAST_EXPONENT; i++)
1850     {
1851         int disc = 1 << i;
1852         if (disc & SPTYP_DIVINATION)
1853             continue;
1854
1855         if (god_dislikes_spell_discipline(disc, god))
1856             continue;
1857
1858         int junk1 = 0, junk2 = 0;
1859         vector<spell_type> spells;
1860         _get_spell_list(spells, disc, disc, god, !completely_random,
1861                         junk1, junk2, !completely_random);
1862
1863         if (spells.empty())
1864             continue;
1865
1866         ok_discs.push_back(disc);
1867         skills.push_back(spell_type2skill(disc));
1868         spellcount.push_back(spells.size());
1869     }
1870
1871     int num_discs = ok_discs.size();
1872
1873     if (num_discs == 0)
1874     {
1875 #ifdef DEBUG
1876         mpr("No valid disciplines with which to make a themed randart "
1877             "spellbook.", MSGCH_ERROR);
1878 #endif
1879         // Only happens if !completely_random and the player already knows
1880         // all available spells. We could simply re-allow all disciplines
1881         // but the player isn't going to get any new spells, anyway, so just
1882         // consider this acquirement failed. (jpeg)
1883         return false;
1884     }
1885
1886     int skill_weights[SPTYP_LAST_EXPONENT + 1];
1887
1888     memset(skill_weights, 0, (SPTYP_LAST_EXPONENT + 1) * sizeof(int));
1889
1890     if (!completely_random)
1891     {
1892         int total_skills = 0;
1893         for (int i = 0; i < num_discs; i++)
1894         {
1895             skill_type skill  = skills[i];
1896             int weight = 2 * you.skills[skill] + 1;
1897
1898             if (spellcount[i] < 3)
1899                 weight *= spellcount[i]/3;
1900
1901             skill_weights[i] = max(0, weight);
1902             total_skills += skill_weights[i];
1903         }
1904
1905         if (total_skills == 0)
1906             completely_random = true;
1907     }
1908
1909     if (completely_random)
1910     {
1911         for (int i = 0; i < num_discs; i++)
1912             skill_weights[i] = 1;
1913     }
1914
1915     do
1916     {
1917         disc1 = ok_discs[choose_random_weighted(skill_weights,
1918                                                 skill_weights + num_discs)];
1919         disc2 = ok_discs[choose_random_weighted(skill_weights,
1920                                                 skill_weights + num_discs)];
1921     }
1922     while (disciplines_conflict(disc1, disc2));
1923
1924     return true;
1925 }
1926
1927 static bool _get_weighted_spells(bool completely_random, god_type god,
1928                                  int disc1, int disc2,
1929                                  int num_spells, int max_levels,
1930                                  const vector<spell_type> &spells,
1931                                  spell_type chosen_spells[])
1932 {
1933     ASSERT(num_spells <= (int) spells.size());
1934     ASSERT(num_spells <= SPELLBOOK_SIZE);
1935     ASSERT(num_spells > 0);
1936     ASSERT(max_levels > 0);
1937
1938     int spell_weights[NUM_SPELLS];
1939     memset(spell_weights, 0, NUM_SPELLS * sizeof(int));
1940
1941     if (completely_random)
1942     {
1943         for (unsigned int i = 0; i < spells.size(); i++)
1944         {
1945             spell_type spl = spells[i];
1946             if (god == GOD_XOM)
1947                 spell_weights[spl] = count_bits(get_spell_disciplines(spl));
1948             else
1949                 spell_weights[spl] = 1;
1950         }
1951     }
1952     else
1953     {
1954         const int Spc = you.skills[SK_SPELLCASTING];
1955         for (unsigned int i = 0; i < spells.size(); i++)
1956         {
1957             spell_type spell = spells[i];
1958             unsigned int disciplines = get_spell_disciplines(spell);
1959
1960             int d = 1;
1961             if ((disciplines & disc1) && (disciplines & disc2))
1962                 d = 2;
1963
1964             int c = 1;
1965             if (!you.seen_spell[spell])
1966                 c = 4;
1967             else if (!is_memorised(spell))
1968                 c = 2;
1969
1970             int total_skill = 0;
1971             int num_skills  = 0;
1972             for (int j = 0; j <= SPTYP_LAST_EXPONENT; j++)
1973             {
1974                 int disc = 1 << j;
1975
1976                 if (disciplines & disc)
1977                 {
1978                     total_skill += you.skills[spell_type2skill(disc)];
1979                     num_skills++;
1980                 }
1981             }
1982             int w = 1;
1983             if (num_skills > 0)
1984                 w = (2 + (total_skill / num_skills)) / 3;
1985             w = max(1, w);
1986
1987             int l = 5 - abs(3 * spell_difficulty(spell) - Spc) / 7;
1988
1989             int weight = d * c * w * l;
1990
1991             ASSERT(weight > 0);
1992             spell_weights[spell] = weight;
1993         }
1994     }
1995
1996     int book_pos    = 0;
1997     int spells_left = spells.size();
1998     while (book_pos < num_spells && max_levels > 0 && spells_left > 0)
1999     {
2000         if (chosen_spells[book_pos] != SPELL_NO_SPELL)
2001         {
2002             spell_type spell = chosen_spells[book_pos];
2003             spell_weights[spell]  = 0;
2004             max_levels           -= spell_difficulty(spell);
2005             spells_left--;
2006             book_pos++;
2007             continue;
2008         }
2009
2010         spell_type spell =
2011             (spell_type) choose_random_weighted(spell_weights,
2012                                                 spell_weights + NUM_SPELLS);
2013         ASSERT(is_valid_spell(spell));
2014         ASSERT(spell_weights[spell] > 0);
2015
2016         int levels = spell_difficulty(spell);
2017
2018         if (levels > max_levels)
2019         {
2020             spell_weights[spell] = 0;
2021             spells_left--;
2022             continue;
2023         }
2024         chosen_spells[book_pos++] = spell;
2025         spell_weights[spell]      = 0;
2026         max_levels               -= levels;
2027         spells_left--;
2028     }
2029     ASSERT(max_levels >= 0);
2030
2031     return book_pos > 0;
2032 }
2033
2034 static void _remove_nondiscipline_spells(spell_type chosen_spells[],
2035                                          int d1, int d2,
2036                                          spell_type exclude = SPELL_NO_SPELL)
2037 {
2038     int replace = -1;
2039     for (int i = 0; i < SPELLBOOK_SIZE; i++)
2040     {
2041         if (chosen_spells[i] == SPELL_NO_SPELL)
2042             break;
2043
2044         if (chosen_spells[i] == exclude)
2045             continue;
2046
2047         // If a spell matches neither the first nor the second type
2048         // (that may be the same) remove it.
2049         if (!spell_typematch(chosen_spells[i], d1)
2050             && !spell_typematch(chosen_spells[i], d2))
2051         {
2052             chosen_spells[i] = SPELL_NO_SPELL;
2053             if (replace == -1)
2054                 replace = i;
2055         }
2056         else if (replace != -1)
2057         {
2058             chosen_spells[replace] = chosen_spells[i];
2059             chosen_spells[i] = SPELL_NO_SPELL;
2060             replace++;
2061         }
2062     }
2063 }
2064
2065 static void _add_included_spells(spell_type chosen_spells[SPELLBOOK_SIZE],
2066                                  vector<spell_type> incl_spells)
2067 {
2068     for (unsigned int i = 0; i < incl_spells.size(); ++i)
2069     {
2070         spell_type incl_spell = incl_spells[i];
2071
2072         if (incl_spell == SPELL_NO_SPELL)
2073             continue;
2074
2075         for (int j = 0; j < SPELLBOOK_SIZE; ++j)
2076         {
2077             // Already included.
2078             if (chosen_spells[j] == incl_spell)
2079                 break;
2080
2081             if (chosen_spells[j] == SPELL_NO_SPELL)
2082             {
2083                 // Add to spells.
2084                 chosen_spells[j] = incl_spell;
2085                 break;
2086             }
2087         }
2088     }
2089 }
2090
2091 // Takes a book of any type, a spell discipline or two, the number of spells
2092 // (up to 8), the total spell levels of all spells, a spell that absolutely
2093 // has to be included, and the name of whomever the book should be named after.
2094 // With all that information the book is turned into a random artefact
2095 // containing random spells of the given disciplines (random if none set).
2096 bool make_book_theme_randart(item_def &book, int disc1, int disc2,
2097                              int num_spells, int max_levels,
2098                              spell_type incl_spell, string owner,
2099                              string title)
2100 {
2101     vector<spell_type> spells;
2102     if (incl_spell != SPELL_NO_SPELL)
2103         spells.push_back(incl_spell);
2104     return make_book_theme_randart(book, spells, disc1, disc2,
2105                                    num_spells, max_levels, owner, title);
2106 }
2107
2108 bool make_book_theme_randart(item_def &book,
2109                              vector<spell_type> incl_spells,
2110                              int disc1, int disc2,
2111                              int num_spells, int max_levels,
2112                              string owner, string title)
2113 {
2114     ASSERT(book.base_type == OBJ_BOOKS);
2115
2116     god_type god;
2117     (void) origin_is_god_gift(book, &god);
2118
2119     const bool completely_random =
2120         god == GOD_XOM || (god == GOD_NO_GOD && !origin_is_acquirement(book));
2121
2122     if (num_spells == -1)
2123         num_spells = SPELLBOOK_SIZE;
2124     ASSERT_RANGE(num_spells, 0 + 1, SPELLBOOK_SIZE + 1);
2125
2126     if (max_levels == -1)
2127         max_levels = 255;
2128
2129     if (disc1 == 0 && disc2 == 0)
2130     {
2131         if (!_get_weighted_discs(completely_random, god, disc1, disc2))
2132         {
2133             if (completely_random)
2134                 return false;
2135
2136             // Rather than give up at this point, choose schools randomly.
2137             // This way, an acquirement won't fail once the player has
2138             // seen all spells.
2139             if (!_get_weighted_discs(true, god, disc1, disc2))
2140                 return false;
2141         }
2142     }
2143     else if (disc2 == 0)
2144         disc2 = disc1;
2145
2146     ASSERT(disc1 < (1 << (SPTYP_LAST_EXPONENT + 1)));
2147     ASSERT(disc2 < (1 << (SPTYP_LAST_EXPONENT + 1)));
2148     ASSERT(count_bits(disc1) == 1 && count_bits(disc2) == 1);
2149
2150     int disc1_pos = 0, disc2_pos = 0;
2151     for (int i = 0; i <= SPTYP_LAST_EXPONENT; i++)
2152     {
2153         if (disc1 & (1 << i))
2154             disc1_pos = i;
2155         if (disc2 & (1 << i))
2156             disc2_pos = i;
2157     }
2158
2159     book.plus  = num_spells | (max_levels << 8);
2160     book.plus2 = disc1_pos  | (disc2_pos  << 8);
2161
2162     book.sub_type = BOOK_RANDART_THEME;
2163     _make_book_randart(book);
2164
2165     int god_discard        = 0;
2166     int uncastable_discard = 0;
2167
2168     vector<spell_type> spells;
2169     _get_spell_list(spells, disc1, disc2, god, !completely_random,
2170                     god_discard, uncastable_discard);
2171
2172     if (num_spells > (int) spells.size())
2173         num_spells = spells.size();
2174
2175     spell_type chosen_spells[SPELLBOOK_SIZE];
2176     for (int i = 0; i < SPELLBOOK_SIZE; i++)
2177         chosen_spells[i] = SPELL_NO_SPELL;
2178
2179     _add_included_spells(chosen_spells, incl_spells);
2180
2181     // If max_levels is 1, there might not be any suitable spells (for
2182     // example, in Charms).  Try one more time with max_levels = 2.
2183     while (!_get_weighted_spells(completely_random, god, disc1, disc2,
2184                                  num_spells, max_levels, spells,
2185                                  chosen_spells))
2186     {
2187         if (max_levels != 1)
2188             die("_get_weighted_spells() failed");
2189
2190         ++max_levels;
2191     }
2192
2193     sort(chosen_spells, chosen_spells + SPELLBOOK_SIZE, _compare_spells);
2194     ASSERT(chosen_spells[0] != SPELL_NO_SPELL);
2195
2196     CrawlHashTable &props = book.props;
2197     props.erase(SPELL_LIST_KEY);
2198     props[SPELL_LIST_KEY].new_vector(SV_INT).resize(SPELLBOOK_SIZE);
2199
2200     CrawlVector &spell_vec = props[SPELL_LIST_KEY].get_vector();
2201     spell_vec.set_max_size(SPELLBOOK_SIZE);
2202
2203     // Count how often each spell school appears in the book.
2204     int count[SPTYP_LAST_EXPONENT+1];
2205     for (int k = 0; k <= SPTYP_LAST_EXPONENT; k++)
2206         count[k] = 0;
2207
2208     for (int i = 0; i < SPELLBOOK_SIZE; i++)
2209     {
2210         if (chosen_spells[i] == SPELL_NO_SPELL)
2211             continue;
2212
2213         for (int k = 0; k <= SPTYP_LAST_EXPONENT; k++)
2214             if (spell_typematch(chosen_spells[i], 1 << k))
2215                 count[k]++;
2216     }
2217
2218     // Remember the two dominant spell schools ...
2219     int max1 = 0;
2220     int max2 = 0;
2221     int num1 = 1;
2222     int num2 = 0;
2223     for (int k = 1; k <= SPTYP_LAST_EXPONENT; k++)
2224     {
2225         if (count[k] > count[max1])
2226         {
2227             max2 = max1;
2228             num2 = num1;
2229             max1 = k;
2230             num1 = 1;
2231         }
2232         else
2233         {
2234             if (count[k] == count[max1])
2235                 num1++;
2236
2237             if (max2 == max1 || count[k] > count[max2])
2238             {
2239                 max2 = k;
2240                 if (count[k] == count[max1])
2241                     num2 = num1;
2242                 else
2243                     num2 = 1;
2244             }
2245             else if (count[k] == count[max2])
2246                 num2++;
2247         }
2248     }
2249
2250     // If there are several "secondary" disciplines with the same count
2251     // ignore all of them. Same, if the secondary discipline appears only once.
2252     if (num2 > 1 && count[max1] > count[max2] || count[max2] < 2)
2253         max2 = max1;
2254
2255     // Remove spells that don't fit either discipline.
2256     _remove_nondiscipline_spells(chosen_spells, 1 << max1, 1 << max2);
2257     _add_included_spells(chosen_spells, incl_spells);
2258
2259     // Resort spells.
2260     if (!incl_spells.empty())
2261         sort(chosen_spells, chosen_spells + SPELLBOOK_SIZE, _compare_spells);
2262     ASSERT(chosen_spells[0] != SPELL_NO_SPELL);
2263
2264     // ... and change disc1 and disc2 accordingly.
2265     disc1 = 1 << max1;
2266     if (max1 == max2)
2267         disc2 = disc1;
2268     else
2269         disc2 = 1 << max2;
2270
2271     int highest_level = 0;
2272     int lowest_level  = 10;
2273     bool all_spells_disc1 = true;
2274
2275     // Finally fill the spell vector.
2276     for (int i = 0; i < SPELLBOOK_SIZE; i++)
2277     {
2278         spell_vec[i].get_int() = chosen_spells[i];
2279         int diff = spell_difficulty(chosen_spells[i]);
2280         if (diff > highest_level)
2281             highest_level = diff;
2282         else if (diff < lowest_level)
2283             lowest_level = diff;
2284
2285         if (all_spells_disc1 && is_valid_spell(chosen_spells[i])
2286             && !spell_typematch(chosen_spells[i], disc1))
2287         {
2288             all_spells_disc1 = false;
2289         }
2290     }
2291
2292     // Every spell in the book is of school disc1.
2293     if (disc1 == disc2)
2294         all_spells_disc1 = true;
2295
2296     // If the owner hasn't been set already use
2297     // a) the god's name for god gifts (only applies to Sif Muna and Xom),
2298     // b) a name depending on the spell disciplines, for pure books
2299     // c) a random name (all god gifts not named earlier)
2300     // d) an applicable god's name
2301     // ... else leave it unnamed (around 57% chance for non-god gifts)
2302     if (owner.empty())
2303     {
2304         const bool god_gift = (god != GOD_NO_GOD);
2305         if (god_gift && !one_chance_in(4))
2306             owner = god_name(god, false);
2307         else if (god_gift && one_chance_in(3) || one_chance_in(5))
2308         {
2309             bool highlevel = (highest_level >= 7 + random2(3)
2310                               && (lowest_level > 1 || coinflip()));
2311
2312             if (disc1 != disc2)
2313             {
2314                 string schools[2];
2315                 schools[0] = spelltype_long_name(disc1);
2316                 schools[1] = spelltype_long_name(disc2);
2317                 sort(schools, schools + 2);
2318                 string lookup = schools[0] + " " + schools[1];
2319
2320                 if (highlevel)
2321                     owner = getRandNameString("highlevel " + lookup + " owner");
2322
2323                 if (owner.empty() || owner == "__NONE")
2324                     owner = getRandNameString(lookup + " owner");
2325
2326                 if (owner == "__NONE")
2327                     owner = "";
2328             }
2329
2330             if (owner.empty() && all_spells_disc1)
2331             {
2332                 string lookup = spelltype_long_name(disc1);
2333                 if (highlevel && disc1 == disc2)
2334                     owner = getRandNameString("highlevel " + lookup + " owner");
2335
2336                 if (owner.empty() || owner == "__NONE")
2337                     owner = getRandNameString(lookup + " owner");
2338
2339                 if (owner == "__NONE")
2340                     owner = "";
2341             }
2342         }
2343
2344         if (owner.empty())
2345         {
2346             if (god_gift || one_chance_in(5)) // Use a random name.
2347                 owner = make_name(random_int(), false);
2348             else if (!god_gift && one_chance_in(9))
2349             {
2350                 god = GOD_SIF_MUNA;
2351                 switch (disc1)
2352                 {
2353                 case SPTYP_NECROMANCY:
2354                     if (all_spells_disc1 && !one_chance_in(6))
2355                         god = GOD_KIKUBAAQUDGHA;
2356                     break;
2357                 case SPTYP_CONJURATION:
2358                     if (all_spells_disc1 && !one_chance_in(4))
2359                         god = GOD_VEHUMET;
2360                     break;
2361                 default:
2362                     break;
2363                 }
2364                 owner = god_name(god, false);
2365             }
2366         }
2367     }
2368
2369     string name = "";
2370
2371     if (!owner.empty())
2372     {
2373         name = apostrophise(owner) + " ";
2374         book.props["is_named"].get_bool() = true;
2375     }
2376     else
2377         book.props["is_named"].get_bool() = false;
2378
2379     string bookname = "";
2380     if (!title.empty())
2381         bookname = title;
2382     else
2383     {
2384         // Sometimes use a completely random title.
2385         if (owner == "Xom" && !one_chance_in(20))
2386             bookname = getRandNameString("Xom_book_title");
2387         else if (one_chance_in(20) && (owner.empty() || one_chance_in(3)))
2388             bookname = getRandNameString("random_book_title");
2389         bookname = replace_name_parts(bookname, book);
2390     }
2391
2392     if (!bookname.empty())
2393         name += getRandNameString("book_noun") + " of " + bookname;
2394     else
2395     {
2396         // Give a name that reflects the primary and secondary
2397         // spell disciplines of the spells contained in the book.
2398         name += getRandNameString("book_name") + " ";
2399
2400         // For the actual name there's a 66% chance of getting something like
2401         //  <book> of the Fiery Traveller (Translocation/Fire), else
2402         //  <book> of Displacement and Flames.
2403         string type_name;
2404         if (disc1 != disc2 && !one_chance_in(3))
2405         {
2406             string lookup = spelltype_long_name(disc2);
2407             type_name = getRandNameString(lookup + " adj");
2408         }
2409
2410         if (type_name.empty())
2411         {
2412             // No adjective found, use the normal method of combining two nouns.
2413             type_name = getRandNameString(spelltype_long_name(disc1));
2414             if (type_name.empty())
2415                 name += spelltype_long_name(disc1);
2416             else
2417                 name += type_name;
2418
2419             if (disc1 != disc2)
2420             {
2421                 name += " and ";
2422                 type_name = getRandNameString(spelltype_long_name(disc2));
2423
2424                 if (type_name.empty())
2425                     name += spelltype_long_name(disc2);
2426                 else
2427                     name += type_name;
2428             }
2429         }
2430         else
2431         {
2432             bookname = type_name + " ";
2433
2434             // Add the noun for the first discipline.
2435             type_name = getRandNameString(spelltype_long_name(disc1));
2436             if (type_name.empty())
2437                 bookname += spelltype_long_name(disc1);
2438             else
2439             {
2440                 if (type_name.find("the ", 0) != string::npos)
2441                 {
2442                     type_name = replace_all(type_name, "the ", "");
2443                     bookname = "the " + bookname;
2444                 }
2445                 bookname += type_name;
2446             }
2447             name += bookname;
2448         }
2449     }
2450
2451     set_artefact_name(book, name);
2452
2453     // Save primary/secondary disciplines back into the book.
2454     book.plus  = max1;
2455     book.plus2 = max2;
2456
2457     return true;
2458 }
2459
2460 // Give Roxanne a randart spellbook of the disciplines Transmutations/Earth
2461 // that includes Statue Form and is named after her.
2462 void make_book_Roxanne_special(item_def *book)
2463 {
2464     int disc =  coinflip() ? SPTYP_TRANSMUTATION : SPTYP_EARTH;
2465     make_book_theme_randart(*book, disc, 0, 5, 19,
2466                             SPELL_STATUE_FORM, "Roxanne");
2467 }
2468
2469 void make_book_Kiku_gift(item_def &book, bool first)
2470 {
2471     book.sub_type = BOOK_RANDART_THEME;
2472     _make_book_randart(book);
2473
2474     spell_type chosen_spells[SPELLBOOK_SIZE];
2475     for (int i = 0; i < SPELLBOOK_SIZE; i++)
2476         chosen_spells[i] = SPELL_NO_SPELL;
2477
2478     if (first)
2479     {
2480         chosen_spells[0] = coinflip() ? SPELL_PAIN : SPELL_ANIMATE_SKELETON;
2481         if (you.species == SP_FELID || one_chance_in(3))
2482         {
2483             chosen_spells[1] = SPELL_CORPSE_ROT;
2484             chosen_spells[2] = SPELL_SUBLIMATION_OF_BLOOD;
2485         }
2486         else
2487         {
2488             chosen_spells[1] = coinflip() ? SPELL_CORPSE_ROT : SPELL_SUBLIMATION_OF_BLOOD;
2489             chosen_spells[2] = SPELL_LETHAL_INFUSION;
2490         }
2491         chosen_spells[3] = (you.species == SP_DEEP_DWARF
2492                             || you.species == SP_MUMMY
2493                             || coinflip())
2494                            ? SPELL_VAMPIRIC_DRAINING : SPELL_REGENERATION;
2495         chosen_spells[4] = SPELL_CONTROL_UNDEAD;
2496     }
2497     else
2498     {
2499         chosen_spells[0] = coinflip() ? SPELL_ANIMATE_DEAD : SPELL_TWISTED_RESURRECTION;
2500         chosen_spells[1] = (you.species == SP_FELID || coinflip())
2501                            ? SPELL_AGONY : SPELL_EXCRUCIATING_WOUNDS;
2502         chosen_spells[2] = random_choose(SPELL_BOLT_OF_DRAINING,
2503                                          SPELL_SIMULACRUM,
2504                                          SPELL_DEATH_CHANNEL,
2505                                          -1);
2506         spell_type extra_spell;
2507         do
2508         {
2509             extra_spell = random_choose(SPELL_ANIMATE_DEAD,
2510                                         SPELL_TWISTED_RESURRECTION,
2511                                         SPELL_AGONY,
2512                                         SPELL_EXCRUCIATING_WOUNDS,
2513                                         SPELL_BOLT_OF_DRAINING,
2514                                         SPELL_SIMULACRUM,
2515                                         SPELL_DEATH_CHANNEL,
2516                                         -1);
2517             if (you.species == SP_FELID && extra_spell == SPELL_EXCRUCIATING_WOUNDS)
2518                 extra_spell = SPELL_NO_SPELL;
2519             for (int i = 0; i < 3; i++)
2520                 if (extra_spell == chosen_spells[i])
2521                     extra_spell = SPELL_NO_SPELL;
2522         }
2523         while (extra_spell == SPELL_NO_SPELL);
2524         chosen_spells[3] = extra_spell;
2525         chosen_spells[4] = SPELL_DISPEL_UNDEAD;
2526     }
2527
2528     sort(chosen_spells, chosen_spells + SPELLBOOK_SIZE, _compare_spells);
2529
2530     CrawlHashTable &props = book.props;
2531     props.erase(SPELL_LIST_KEY);
2532     props[SPELL_LIST_KEY].new_vector(SV_INT).resize(SPELLBOOK_SIZE);
2533
2534     CrawlVector &spell_vec = props[SPELL_LIST_KEY].get_vector();
2535     spell_vec.set_max_size(SPELLBOOK_SIZE);
2536
2537     for (int i = 0; i < SPELLBOOK_SIZE; i++)
2538         spell_vec[i].get_int() = chosen_spells[i];
2539
2540     string name = "Kikubaaqudgha's ";
2541     book.props["is_named"].get_bool() = true;
2542     name += getRandNameString("book_name") + " ";
2543     string type_name = getRandNameString("Necromancy");
2544     if (type_name.empty())
2545         name += "Necromancy";
2546     else
2547         name += type_name;
2548     set_artefact_name(book, name);
2549 }
2550
2551 bool book_has_title(const item_def &book)
2552 {
2553     ASSERT(book.base_type == OBJ_BOOKS);
2554
2555     if (!is_artefact(book))
2556         return false;
2557
2558     return (book.props.exists("is_named")
2559             && book.props["is_named"].get_bool() == true);
2560 }
2561
2562 void destroy_spellbook(const item_def &book)
2563 {
2564     int j, maxlevel = 0;
2565     for (j = 0; j < SPELLBOOK_SIZE; j++)
2566     {
2567         spell_type stype = which_spell_in_book(book, j);
2568         if (stype == SPELL_NO_SPELL)
2569             continue;
2570         maxlevel = max(maxlevel, spell_difficulty(stype));
2571     }
2572
2573     god_type god;
2574     // The known boolean is being used to double penance when the destroyed
2575     // book is a gift of Sif Muna.
2576     did_god_conduct(DID_DESTROY_SPELLBOOK, maxlevel + 5,
2577                     origin_is_god_gift(book, &god) && god == GOD_SIF_MUNA);
2578 }