Don't give pan lords rings of fog
[crawl.git] / crawl-ref / source / decks.cc
1 /**
2  * @file
3  * @brief Functions with decks of cards.
4 **/
5
6 #include "AppHdr.h"
7
8 #include "decks.h"
9
10 #include <algorithm>
11 #include <iostream>
12 #include <sstream>
13
14 #include "act-iter.h"
15 #include "artefact.h"
16 #include "attitude-change.h"
17 #include "cloud.h"
18 #include "coordit.h"
19 #include "dactions.h"
20 #include "database.h"
21 #include "directn.h"
22 #include "dungeon.h"
23 #include "effects.h"
24 #include "english.h"
25 #include "evoke.h"
26 #include "food.h"
27 #include "ghost.h"
28 #include "godwrath.h"
29 #include "invent.h"
30 #include "itemprop.h"
31 #include "items.h"
32 #include "item_use.h"
33 #include "libutil.h"
34 #include "macro.h"
35 #include "message.h"
36 #include "misc.h"
37 #include "mon-cast.h"
38 #include "mon-clone.h"
39 #include "mon-death.h"
40 #include "mon-place.h"
41 #include "mon-poly.h"
42 #include "mon-project.h"
43 #include "mutation.h"
44 #include "notes.h"
45 #include "output.h"
46 #include "player-equip.h"
47 #include "player-stats.h"
48 #include "potion.h"
49 #include "prompt.h"
50 #include "religion.h"
51 #include "spl-clouds.h"
52 #include "spl-goditem.h"
53 #include "spl-miscast.h"
54 #include "spl-monench.h"
55 #include "spl-other.h"
56 #include "spl-selfench.h"
57 #include "spl-summoning.h"
58 #include "spl-transloc.h"
59 #include "spl-wpnench.h"
60 #include "state.h"
61 #include "stringutil.h"
62 #include "teleport.h"
63 #include "terrain.h"
64 #include "transform.h"
65 #include "traps.h"
66 #include "uncancel.h"
67 #include "view.h"
68 #include "xom.h"
69
70 // DECK STRUCTURE: deck.initial_cards is the number of cards the deck *started*
71 // with, deck.used_count is* the number of cards drawn, deck.rarity is the
72 // deck rarity, deck.props["cards"] holds the list of cards (with the
73 // highest index card being the top card, and index 0 being the bottom
74 // card), deck.props["drawn_cards"] holds the list of drawn cards
75 // (with index 0 being the first drawn), deck.props["card_flags"]
76 // holds the flags for each card, deck.props["num_marked"] is the
77 // number of marked cards left in the deck.
78 //
79 // if deck.used_count is negative, it's actually -(cards_left). wtf.
80 //
81 // The card type and per-card flags are each stored as unsigned bytes,
82 // for a maximum of 256 different kinds of cards and 8 bits of flags.
83
84 static void _deck_ident(item_def& deck);
85
86 struct card_with_weights
87 {
88     card_type card;
89     int weight[3];
90 };
91
92 typedef card_with_weights deck_archetype;
93
94 #define END_OF_DECK {NUM_CARDS, {0,0,0}}
95
96 const deck_archetype deck_of_transport[] =
97 {
98     { CARD_WARPWRIGHT, {5, 5, 5} },
99     { CARD_SWAP,       {5, 5, 5} },
100     { CARD_VELOCITY,   {5, 5, 5} },
101     { CARD_SOLITUDE,   {5, 5, 5} },
102     END_OF_DECK
103 };
104
105 const deck_archetype deck_of_emergency[] =
106 {
107     { CARD_TOMB,       {5, 5, 5} },
108     { CARD_BANSHEE,    {5, 5, 5} },
109     { CARD_DAMNATION,  {0, 1, 2} },
110     { CARD_SHAFT,      {5, 5, 5} },
111     { CARD_ALCHEMIST,  {5, 5, 5} },
112     { CARD_ELIXIR,     {5, 5, 5} },
113     { CARD_CLOUD,      {5, 5, 5} },
114     END_OF_DECK
115 };
116
117 const deck_archetype deck_of_destruction[] =
118 {
119     { CARD_VITRIOL,  {5, 5, 5} },
120     { CARD_HAMMER,   {5, 5, 5} },
121     { CARD_VENOM,    {5, 5, 5} },
122     { CARD_STORM,    {5, 5, 5} },
123     { CARD_PAIN,     {5, 5, 3} },
124     { CARD_ORB,      {5, 5, 5} },
125     { CARD_DEGEN,    {5, 5, 5} },
126     END_OF_DECK
127 };
128
129 const deck_archetype deck_of_battle[] =
130 {
131     { CARD_ELIXIR,        {5, 5, 5} },
132     { CARD_POTION,        {5, 5, 5} },
133     { CARD_HELM,          {5, 5, 5} },
134     { CARD_BLADE,         {5, 5, 5} },
135     { CARD_SHADOW,        {5, 5, 5} },
136     { CARD_FORTITUDE,     {5, 5, 5} },
137     END_OF_DECK
138 };
139
140 const deck_archetype deck_of_summoning[] =
141 {
142     { CARD_CRUSADE,         {5, 5, 5} },
143     { CARD_ELEMENTS,        {5, 5, 5} },
144     { CARD_SUMMON_DEMON,    {5, 5, 5} },
145     { CARD_SUMMON_WEAPON,   {5, 5, 5} },
146     { CARD_SUMMON_FLYING,   {5, 5, 5} },
147     { CARD_RANGERS,         {5, 5, 5} },
148     { CARD_SUMMON_UGLY,     {5, 5, 5} },
149     { CARD_ILLUSION,        {5, 5, 5} },
150     END_OF_DECK
151 };
152
153 const deck_archetype deck_of_wonders[] =
154 {
155     { CARD_FOCUS,             {3, 3, 3} },
156     { CARD_HELIX,             {3, 4, 5} },
157     { CARD_WILD_MAGIC,        {5, 5, 5} },
158     { CARD_DOWSING,           {5, 5, 5} },
159     { CARD_MERCENARY,         {5, 5, 5} },
160     { CARD_ALCHEMIST,         {5, 5, 5} },
161     { CARD_PLACID_MAGIC,      {5, 5, 5} },
162     END_OF_DECK
163 };
164
165 #if TAG_MAJOR_VERSION == 34
166 const deck_archetype deck_of_dungeons[] =
167 {
168     { CARD_WATER,     {5, 5, 5} },
169     { CARD_GLASS,     {5, 5, 5} },
170     { CARD_DOWSING,   {5, 5, 5} },
171     { CARD_TROWEL,    {0, 0, 3} },
172     { CARD_MINEFIELD, {5, 5, 5} },
173     END_OF_DECK
174 };
175 #endif
176
177 const deck_archetype deck_of_oddities[] =
178 {
179     { CARD_WRATH,   {5, 5, 5} },
180     { CARD_XOM,     {5, 5, 5} },
181     { CARD_FEAST,   {5, 5, 5} },
182     { CARD_FAMINE,  {5, 5, 5} },
183     { CARD_CURSE,   {5, 5, 5} },
184     { CARD_HELIX,   {5, 5, 5} },
185     { CARD_FOCUS,   {5, 5, 5} },
186     END_OF_DECK
187 };
188
189 const deck_archetype deck_of_punishment[] =
190 {
191     { CARD_WRAITH,     {5, 5, 5} },
192     { CARD_WRATH,      {5, 5, 5} },
193     { CARD_XOM,        {5, 5, 5} },
194     { CARD_FAMINE,     {5, 5, 5} },
195     { CARD_CURSE,      {5, 5, 5} },
196     { CARD_DAMNATION,  {3, 3, 3} },
197     { CARD_SWINE,      {5, 5, 5} },
198     { CARD_TORMENT,    {5, 5, 5} },
199     END_OF_DECK
200 };
201
202 static void _check_odd_card(uint8_t flags)
203 {
204     if ((flags & CFLAG_ODDITY) && !(flags & CFLAG_SEEN))
205         mpr("This card doesn't seem to belong here.");
206 }
207
208 static bool _card_forbidden(card_type card)
209 {
210     if (crawl_state.game_is_zotdef())
211     {
212         switch (card)
213         {
214         case CARD_TOMB:
215         case CARD_WARPWRIGHT:
216         case CARD_STAIRS:
217             return true;
218         default:
219             break;
220         }
221     }
222     return false;
223 }
224
225 int cards_in_deck(const item_def &deck)
226 {
227     ASSERT(is_deck(deck));
228
229     const CrawlHashTable &props = deck.props;
230     ASSERT(props.exists("cards"));
231
232     return props["cards"].get_vector().size();
233 }
234
235 static void _shuffle_deck(item_def &deck)
236 {
237     ASSERT(is_deck(deck));
238
239     CrawlHashTable &props = deck.props;
240     ASSERT(props.exists("cards"));
241
242     CrawlVector &cards = props["cards"].get_vector();
243
244     CrawlVector &flags = props["card_flags"].get_vector();
245     ASSERT(flags.size() == cards.size());
246
247     // Don't use shuffle(), since we want to apply exactly the
248     // same shuffling to both the cards vector and the flags vector.
249     vector<vec_size> pos;
250     for (size_t i = 0; i < cards.size(); ++i)
251         pos.push_back(random2(cards.size()));
252
253     for (vec_size i = 0; i < pos.size(); ++i)
254     {
255         swap(cards[i], cards[pos[i]]);
256         swap(flags[i], flags[pos[i]]);
257     }
258 }
259
260 card_type get_card_and_flags(const item_def& deck, int idx,
261                              uint8_t& _flags)
262 {
263     const CrawlHashTable &props = deck.props;
264     const CrawlVector    &cards = props["cards"].get_vector();
265     const CrawlVector    &flags = props["card_flags"].get_vector();
266
267     // Negative idx means read from the end.
268     if (idx < 0)
269         idx += static_cast<int>(cards.size());
270
271     _flags = (uint8_t) flags[idx].get_byte();
272
273     return static_cast<card_type>(cards[idx].get_byte());
274 }
275
276 static void _set_card_and_flags(item_def& deck, int idx, card_type card,
277                                 uint8_t _flags)
278 {
279     CrawlHashTable &props = deck.props;
280     CrawlVector    &cards = props["cards"].get_vector();
281     CrawlVector    &flags = props["card_flags"].get_vector();
282
283     if (idx < 0)
284         idx = static_cast<int>(cards.size()) + idx;
285
286     cards[idx].get_byte() = card;
287     flags[idx].get_byte() = _flags;
288 }
289
290 const char* card_name(card_type card)
291 {
292     switch (card)
293     {
294 #if TAG_MAJOR_VERSION == 34
295     case CARD_PORTAL:          return "the Portal";
296     case CARD_WARP:            return "the Warp";
297     case CARD_BATTLELUST:      return "Battlelust";
298     case CARD_METAMORPHOSIS:   return "Metamorphosis";
299     case CARD_SHUFFLE:         return "Shuffle";
300     case CARD_EXPERIENCE:      return "Experience";
301     case CARD_SAGE:            return "the Sage";
302     case CARD_TROWEL:          return "the Trowel";
303     case CARD_MINEFIELD:       return "the Minefield";
304     case CARD_GENIE:           return "the Genie";
305     case CARD_WATER:           return "Water";
306     case CARD_GLASS:           return "Vitrification";
307     case CARD_BARGAIN:         return "the Bargain";
308     case CARD_SUMMON_ANIMAL:   return "the Herd";
309     case CARD_SUMMON_SKELETON: return "the Bones";
310 #endif
311     case CARD_SWAP:            return "Swap";
312     case CARD_VELOCITY:        return "Velocity";
313     case CARD_DAMNATION:       return "Damnation";
314     case CARD_SOLITUDE:        return "Solitude";
315     case CARD_ELIXIR:          return "the Elixir";
316     case CARD_HELM:            return "the Helm";
317     case CARD_BLADE:           return "the Blade";
318     case CARD_SHADOW:          return "the Shadow";
319     case CARD_POTION:          return "the Potion";
320     case CARD_FOCUS:           return "Focus";
321     case CARD_HELIX:           return "the Helix";
322     case CARD_DOWSING:         return "Dowsing";
323     case CARD_STAIRS:          return "the Stairs";
324     case CARD_TOMB:            return "the Tomb";
325     case CARD_BANSHEE:         return "the Banshee";
326     case CARD_WILD_MAGIC:      return "Wild Magic";
327     case CARD_PLACID_MAGIC:    return "Placid Magic";
328     case CARD_CRUSADE:         return "the Crusade";
329     case CARD_ELEMENTS:        return "the Elements";
330     case CARD_SUMMON_DEMON:    return "the Pentagram";
331     case CARD_SUMMON_WEAPON:   return "the Dance";
332     case CARD_SUMMON_FLYING:   return "Foxfire";
333     case CARD_RANGERS:         return "the Rangers";
334     case CARD_SUMMON_UGLY:     return "Repulsiveness";
335     case CARD_XOM:             return "Xom";
336     case CARD_FAMINE:          return "Famine";
337     case CARD_FEAST:           return "the Feast";
338     case CARD_WARPWRIGHT:      return "Warpwright";
339     case CARD_SHAFT:           return "the Shaft";
340     case CARD_VITRIOL:         return "Vitriol";
341     case CARD_CLOUD:           return "the Cloud";
342     case CARD_HAMMER:          return "the Hammer";
343     case CARD_VENOM:           return "Venom";
344     case CARD_STORM:           return "the Storm";
345     case CARD_FORTITUDE:       return "Fortitude";
346     case CARD_PAIN:            return "Pain";
347     case CARD_TORMENT:         return "Torment";
348     case CARD_WRATH:           return "Wrath";
349     case CARD_WRAITH:          return "the Wraith";
350     case CARD_CURSE:           return "the Curse";
351     case CARD_SWINE:           return "the Swine";
352     case CARD_ALCHEMIST:       return "the Alchemist";
353     case CARD_ORB:             return "the Orb";
354     case CARD_MERCENARY:       return "the Mercenary";
355     case CARD_ILLUSION:        return "the Illusion";
356     case CARD_DEGEN:           return "Degeneration";
357     case NUM_CARDS:            return "a buggy card";
358     }
359     return "a very buggy card";
360 }
361
362 card_type name_to_card(string name)
363 {
364     for (int i = 0; i < NUM_CARDS; i++)
365     {
366         if (card_name(static_cast<card_type>(i)) == name)
367             return static_cast<card_type>(i);
368     }
369     return NUM_CARDS;
370 }
371
372 static const vector<const deck_archetype *> _subdecks(uint8_t deck_type)
373 {
374     vector<const deck_archetype *> subdecks;
375
376     switch (deck_type)
377     {
378     case MISC_DECK_OF_ESCAPE:
379         return { deck_of_transport, deck_of_emergency };
380     case MISC_DECK_OF_DESTRUCTION:
381         return { deck_of_destruction };
382 #if TAG_MAJOR_VERSION == 34
383     case MISC_DECK_OF_DUNGEONS:
384         return { deck_of_dungeons };
385 #endif
386     case MISC_DECK_OF_SUMMONING:
387         return { deck_of_summoning };
388     case MISC_DECK_OF_WONDERS:
389         return { deck_of_wonders };
390     case MISC_DECK_OF_PUNISHMENT:
391         return { deck_of_punishment };
392     case MISC_DECK_OF_WAR:
393         return { deck_of_battle, deck_of_summoning };
394     case MISC_DECK_OF_CHANGES:
395         return { deck_of_battle, deck_of_wonders };
396     case MISC_DECK_OF_DEFENCE:
397         return { deck_of_emergency, deck_of_battle };
398     }
399
400 #ifdef ASSERTS
401     die("No subdecks found for %u", unsigned(deck_type));
402 #endif
403     return {};
404 }
405
406 const string deck_contents(uint8_t deck_type)
407 {
408     string output = "It may contain the following cards: ";
409     bool first = true;
410
411     // XXX: This awkward way of doing things is intended to prevent a card
412     // that appears in multiple subdecks from showing up twice in the
413     // output.
414     FixedVector<bool, NUM_CARDS> cards;
415     cards.init(false);
416     for (const deck_archetype *pdeck : _subdecks(deck_type))
417         for (int j = 0; pdeck[j].card != NUM_CARDS; ++j)
418             cards[pdeck[j].card] = true;
419
420     for (int i = 0; i < NUM_CARDS; i++)
421     {
422         if (!cards[i])
423             continue;
424
425         if (!first)
426             output += ", ";
427         else
428             first = false;
429
430         output += card_name(static_cast<card_type>(i));
431     }
432
433     if (first)
434         output += "BUGGY cards";
435     output += ".";
436
437     return output;
438 }
439
440 static const deck_archetype* _random_sub_deck(uint8_t deck_type)
441 {
442     const vector<const deck_archetype *> subdecks = _subdecks(deck_type);
443     const deck_archetype *pdeck = subdecks[random2(subdecks.size())];
444
445     ASSERT(pdeck);
446
447     return pdeck;
448 }
449
450 static card_type _choose_from_archetype(const deck_archetype* pdeck,
451                                         deck_rarity_type rarity)
452 {
453     // Random rarity should have been replaced by one of the others by now.
454     ASSERT_RANGE(rarity, DECK_RARITY_COMMON, DECK_RARITY_LEGENDARY + 1);
455
456     // FIXME: We should use one of the various choose_random_weighted
457     // functions here, probably with an iterator, instead of
458     // duplicating the implementation.
459
460     int totalweight = 0;
461     card_type result = NUM_CARDS;
462     for (int i = 0; pdeck[i].card != NUM_CARDS; ++i)
463     {
464         const card_with_weights& cww = pdeck[i];
465         if (_card_forbidden(cww.card))
466             continue;
467         totalweight += cww.weight[rarity - DECK_RARITY_COMMON];
468         if (x_chance_in_y(cww.weight[rarity - DECK_RARITY_COMMON], totalweight))
469             result = cww.card;
470     }
471     return result;
472 }
473
474 static card_type _random_card(uint8_t deck_type, deck_rarity_type rarity,
475                               bool &was_oddity)
476 {
477     const deck_archetype *pdeck = _random_sub_deck(deck_type);
478
479     if (one_chance_in(100))
480     {
481         pdeck      = deck_of_oddities;
482         was_oddity = true;
483     }
484
485     return _choose_from_archetype(pdeck, rarity);
486 }
487
488 static card_type _random_card(const item_def& item, bool &was_oddity)
489 {
490     return _random_card(item.sub_type, item.deck_rarity, was_oddity);
491 }
492
493 static card_type _draw_top_card(item_def& deck, bool message,
494                                 uint8_t &_flags)
495 {
496     CrawlHashTable &props = deck.props;
497     CrawlVector    &cards = props["cards"].get_vector();
498     CrawlVector    &flags = props["card_flags"].get_vector();
499
500     int num_cards = cards.size();
501     int idx       = num_cards - 1;
502
503     ASSERT(num_cards > 0);
504
505     card_type card = get_card_and_flags(deck, idx, _flags);
506     cards.pop_back();
507     flags.pop_back();
508
509     if (message)
510     {
511         const char *verb = (_flags & CFLAG_DEALT) ? "deal" : "draw";
512
513         if (_flags & CFLAG_MARKED)
514             mprf("You %s %s.", verb, card_name(card));
515         else
516             mprf("You %s a card... It is %s.", verb, card_name(card));
517
518         _check_odd_card(_flags);
519     }
520
521     return card;
522 }
523
524 static void _push_top_card(item_def& deck, card_type card,
525                            uint8_t _flags)
526 {
527     CrawlHashTable &props = deck.props;
528     CrawlVector    &cards = props["cards"].get_vector();
529     CrawlVector    &flags = props["card_flags"].get_vector();
530
531     cards.push_back((char) card);
532     flags.push_back((char) _flags);
533 }
534
535 static void _remember_drawn_card(item_def& deck, card_type card, bool allow_id)
536 {
537     ASSERT(is_deck(deck));
538     CrawlHashTable &props = deck.props;
539     CrawlVector &drawn = props["drawn_cards"].get_vector();
540     drawn.push_back(static_cast<char>(card));
541
542     // Once you've drawn two cards, you know the deck.
543     if (allow_id && (drawn.size() >= 2 || origin_is_god_gift(deck)))
544         _deck_ident(deck);
545 }
546
547 const vector<card_type> get_drawn_cards(const item_def& deck)
548 {
549     vector<card_type> result;
550     if (is_deck(deck))
551     {
552         const CrawlHashTable &props = deck.props;
553         const CrawlVector &drawn = props["drawn_cards"].get_vector();
554         for (unsigned int i = 0; i < drawn.size(); ++i)
555         {
556             const char tmp = drawn[i];
557             result.push_back(static_cast<card_type>(tmp));
558         }
559     }
560     return result;
561 }
562
563 static bool _check_buggy_deck(item_def& deck)
564 {
565     ostream& strm = msg::streams(MSGCH_DIAGNOSTICS);
566     if (!is_deck(deck))
567     {
568         crawl_state.zero_turns_taken();
569         strm << "This isn't a deck at all!" << endl;
570         return true;
571     }
572
573     CrawlHashTable &props = deck.props;
574
575     if (!props.exists("cards")
576         || props["cards"].get_type() != SV_VEC
577         || props["cards"].get_vector().get_type() != SV_BYTE
578         || cards_in_deck(deck) == 0)
579     {
580         crawl_state.zero_turns_taken();
581
582         if (!props.exists("cards"))
583             strm << "Seems this deck never had any cards in the first place!";
584         else if (props["cards"].get_type() != SV_VEC)
585             strm << "'cards' property isn't a vector.";
586         else
587         {
588             if (props["cards"].get_vector().get_type() != SV_BYTE)
589                 strm << "'cards' vector doesn't contain bytes.";
590
591             if (cards_in_deck(deck) == 0)
592             {
593                 strm << "Strange, this deck is already empty.";
594
595                 int cards_left = 0;
596                 if (deck.used_count >= 0)
597                     cards_left = deck.initial_cards - deck.used_count;
598                 else
599                     cards_left = -deck.used_count;
600
601                 if (cards_left != 0)
602                 {
603                     strm << " But there should have been " <<  cards_left
604                          << " cards left.";
605                 }
606             }
607         }
608         strm << endl
609              << "A swarm of software bugs snatches the deck from you "
610                 "and whisks it away." << endl;
611
612         if (deck.link == you.equip[EQ_WEAPON])
613             unwield_item();
614
615         dec_inv_item_quantity(deck.link, 1);
616
617         return true;
618     }
619
620     bool problems = false;
621
622     CrawlVector &cards = props["cards"].get_vector();
623     CrawlVector &flags = props["card_flags"].get_vector();
624
625     vec_size num_cards = cards.size();
626     vec_size num_flags = flags.size();
627
628     unsigned int num_buggy     = 0;
629     unsigned int num_marked    = 0;
630
631     for (vec_size i = 0; i < num_cards; ++i)
632     {
633         uint8_t card   = cards[i].get_byte();
634         uint8_t _flags = flags[i].get_byte();
635
636         // Bad card, or "dealt" card not on the top.
637         if (card >= NUM_CARDS
638             || (_flags & CFLAG_DEALT) && i < num_cards - 1)
639         {
640             cards.erase(i);
641             flags.erase(i);
642             i--;
643             num_cards--;
644             num_buggy++;
645         }
646         else if (_flags & CFLAG_MARKED)
647             num_marked++;
648     }
649
650     if (num_buggy > 0)
651     {
652         strm << num_buggy << " buggy cards found in the deck, discarding them."
653              << endl;
654
655         deck.used_count += num_buggy;
656
657         num_cards = cards.size();
658         num_flags = cards.size();
659
660         problems = true;
661     }
662
663     if (num_cards == 0)
664     {
665         crawl_state.zero_turns_taken();
666
667         strm << "Oops, all of the cards seem to be gone." << endl
668              << "A swarm of software bugs snatches the deck from you "
669                 "and whisks it away." << endl;
670
671         if (deck.link == you.equip[EQ_WEAPON])
672             unwield_item();
673
674         dec_inv_item_quantity(deck.link, 1);
675
676         return true;
677     }
678
679     if (num_cards > deck.initial_cards)
680     {
681         if (deck.initial_cards == 0)
682             strm << "Deck was created with zero cards???" << endl;
683         else if (deck.initial_cards < 0)
684             strm << "Deck was created with *negative* cards?!" << endl;
685         else
686             strm << "Deck has more cards than it was created with?" << endl;
687
688         deck.initial_cards = num_cards;
689         problems  = true;
690     }
691
692     if (num_cards > num_flags)
693     {
694         strm << (num_cards - num_flags) << " more cards than flags.";
695         strm << endl;
696         for (unsigned int i = num_flags + 1; i <= num_cards; ++i)
697             flags[i] = static_cast<char>(0);
698
699         problems = true;
700     }
701     else if (num_flags > num_cards)
702     {
703         strm << (num_cards - num_flags) << " more cards than flags.";
704         strm << endl;
705
706         for (unsigned int i = num_flags; i > num_cards; --i)
707             flags.erase(i);
708
709         problems = true;
710     }
711
712     if (props["num_marked"].get_byte() > static_cast<char>(num_cards))
713     {
714         strm << "More cards marked than in the deck?" << endl;
715         props["num_marked"] = static_cast<char>(num_marked);
716         problems = true;
717     }
718     else if (props["num_marked"].get_byte() != static_cast<char>(num_marked))
719     {
720         strm << "Oops, counted " << static_cast<int>(num_marked)
721              << " marked cards, but num_marked is "
722              << (static_cast<int>(props["num_marked"].get_byte()));
723         strm << endl;
724
725         props["num_marked"] = static_cast<char>(num_marked);
726         problems = true;
727     }
728
729     if (deck.used_count >= 0)
730     {
731         if (deck.initial_cards != (deck.used_count + num_cards))
732         {
733             strm << "Have you used " << deck.used_count << " cards, or "
734                  << (deck.initial_cards - num_cards) << "? Oops.";
735             strm << endl;
736             deck.used_count = deck.initial_cards - num_cards;
737             problems = true;
738         }
739     }
740     else
741     {
742         if (-deck.used_count != num_cards)
743         {
744             strm << "There are " << num_cards << " cards left, not "
745                  << (-deck.used_count) << ".  Oops.";
746             strm << endl;
747             deck.used_count = -num_cards;
748             problems = true;
749         }
750     }
751
752     if (!problems)
753         return false;
754
755     you.wield_change = true;
756
757     if (!yesno("Problems might not have been completely fixed; "
758                "still use deck?", true, 'n'))
759     {
760         crawl_state.zero_turns_taken();
761         return true;
762     }
763     return false;
764 }
765
766 // Choose a deck from inventory and return its slot (or -1).
767 static int _choose_inventory_deck(const char* prompt)
768 {
769     const int slot = prompt_invent_item(prompt,
770                                         MT_INVLIST, OSEL_DRAW_DECK,
771                                         true, true, true, 0, -1, NULL,
772                                         OPER_EVOKE);
773
774     if (prompt_failed(slot))
775         return -1;
776
777     if (!is_deck(you.inv[slot]))
778     {
779         mpr("That isn't a deck!");
780         return -1;
781     }
782
783     return slot;
784 }
785
786 static void _deck_ident(item_def& deck)
787 {
788     if (in_inventory(deck) && !item_ident(deck, ISFLAG_KNOW_TYPE))
789     {
790         set_ident_flags(deck, ISFLAG_KNOW_TYPE);
791         mprf("This is %s.", deck.name(DESC_A).c_str());
792         you.wield_change = true;
793     }
794 }
795
796 bool deck_identify_first(int slot)
797 {
798     item_def& deck(you.inv[slot]);
799     if (top_card_is_known(deck))
800         return false;
801
802     uint8_t flags;
803     card_type card = get_card_and_flags(deck, -1, flags);
804
805     _set_card_and_flags(deck, -1, card, flags | CFLAG_SEEN | CFLAG_MARKED);
806     deck.props["num_marked"]++;
807
808     mprf("You get a glimpse of the first card. It is %s.", card_name(card));
809     return true;
810 }
811
812 // Draw the top four cards of an unmarked deck and play them all.
813 // Discards the rest of the deck.  Return false if the operation was
814 // failed/aborted along the way.
815 bool deck_deal()
816 {
817     const int slot = _choose_inventory_deck("Deal from which deck?");
818     if (slot == -1)
819     {
820         crawl_state.zero_turns_taken();
821         return false;
822     }
823     item_def& deck(you.inv[slot]);
824     if (_check_buggy_deck(deck))
825         return false;
826
827     CrawlHashTable &props = deck.props;
828     if (props["num_marked"].get_byte() > 0)
829     {
830         mpr("You cannot deal from marked decks.");
831         crawl_state.zero_turns_taken();
832         return false;
833     }
834     if (props["stacked"].get_bool())
835     {
836         mpr("This deck seems insufficiently random for dealing.");
837         crawl_state.zero_turns_taken();
838         return false;
839     }
840
841     const int num_cards = cards_in_deck(deck);
842     _deck_ident(deck);
843
844     if (num_cards == 1)
845         mpr("There's only one card left!");
846     else if (num_cards < 4)
847         mprf("The deck only has %d cards.", num_cards);
848
849     const int num_to_deal = (num_cards < 4 ? num_cards : 4);
850
851     for (int i = 0; i < num_to_deal; ++i)
852     {
853         int last = cards_in_deck(deck) - 1;
854         uint8_t flags;
855
856         // Flag the card as dealt (changes messages and gives no piety).
857         card_type card = get_card_and_flags(deck, last, flags);
858         _set_card_and_flags(deck, last, card, flags | CFLAG_DEALT);
859
860         evoke_deck(deck);
861         redraw_screen();
862     }
863
864     // Nemelex doesn't like dealers with inadequate decks.
865     if (num_to_deal < 4)
866     {
867         mpr("Nemelex gives you another card to finish dealing.");
868         draw_from_deck_of_punishment(true);
869     }
870
871     // If the deck had cards left, exhaust it.
872     if (deck.quantity > 0)
873     {
874         canned_msg(MSG_DECK_EXHAUSTED);
875         if (slot == you.equip[EQ_WEAPON])
876             unwield_item();
877
878         dec_inv_item_quantity(slot, 1);
879     }
880
881     return true;
882 }
883
884 static void _redraw_stacked_cards(const vector<card_type>& draws,
885                                   unsigned int selected)
886 {
887     for (unsigned int i = 0; i < draws.size(); ++i)
888     {
889         cgotoxy(1, i+2);
890         textcolour(selected == i ? WHITE : LIGHTGREY);
891         cprintf("%u - %s", i+1, card_name(draws[i]));
892         clear_to_end_of_line();
893     }
894 }
895
896 static bool _card_in_deck(card_type card, const deck_archetype *pdeck)
897 {
898     for (int i = 0; pdeck[i].card != NUM_CARDS; ++i)
899     {
900         if (pdeck[i].card == card)
901             return true;
902     }
903
904     return false;
905 }
906
907 string which_decks(card_type card)
908 {
909     vector<string> decks;
910     string output = "";
911     bool punishment = false;
912     for (uint8_t deck = MISC_FIRST_DECK; deck <= MISC_LAST_DECK; deck++)
913     {
914         for (const deck_archetype *subdeck : _subdecks(deck))
915         {
916             if (_card_in_deck(card, subdeck))
917             {
918                 if (deck == MISC_DECK_OF_PUNISHMENT)
919                     punishment = true;
920                 else
921                 {
922                     item_def tmp;
923                     tmp.base_type = OBJ_MISCELLANY;
924                     tmp.sub_type = deck;
925                     // 8 - "deck of "
926                     decks.push_back(sub_type_string(tmp, true).substr(8));
927                 }
928                 break;
929             }
930         }
931     }
932
933     if (decks.size())
934     {
935         output += "It is usually found in decks of "
936                +  comma_separated_line(decks.begin(), decks.end());
937         if (punishment)
938             output += ", or in Nemelex Xobeh's deck of punishment";
939         output += ".";
940     }
941     else if (punishment)
942     {
943         output += "It is usually only found in Nemelex Xobeh's deck of "
944                   "punishment.";
945     }
946     else
947         output += " It is normally not part of any deck.";
948
949     return output;
950 }
951
952 static void _describe_cards(vector<card_type> cards)
953 {
954     ASSERT(!cards.empty());
955
956 #ifdef USE_TILE_WEB
957     tiles_crt_control show_as_menu(CRT_MENU, "describe_cards");
958 #endif
959
960     ostringstream data;
961     for (card_type card : cards)
962     {
963         string name = card_name(card);
964         string desc = getLongDescription(name + " card");
965         if (desc.empty())
966             desc = "No description found.";
967
968         name = uppercase_first(name);
969         data << "<w>" << name << "</w>\n"
970              << get_linebreak_string(desc, get_number_of_cols() - 1)
971              << "\n" << which_decks(card) << "\n";
972     }
973     formatted_string fs = formatted_string::parse_string(data.str());
974     clrscr();
975     fs.display();
976     getchm();
977 }
978
979 // Stack a deck: look at the next five cards, put them back in any
980 // order, discard the rest of the deck.
981 // Return false if the operation was failed/aborted along the way.
982 bool deck_stack()
983 {
984     const int slot = _choose_inventory_deck("Stack which deck?");
985     if (slot == -1)
986     {
987         crawl_state.zero_turns_taken();
988         return false;
989     }
990
991     item_def& deck(you.inv[slot]);
992     if (_check_buggy_deck(deck))
993         return false;
994
995     CrawlHashTable &props = deck.props;
996     if (props["num_marked"].get_byte() > 0)
997     {
998         mpr("You can't stack a marked deck.");
999         crawl_state.zero_turns_taken();
1000         return false;
1001     }
1002
1003     _deck_ident(deck);
1004     const int num_cards    = cards_in_deck(deck);
1005
1006     if (num_cards == 1)
1007         mpr("There's only one card left!");
1008     else if (num_cards < 5)
1009         mprf("The deck only has %d cards.", num_cards);
1010     else if (num_cards == 5)
1011         mpr("The deck has exactly five cards.");
1012     else
1013     {
1014         mprf("You draw the first five cards out of %d and discard the rest.",
1015              num_cards);
1016     }
1017     more();
1018
1019     run_uncancel(UNC_STACK_FIVE, slot);
1020     return true;
1021 }
1022
1023 bool stack_five(int slot)
1024 {
1025     item_def& deck(you.inv[slot]);
1026     if (_check_buggy_deck(deck))
1027         return false;
1028
1029     const int num_cards    = cards_in_deck(deck);
1030     const int num_to_stack = (num_cards < 5 ? num_cards : 5);
1031
1032 #ifdef USE_TILE_WEB
1033     tiles_crt_control show_as_menu(CRT_MENU, "deck_stack");
1034 #endif
1035
1036     vector<card_type> draws;
1037     vector<uint8_t>   flags;
1038     for (int i = 0; i < num_cards; ++i)
1039     {
1040         uint8_t   _flags;
1041         card_type card = _draw_top_card(deck, false, _flags);
1042
1043         if (i < num_to_stack)
1044         {
1045             draws.push_back(card);
1046             flags.push_back(_flags | CFLAG_SEEN | CFLAG_MARKED);
1047         }
1048         // Rest of deck is discarded.
1049     }
1050
1051     CrawlHashTable &props = deck.props;
1052     deck.used_count = -num_to_stack;
1053     props["num_marked"] = static_cast<char>(num_to_stack);
1054     // Remember that the deck was stacked even if it is later unmarked
1055     // (e.g. by Nemelex abandonment).
1056     props["stacked"] = true;
1057     you.wield_change = true;
1058     bool done = true;
1059
1060     if (draws.size() > 1)
1061     {
1062         bool need_prompt_redraw = true;
1063         unsigned int selected = draws.size();
1064         while (true)
1065         {
1066             if (need_prompt_redraw)
1067             {
1068                 clrscr();
1069                 cgotoxy(1,1);
1070                 textcolour(WHITE);
1071                 cprintf("Press a digit to select a card, then another digit "
1072                         "to swap it.");
1073                 cgotoxy(1,10);
1074                 cprintf("Press ? for the card descriptions, or Enter to "
1075                         "accept.");
1076
1077                 _redraw_stacked_cards(draws, selected);
1078                 need_prompt_redraw = false;
1079             }
1080
1081             // Hand-hacked implementation, instead of using Menu. Oh well.
1082             const int c = getchk();
1083             if (c == CK_ENTER)
1084             {
1085                 cgotoxy(1,11);
1086                 textcolour(LIGHTGREY);
1087                 cprintf("Are you done? (press y or Y to confirm)");
1088                 if (toupper(getchk()) == 'Y')
1089                     break;
1090
1091                 cgotoxy(1,11);
1092                 clear_to_end_of_line();
1093                 continue;
1094             }
1095
1096             if (c == '?')
1097             {
1098                 _describe_cards(draws);
1099                 need_prompt_redraw = true;
1100             }
1101             else if (c >= '1' && c <= '0' + static_cast<int>(draws.size()))
1102             {
1103                 const unsigned int new_selected = c - '1';
1104                 if (selected < draws.size())
1105                 {
1106                     swap(draws[selected], draws[new_selected]);
1107                     swap(flags[selected], flags[new_selected]);
1108                     selected = draws.size();
1109                 }
1110                 else
1111                     selected = new_selected;
1112
1113                 _redraw_stacked_cards(draws, selected);
1114             }
1115             else if (c == CK_ESCAPE && crawl_state.seen_hups)
1116             {
1117                 done = false;
1118                 break; // continue on game restore
1119             }
1120         }
1121         redraw_screen();
1122     }
1123     for (unsigned int i = 0; i < draws.size(); ++i)
1124     {
1125         _push_top_card(deck, draws[draws.size() - 1 - i],
1126                        flags[flags.size() - 1 - i]);
1127     }
1128
1129     _check_buggy_deck(deck);
1130     you.wield_change = true;
1131
1132     return done;
1133 }
1134
1135 // Draw the next three cards, discard two and pick one.
1136 bool deck_triple_draw()
1137 {
1138     const int slot = _choose_inventory_deck("Triple draw from which deck?");
1139     if (slot == -1)
1140     {
1141         crawl_state.zero_turns_taken();
1142         return false;
1143     }
1144
1145     item_def& deck(you.inv[slot]);
1146     if (_check_buggy_deck(deck))
1147         return false;
1148
1149     run_uncancel(UNC_DRAW_THREE, slot);
1150     return true;
1151 }
1152
1153 bool draw_three(int slot)
1154 {
1155     item_def& deck(you.inv[slot]);
1156
1157     if (_check_buggy_deck(deck))
1158         return false;
1159
1160     const int num_cards = cards_in_deck(deck);
1161
1162     // We have to identify the deck before removing cards from it.
1163     // Otherwise, _remember_drawn_card() will implicitly call
1164     // _deck_ident() when the deck might have no cards left.
1165     _deck_ident(deck);
1166
1167     if (num_cards == 1)
1168     {
1169         // Only one card to draw, so just draw it.
1170         mpr("There's only one card left!");
1171         evoke_deck(deck);
1172         return true;
1173     }
1174
1175     const int num_to_draw = (num_cards < 3 ? num_cards : 3);
1176     vector<card_type> draws;
1177     vector<uint8_t>   flags;
1178
1179     for (int i = 0; i < num_to_draw; ++i)
1180     {
1181         uint8_t _flags;
1182         card_type card = _draw_top_card(deck, false, _flags);
1183
1184         draws.push_back(card);
1185         flags.push_back(_flags);
1186     }
1187
1188     int selected = -1;
1189     bool need_prompt_redraw = true;
1190     while (true)
1191     {
1192         if (need_prompt_redraw)
1193         {
1194             mpr("You draw... (choose one card, ? for their descriptions)");
1195             for (int i = 0; i < num_to_draw; ++i)
1196             {
1197                 msg::streams(MSGCH_PROMPT) << (static_cast<char>(i + 'a')) << " - "
1198                                            << card_name(draws[i]) << endl;
1199             }
1200             need_prompt_redraw = false;
1201         }
1202         const int keyin = toalower(get_ch());
1203
1204         if (crawl_state.seen_hups)
1205         {
1206             // Return the cards, for now.
1207             for (int i = 0; i < num_to_draw; ++i)
1208                 _push_top_card(deck, draws[i], flags[i]);
1209
1210             return false;
1211         }
1212
1213         if (keyin == '?')
1214         {
1215             _describe_cards(draws);
1216             redraw_screen();
1217             need_prompt_redraw = true;
1218         }
1219         else if (keyin >= 'a' && keyin < 'a' + num_to_draw)
1220         {
1221             selected = keyin - 'a';
1222             break;
1223         }
1224         else
1225             canned_msg(MSG_HUH);
1226     }
1227
1228     // Note how many cards were removed from the deck.
1229     deck.used_count += num_to_draw;
1230
1231     // Don't forget to update the number of marked ones, too.
1232     // But don't reduce the number of non-brownie draws.
1233     uint8_t num_marked_left = deck.props["num_marked"].get_byte();
1234     for (int i = 0; i < num_to_draw; ++i)
1235     {
1236         _remember_drawn_card(deck, draws[i], false);
1237         if (flags[i] & CFLAG_MARKED)
1238         {
1239             ASSERT(num_marked_left > 0);
1240             --num_marked_left;
1241         }
1242     }
1243     deck.props["num_marked"] = num_marked_left;
1244
1245     you.wield_change = true;
1246
1247     // Make deck disappear *before* the card effect, since we
1248     // don't want to unwield an empty deck.
1249     const deck_rarity_type rarity = deck.deck_rarity;
1250     if (cards_in_deck(deck) == 0)
1251     {
1252         canned_msg(MSG_DECK_EXHAUSTED);
1253         if (slot == you.equip[EQ_WEAPON])
1254             unwield_item();
1255
1256         dec_inv_item_quantity(slot, 1);
1257     }
1258
1259     // Note that card_effect() might cause you to unwield the deck.
1260     card_effect(draws[selected], rarity,
1261                 flags[selected] | CFLAG_SEEN | CFLAG_MARKED, false);
1262
1263     return true;
1264 }
1265
1266 // This is Nemelex retribution. If deal is true, use the word "deal"
1267 // rather than "draw" (for the Deal Four out-of-cards situation).
1268 void draw_from_deck_of_punishment(bool deal)
1269 {
1270     bool oddity;
1271     uint8_t flags = CFLAG_PUNISHMENT;
1272     if (deal)
1273         flags |= CFLAG_DEALT;
1274     card_type card = _random_card(MISC_DECK_OF_PUNISHMENT, DECK_RARITY_COMMON,
1275                                   oddity);
1276
1277     mprf("You %s a card...", deal ? "deal" : "draw");
1278     card_effect(card, DECK_RARITY_COMMON, flags);
1279 }
1280
1281 static int _xom_check_card(item_def &deck, card_type card,
1282                            uint8_t flags)
1283 {
1284     int amusement = 64;
1285
1286     if (flags & CFLAG_PUNISHMENT)
1287         amusement = 200;
1288     else if (!item_type_known(deck))
1289         amusement *= 2;
1290     // Expecting one type of card but got another, real funny.
1291     else if (flags & CFLAG_ODDITY)
1292         amusement = 200;
1293
1294     if (player_in_a_dangerous_place())
1295         amusement *= 2;
1296
1297     switch (card)
1298     {
1299     case CARD_XOM:
1300         // Handled elsewhere
1301         amusement = 0;
1302         break;
1303
1304     case CARD_DAMNATION:
1305         // Nothing happened, boring.
1306         if (player_in_branch(BRANCH_ABYSS))
1307             amusement = 0;
1308         break;
1309
1310     case CARD_FAMINE:
1311     case CARD_CURSE:
1312     case CARD_SWINE:
1313         // Always hilarious.
1314         amusement = 255;
1315
1316     default:
1317         break;
1318     }
1319
1320     return amusement;
1321 }
1322
1323 void evoke_deck(item_def& deck)
1324 {
1325     if (_check_buggy_deck(deck))
1326         return;
1327
1328     bool allow_id = in_inventory(deck) && !item_ident(deck, ISFLAG_KNOW_TYPE);
1329
1330     const deck_rarity_type rarity = deck.deck_rarity;
1331     CrawlHashTable &props = deck.props;
1332
1333     uint8_t flags = 0;
1334     card_type card = _draw_top_card(deck, true, flags);
1335
1336     // Passive Nemelex retribution: sometimes a card gets swapped out.
1337     // More likely to happen with marked decks.
1338     if (player_under_penance(GOD_NEMELEX_XOBEH))
1339     {
1340         int c = 1;
1341         if ((flags & (CFLAG_MARKED | CFLAG_SEEN))
1342             || props["num_marked"].get_byte() > 0)
1343         {
1344             c = 3;
1345         }
1346
1347         if (x_chance_in_y(c * you.penance[GOD_NEMELEX_XOBEH], 3000))
1348         {
1349             card_type old_card = card;
1350             card = _choose_from_archetype(deck_of_punishment, rarity);
1351             if (card != old_card)
1352             {
1353                 flags |= CFLAG_PUNISHMENT;
1354                 simple_god_message(" seems to have exchanged this card "
1355                                    "behind your back!", GOD_NEMELEX_XOBEH);
1356                 mprf("It's actually %s.", card_name(card));
1357                 // You never completely appease Nemelex, but the effects
1358                 // get less frequent.
1359                 you.penance[GOD_NEMELEX_XOBEH] -=
1360                     random2((you.penance[GOD_NEMELEX_XOBEH]+18) / 10);
1361             }
1362         }
1363     }
1364
1365     const int amusement   = _xom_check_card(deck, card, flags);
1366
1367     // Oddity and punishment cards don't give any information about the deck.
1368     if (flags & (CFLAG_ODDITY | CFLAG_PUNISHMENT))
1369         allow_id = false;
1370
1371     // Do these before the deck item_def object is gone.
1372     if (flags & CFLAG_MARKED)
1373         props["num_marked"]--;
1374
1375     deck.used_count++;
1376     _remember_drawn_card(deck, card, allow_id);
1377
1378     // Get rid of the deck *before* the card effect because a card
1379     // might cause a wielded deck to be swapped out for something else,
1380     // in which case we don't want an empty deck to go through the
1381     // swapping process.
1382     const bool deck_gone = (cards_in_deck(deck) == 0);
1383     if (deck_gone)
1384     {
1385         canned_msg(MSG_DECK_EXHAUSTED);
1386         dec_inv_item_quantity(deck.link, 1);
1387     }
1388
1389     card_effect(card, rarity, flags, false);
1390
1391     if (!(flags & CFLAG_MARKED))
1392     {
1393         // Could a Xom worshipper ever get a stacked deck in the first
1394         // place?
1395         xom_is_stimulated(amusement);
1396     }
1397
1398     // Always wield change, since the number of cards used/left has
1399     // changed, and it might be wielded.
1400     you.wield_change = true;
1401 }
1402
1403 static int _get_power_level(int power, deck_rarity_type rarity)
1404 {
1405     int power_level = 0;
1406     switch (rarity)
1407     {
1408     case DECK_RARITY_COMMON:
1409         break;
1410     case DECK_RARITY_LEGENDARY:
1411         if (x_chance_in_y(power, 500))
1412             ++power_level;
1413         // deliberate fall-through
1414     case DECK_RARITY_RARE:
1415         if (x_chance_in_y(power, 700))
1416             ++power_level;
1417         break;
1418     case DECK_RARITY_RANDOM:
1419         die("unset deck rarity");
1420     }
1421     dprf("Power level: %d", power_level);
1422     return power_level;
1423 }
1424
1425 static void _suppressed_card_message(god_type god, conduct_type done)
1426 {
1427     string forbidden_act;
1428
1429     switch (done)
1430     {
1431         case DID_NECROMANCY:
1432         case DID_UNHOLY: forbidden_act = "evil"; break;
1433
1434         case DID_POISON: forbidden_act = "poisonous"; break;
1435
1436         case DID_CHAOS: forbidden_act = "chaotic"; break;
1437
1438         case DID_HASTY: forbidden_act = "hasty"; break;
1439
1440         case DID_FIRE: forbidden_act = "fiery"; break;
1441
1442         default: forbidden_act = "buggy"; break;
1443     }
1444
1445     mprf("By %s power, the %s magic on the card dissipates harmlessly.",
1446          apostrophise(god_name(you.religion)).c_str(), forbidden_act.c_str());
1447 }
1448
1449 // Actual card implementations follow.
1450
1451 static void _swap_monster_card(int power, deck_rarity_type rarity)
1452 {
1453     // Swap between you and another monster.
1454     // Don't choose yourself unless there are no monsters nearby.
1455     monster* mon_to_swap = choose_random_nearby_monster(0);
1456     if (!mon_to_swap)
1457         mpr("You spin around.");
1458     else
1459         swap_with_monster(mon_to_swap);
1460 }
1461
1462 static void _velocity_card(int power, deck_rarity_type rarity)
1463 {
1464
1465     const int power_level = _get_power_level(power, rarity);
1466     bool did_something = false;
1467     enchant_type for_allies = ENCH_NONE, for_hostiles = ENCH_NONE;
1468
1469     if (you.duration[DUR_SLOW] && (power_level > 0 || coinflip()))
1470     {
1471         if (you_worship(GOD_CHEIBRIADOS))
1472             simple_god_message(" protects you from inadvertent hurry.");
1473         else
1474         {
1475             you.duration[DUR_SLOW] = 1;
1476             did_something = true;
1477         }
1478     }
1479
1480     if (you.duration[DUR_HASTE] && (power_level == 0 && coinflip()))
1481     {
1482         you.duration[DUR_HASTE] = 1;
1483         did_something = true;
1484     }
1485
1486     switch (power_level)
1487     {
1488         case 0:
1489             for_allies = for_hostiles = random_choose(ENCH_SLOW, ENCH_HASTE,
1490                                                       ENCH_SWIFT);
1491             break;
1492
1493         case 1:
1494             if (coinflip())
1495                 for_allies = ENCH_HASTE;
1496             else
1497                 for_hostiles = ENCH_SLOW;
1498             break;
1499
1500         case 2:
1501             for_allies = ENCH_HASTE; for_hostiles = ENCH_SLOW;
1502             break;
1503     }
1504
1505     for (radius_iterator ri(you.pos(), LOS_NO_TRANS); ri; ++ri)
1506     {
1507         monster* mon = monster_at(*ri);
1508
1509         if (mon && !mons_immune_magic(mon))
1510         {
1511             const bool hostile = !mon->wont_attack();
1512             const bool haste_immune = (mon->check_stasis(false)
1513                                 || mons_is_immotile(mon));
1514
1515             bool did_haste = false;
1516             bool did_swift = false;
1517
1518             if (hostile)
1519             {
1520                 if (for_hostiles != ENCH_NONE)
1521                 {
1522                     if (for_hostiles == ENCH_SLOW)
1523                     {
1524                         do_slow_monster(mon, &you);
1525                         did_something = true;
1526                     }
1527                     else if (!(for_hostiles == ENCH_HASTE && haste_immune))
1528                     {
1529                         if (you_worship(GOD_CHEIBRIADOS))
1530                             _suppressed_card_message(you.religion, DID_HASTY);
1531                         else
1532                         {
1533                             mon->add_ench(for_hostiles);
1534                             did_something = true;
1535                             if (for_hostiles == ENCH_HASTE)
1536                                 did_haste = true;
1537                             else if (for_hostiles == ENCH_SWIFT)
1538                                 did_swift = true;
1539                         }
1540                     }
1541                 }
1542             }
1543             else //allies
1544             {
1545                 if (for_allies != ENCH_NONE)
1546                 {
1547                     if (for_allies == ENCH_SLOW)
1548                     {
1549                         do_slow_monster(mon, &you);
1550                         did_something = true;
1551                     }
1552                     else if (!(for_allies == ENCH_HASTE && haste_immune))
1553                     {
1554                         if (you_worship(GOD_CHEIBRIADOS))
1555                             _suppressed_card_message(you.religion, DID_HASTY);
1556                         else
1557                         {
1558                             mon->add_ench(for_allies);
1559                             did_something = true;
1560                             if (for_allies == ENCH_HASTE)
1561                                 did_haste = true;
1562                             else if (for_allies == ENCH_SWIFT)
1563                                 did_swift = true;
1564                         }
1565                     }
1566                 }
1567             }
1568
1569             if (did_haste)
1570                 simple_monster_message(mon, " seems to speed up.");
1571
1572             if (did_swift)
1573                 simple_monster_message(mon, " is moving somewhat quickly.");
1574         }
1575     }
1576
1577     if (!did_something)
1578         canned_msg(MSG_NOTHING_HAPPENS);
1579 }
1580
1581 static void _banshee_card(int power, deck_rarity_type rarity)
1582 {
1583     const int power_level = _get_power_level(power, rarity);
1584
1585     if (!is_good_god(you.religion))
1586     {
1587         for (radius_iterator ri(you.pos(), LOS_NO_TRANS); ri; ++ri)
1588         {
1589             monster* mon = monster_at(*ri);
1590
1591             if (mon && !mon->wont_attack())
1592                 mon->drain_exp(&you, false, 3 * (power_level + 1));
1593         }
1594     }
1595     mass_enchantment(ENCH_FEAR, power);
1596 }
1597
1598 static void _damnation_card(int power, deck_rarity_type rarity)
1599 {
1600     if (player_in_branch(BRANCH_ABYSS))
1601     {
1602         canned_msg(MSG_NOTHING_HAPPENS);
1603         return;
1604     }
1605
1606     // Calculate how many extra banishments you get.
1607     const int power_level = _get_power_level(power, rarity);
1608     int nemelex_bonus = 0;
1609     if (in_good_standing(GOD_NEMELEX_XOBEH))
1610         nemelex_bonus = you.piety;
1611
1612     int extra_targets = power_level + random2(you.skill(SK_EVOCATIONS, 20)
1613                                               + nemelex_bonus) / 240;
1614
1615     for (int i = 0; i < 1 + extra_targets; ++i)
1616     {
1617         // Pick a random monster nearby to banish (or yourself).
1618         monster* mon_to_banish = choose_random_nearby_monster(1);
1619
1620         // Bonus banishments only banish monsters.
1621         if (i != 0 && !mon_to_banish)
1622             continue;
1623
1624         if (!mon_to_banish) // Banish yourself!
1625         {
1626             banished("drawing a card");
1627             break;              // Don't banish anything else.
1628         }
1629         else
1630             mon_to_banish->banish(&you);
1631     }
1632 }
1633
1634 static void _warpwright_card(int power, deck_rarity_type rarity)
1635 {
1636     const int power_level = _get_power_level(power, rarity);
1637
1638     if (player_in_branch(BRANCH_ABYSS))
1639     {
1640         mpr("The power of the Abyss blocks your magic.");
1641         return;
1642     }
1643
1644     int count = 0;
1645     coord_def f;
1646     for (adjacent_iterator ai(you.pos()); ai; ++ai)
1647         if (grd(*ai) == DNGN_FLOOR && !find_trap(*ai) && one_chance_in(++count))
1648             f = *ai;
1649
1650     if (count > 0)              // found a spot
1651     {
1652         if (place_specific_trap(f, TRAP_TELEPORT, 1 + random2(5 * power_level)))
1653         {
1654             // Mark it discovered if enough power.
1655             if (x_chance_in_y(power_level, 2))
1656                 find_trap(f)->reveal();
1657         }
1658     }
1659 }
1660
1661 static void _shaft_card(int power, deck_rarity_type rarity)
1662 {
1663     const int power_level = _get_power_level(power, rarity);
1664
1665     if (is_valid_shaft_level())
1666     {
1667         if (grd(you.pos()) == DNGN_FLOOR
1668             && place_specific_trap(you.pos(), TRAP_SHAFT))
1669         {
1670             find_trap(you.pos())->reveal();
1671             mpr("A shaft materialises beneath you!");
1672         }
1673
1674         for (radius_iterator di(you.pos(), LOS_NO_TRANS); di; ++di)
1675         {
1676             monster *mons = monster_at(*di);
1677
1678             if (mons && !mons->wont_attack()
1679                 && grd(mons->pos()) == DNGN_FLOOR
1680                 && !mons->airborne() && !mons_is_firewood(mons)
1681                 && x_chance_in_y(power_level, 3))
1682             {
1683                 mons->do_shaft();
1684             }
1685         }
1686     }
1687     else
1688         canned_msg(MSG_NOTHING_HAPPENS);
1689 }
1690
1691 static void _solitude_card(int power, deck_rarity_type rarity)
1692 {
1693     const int power_level = _get_power_level(power, rarity);
1694
1695     cast_dispersal(power/4);
1696
1697     if (power_level == 2)
1698         cast_disjunction(power/4, false);
1699 }
1700
1701 static int stair_draw_count = 0;
1702
1703 // This does not describe an actual card. Instead, it only exists to test
1704 // the stair movement effect in wizard mode ("&c stairs").
1705 static void _stairs_card(int /*power*/, deck_rarity_type /*rarity*/)
1706 {
1707     you.duration[DUR_REPEL_STAIRS_MOVE]  = 0;
1708     you.duration[DUR_REPEL_STAIRS_CLIMB] = 0;
1709
1710     if (feat_stair_direction(grd(you.pos())) == CMD_NO_CMD)
1711         you.duration[DUR_REPEL_STAIRS_MOVE]  = 1000;
1712     else
1713         you.duration[DUR_REPEL_STAIRS_CLIMB] =  500; // more annoying
1714
1715     vector<coord_def> stairs_avail;
1716
1717     for (radius_iterator ri(you.pos(), LOS_DEFAULT, true); ri; ++ri)
1718     {
1719         dungeon_feature_type feat = grd(*ri);
1720         if (feat_stair_direction(feat) != CMD_NO_CMD
1721             && feat != DNGN_ENTER_SHOP)
1722         {
1723             stairs_avail.push_back(*ri);
1724         }
1725     }
1726
1727     if (stairs_avail.empty())
1728     {
1729         mpr("No stairs available to move.");
1730         return;
1731     }
1732
1733     shuffle_array(stairs_avail);
1734
1735     for (coord_def stair : stairs_avail)
1736         move_stair(stair, stair_draw_count % 2, false);
1737
1738     stair_draw_count++;
1739 }
1740
1741 static void _damaging_card(card_type card, int power, deck_rarity_type rarity,
1742                            bool dealt = false)
1743 {
1744     const int power_level = _get_power_level(power, rarity);
1745     const char *participle = dealt ? "dealt" : "drawn";
1746
1747     dist target;
1748     zap_type ztype = ZAP_DEBUGGING_RAY;
1749     const zap_type hammerzaps[3]  = { ZAP_STONE_ARROW, ZAP_IRON_SHOT,
1750                                       ZAP_LEHUDIBS_CRYSTAL_SPEAR };
1751     const zap_type painzaps[2]   = { ZAP_AGONY, ZAP_BOLT_OF_DRAINING };
1752     const zap_type orbzaps[3]    = { ZAP_ISKENDERUNS_MYSTIC_BLAST, ZAP_IOOD,
1753                                      ZAP_IOOD };
1754     bool venom_vuln = false;
1755
1756     switch (card)
1757     {
1758     case CARD_VITRIOL:
1759         if (power_level == 2 || (power_level == 1 && coinflip()))
1760             ztype = ZAP_CORROSIVE_BOLT;
1761         else
1762             ztype = ZAP_BREATHE_ACID;
1763         break;
1764
1765     case CARD_VENOM:
1766         if (power_level < 2)
1767             venom_vuln = true;
1768
1769         if (power_level == 2 || (power_level == 1 && coinflip()))
1770             ztype = ZAP_POISON_ARROW;
1771         else
1772             ztype = ZAP_VENOM_BOLT;
1773         break;
1774
1775     case CARD_HAMMER:  ztype = hammerzaps[power_level];  break;
1776     case CARD_ORB:     ztype = orbzaps[power_level];     break;
1777
1778     case CARD_PAIN:
1779         if (power_level == 2)
1780         {
1781             if (is_good_god(you.religion))
1782             {
1783                 _suppressed_card_message(you.religion, DID_NECROMANCY);
1784                 return;
1785             }
1786
1787             if (monster *ghost = create_monster(
1788                                     mgen_data(MONS_FLAYED_GHOST, BEH_FRIENDLY,
1789                                     &you, 3, 0, you.pos(), MHITYOU)))
1790             {
1791                 bool msg = true;
1792                 bolt beem;
1793                 int dam = 5;
1794
1795                 beem.origin_spell = SPELL_FLAY;
1796                 beem.source = ghost->pos();
1797                 beem.source_id = ghost->mid;
1798                 beem.range = 0;
1799
1800                 if (!you.res_torment())
1801                 {
1802                     if (can_shave_damage())
1803                         dam = do_shave_damage(dam);
1804
1805                     if (dam > 0)
1806                         dec_hp(dam, false);
1807                 }
1808
1809                 for (radius_iterator di(ghost->pos(), LOS_NO_TRANS); di; ++di)
1810                 {
1811                     monster *mons = monster_at(*di);
1812
1813                     if (!mons || mons->wont_attack()
1814                         || mons->holiness() != MH_NATURAL)
1815                     {
1816                         continue;
1817                     }
1818
1819                     beem.target = mons->pos();
1820                     ghost->foe = mons->mindex();
1821                     mons_cast(ghost, beem, SPELL_FLAY,
1822                              ghost->spell_slot_flags(SPELL_FLAY), msg);
1823                     msg = false;
1824                 }
1825
1826                 ghost->foe = MHITYOU;
1827             }
1828
1829             return;
1830         }
1831         else
1832             ztype = painzaps[power_level];
1833         break;
1834
1835     default:
1836         break;
1837     }
1838
1839     string prompt = "You have ";
1840     prompt += participle;
1841     prompt += " ";
1842     prompt += card_name(card);
1843     prompt += ".";
1844
1845     bolt beam;
1846     beam.range = LOS_RADIUS;
1847
1848     if (card == CARD_VENOM && you_worship(GOD_SHINING_ONE))
1849     {
1850         _suppressed_card_message(you.religion, DID_POISON);
1851         return;
1852     }
1853
1854     if (card == CARD_PAIN && is_good_god(you.religion))
1855     {
1856         _suppressed_card_message(you.religion, DID_NECROMANCY);
1857         return;
1858     }
1859
1860     if (spell_direction(target, beam, DIR_NONE, TARG_HOSTILE,
1861                         LOS_RADIUS, true, true, false, NULL, prompt.c_str())
1862         && player_tracer(ZAP_DEBUGGING_RAY, power/6, beam))
1863     {
1864         if (you.confused())
1865         {
1866             target.confusion_fuzz();
1867             beam.set_target(target);
1868         }
1869
1870         if (ztype == ZAP_IOOD)
1871         {
1872             if (power_level == 1)
1873                 cast_iood(&you, power/6, &beam);
1874             else
1875                 cast_iood_burst(power/6, beam.target);
1876         }
1877         else
1878             zapping(ztype, power/6, beam);
1879             if (venom_vuln)
1880             {
1881                 mpr("Releasing that poison leaves you vulnerable to poison.");
1882                 you.increase_duration(DUR_POISON_VULN, 10 - power_level * 5 + random2(6), 50);
1883             }
1884     }
1885     else if (ztype == ZAP_IOOD && power_level == 2)
1886     {
1887         // cancelled orb bursts just become uncontrolled
1888         cast_iood_burst(power/6, coord_def(-1, -1));
1889     }
1890 }
1891
1892 static void _elixir_card(int power, deck_rarity_type rarity)
1893 {
1894     int power_level = _get_power_level(power, rarity);
1895     const int dur = random2avg(10 * (power_level + 1), 2) * BASELINE_DELAY;
1896
1897     you.duration[DUR_ELIXIR_HEALTH] = 0;
1898     you.duration[DUR_ELIXIR_MAGIC] = 0;
1899
1900     if (power_level == 0)
1901     {
1902         if (coinflip())
1903             you.set_duration(DUR_ELIXIR_HEALTH, 1 + random2(3));
1904         else
1905             you.set_duration(DUR_ELIXIR_MAGIC, 3 + random2(5));
1906     }
1907     else if (power_level == 1)
1908     {
1909         if (you.hp * 2 < you.hp_max)
1910             you.set_duration(DUR_ELIXIR_HEALTH, 3 + random2(3));
1911         else
1912             you.set_duration(DUR_ELIXIR_MAGIC, 10);
1913     }
1914     else if (power_level >= 2)
1915     {
1916         you.set_duration(DUR_ELIXIR_HEALTH, 10);
1917         you.set_duration(DUR_ELIXIR_MAGIC, 10);
1918     }
1919
1920     for (radius_iterator ri(you.pos(), LOS_NO_TRANS); ri; ++ri)
1921     {
1922         monster* mon = monster_at(*ri);
1923
1924         if (mon && mon->wont_attack())
1925         {
1926             mon->add_ench(mon_enchant(ENCH_EPHEMERAL_INFUSION, 50 * (power_level + 1),
1927                                       &you, dur));
1928         }
1929     }
1930 }
1931
1932 static void _helm_card(int power, deck_rarity_type rarity)
1933 {
1934     const int power_level = _get_power_level(power, rarity);
1935     bool do_phaseshift = false;
1936     bool do_stoneskin  = false;
1937     bool do_shield     = false;
1938     bool do_resistance = false;
1939
1940     // Chances are cumulative.
1941     if (power_level >= 2)
1942     {
1943         if (coinflip()) do_phaseshift = true;
1944         if (coinflip()) do_stoneskin  = true;
1945         if (coinflip()) do_shield     = true;
1946         do_resistance = true;
1947     }
1948     if (power_level >= 1)
1949     {
1950         if (coinflip()) do_phaseshift = true;
1951         if (coinflip()) do_stoneskin  = true;
1952         if (coinflip()) do_shield     = true;
1953     }
1954     if (power_level >= 0)
1955     {
1956         if (coinflip())
1957             do_phaseshift = true;
1958         else
1959             do_stoneskin  = true;
1960     }
1961
1962     if (do_phaseshift)
1963         cast_phase_shift(random2(power/4));
1964     if (do_stoneskin)
1965         cast_stoneskin(random2(power/4));
1966     if (do_resistance)
1967     {
1968         mpr("You feel resistant.");
1969         you.increase_duration(DUR_RESISTANCE, random2(power/7) + 1);
1970     }
1971     if (do_shield)
1972     {
1973         if (you.duration[DUR_MAGIC_SHIELD] == 0)
1974             mpr("A magical shield forms in front of you.");
1975         you.increase_duration(DUR_MAGIC_SHIELD, random2(power/6) + 1);
1976     }
1977
1978     for (radius_iterator ri(you.pos(), LOS_NO_TRANS); ri; ++ri)
1979     {
1980         monster* mon = monster_at(*ri);
1981
1982         if (mon && mon->wont_attack() && x_chance_in_y(power_level, 2))
1983             mon->add_ench(coinflip() ? ENCH_STONESKIN : ENCH_SHROUD);
1984     }
1985 }
1986
1987 static void _blade_card(int power, deck_rarity_type rarity)
1988 {
1989     const int power_level = _get_power_level(power, rarity);
1990     const bool cleaving = you.duration[DUR_CLEAVE] > 0;
1991     const item_def* const weapon = you.weapon();
1992     const bool axe = weapon && item_attack_skill(*weapon) == SK_AXES;
1993     const bool bladed = weapon && can_cut_meat(*weapon);
1994     const bool plural = (weapon && weapon->quantity > 1) || !weapon;
1995     string hand_part = "Your " + you.hand_name(true);
1996
1997     you.increase_duration(DUR_CLEAVE, 10 + random2((power_level + 1) * 10));
1998
1999     if (!cleaving)
2000     {
2001         mprf(MSGCH_DURATION,
2002              "%s look%s %ssharp%s",
2003              (weapon) ? weapon->name(DESC_YOUR).c_str() : hand_part.c_str(),
2004              (plural) ?  "" : "s", (bladed) ? "" : "oddly ",
2005              (axe) ? " (like it always does)." : ".");
2006     }
2007     else
2008         mprf(MSGCH_DURATION, "Your cleaving ability is renewed.");
2009 }
2010
2011 static void _shadow_card(int power, deck_rarity_type rarity)
2012 {
2013     const int power_level = _get_power_level(power, rarity);
2014     const int duration = random2(power/4) + 1;
2015
2016     if (power_level != 1)
2017     {
2018         mpr(you.duration[DUR_STEALTH] ? "You feel more catlike."
2019                                       : "You feel stealthy.");
2020         you.increase_duration(DUR_STEALTH, duration);
2021     }
2022
2023     if (power_level > 0 && !you.haloed())
2024         cast_darkness(duration, false);
2025 }
2026
2027 static void _potion_card(int power, deck_rarity_type rarity)
2028 {
2029     const int power_level = _get_power_level(power, rarity);
2030
2031     potion_type pot = random_choose_weighted(3, POT_CURING,
2032                                              1, POT_AGILITY,
2033                                              1, POT_BRILLIANCE,
2034                                              1, POT_MIGHT,
2035                                              1, POT_BERSERK_RAGE,
2036                                              1, POT_INVISIBILITY,
2037                                              0);
2038
2039     if (power_level >= 1 && coinflip())
2040         pot = (coinflip() ? POT_RESISTANCE : POT_HASTE);
2041
2042     if (power_level >= 2 && coinflip())
2043         pot = (coinflip() ? POT_HEAL_WOUNDS : POT_MAGIC);
2044
2045     if (you_worship(GOD_CHEIBRIADOS) && (pot == POT_HASTE
2046         || pot == POT_BERSERK_RAGE))
2047     {
2048         simple_god_message(" protects you from inadvertent hurry.");
2049         return;
2050     }
2051
2052     potion_effect(pot, random2(power/4));
2053
2054     for (radius_iterator ri(you.pos(), LOS_NO_TRANS); ri; ++ri)
2055     {
2056         monster* mon = monster_at(*ri);
2057
2058         if (mon && mon->friendly())
2059             mon->drink_potion_effect(pot, true);
2060     }
2061
2062 }
2063
2064 static void _focus_card(int power, deck_rarity_type rarity)
2065 {
2066     stat_type best_stat = STAT_STR;
2067     stat_type worst_stat = STAT_STR;
2068
2069     for (int i = 1; i < 3; ++i)
2070     {
2071         stat_type s = static_cast<stat_type>(i);
2072         const int best_diff = you.base_stats[s] - you.base_stats[best_stat];
2073         if (best_diff > 0 || best_diff == 0 && coinflip())
2074             best_stat = s;
2075
2076         const int worst_diff = you.base_stats[s] - you.base_stats[worst_stat];
2077         if (worst_diff < 0 || worst_diff == 0 && coinflip())
2078             worst_stat = s;
2079     }
2080
2081     while (best_stat == worst_stat)
2082     {
2083         best_stat  = static_cast<stat_type>(random2(3));
2084         worst_stat = static_cast<stat_type>(random2(3));
2085     }
2086
2087     modify_stat(best_stat, 1, true, true);
2088     modify_stat(worst_stat, -1, true, true);
2089 }
2090
2091 static void _remove_bad_mutation()
2092 {
2093     // Ensure that only bad mutations are removed.
2094     if (!delete_mutation(RANDOM_BAD_MUTATION, "helix card", false, false, false, true))
2095         mpr("You feel transcendent for a moment.");
2096 }
2097
2098 static void _helix_card(int power, deck_rarity_type rarity)
2099 {
2100     const int power_level = _get_power_level(power, rarity);
2101
2102     if (power_level == 0)
2103     {
2104         switch (how_mutated() ? random2(3) : 0)
2105         {
2106         case 0:
2107             mutate(RANDOM_MUTATION, "helix card");
2108             break;
2109         case 1:
2110             delete_mutation(RANDOM_MUTATION, "helix card");
2111             mutate(RANDOM_MUTATION, "helix card");
2112             break;
2113         case 2:
2114             delete_mutation(RANDOM_MUTATION, "helix card");
2115             break;
2116         }
2117     }
2118     else if (power_level == 1)
2119     {
2120         switch (how_mutated() ? random2(3) : 0)
2121         {
2122         case 0:
2123             mutate(coinflip() ? RANDOM_GOOD_MUTATION : RANDOM_MUTATION,
2124                    "helix card");
2125             break;
2126         case 1:
2127             if (coinflip())
2128                 _remove_bad_mutation();
2129             else
2130                 delete_mutation(RANDOM_MUTATION, "helix card");
2131             break;
2132         case 2:
2133             if (coinflip())
2134             {
2135                 if (coinflip())
2136                 {
2137                     _remove_bad_mutation();
2138                     mutate(RANDOM_MUTATION, "helix card");
2139                 }
2140                 else
2141                 {
2142                     delete_mutation(RANDOM_MUTATION, "helix card");
2143                     mutate(RANDOM_GOOD_MUTATION, "helix card");
2144                 }
2145             }
2146             else
2147             {
2148                 delete_mutation(RANDOM_MUTATION, "helix card");
2149                 mutate(RANDOM_MUTATION, "helix card");
2150             }
2151             break;
2152         }
2153     }
2154     else
2155     {
2156         switch (random2(3))
2157         {
2158         case 0:
2159             _remove_bad_mutation();
2160             break;
2161         case 1:
2162             mutate(RANDOM_GOOD_MUTATION, "helix card");
2163             break;
2164         case 2:
2165             if (coinflip())
2166             {
2167                 // If you get unlucky, you could get here with no bad
2168                 // mutations and simply get a mutation effect. Oh well.
2169                 _remove_bad_mutation();
2170                 mutate(RANDOM_MUTATION, "helix card");
2171             }
2172             else
2173             {
2174                 delete_mutation(RANDOM_MUTATION, "helix card");
2175                 mutate(RANDOM_GOOD_MUTATION, "helix card");
2176             }
2177             break;
2178         }
2179     }
2180 }
2181
2182 static void _dowsing_card(int power, deck_rarity_type rarity)
2183 {
2184     const int power_level = _get_power_level(power, rarity);
2185     bool things_to_do[3] = { false, false, false };
2186     things_to_do[random2(3)] = true;
2187
2188     if (power_level == 1)
2189         things_to_do[random2(3)] = true;
2190
2191     if (power_level >= 2)
2192     {
2193         for (int i = 0; i < 3; ++i)
2194             things_to_do[i] = true;
2195     }
2196
2197     if (things_to_do[0])
2198         magic_mapping(random2(power/2) + 18, random2(power*2), false);
2199     if (things_to_do[1])
2200     {
2201         if (detect_traps(random2(power)))
2202             mpr("You sense traps nearby.");
2203         if (detect_items(random2(power)))
2204             mpr("You sense items nearby.");
2205     }
2206     if (things_to_do[2])
2207     {
2208         you.set_duration(DUR_TELEPATHY, random2(power), 0,
2209                          "You feel telepathic!");
2210         detect_creatures(1 + you.duration[DUR_TELEPATHY] * 2 / BASELINE_DELAY,
2211                          true);
2212     }
2213 }
2214
2215 // Special case for *your* god, maybe?
2216 static void _godly_wrath()
2217 {
2218     int tries = 100;
2219     while (tries-- > 0)
2220     {
2221         god_type god = random_god();
2222
2223         // Don't recursively make player draw from the Deck of Punishment.
2224         if (god == GOD_NEMELEX_XOBEH)
2225             continue;
2226
2227         // Stop once we find a god willing to punish the player.
2228         if (divine_retribution(god))
2229             break;
2230     }
2231
2232     if (tries <= 0)
2233         mpr("You somehow manage to escape divine attention...");
2234 }
2235
2236 static void _curse_card(int power, deck_rarity_type rarity)
2237 {
2238     const int power_level = _get_power_level(power, rarity);
2239
2240     mpr("You feel a malignant aura surround you.");
2241     if (power_level >= 2)
2242     {
2243         // Curse (almost) everything.
2244         // Ignore holy wrath weapons here, to avoid being stuck in a loop
2245         while (curse_an_item(true) && !one_chance_in(1000))
2246             ;
2247     }
2248     else if (power_level == 1)
2249     {
2250         // Curse an average of four items.
2251         while (curse_an_item(true) && !one_chance_in(4))
2252             ;
2253     }
2254     else
2255     {
2256         // Curse 1.5 items on average.
2257         if (curse_an_item() && coinflip())
2258             curse_an_item();
2259     }
2260 }
2261
2262 static void _crusade_card(int power, deck_rarity_type rarity)
2263 {
2264     const int power_level = _get_power_level(power, rarity);
2265     if (power_level >= 1)
2266     {
2267         // A chance to convert opponents.
2268         for (monster_near_iterator mi(you.pos(), LOS_NO_TRANS); mi; ++mi)
2269         {
2270             if (mi->friendly()
2271                || mi->holiness() != MH_NATURAL
2272                || mons_is_unique(mi->type)
2273                || mons_immune_magic(*mi)
2274                || player_will_anger_monster(*mi))
2275             {
2276                 continue;
2277             }
2278
2279             // Note that this bypasses the magic resistance
2280             // (though not immunity) check.  Specifically,
2281             // you can convert Killer Klowns this way.
2282             // Might be too good.
2283             if (mi->get_hit_dice() * 35 < random2(power))
2284             {
2285                 simple_monster_message(*mi, " is converted.");
2286                 mi->add_ench(ENCH_CHARM);
2287                 mons_att_changed(*mi);
2288             }
2289         }
2290     }
2291     cast_aura_of_abjuration(power/4);
2292 }
2293
2294 static void _summon_demon_card(int power, deck_rarity_type rarity)
2295 {
2296     const int power_level = _get_power_level(power, rarity);
2297     // one demon, and one other demonic creature
2298     monster_type dct, dct2;
2299     if (power_level >= 2)
2300     {
2301         dct = random_choose(MONS_BALRUG, MONS_BLIZZARD_DEMON,
2302               MONS_GREEN_DEATH, MONS_SHADOW_DEMON, MONS_CACODEMON,
2303               MONS_HELL_BEAST, MONS_REAPER, MONS_LOROCYPROCA,
2304               MONS_HELLION, MONS_TORMENTOR);
2305         dct2 = MONS_PANDEMONIUM_LORD;
2306     }
2307     else if (power_level == 1)
2308     {
2309         dct = random_choose(MONS_SUN_DEMON, MONS_ICE_DEVIL,
2310               MONS_SOUL_EATER, MONS_CHAOS_SPAWN, MONS_SMOKE_DEMON,
2311               MONS_YNOXINUL, MONS_NEQOXEC);
2312         dct2 = MONS_RAKSHASA;
2313     }
2314     else
2315     {
2316         dct = random_choose(MONS_RED_DEVIL, MONS_BLUE_DEVIL,
2317               MONS_RUST_DEVIL, MONS_HELLWING, MONS_ORANGE_DEMON,
2318               MONS_SIXFIRHY);
2319         dct2 = MONS_HELL_HOUND;
2320     }
2321
2322     if (is_good_god(you.religion))
2323     {
2324         _suppressed_card_message(you.religion, DID_UNHOLY);
2325         return;
2326     }
2327
2328     // FIXME: The manual testing for message printing is there because
2329     // we can't rely on create_monster() to do it for us. This is
2330     // because if you are completely surrounded by walls, create_monster()
2331     // will never manage to give a position which isn't (-1,-1)
2332     // and thus not print the message.
2333     // This hack appears later in this file as well.
2334     if (!create_monster(
2335             mgen_data(dct, BEH_FRIENDLY, &you,
2336                       5 - power_level, 0, you.pos(), MHITYOU, MG_AUTOFOE),
2337             false))
2338     {
2339         mpr("You see a puff of smoke.");
2340     }
2341
2342     create_monster(
2343             mgen_data(dct2,
2344                       BEH_FRIENDLY, &you, 5 - power_level, 0, you.pos(), MHITYOU,
2345                       MG_AUTOFOE));
2346
2347 }
2348
2349 static void _elements_card(int power, deck_rarity_type rarity)
2350 {
2351
2352     const int power_level = _get_power_level(power, rarity);
2353     const monster_type element_list[][3] =
2354     {
2355        {MONS_RAIJU, MONS_WIND_DRAKE, MONS_SHOCK_SERPENT},
2356        {MONS_BASILISK, MONS_BORING_BEETLE, MONS_BOULDER_BEETLE},
2357        {MONS_MOTTLED_DRAGON, MONS_MOLTEN_GARGOYLE, MONS_SALAMANDER_FIREBRAND},
2358        {MONS_ICE_BEAST, MONS_POLAR_BEAR, MONS_ICE_DRAGON}
2359     };
2360
2361     int start = random2(ARRAYSZ(element_list));
2362
2363     for (int i = 0; i < 3; ++i)
2364     {
2365         monster_type mons_type = element_list[start % ARRAYSZ(element_list)][power_level];
2366         monster hackmon;
2367
2368         hackmon.type = mons_type;
2369         mons_load_spells(&hackmon);
2370
2371         if (you_worship(GOD_DITHMENOS) && mons_is_fiery(&hackmon))
2372         {
2373             _suppressed_card_message(you.religion, DID_FIRE);
2374             start++;
2375             continue;
2376         }
2377
2378         create_monster(
2379             mgen_data(mons_type, BEH_FRIENDLY, &you, power_level + 2, 0,
2380                       you.pos(), MHITYOU, MG_AUTOFOE));
2381         start++;
2382     }
2383
2384 }
2385
2386 static void _summon_dancing_weapon(int power, deck_rarity_type rarity)
2387 {
2388     const int power_level = _get_power_level(power, rarity);
2389
2390     monster *mon =
2391         create_monster(
2392             mgen_data(MONS_DANCING_WEAPON, BEH_FRIENDLY, &you,
2393                       power_level + 2, 0, you.pos(), MHITYOU, MG_AUTOFOE),
2394             false);
2395
2396     // Given the abundance of Nemelex decks, not setting hard reset
2397     // leaves a trail of weapons behind, most of which just get
2398     // offered to Nemelex again, adding an unnecessary source of
2399     // piety.
2400     // This is of course irrelevant now that Nemelex sacrifices
2401     // are gone.
2402     if (mon)
2403     {
2404         // Override the weapon.
2405         ASSERT(mon->weapon() != NULL);
2406         item_def& wpn(*mon->weapon());
2407
2408         if (power_level == 0)
2409         {
2410             // Wimpy, negative-enchantment weapon.
2411             wpn.plus = random2(3) - 2;
2412             wpn.sub_type = (coinflip() ? WPN_QUARTERSTAFF : WPN_HAND_AXE);
2413
2414             set_item_ego_type(wpn, OBJ_WEAPONS,
2415                               coinflip() ? SPWPN_VENOM : SPWPN_NORMAL);
2416         }
2417         else if (power_level == 1)
2418         {
2419             // This is getting good.
2420             wpn.plus = random2(4) - 1;
2421             wpn.sub_type = (coinflip() ? WPN_LONG_SWORD : WPN_TRIDENT);
2422
2423             if (coinflip())
2424             {
2425                 set_item_ego_type(wpn, OBJ_WEAPONS,
2426                                   coinflip() ? SPWPN_FLAMING : SPWPN_FREEZING);
2427             }
2428             else
2429                 set_item_ego_type(wpn, OBJ_WEAPONS, SPWPN_NORMAL);
2430         }
2431         else if (power_level == 2)
2432         {
2433             // Rare and powerful.
2434             wpn.plus = random2(4) + 2;
2435             wpn.sub_type = (coinflip() ? WPN_DEMON_TRIDENT : WPN_EXECUTIONERS_AXE);
2436
2437             set_item_ego_type(wpn, OBJ_WEAPONS,
2438                               coinflip() ? SPWPN_SPEED : SPWPN_ELECTROCUTION);
2439         }
2440
2441         item_colour(wpn);
2442
2443         // sometimes give a randart instead
2444         if (one_chance_in(3))
2445         {
2446             make_item_randart(wpn, true);
2447             set_ident_flags(wpn, ISFLAG_KNOW_PROPERTIES| ISFLAG_KNOW_TYPE);
2448         }
2449
2450         mon->flags |= MF_HARD_RESET;
2451
2452         ghost_demon newstats;
2453         newstats.init_dancing_weapon(wpn, power / 4);
2454
2455         mon->set_ghost(newstats);
2456         mon->ghost_demon_init();
2457     }
2458     else
2459         mpr("You see a puff of smoke.");
2460 }
2461
2462 static void _summon_flying(int power, deck_rarity_type rarity)
2463 {
2464     const int power_level = _get_power_level(power, rarity);
2465
2466     const monster_type flytypes[] =
2467     {
2468         MONS_INSUBSTANTIAL_WISP, MONS_KILLER_BEE, MONS_RAVEN,
2469         MONS_VAMPIRE_MOSQUITO, MONS_YELLOW_WASP, MONS_RED_WASP
2470     };
2471     const int num_flytypes = ARRAYSZ(flytypes);
2472
2473     // Choose what kind of monster.
2474     monster_type result;
2475     const int how_many = 2 + random2(3) + power_level * 3;
2476     bool hostile_invis = false;
2477
2478     do
2479     {
2480         result = flytypes[random2(num_flytypes - 2) + power_level];
2481     }
2482     while (is_good_god(you.religion) && result == MONS_VAMPIRE_MOSQUITO);
2483
2484     for (int i = 0; i < how_many; ++i)
2485     {
2486         const bool friendly = !one_chance_in(power_level + 4);
2487
2488         create_monster(
2489             mgen_data(result,
2490                       friendly ? BEH_FRIENDLY : BEH_HOSTILE, &you,
2491                       3, 0, you.pos(), MHITYOU, MG_AUTOFOE));
2492
2493         if (mons_class_flag(result, M_INVIS) && !you.can_see_invisible() && !friendly)
2494             hostile_invis = true;
2495     }
2496
2497     if (hostile_invis)
2498         mpr("You sense the presence of something unfriendly.");
2499 }
2500
2501 static void _summon_rangers(int power, deck_rarity_type rarity)
2502 {
2503     const int power_level = _get_power_level(power, rarity);
2504     monster_type dctr, dctr2, dctr3, dctr4;
2505     monster_type base_choice, big_choice, mid_choice, placed_choice;
2506     dctr = random_choose(MONS_CENTAUR, MONS_YAKTAUR);
2507     dctr2 = random_choose(MONS_CENTAUR_WARRIOR, MONS_FAUN);
2508     dctr3 = random_choose(MONS_YAKTAUR_CAPTAIN, MONS_NAGA_SHARPSHOOTER);
2509     dctr4 = random_choose(MONS_SATYR, MONS_MERFOLK_JAVELINEER,
2510                           MONS_DEEP_ELF_MASTER_ARCHER);
2511     const int launch_count = 1 + random2(2);
2512
2513     if (power_level >= 2)
2514     {
2515         base_choice = dctr2;
2516         big_choice  = dctr4;
2517         mid_choice  = dctr3;
2518     }
2519     else
2520     {
2521         base_choice = dctr;
2522         {
2523             if (power_level == 1)
2524             {
2525                 big_choice  = dctr3;
2526                 mid_choice  = dctr2;
2527             }
2528             else
2529             {
2530                 big_choice  = dctr;
2531                 mid_choice  = dctr;
2532             }
2533         }
2534     }
2535
2536     if (launch_count < 2)
2537         placed_choice = big_choice;
2538     else
2539         placed_choice = mid_choice;
2540
2541     for (int i = 0; i < launch_count; ++i)
2542     {
2543         create_monster(
2544             mgen_data(base_choice,
2545                       BEH_FRIENDLY, &you, 5 - power_level, 0, you.pos(), MHITYOU,
2546                       MG_AUTOFOE));
2547     }
2548
2549     create_monster(
2550         mgen_data(placed_choice,
2551                   BEH_FRIENDLY, &you, 5 - power_level, 0, you.pos(), MHITYOU,
2552                   MG_AUTOFOE));
2553
2554 }
2555
2556 static void _summon_ugly(int power, deck_rarity_type rarity)
2557 {
2558     const int power_level = _get_power_level(power, rarity);
2559     const bool friendly = !one_chance_in(4 + power_level * 2);
2560     monster_type ugly;
2561     if (power_level >= 1)
2562         ugly = MONS_VERY_UGLY_THING;
2563     else
2564         ugly = MONS_UGLY_THING;
2565
2566     // TODO: Handle Dithmenos and red uglies
2567
2568     if (you_worship(GOD_ZIN))
2569     {
2570         _suppressed_card_message(you.religion, DID_CHAOS);
2571         return;
2572     }
2573
2574     if (!create_monster(mgen_data(ugly,
2575                                   friendly ? BEH_FRIENDLY : BEH_HOSTILE,
2576                                   &you,
2577                                   min(power/50 + 1, 5), 0,
2578                                   you.pos(), MHITYOU, MG_AUTOFOE),
2579                         false))
2580     {
2581         mpr("You see a puff of smoke.");
2582     }
2583
2584     if (power_level == 2)
2585     {
2586         create_monster(mgen_data(MONS_UGLY_THING,
2587                         friendly ? BEH_FRIENDLY : BEH_HOSTILE,
2588                         &you,
2589                         min(power/50 + 1, 5), 0,
2590                         you.pos(), MHITYOU, MG_AUTOFOE));
2591     }
2592
2593 }
2594
2595 static void _mercenary_card(int power, deck_rarity_type rarity)
2596 {
2597     const int power_level = _get_power_level(power, rarity);
2598     const monster_type merctypes[] =
2599     {
2600         MONS_BIG_KOBOLD, MONS_MERFOLK, MONS_NAGA,
2601         MONS_TENGU, MONS_DEEP_ELF_CONJURER, MONS_ORC_KNIGHT,
2602         RANDOM_BASE_DEMONSPAWN, MONS_OGRE_MAGE, MONS_MINOTAUR,
2603         RANDOM_BASE_DRACONIAN, MONS_DEEP_ELF_BLADEMASTER,
2604     };
2605
2606     int merc;
2607     monster *mon;
2608     bool hated = player_mutation_level(MUT_NO_LOVE);
2609
2610     while (1)
2611     {
2612         merc = power_level + random2(3 * (power_level + 1));
2613         ASSERT(merc < (int)ARRAYSZ(merctypes));
2614
2615         mgen_data mg(merctypes[merc], BEH_HOSTILE, &you,
2616                     0, 0, you.pos(), MHITYOU, MG_FORCE_BEH, you.religion);
2617
2618         mg.extra_flags |= (MF_NO_REWARD | MF_HARD_RESET);
2619
2620         // This is a bit of a hack to use give_monster_proper_name to feed
2621         // the mgen_data, but it gets the job done.
2622         monster tempmon;
2623         tempmon.type = merctypes[merc];
2624         if (give_monster_proper_name(&tempmon, false))
2625             mg.mname = tempmon.mname;
2626         else
2627             mg.mname = make_name(random_int(), false);
2628         // This is used for giving the merc better stuff in mon-gear.
2629         mg.props["mercenary items"] = true;
2630
2631         mon = create_monster(mg);
2632
2633         if (!mon)
2634         {
2635             mpr("You see a puff of smoke.");
2636             return;
2637         }
2638
2639         // always hostile, don't try to find a good one
2640         if (hated)
2641             break;
2642         if (player_will_anger_monster(mon))
2643         {
2644             dprf("God %s doesn't like %s, retrying.",
2645             god_name(you.religion).c_str(), mon->name(DESC_THE).c_str());
2646             monster_die(mon, KILL_RESET, NON_MONSTER);
2647             continue;
2648         }
2649         else
2650             break;
2651     }
2652
2653     mon->props["dbname"].get_string() = mons_class_name(merctypes[merc]);
2654
2655     redraw_screen(); // We want to see the monster while it's asking to be paid.
2656
2657     if (hated)
2658     {
2659         simple_monster_message(mon, " is unwilling to work for you!");
2660         return;
2661     }
2662
2663     const int fee = fuzz_value(exper_value(mon), 15, 15);
2664     if (fee > you.gold)
2665     {
2666         mprf("You cannot afford %s fee of %d gold!",
2667              mon->name(DESC_ITS).c_str(), fee);
2668         simple_monster_message(mon, " attacks!");
2669         return;
2670     }
2671
2672     mon->props["mercenary_fee"] = fee;
2673     run_uncancel(UNC_MERCENARY, mon->mid);
2674 }
2675
2676 bool recruit_mercenary(int mid)
2677 {
2678     monster *mon = monster_by_mid(mid);
2679     if (!mon)
2680         return true; // wut?
2681
2682     int fee = mon->props["mercenary_fee"].get_int();
2683     const string prompt = make_stringf("Pay %s fee of %d gold?",
2684                                        mon->name(DESC_ITS).c_str(), fee);
2685     bool paid = yesno(prompt.c_str(), false, 0);
2686     const string message = make_stringf("Hired %s for %d gold.",
2687                                         mon->full_name(DESC_A).c_str(), fee);
2688     if (crawl_state.seen_hups)
2689         return false;
2690
2691     mon->props.erase("mercenary_fee");
2692     if (!paid)
2693     {
2694         simple_monster_message(mon, " attacks!");
2695         return true;
2696     }
2697
2698     simple_monster_message(mon, " joins your ranks!");
2699     mon->attitude = ATT_FRIENDLY;
2700     mons_att_changed(mon);
2701     take_note(Note(NOTE_MESSAGE, 0, 0, message.c_str()), true);
2702     you.del_gold(fee);
2703     return true;
2704 }
2705
2706 static void _alchemist_card(int power, deck_rarity_type rarity)
2707 {
2708     const int power_level = _get_power_level(power, rarity);
2709     const int gold_max = min(you.gold, random2avg(100, 2) * (1 + power_level));
2710     int gold_used = 0;
2711
2712     dprf("%d gold available to spend.", gold_max);
2713
2714     // Spend some gold to regain health.
2715     int hp = min((gold_max - gold_used) / 3, you.hp_max - you.hp);
2716     if (hp > 0)
2717     {
2718         you.del_gold(hp * 2);
2719         inc_hp(hp);
2720         gold_used += hp * 2;
2721         mpr("You feel better.");
2722         dprf("Gained %d health, %d gold remaining.", hp, gold_max - gold_used);
2723     }
2724     // Maybe spend some more gold to regain magic.
2725     int mp = min((gold_max - gold_used) / 5,
2726                  you.max_magic_points - you.magic_points);
2727     if (mp > 0 && x_chance_in_y(power_level + 1, 5))
2728     {
2729         you.del_gold(mp * 5);
2730         inc_mp(mp);
2731         gold_used += mp * 5;
2732         mpr("You feel your power returning.");
2733         dprf("Gained %d magic, %d gold remaining.", mp, gold_max - gold_used);
2734     }
2735
2736     if (gold_used > 0)
2737         mprf("%d of your gold pieces vanish!", gold_used);
2738     else
2739         canned_msg(MSG_NOTHING_HAPPENS);
2740 }
2741
2742 static void _cloud_card(int power, deck_rarity_type rarity)
2743 {
2744     const int power_level = _get_power_level(power, rarity);
2745     bool something_happened = false;
2746
2747     for (radius_iterator di(you.pos(), LOS_NO_TRANS); di; ++di)
2748     {
2749         monster *mons = monster_at(*di);
2750         cloud_type cloudy;
2751
2752         switch (power_level)
2753         {
2754             case 0: cloudy = (you_worship(GOD_SHINING_ONE) || !one_chance_in(5))
2755                               ? CLOUD_MEPHITIC : CLOUD_POISON;
2756                     break;
2757
2758             case 1: cloudy = (you_worship(GOD_DITHMENOS) || coinflip())
2759                               ? CLOUD_COLD : CLOUD_FIRE;
2760                      break;
2761
2762             case 2: cloudy = (is_good_god(you.religion) || coinflip())
2763                               ? CLOUD_ACID: CLOUD_MIASMA;
2764                     break;
2765
2766             default: cloudy = CLOUD_DEBUGGING;
2767         }
2768
2769         if (!mons || (mons && (mons->wont_attack()
2770             || mons_is_firewood(mons))))
2771         {
2772             continue;
2773         }
2774
2775         for (adjacent_iterator ai(mons->pos()); ai; ++ai)
2776         {
2777             // don't place clouds on the player or monsters
2778             if (*ai == you.pos() || monster_at(*ai))
2779                 continue;
2780
2781             if (grd(*ai) == DNGN_FLOOR && env.cgrid(*ai) == EMPTY_CLOUD)
2782             {
2783                 const int cloud_power = 5 + random2((power_level + 1) * 3);
2784                 place_cloud(cloudy, *ai, cloud_power, &you);
2785
2786                 if (you.see_cell(*ai))
2787                 something_happened = true;
2788             }
2789         }
2790     }
2791
2792     if (something_happened)
2793         mpr("Clouds appear around you!");
2794     else
2795         canned_msg(MSG_NOTHING_HAPPENS);
2796 }
2797
2798 static void _fortitude_card(int power, deck_rarity_type rarity)
2799 {
2800     const int power_level = _get_power_level(power, rarity);
2801     const bool strong = you.duration[DUR_FORTITUDE] > 0;
2802
2803     you.increase_duration(DUR_FORTITUDE, 10 + random2((power_level + 1) * 10));
2804
2805     if (!strong)
2806     {
2807         mprf(MSGCH_DURATION, "You are filled with a great fortitude.");
2808         notify_stat_change(STAT_STR, 10, true, "");
2809     }
2810     else
2811         mprf(MSGCH_DURATION, "You become more resolute.");
2812 }
2813
2814 static void _storm_card(int power, deck_rarity_type rarity)
2815 {
2816     const int power_level = _get_power_level(power, rarity);
2817
2818     if (coinflip())
2819     {
2820         const int num_to_summ = 1 + random2(1 + power_level);
2821         for (int i = 0; i < num_to_summ; ++i)
2822         {
2823             create_monster(
2824                     mgen_data(MONS_AIR_ELEMENTAL,
2825                               BEH_FRIENDLY, &you, 3, 0, you.pos(), MHITYOU,
2826                               MG_AUTOFOE));
2827         }
2828     }
2829     else
2830     {
2831         wind_blast(&you, (power_level == 0) ? 100 : 200, coord_def(), true);
2832
2833         for (radius_iterator ri(you.pos(), 5, C_ROUND, LOS_SOLID); ri; ++ri)
2834         {
2835             monster *mons = monster_at(*ri);
2836
2837             if (adjacent(*ri, you.pos()))
2838                 continue;
2839
2840             if (mons && mons->wont_attack())
2841                 continue;
2842
2843
2844             if ((feat_has_solid_floor(grd(*ri))
2845                  || grd(*ri) == DNGN_DEEP_WATER)
2846                 && env.cgrid(*ri) == EMPTY_CLOUD)
2847             {
2848                 place_cloud(CLOUD_STORM, *ri,
2849                             5 + (power_level + 1) * random2(10), & you);
2850             }
2851         }
2852     }
2853
2854     if (power_level > 1 || (power_level == 1 && coinflip()))
2855     {
2856         if (coinflip())
2857         {
2858             coord_def pos;
2859             int tries = 0;
2860
2861             do
2862             {
2863                 random_near_space(&you, you.pos(), pos, true);
2864                 tries++;
2865             }
2866             while (distance2(pos, you.pos()) < 3 && tries < 50);
2867
2868             if (tries > 50)
2869                 pos = you.pos();
2870
2871
2872             if (create_monster(
2873                         mgen_data(MONS_TWISTER,
2874                                   BEH_HOSTILE, &you, 1 + random2(power_level + 1),
2875                                   0, pos, MHITYOU, MG_FORCE_PLACE)))
2876             {
2877                 mpr("A tornado forms.");
2878             }
2879         }
2880         else
2881         {
2882             // create some water so the wellspring can place
2883             create_feat_splash(you.pos(), 2, 3);
2884             create_monster(
2885                     mgen_data(MONS_ELEMENTAL_WELLSPRING,
2886                               BEH_FRIENDLY, &you, 3, 0, you.pos(), MHITYOU,
2887                               MG_AUTOFOE));
2888         }
2889     }
2890  }
2891
2892 static void _illusion_card(int power, deck_rarity_type rarity)
2893 {
2894     const int power_level = _get_power_level(power, rarity);
2895     monster* mon = get_free_monster();
2896
2897     if (!mon || monster_at(you.pos()))
2898         return;
2899
2900     mon->type = MONS_PLAYER;
2901     mon->behaviour = BEH_SEEK;
2902     mon->attitude = ATT_FRIENDLY;
2903     mon->set_position(you.pos());
2904     mon->mid = MID_PLAYER;
2905     mgrd(you.pos()) = mon->mindex();
2906
2907     mons_summon_illusion_from(mon, (actor *)&you, SPELL_NO_SPELL, power_level);
2908     mon->reset();
2909  }
2910
2911 static void _degeneration_card(int power, deck_rarity_type rarity)
2912 {
2913     const int power_level = _get_power_level(power, rarity);
2914     bool effects = false;
2915
2916     if (you_worship(GOD_ZIN))
2917     {
2918         _suppressed_card_message(you.religion, DID_CHAOS);
2919         return;
2920     }
2921
2922     for (radius_iterator di(you.pos(), LOS_NO_TRANS); di; ++di)
2923     {
2924         monster *mons = monster_at(*di);
2925
2926         if (mons && (mons->wont_attack() || mons_is_firewood(mons)))
2927             continue;
2928
2929         if (mons &&
2930             x_chance_in_y((power_level + 1) * 5 + random2(5),
2931                           mons->get_hit_dice()))
2932         {
2933             if (mons->can_polymorph())
2934             {
2935                 monster_polymorph(mons, RANDOM_MONSTER, PPT_LESS);
2936                 mons->malmutate("");
2937             }
2938             else if (mons->holiness() == MH_UNDEAD)
2939             {
2940                 const int daze_time = (5 + 5 * power_level) * BASELINE_DELAY;
2941                 mons->add_ench(mon_enchant(ENCH_DAZED, 0, &you, daze_time));
2942                 simple_monster_message(mons, " is dazed by the mutagenic energy.");
2943             }
2944             else
2945                 continue;
2946
2947             effects = true;
2948         }
2949     }
2950
2951     if (!effects)
2952         canned_msg(MSG_NOTHING_HAPPENS);
2953 }
2954
2955 static void _placid_magic_card(int power, deck_rarity_type rarity)
2956 {
2957     const int power_level = _get_power_level(power, rarity);
2958     const int drain = max(you.magic_points - random2(power_level * 3), 0);
2959
2960     mpr("You feel magic draining away.");
2961
2962     drain_mp(drain);
2963     debuff_player();
2964
2965     for (radius_iterator di(you.pos(), LOS_NO_TRANS); di; ++di)
2966     {
2967         monster *mons = monster_at(*di);
2968
2969         if (!mons || mons->wont_attack())
2970             continue;
2971
2972         debuff_monster(mons);
2973         if (!mons->antimagic_susceptible())
2974             continue;
2975
2976         // XXX: this should be refactored together with other effects that
2977         // apply antimagic.
2978         const int duration = random2(div_rand_round(power / 3,
2979                                                     mons->get_hit_dice()))
2980                              * BASELINE_DELAY;
2981         mons->add_ench(mon_enchant(ENCH_ANTIMAGIC, 0, &you, duration));
2982         mprf("%s magic leaks into the air.",
2983              apostrophise(mons->name(DESC_THE)).c_str());
2984     }
2985 }
2986
2987 static void _wild_magic_card(int power, deck_rarity_type rarity)
2988 {
2989     const int power_level = _get_power_level(power, rarity);
2990     int num_affected = 0;
2991
2992     for (radius_iterator di(you.pos(), LOS_NO_TRANS); di; ++di)
2993     {
2994         monster *mons = monster_at(*di);
2995
2996         if (!mons || mons->wont_attack() || mons_is_firewood(mons))
2997             continue;
2998
2999         if (x_chance_in_y((power_level + 1) * 5 + random2(5),
3000                            mons->get_hit_dice()))
3001         {
3002             MiscastEffect(mons, actor_by_mid(MID_YOU_FAULTLESS),
3003                         DECK_MISCAST, SPTYP_RANDOM,
3004                         random2(power/15) + 5, random2(power),
3005                         "a card of wild magic");
3006
3007             num_affected++;
3008         }
3009     }
3010
3011     if (num_affected > 0)
3012     {
3013         int mp = 0;
3014
3015         for (int i = 0; i < num_affected; ++i)
3016             mp += random2(5);
3017
3018         inc_mp(mp);
3019         mpr("You feel a surge of magic.");
3020     }
3021     else
3022         canned_msg(MSG_NOTHING_HAPPENS);
3023 }
3024
3025 // Punishment cards don't have their power adjusted depending on Nemelex piety
3026 // or penance, and are based on experience level instead of evocations skill
3027 // for more appropriate scaling.
3028 static int _card_power(deck_rarity_type rarity, bool punishment)
3029 {
3030     int result = 0;
3031
3032     if (!punishment)
3033     {
3034         if (player_under_penance(GOD_NEMELEX_XOBEH))
3035             result -= you.penance[GOD_NEMELEX_XOBEH];
3036         else if (you_worship(GOD_NEMELEX_XOBEH))
3037         {
3038             result = you.piety;
3039             result *= (you.skill(SK_EVOCATIONS, 100) + 2500);
3040             result /= 2700;
3041         }
3042     }
3043
3044     result += (punishment) ? you.experience_level * 18
3045                            : you.skill(SK_EVOCATIONS, 9);
3046
3047     if (rarity == DECK_RARITY_RARE)
3048         result += 150;
3049     else if (rarity == DECK_RARITY_LEGENDARY)
3050         result += 300;
3051
3052     if (result < 0)
3053         result = 0;
3054
3055     return result;
3056 }
3057
3058 void card_effect(card_type which_card, deck_rarity_type rarity,
3059                  uint8_t flags, bool tell_card)
3060 {
3061     ASSERT(!_card_forbidden(which_card));
3062
3063     const char *participle = (flags & CFLAG_DEALT) ? "dealt" : "drawn";
3064     const int power = _card_power(rarity, flags & CFLAG_PUNISHMENT);
3065
3066     dprf("Card power: %d, rarity: %d", power, rarity);
3067
3068     if (tell_card)
3069     {
3070         // These card types will usually give this message in the targeting
3071         // prompt, and the cases where they don't are handled specially.
3072         if (which_card != CARD_VITRIOL && which_card != CARD_HAMMER
3073             && which_card != CARD_PAIN && which_card != CARD_VENOM
3074             && which_card != CARD_ORB)
3075         {
3076             mprf("You have %s %s.", participle, card_name(which_card));
3077         }
3078     }
3079
3080     if (which_card == CARD_XOM && !crawl_state.is_god_acting())
3081     {
3082         if (you_worship(GOD_XOM))
3083         {
3084             // Being a self-centered deity, Xom *always* finds this
3085             // maximally hilarious.
3086             god_speaks(GOD_XOM, "Xom roars with laughter!");
3087             you.gift_timeout = 200;
3088         }
3089         else if (player_under_penance(GOD_XOM))
3090             god_speaks(GOD_XOM, "Xom laughs nastily.");
3091     }
3092
3093     switch (which_card)
3094     {
3095     case CARD_SWAP:             _swap_monster_card(power, rarity); break;
3096     case CARD_VELOCITY:         _velocity_card(power, rarity); break;
3097     case CARD_DAMNATION:        _damnation_card(power, rarity); break;
3098     case CARD_SOLITUDE:         _solitude_card(power, rarity); break;
3099     case CARD_ELIXIR:           _elixir_card(power, rarity); break;
3100     case CARD_HELM:             _helm_card(power, rarity); break;
3101     case CARD_BLADE:            _blade_card(power, rarity); break;
3102     case CARD_SHADOW:           _shadow_card(power, rarity); break;
3103     case CARD_POTION:           _potion_card(power, rarity); break;
3104     case CARD_FOCUS:            _focus_card(power, rarity); break;
3105     case CARD_HELIX:            _helix_card(power, rarity); break;
3106     case CARD_DOWSING:          _dowsing_card(power, rarity); break;
3107     case CARD_STAIRS:           _stairs_card(power, rarity); break;
3108     case CARD_CURSE:            _curse_card(power, rarity); break;
3109     case CARD_WARPWRIGHT:       _warpwright_card(power, rarity); break;
3110     case CARD_SHAFT:            _shaft_card(power, rarity); break;
3111     case CARD_TOMB:             entomb(10 + power/20 + random2(power/4)); break;
3112     case CARD_WRAITH:           drain_player(power / 4, false); break;
3113     case CARD_WRATH:            _godly_wrath(); break;
3114     case CARD_CRUSADE:          _crusade_card(power, rarity); break;
3115     case CARD_SUMMON_DEMON:     _summon_demon_card(power, rarity); break;
3116     case CARD_ELEMENTS:         _elements_card(power, rarity); break;
3117     case CARD_RANGERS:          _summon_rangers(power, rarity); break;
3118     case CARD_SUMMON_WEAPON:    _summon_dancing_weapon(power, rarity); break;
3119     case CARD_SUMMON_FLYING:    _summon_flying(power, rarity); break;
3120     case CARD_SUMMON_UGLY:      _summon_ugly(power, rarity); break;
3121     case CARD_XOM:              xom_acts(5 + random2(power/10)); break;
3122     case CARD_BANSHEE:          _banshee_card(power, rarity); break;
3123     case CARD_TORMENT:          torment(&you, TORMENT_CARDS, you.pos()); break;
3124     case CARD_ALCHEMIST:        _alchemist_card(power, rarity); break;
3125     case CARD_MERCENARY:        _mercenary_card(power, rarity); break;
3126     case CARD_CLOUD:            _cloud_card(power, rarity); break;
3127     case CARD_FORTITUDE:        _fortitude_card(power, rarity); break;
3128     case CARD_STORM:            _storm_card(power, rarity); break;
3129     case CARD_ILLUSION:         _illusion_card(power, rarity); break;
3130     case CARD_DEGEN:            _degeneration_card(power, rarity); break;
3131     case CARD_PLACID_MAGIC:     _placid_magic_card(power, rarity); break;
3132     case CARD_WILD_MAGIC:       _wild_magic_card(power, rarity); break;
3133
3134     case CARD_VENOM:
3135     case CARD_VITRIOL:
3136     case CARD_HAMMER:
3137     case CARD_PAIN:
3138     case CARD_ORB:
3139         _damaging_card(which_card, power, rarity, flags & CFLAG_DEALT);
3140         break;
3141
3142     case CARD_FAMINE:
3143         if (you_foodless())
3144             mpr("You feel rather smug.");
3145         else
3146             set_hunger(min(you.hunger, HUNGER_STARVING / 2), true);
3147         break;
3148
3149     case CARD_FEAST:
3150         if (you_foodless())
3151             mpr("You feel a horrible emptiness.");
3152         else
3153             set_hunger(HUNGER_MAXIMUM, true);
3154         break;
3155
3156     case CARD_SWINE:
3157         if (!transform(5 + power/10 + random2(power/10), TRAN_PIG, true))
3158         {
3159             mpr("You feel like a pig.");
3160             break;
3161         }
3162         break;
3163
3164 #if TAG_MAJOR_VERSION == 34
3165     case CARD_SHUFFLE:
3166     case CARD_EXPERIENCE:
3167     case CARD_SAGE:
3168     case CARD_WATER:
3169     case CARD_GLASS:
3170     case CARD_TROWEL:
3171     case CARD_MINEFIELD:
3172     case CARD_PORTAL:
3173     case CARD_WARP:
3174     case CARD_GENIE:
3175     case CARD_BATTLELUST:
3176     case CARD_BARGAIN:
3177     case CARD_METAMORPHOSIS:
3178     case CARD_SUMMON_ANIMAL:
3179     case CARD_SUMMON_SKELETON:
3180         mpr("This type of card no longer exists!");
3181         break;
3182 #endif
3183
3184     case NUM_CARDS:
3185         // The compiler will complain if any card remains unhandled.
3186         mprf("You have %s a buggy card!", participle);
3187         break;
3188     }
3189 }
3190
3191 bool top_card_is_known(const item_def &deck)
3192 {
3193     if (!is_deck(deck))
3194         return false;
3195
3196     uint8_t flags;
3197     get_card_and_flags(deck, -1, flags);
3198
3199     return flags & CFLAG_MARKED;
3200 }
3201
3202 card_type top_card(const item_def &deck)
3203 {
3204     if (!is_deck(deck))
3205         return NUM_CARDS;
3206
3207     uint8_t flags;
3208     card_type card = get_card_and_flags(deck, -1, flags);
3209
3210     UNUSED(flags);
3211
3212     return card;
3213 }
3214
3215 bool is_deck(const item_def &item)
3216 {
3217     return item.base_type == OBJ_MISCELLANY
3218            && item.sub_type >= MISC_FIRST_DECK
3219            && item.sub_type <= MISC_LAST_DECK;
3220 }
3221
3222 bool bad_deck(const item_def &item)
3223 {
3224     if (!is_deck(item))
3225         return false;
3226
3227     return !item.props.exists("cards")
3228            || item.props["cards"].get_type() != SV_VEC
3229            || item.props["cards"].get_vector().get_type() != SV_BYTE
3230            || cards_in_deck(item) == 0;
3231 }
3232
3233 colour_t deck_rarity_to_colour(deck_rarity_type rarity)
3234 {
3235     switch (rarity)
3236     {
3237     case DECK_RARITY_COMMON:
3238         return GREEN;
3239
3240     case DECK_RARITY_RARE:
3241         return MAGENTA;
3242
3243     case DECK_RARITY_LEGENDARY:
3244         return LIGHTMAGENTA;
3245
3246     case DECK_RARITY_RANDOM:
3247         die("unset deck rarity");
3248     }
3249
3250     return WHITE;
3251 }
3252
3253 void init_deck(item_def &item)
3254 {
3255     CrawlHashTable &props = item.props;
3256
3257     ASSERT(is_deck(item));
3258     ASSERT(!props.exists("cards"));
3259     ASSERT_RANGE(item.initial_cards, 1, 128);
3260     ASSERT(item.special >= DECK_RARITY_COMMON
3261            && item.special <= DECK_RARITY_LEGENDARY);
3262
3263     const store_flags fl = SFLAG_CONST_TYPE;
3264
3265     props["cards"].new_vector(SV_BYTE, fl).resize((vec_size)
3266                                                   item.initial_cards);
3267     props["card_flags"].new_vector(SV_BYTE, fl).resize((vec_size)
3268                                                        item.initial_cards);
3269     props["drawn_cards"].new_vector(SV_BYTE, fl);
3270
3271     for (int i = 0; i < item.initial_cards; ++i)
3272     {
3273         bool      was_odd = false;
3274         card_type card    = _random_card(item, was_odd);
3275
3276         uint8_t flags = 0;
3277         if (was_odd)
3278             flags = CFLAG_ODDITY;
3279
3280         _set_card_and_flags(item, i, card, flags);
3281     }
3282
3283     ASSERT(cards_in_deck(item) == item.initial_cards);
3284
3285     props["num_marked"]        = (char) 0;
3286
3287     props.assert_validity();
3288
3289     item.used_count  = 0;
3290 }
3291
3292 static void _unmark_deck(item_def& deck)
3293 {
3294     if (!is_deck(deck))
3295         return;
3296
3297     CrawlHashTable &props = deck.props;
3298     if (!props.exists("card_flags"))
3299         return;
3300
3301     CrawlVector &flags = props["card_flags"].get_vector();
3302
3303     for (unsigned int i = 0; i < flags.size(); ++i)
3304     {
3305         flags[i] =
3306             static_cast<char>((static_cast<char>(flags[i]) & ~CFLAG_MARKED));
3307     }
3308
3309     props["num_marked"] = static_cast<char>(0);
3310 }
3311
3312 static void _unmark_and_shuffle_deck(item_def& deck)
3313 {
3314     if (is_deck(deck))
3315     {
3316         _unmark_deck(deck);
3317         _shuffle_deck(deck);
3318     }
3319 }
3320
3321 void shuffle_all_decks_on_level()
3322 {
3323     for (int i = 0; i < MAX_ITEMS; ++i)
3324     {
3325         item_def& item(mitm[i]);
3326         if (item.defined() && is_deck(item))
3327         {
3328 #ifdef DEBUG_DIAGNOSTICS
3329             mprf(MSGCH_DIAGNOSTICS, "Shuffling: %s on %s",
3330                  item.name(DESC_PLAIN).c_str(),
3331                  level_id::current().describe().c_str());
3332 #endif
3333             _unmark_and_shuffle_deck(item);
3334         }
3335     }
3336 }
3337
3338 static bool _shuffle_inventory_decks()
3339 {
3340     bool success = false;
3341
3342     for (int i = 0; i < ENDOFPACK; ++i)
3343     {
3344         item_def& item(you.inv[i]);
3345         if (item.defined() && is_deck(item))
3346         {
3347 #ifdef DEBUG_DIAGNOSTICS
3348             mprf(MSGCH_DIAGNOSTICS, "Shuffling in inventory: %s",
3349                  item.name(DESC_PLAIN).c_str());
3350 #endif
3351             _unmark_and_shuffle_deck(item);
3352
3353             success = true;
3354         }
3355     }
3356
3357     return success;
3358 }
3359
3360 void nemelex_shuffle_decks()
3361 {
3362     add_daction(DACT_SHUFFLE_DECKS);
3363     _shuffle_inventory_decks();
3364
3365     // Wildly inaccurate, but of similar quality as the old code which
3366     // was triggered by the presence of any deck anywhere.
3367     if (you.num_total_gifts[GOD_NEMELEX_XOBEH])
3368         god_speaks(GOD_NEMELEX_XOBEH, "You hear Nemelex Xobeh chuckle.");
3369 }