1 /**
2  * @file
3  * @brief Acquirement and Trog/Oka/Sif gifts.
4 **/
5 
6 #include "AppHdr.h"
7 
8 #include "acquire.h"
9 
10 #include <algorithm>
11 #include <cmath>
12 #include <cstdio>
13 #include <cstdlib>
14 #include <cstring>
15 #include <queue>
16 #include <set>
17 
18 #include "ability.h"
19 #include "artefact.h"
20 #include "art-enum.h"
21 #include "colour.h"
22 #include "describe.h"
23 #include "dungeon.h"
24 #include "god-item.h"
25 #include "god-passive.h"
26 #include "item-name.h"
27 #include "item-prop.h"
28 #include "item-status-flag-type.h"
29 #include "items.h"
30 #include "item-use.h"
31 #include "invent.h"
32 #include "known-items.h"
33 #include "libutil.h"
34 #include "macro.h"
35 #include "message.h"
36 #include "notes.h"
37 #include "output.h"
38 #include "options.h"
39 #include "prompt.h"
40 #include "randbook.h"
41 #include "random.h"
42 #include "religion.h"
43 #include "shopping.h"
44 #include "skills.h"
45 #include "spl-book.h"
46 #include "spl-util.h"
47 #include "state.h"
48 #include "stringutil.h"
49 #include "tag-version.h"
50 #include "terrain.h"
51 #include "unwind.h"
52 #include "ui.h"
53 
54 static equipment_type _acquirement_armour_slot(bool);
55 static armour_type _acquirement_armour_for_slot(equipment_type, bool);
56 static armour_type _acquirement_shield_type();
57 static armour_type _acquirement_body_armour(bool);
58 static armour_type _useless_armour_type();
59 
60 /**
61  * Get a randomly rounded value for the player's specified skill, unmodified
62  * by crosstraining, draining, etc.
63  *
64  * @param skill     The skill in question; e.g. SK_ARMOUR.
65  * @param mult      A multiplier to the skill, for higher precision.
66  * @return          A rounded value of that skill; e.g. _skill_rdiv(SK_ARMOUR)
67  *                  for a value of 10.9 will return 11 90% of the time &
68  *                  10 the remainder.
69  */
_skill_rdiv(skill_type skill,int mult=1)70 static int _skill_rdiv(skill_type skill, int mult = 1)
71 {
72     const int scale = 256;
73     return div_rand_round(you.skill(skill, mult * scale, true), scale);
74 }
75 
76 /**
77  * Choose a random subtype of armour to generate through acquirement/divine
78  * gifts.
79  *
80  * Guaranteed to be wearable, in principle.
81  *
82  * @param divine    Lowers the odds of high-tier body armours being chosen.
83  * @return          The armour_type of the armour to be generated.
84  */
_acquirement_armour_subtype(bool divine,int &,int)85 static int _acquirement_armour_subtype(bool divine, int & /*quantity*/,
86                                        int /*agent*/)
87 {
88     const equipment_type slot_type = _acquirement_armour_slot(divine);
89     return _acquirement_armour_for_slot(slot_type, divine);
90 }
91 
92 /**
93  * Take a set of weighted elements and a filter, and return a random element
94  * from those elements that fulfills the filter condition.
95  *
96  * @param weights       The elements to choose from.
97  * @param filter        An optional filter; if present, only elements for which
98  *                      the filter returns true may be chosen.
99  * @return              A random element from the given list.
100  */
101 template<class M>
filtered_vector_select(vector<pair<M,int>> weights,function<bool (M)> filter)102 M filtered_vector_select(vector<pair<M, int>> weights, function<bool(M)> filter)
103 {
104     for (auto &weight : weights)
105     {
106         if (filter && !filter(weight.first))
107             weight.second = 0;
108         else
109             weight.second = max(weight.second, 0); // cleanup
110     }
111 
112     M *chosen_elem = random_choose_weighted(weights);
113     ASSERT(chosen_elem);
114     return *chosen_elem;
115 }
116 
117 /**
118  * Choose a random slot to acquire armour for.
119  *
120  * For most races, even odds for all armour slots when acquiring, or 50-50
121  * split between body armour/aux armour when getting god gifts.
122  *
123  * Nagas get a high extra chance for bardings, especially if they haven't
124  * seen any yet.
125  *
126  * Guaranteed to be wearable, in principle.
127  *
128  * @param divine    Whether the item is a god gift.
129  * @return          A random equipment slot; e.g. EQ_SHIELD, EQ_BODY_ARMOUR...
130  */
_acquirement_armour_slot(bool divine)131 static equipment_type _acquirement_armour_slot(bool divine)
132 {
133     if (you.wear_barding()
134         && one_chance_in(you.seen_armour[ARM_BARDING] ? 4 : 2))
135     {
136             return EQ_BOOTS;
137     }
138 
139     vector<pair<equipment_type, int>> weights = {
140         { EQ_BODY_ARMOUR,   divine ? 5 : 1 },
141         { EQ_SHIELD,        1 },
142         { EQ_CLOAK,         1 },
143         { EQ_HELMET,        1 },
144         { EQ_GLOVES,        1 },
145         { EQ_BOOTS,         1 },
146     };
147 
148     return filtered_vector_select<equipment_type>(weights,
149         [] (equipment_type etyp) {
150             return you_can_wear(etyp); // evading template nonsense
151         });
152 }
153 
154 
155 /**
156  * Choose a random subtype of armour that will fit in the given equipment slot,
157  * to generate through acquirement/divine gifts.
158  *
159  * Guaranteed to be usable by the player & weighted weakly by their skills;
160  * heavy investment in armour skill, relative to dodging & spellcasting, makes
161  * heavier armours more likely to be generated.
162  *
163  * @param divine    Whether the armour is a god gift.
164  * @return          The armour_type of the armour to be generated.
165  */
_acquirement_armour_for_slot(equipment_type slot_type,bool divine)166 static armour_type _acquirement_armour_for_slot(equipment_type slot_type,
167                                                 bool divine)
168 {
169     switch (slot_type)
170     {
171         case EQ_CLOAK:
172             if (you_can_wear(EQ_CLOAK) == MB_TRUE)
173                 return random_choose(ARM_CLOAK, ARM_SCARF);
174             return ARM_SCARF;
175         case EQ_GLOVES:
176             return ARM_GLOVES;
177         case EQ_BOOTS:
178             if (you.wear_barding())
179                 return ARM_BARDING;
180             else
181                 return ARM_BOOTS;
182         case EQ_HELMET:
183             if (you_can_wear(EQ_HELMET) == MB_TRUE)
184                 return random_choose(ARM_HELMET, ARM_HAT);
185             return ARM_HAT;
186         case EQ_SHIELD:
187             return _acquirement_shield_type();
188         case EQ_BODY_ARMOUR:
189             return _acquirement_body_armour(divine);
190         default:
191             die("Unknown armour slot %d!", slot_type);
192     }
193 }
194 
195 /**
196  * Choose a random type of shield to be generated via acquirement or god gifts.
197  *
198  * Weighted by Shields skill & the secret racial shield bonus.
199  *
200  * Ratios by shields skill & player size (B = buckler, K = kite shield, P = tower shield)
201  *
202  *     Shields    0           5         10          15        20
203  * Large:   {6B}/5K/4P  ~{1B}/1K/1P  ~{1B}/5K/7P  ~2K/3P     1K/2P
204  * Med.:        2B/1K    6B/4K/1P      2B/2K/1P   4B/8K/3P   1K/1P
205  * Small:      ~3B/1K     ~5B/2K      ~2B/1K     ~3B/2K     ~1B/1K
206  *
207  * XXX: possibly shield skill should count for more for non-med races?
208  *
209  * @return A potentially wearable type of shield.
210  */
_acquirement_shield_type()211 static armour_type _acquirement_shield_type()
212 {
213     const int scale = 256;
214     vector<pair<armour_type, int>> weights = {
215         { ARM_BUCKLER,       player_shield_racial_factor() * 4 * scale
216                                 - _skill_rdiv(SK_SHIELDS, scale) },
217         { ARM_KITE_SHIELD,        10 * scale },
218         { ARM_TOWER_SHIELD,  20 * scale
219                              - player_shield_racial_factor() * 4 * scale
220                              + _skill_rdiv(SK_SHIELDS, scale / 2) },
221     };
222 
223     return filtered_vector_select<armour_type>(weights, [] (armour_type shtyp) {
224         return check_armour_size(shtyp,  you.body_size(PSIZE_TORSO, true));
225     });
226 }
227 
228 /**
229  * Determine the weight (likelihood) to acquire a specific type of body armour.
230  *
231  * If divine is set, returns the base weight for the armour type.
232  * Otherwise, if warrior is set, multiplies the base weight by the base ac^2.
233  * Otherwise, uses the player's Armour skill to crudely guess how likely they
234  * are to want the armour, based on its EVP.
235  *
236  * @param armour    The type of armour in question. (E.g. ARM_ROBE.)
237  * @param divine    Whether the 'acquirement' is actually a god gift.
238  * @param warrior   Whether we think the player only cares about AC.
239  * @return          A weight for the armour.
240  */
_body_acquirement_weight(armour_type armour,bool divine,bool warrior)241 static int _body_acquirement_weight(armour_type armour,
242                                     bool divine, bool warrior)
243 {
244     const int base_weight = armour_acq_weight(armour);
245     if (divine)
246         return base_weight; // gods don't care about your skills, apparently
247 
248     if (warrior)
249     {
250         const int ac = armour_prop(armour, PARM_AC);
251         return base_weight * ac * ac;
252     }
253 
254     // highest chance when armour skill = (displayed) evp - 3
255     const int evp = armour_prop(armour, PARM_EVASION);
256     const int skill = min(27, _skill_rdiv(SK_ARMOUR) + 3);
257     const int sk_diff = skill + evp / 10;
258     const int inv_diff = max(1, 27 - sk_diff);
259     // armour closest to ideal evp is 27^3 times as likely as the furthest away
260     return base_weight * inv_diff * inv_diff * inv_diff;
261 }
262 
263 /**
264  * Choose a random type of body armour to be generated via acquirement or
265  * god gifts.
266  *
267  * @param divine      Whether the armour is a god gift.
268  * @return A potentially wearable type of body armour..
269  */
_acquirement_body_armour(bool divine)270 static armour_type _acquirement_body_armour(bool divine)
271 {
272     // Using an arbitrary legacy formula, do we think the player doesn't care
273     // about armour EVP?
274     int light_pref = _skill_rdiv(SK_SPELLCASTING, 3);
275     light_pref += _skill_rdiv(SK_DODGING);
276     light_pref = random2(light_pref);
277     const bool warrior = light_pref < random2(_skill_rdiv(SK_ARMOUR, 2));
278 
279     vector<pair<armour_type, int>> weights;
280     for (int i = ARM_FIRST_MUNDANE_BODY; i < NUM_ARMOURS; ++i)
281     {
282         const armour_type armour = (armour_type)i;
283         if (get_armour_slot(armour) != EQ_BODY_ARMOUR)
284             continue;
285 
286         if (!check_armour_size(armour, you.body_size(PSIZE_TORSO, true)))
287             continue;
288 
289         const int weight = _body_acquirement_weight(armour, divine, warrior);
290 
291         if (weight)
292         {
293             const pair<armour_type, int> weight_pair = { armour, weight };
294             weights.push_back(weight_pair);
295         }
296     }
297 
298     const armour_type* armour_ptr = random_choose_weighted(weights);
299     ASSERT(armour_ptr);
300     return *armour_ptr;
301 }
302 
303 /**
304  * Choose a random type of armour that the player cannot wear, for Xom to spite
305  * the player with.
306  *
307  * @return  A random useless armour_type.
308  */
_useless_armour_type()309 static armour_type _useless_armour_type()
310 {
311     vector<pair<equipment_type, int>> weights = {
312         { EQ_BODY_ARMOUR, 1 }, { EQ_SHIELD, 1 }, { EQ_CLOAK, 1 },
313         { EQ_HELMET, 1 }, { EQ_GLOVES, 1 }, { EQ_BOOTS, 1 },
314     };
315 
316     // everyone has some kind of boot-slot item they can't wear, regardless
317     // of what you_can_wear() claims
318     for (auto &weight : weights)
319         if (you_can_wear(weight.first) == MB_TRUE && weight.first != EQ_BOOTS)
320             weight.second = 0;
321 
322     const equipment_type* slot_ptr = random_choose_weighted(weights);
323     const equipment_type slot = slot_ptr ? *slot_ptr : EQ_BOOTS;
324 
325     switch (slot)
326     {
327         case EQ_BOOTS:
328             // Boots-wearers get bardings, everyone else gets boots.
329             if (you_can_wear(EQ_BOOTS) == MB_TRUE)
330                 return ARM_BARDING;
331             return ARM_BOOTS;
332         case EQ_GLOVES:
333             return ARM_GLOVES;
334         case EQ_HELMET:
335             if (you_can_wear(EQ_HELMET))
336                 return ARM_HELMET;
337             return random_choose(ARM_HELMET, ARM_HAT);
338         case EQ_CLOAK:
339             return ARM_CLOAK;
340         case EQ_SHIELD:
341         {
342             vector<pair<armour_type, int>> shield_weights = {
343                 { ARM_BUCKLER,       1 },
344                 { ARM_KITE_SHIELD,        1 },
345                 { ARM_TOWER_SHIELD,  1 },
346             };
347 
348             return filtered_vector_select<armour_type>(shield_weights,
349                                           [] (armour_type shtyp) {
350                 return !check_armour_size(shtyp,
351                                           you.body_size(PSIZE_TORSO, true));
352             });
353         }
354         case EQ_BODY_ARMOUR:
355             // only the rarest & most precious of unwearable armours for Xom
356             if (you_can_wear(EQ_BODY_ARMOUR))
357                 return ARM_CRYSTAL_PLATE_ARMOUR;
358             // arbitrary selection of [unwearable] dragon armours
359             return random_choose(ARM_FIRE_DRAGON_ARMOUR,
360                                  ARM_ICE_DRAGON_ARMOUR,
361                                  ARM_PEARL_DRAGON_ARMOUR,
362                                  ARM_GOLD_DRAGON_ARMOUR,
363                                  ARM_SHADOW_DRAGON_ARMOUR,
364                                  ARM_STORM_DRAGON_ARMOUR);
365         default:
366             die("Unknown slot type selected for Xom bad-armour-acq!");
367     }
368 }
369 
_pick_unseen_armour()370 static armour_type _pick_unseen_armour()
371 {
372     // Consider shields uninteresting always, since unlike with other slots
373     // players might well prefer an empty slot to wearing one. We don't
374     // want to try to guess at this by looking at their weapon's handedness
375     // because this would encourage switching weapons or putting on a
376     // shield right before reading acquirement in some cases. --elliptic
377     // This affects only the "unfilled slot" special-case, not regular
378     // acquirement which can always produce (wearable) shields.
379     static const equipment_type armour_slots[] =
380         {  EQ_CLOAK, EQ_HELMET, EQ_GLOVES, EQ_BOOTS  };
381 
382     armour_type picked = NUM_ARMOURS;
383     int count = 0;
384     for (auto &slot : armour_slots)
385     {
386         if (!you_can_wear(slot))
387             continue;
388 
389         const armour_type sub_type = _acquirement_armour_for_slot(slot, false);
390         ASSERT(sub_type != NUM_ARMOURS);
391 
392         if (!you.seen_armour[sub_type] && one_chance_in(++count))
393             picked = sub_type;
394     }
395 
396     return picked;
397 }
398 
399 /**
400  * Randomly choose a class of weapons (those using a specific weapon skill)
401  * for acquirement to give the player. Weight toward the player's skills.
402  *
403  * @param divine    Whether this is a god gift, which are less strongly
404  *                  tailored to the player's skills.
405  * @return          An appropriate weapon skill; e.g. SK_LONG_BLADES.
406  */
_acquirement_weapon_skill(bool divine,int agent)407 static skill_type _acquirement_weapon_skill(bool divine, int agent)
408 {
409     // reservoir sample.
410     int count = 0;
411     skill_type skill = SK_FIGHTING;
412     for (skill_type sk = SK_FIRST_WEAPON;
413          sk <= (agent == GOD_TROG ? SK_LAST_MELEE_WEAPON : SK_LAST_WEAPON);
414          ++sk)
415     {
416         // Adding a small constant allows for the occasional
417         // weapon in an untrained skill.
418         int weight = _skill_rdiv(sk) + 1;
419         // Exaggerate the weighting if it's a scroll acquirement.
420         if (!divine)
421             weight = (weight + 1) * (weight + 2);
422         count += weight;
423 
424         if (x_chance_in_y(weight, count))
425             skill = sk;
426     }
427 
428     return skill;
429 }
430 
_acquirement_weapon_subtype(bool divine,int &,int agent)431 static int _acquirement_weapon_subtype(bool divine, int & /*quantity*/, int agent)
432 {
433     const skill_type skill = _acquirement_weapon_skill(divine, agent);
434 
435     int best_sk = 0;
436     for (int i = SK_FIRST_WEAPON;
437          i <= (agent == GOD_TROG ? SK_LAST_MELEE_WEAPON : SK_LAST_WEAPON);
438          i++)
439     {
440         best_sk = max(best_sk, _skill_rdiv((skill_type)i));
441     }
442     best_sk = max(best_sk, _skill_rdiv(SK_UNARMED_COMBAT));
443 
444     // Now choose a subtype which uses that skill.
445     int result = OBJ_RANDOM;
446     int count = 0;
447     item_def item_considered;
448     item_considered.base_type = OBJ_WEAPONS;
449     // Let's guess the percentage of shield use the player did, this is
450     // based on empirical data where pure-shield MDs get skills like 17 sh
451     // 25 m&f and pure-shield Spriggans 7 sh 18 m&f.
452     const int shield_sk = _skill_rdiv(SK_SHIELDS)
453                           * species_apt_factor(SK_SHIELDS);
454     const int want_shield = min(2 * shield_sk, best_sk) + 10;
455     const int dont_shield = max(best_sk - shield_sk, 0) + 10;
456     // At XL 10, weapons of the handedness you want get weight *2, those of
457     // opposite handedness 1/2, assuming your shields usage is respectively
458     // 0% or 100% in the above formula. At skill 25 that's *3.5 .
459     for (int i = 0; i < NUM_WEAPONS; ++i)
460     {
461         const int wskill = item_attack_skill(OBJ_WEAPONS, i);
462 
463         if (wskill != skill)
464             continue;
465         item_considered.sub_type = i;
466 
467         int acqweight = property(item_considered, PWPN_ACQ_WEIGHT) * 100;
468 
469         if (!acqweight)
470             continue;
471 
472         const bool two_handed = you.hands_reqd(item_considered) == HANDS_TWO;
473 
474         if (two_handed && you.get_mutation_level(MUT_MISSING_HAND))
475             continue;
476 
477         // For non-Trog/Okawaru acquirements, give a boost to high-end items.
478         if (!divine && !is_range_weapon(item_considered))
479         {
480             if (acqweight < 500)
481                 acqweight = 500;
482             // Quick blades get unproportionately hit by damage weighting.
483             if (i == WPN_QUICK_BLADE)
484                 acqweight = acqweight * 25 / 9;
485             int damage = property(item_considered, PWPN_DAMAGE);
486             if (!two_handed)
487                 damage = damage * 3 / 2;
488             damage *= damage * damage;
489             acqweight *= damage / property(item_considered, PWPN_SPEED);
490         }
491 
492         if (two_handed)
493             acqweight = acqweight * dont_shield / want_shield;
494         else
495             acqweight = acqweight * want_shield / dont_shield;
496 
497         if (!you.seen_weapon[i])
498             acqweight *= 5; // strong emphasis on type variety, brands go only second
499 
500         // reservoir sampling
501         if (x_chance_in_y(acqweight, count += acqweight))
502             result = i;
503     }
504     return result;
505 }
506 
_acquirement_missile_subtype(bool,int &,int)507 static int _acquirement_missile_subtype(bool /*divine*/, int & /*quantity*/,
508                                         int /*agent*/)
509 {
510     int count = 0;
511     int skill = SK_THROWING;
512 
513     for (int i = SK_SLINGS; i <= SK_THROWING; i++)
514     {
515         const int sk = _skill_rdiv((skill_type)i);
516         count += sk;
517         if (x_chance_in_y(sk, count))
518             skill = i;
519     }
520 
521     missile_type result = MI_BOOMERANG;
522 
523     switch (skill)
524     {
525     case SK_SLINGS:    result = MI_SLING_BULLET; break;
526     case SK_BOWS:      result = MI_ARROW; break;
527     case SK_CROSSBOWS: result = MI_BOLT; break;
528 
529     case SK_THROWING:
530         {
531             // Choose from among all usable missile types.
532             vector<pair<missile_type, int> > missile_weights;
533 
534             missile_weights.emplace_back(MI_BOOMERANG, 50);
535             missile_weights.emplace_back(MI_DART, 75);
536 
537             if (you.body_size() >= SIZE_MEDIUM)
538                 missile_weights.emplace_back(MI_JAVELIN, 100);
539 
540             if (you.can_throw_large_rocks())
541                 missile_weights.emplace_back(MI_LARGE_ROCK, 100);
542 
543             result = *random_choose_weighted(missile_weights);
544         }
545         break;
546 
547     default:
548         break;
549     }
550     return result;
551 }
552 
_acquirement_jewellery_subtype(bool,int &,int)553 static int _acquirement_jewellery_subtype(bool /*divine*/, int & /*quantity*/,
554                                           int /*agent*/)
555 {
556     int result = 0;
557 
558     // Rings are (number of usable rings) times as common as amulets.
559     const int ring_num = you.arm_count();
560 
561     // Try ten times to give something the player hasn't seen.
562     for (int i = 0; i < 10; i++)
563     {
564         result = one_chance_in(ring_num + 1) ? get_random_amulet_type()
565                                              : get_random_ring_type();
566 
567         // If we haven't seen this yet, we're done.
568         if (!get_ident_type(OBJ_JEWELLERY, result))
569             break;
570     }
571 
572     return result;
573 }
574 
575 
_acquirement_staff_subtype(bool,int &,int)576 static int _acquirement_staff_subtype(bool /*divine*/, int & /*quantity*/,
577                                       int /*agent*/)
578 {
579     vector<pair<stave_type, int>> weights = {
580         { STAFF_FIRE,        _skill_rdiv(SK_FIRE_MAGIC) },
581         { STAFF_COLD,        _skill_rdiv(SK_ICE_MAGIC) },
582         { STAFF_AIR,         _skill_rdiv(SK_AIR_MAGIC) },
583         { STAFF_EARTH,       _skill_rdiv(SK_EARTH_MAGIC) },
584         { STAFF_POISON,      _skill_rdiv(SK_POISON_MAGIC) },
585         { STAFF_DEATH,       _skill_rdiv(SK_NECROMANCY) },
586         { STAFF_CONJURATION, _skill_rdiv(SK_CONJURATIONS) },
587         { NUM_STAVES,        5 },
588     };
589 
590     for (auto &weight : weights)
591     {
592         if (weight.first != NUM_STAVES
593             && get_ident_type(OBJ_STAVES, weight.first))
594         {
595             weight.second = 0;
596         }
597     }
598 
599     stave_type staff = *random_choose_weighted(weights);
600 
601     if (staff == NUM_STAVES)
602     {
603         do
604         {
605             staff = static_cast<stave_type>(random2(NUM_STAVES));
606         }
607         while (item_type_removed(OBJ_STAVES, staff));
608     }
609 
610     return staff;
611 }
612 
613 /**
614  * Return a miscellaneous evokable item for acquirement.
615  * @return   The item type chosen.
616  */
_acquirement_misc_subtype(bool,int &,int)617 static int _acquirement_misc_subtype(bool /*divine*/, int & /*quantity*/,
618                                      int /*agent*/)
619 {
620     const bool NO_LOVE = you.get_mutation_level(MUT_NO_LOVE);
621 
622     const vector<pair<int, int> > choices =
623     {
624         // The player never needs more than one of these.
625         {MISC_BOX_OF_BEASTS,
626             (NO_LOVE || you.seen_misc[MISC_BOX_OF_BEASTS] ? 0 : 20)},
627         {MISC_PHANTOM_MIRROR,
628             (NO_LOVE || you.seen_misc[MISC_PHANTOM_MIRROR] ? 0 : 20)},
629         // Tremorstones are better for heavily armoured characters.
630         {MISC_TIN_OF_TREMORSTONES,
631             (you.seen_misc[MISC_TIN_OF_TREMORSTONES]
632                      ? 0 : 5 + _skill_rdiv(SK_ARMOUR) / 3)},
633         {MISC_LIGHTNING_ROD,
634             (you.seen_misc[MISC_LIGHTNING_ROD]   ? 0 : 20)},
635         {MISC_PHIAL_OF_FLOODS,
636             (you.seen_misc[MISC_PHIAL_OF_FLOODS] ? 0 : 20)},
637         {MISC_CONDENSER_VANE,
638             (you.seen_misc[MISC_CONDENSER_VANE] ? 0 : 20)},
639         {MISC_XOMS_CHESSBOARD,
640             (you.seen_misc[MISC_XOMS_CHESSBOARD] ? 0 : 20)},
641     };
642 
643     const int * const choice = random_choose_weighted(choices);
644 
645     // Possible for everything to be 0 weight - if so just give a random spare.
646     if (choice == nullptr)
647     {
648         return random_choose(MISC_BOX_OF_BEASTS,
649                              MISC_PHANTOM_MIRROR,
650                              MISC_TIN_OF_TREMORSTONES,
651                              MISC_LIGHTNING_ROD,
652                              MISC_PHIAL_OF_FLOODS,
653                              MISC_CONDENSER_VANE,
654                              MISC_XOMS_CHESSBOARD);
655     }
656 
657     return *choice;
658 }
659 
660 /**
661  * Choose a random type of wand to be generated via acquirement or god gifts.
662  *
663  * Heavily weighted toward more useful wands and wands the player hasn't yet
664  * seen.
665  *
666  * @return          A random wand type.
667  */
_acquirement_wand_subtype(bool,int &,int)668 static int _acquirement_wand_subtype(bool /*divine*/, int & /*quantity*/,
669                                      int /*agent */)
670 {
671     vector<pair<wand_type, int>> weights = {
672         { WAND_ACID,            20 },
673         { WAND_ICEBLAST,        20 },
674         { WAND_CHARMING,     you.get_mutation_level(MUT_NO_LOVE) ? 0 : 10 },
675         { WAND_PARALYSIS,       10 },
676         { WAND_MINDBURST,  8 },
677         { WAND_POLYMORPH,       5 },
678         { WAND_DIGGING,         5 },
679         { WAND_FLAME,           2 },
680     };
681 
682     // Unknown wands get a huge weight bonus.
683     for (auto &weight : weights)
684         if (!get_ident_type(OBJ_WANDS, weight.first))
685             weight.second *= 2;
686 
687     const wand_type* wand = random_choose_weighted(weights);
688     ASSERT(wand);
689     return *wand;
690 }
691 
_acquirement_book_subtype(bool,int &,int)692 static int _acquirement_book_subtype(bool /*divine*/, int & /*quantity*/,
693                                      int /*agent*/)
694 {
695     return BOOK_MINOR_MAGIC;
696     //this gets overwritten later, but needs to be a sane value
697     //or asserts will get set off
698 }
699 
700 typedef int (*acquirement_subtype_finder)(bool divine, int &quantity, int agent);
701 static const acquirement_subtype_finder _subtype_finders[] =
702 {
703     _acquirement_weapon_subtype,
704     _acquirement_missile_subtype,
705     _acquirement_armour_subtype,
706     _acquirement_wand_subtype,
707 #if TAG_MAJOR_VERSION == 34
708     0, // no food
709 #endif
710     0, // no scrolls
711     _acquirement_jewellery_subtype,
712     0, // no potions
713     _acquirement_book_subtype,
714     _acquirement_staff_subtype,
715     0, // no, you can't acquire the orb
716     _acquirement_misc_subtype,
717     0, // no corpses
718     0, // gold handled elsewhere, and doesn't have subtypes anyway
719 #if TAG_MAJOR_VERSION == 34
720     0, // no rods
721 #endif
722     0, // no runes either
723 };
724 
_find_acquirement_subtype(object_class_type & class_wanted,int & quantity,bool divine,int agent)725 static int _find_acquirement_subtype(object_class_type &class_wanted,
726                                      int &quantity, bool divine,
727                                      int agent)
728 {
729     COMPILE_CHECK(ARRAYSZ(_subtype_finders) == NUM_OBJECT_CLASSES);
730     ASSERT(class_wanted != OBJ_RANDOM);
731 
732     if (class_wanted == OBJ_ARMOUR && you.has_mutation(MUT_NO_ARMOUR))
733         return OBJ_RANDOM;
734 
735     int type_wanted = OBJ_RANDOM;
736 
737     int useless_count = 0;
738 
739     do
740     {
741         // Wands and misc have a common acquirement class.
742         if (class_wanted == OBJ_MISCELLANY)
743             class_wanted = random_choose(OBJ_WANDS, OBJ_MISCELLANY);
744 
745         if (_subtype_finders[class_wanted])
746         {
747             type_wanted =
748                 (*_subtype_finders[class_wanted])(divine, quantity, agent);
749         }
750 
751         item_def dummy;
752         dummy.base_type = class_wanted;
753         dummy.sub_type = type_wanted;
754         dummy.plus = 1; // empty wands would be useless
755         dummy.flags |= ISFLAG_IDENT_MASK;
756 
757         if (!is_useless_item(dummy, false) && !god_hates_item(dummy)
758             && (agent >= NUM_GODS || god_likes_item_type(dummy,
759                                                          (god_type)agent)))
760         {
761             break;
762         }
763     }
764     while (useless_count++ < 200);
765 
766     return type_wanted;
767 }
768 
769 // The weight of a spell takes into account its disciplines' skill levels
770 // and the spell difficulty.
_spell_weight(spell_type spell)771 static int _spell_weight(spell_type spell)
772 {
773     ASSERT(spell != SPELL_NO_SPELL);
774 
775     int weight = 0;
776     spschools_type disciplines = get_spell_disciplines(spell);
777     int count = 0;
778     for (const auto disc : spschools_type::range())
779     {
780         if (disciplines & disc)
781         {
782             weight += _skill_rdiv(spell_type2skill(disc));
783             count++;
784         }
785     }
786     ASSERT(count > 0);
787 
788     // Particularly difficult spells _reduce_ the overall weight.
789     int leveldiff = 5 - spell_difficulty(spell);
790 
791     return max(0, 2 * weight/count + leveldiff);
792 }
793 
794 // When randomly picking a book for acquirement, use the sum of the
795 // weights of all unknown spells in the book.
_book_weight(book_type book)796 static int _book_weight(book_type book)
797 {
798     ASSERT_RANGE(book, 0, NUM_BOOKS);
799     ASSERT(book != BOOK_MANUAL);
800     ASSERT(book != BOOK_RANDART_LEVEL);
801     ASSERT(book != BOOK_RANDART_THEME);
802 
803     int total_weight = 0;
804     for (spell_type stype : spellbook_template(book))
805     {
806         // Skip over spells already in library.
807         if (you.spell_library[stype])
808             continue;
809         if (god_hates_spell(stype, you.religion))
810             continue;
811 
812         total_weight += _spell_weight(stype);
813     }
814 
815     return total_weight;
816 }
817 
_is_magic_skill(int skill)818 static bool _is_magic_skill(int skill)
819 {
820     return skill >= SK_SPELLCASTING && skill < SK_INVOCATIONS;
821 }
822 
_skill_useless_with_god(int skill)823 static bool _skill_useless_with_god(int skill)
824 {
825     if (skill == SK_INVOCATIONS)
826     {
827         // No active invocations, or uses a different skill.
828         return invo_skill() != SK_INVOCATIONS
829                || you_worship(GOD_XOM)
830                || you_worship(GOD_VEHUMET)
831                || you_worship(GOD_NO_GOD);
832     }
833 
834     switch (you.religion)
835     {
836     case GOD_TROG:
837         return _is_magic_skill(skill);
838     case GOD_ZIN:
839     case GOD_SHINING_ONE:
840     case GOD_ELYVILON:
841         return skill == SK_NECROMANCY;
842     default:
843         return false;
844     }
845 }
846 
847 /**
848  * Randomly decide whether the player should get a manual from a given instance
849  * of book acquirement.
850  *
851  * @param agent     The source of the acquirement (e.g. a god)
852  * @return          Whether the player should get a manual from this book
853  *                  acquirement.
854  */
_should_acquire_manual(int agent)855 static bool _should_acquire_manual(int agent)
856 {
857     // Manuals are too useful for Xom, and useless when gifted from Sif Muna.
858     if (agent == GOD_XOM || agent == GOD_SIF_MUNA)
859         return false;
860 
861     int magic_weights = 0;
862     int other_weights = 0;
863 
864     for (skill_type sk = SK_FIRST_SKILL; sk < NUM_SKILLS; ++sk)
865     {
866         const int weight = _skill_rdiv(sk);
867 
868         if (_is_magic_skill(sk))
869             magic_weights += weight;
870         else
871             other_weights += weight;
872     }
873 
874     if (you_worship(GOD_TROG))
875         magic_weights = 0;
876 
877     // If someone has 25% or more magic skills, never give manuals.
878     // Otherwise, count magic skills double to bias against manuals
879     // for magic users.
880     return magic_weights * 3 < other_weights
881            && x_chance_in_y(other_weights, 2*magic_weights + other_weights);
882 }
883 
884 /**
885  * Turn a given book into an acquirement-quality manual.
886  *
887  * @param book[out]     The book to be turned into a manual.
888  * @return              Whether a manual was successfully created.
889  */
_acquire_manual(item_def & book)890 static bool _acquire_manual(item_def &book)
891 {
892     int weights[NUM_SKILLS] = { 0 };
893     int total_weights = 0;
894 
895     for (skill_type sk = SK_FIRST_SKILL; sk < NUM_SKILLS; ++sk)
896     {
897         const int skl = _skill_rdiv(sk);
898 
899         if (skl == 27 || is_useless_skill(sk))
900             continue;
901 
902         int w = (skl < 12) ? skl + 3 : max(0, 25 - skl);
903 
904         // Greatly reduce the chances of getting a manual for a skill
905         // you couldn't use unless you switched your religion.
906         if (_skill_useless_with_god(sk))
907             w /= 2;
908 
909         weights[sk] = w;
910         total_weights += w;
911     }
912 
913     // Are we too skilled to get any manuals?
914     if (total_weights == 0)
915         return false;
916 
917     book.sub_type = BOOK_MANUAL;
918     book.skill = static_cast<skill_type>(
919                     choose_random_weighted(weights, end(weights)));
920     // Set number of bonus skill points.
921     book.skill_points = random_range(2000, 3000);
922     // Preidentify.
923     set_ident_flags(book, ISFLAG_IDENT_MASK);
924 
925     return true;
926 }
927 
_do_book_acquirement(item_def & book,int agent)928 static bool _do_book_acquirement(item_def &book, int agent)
929 {
930     // items() shouldn't make book a randart for acquirement items.
931     ASSERT(!is_random_artefact(book));
932 
933     if (_should_acquire_manual(agent))
934         return _acquire_manual(book);
935     const int choice = random_choose_weighted(
936                                     30, BOOK_RANDART_THEME,
937        agent == GOD_SIF_MUNA ? 10 : 40, NUM_BOOKS, // normal books
938                                      1, BOOK_RANDART_LEVEL);
939 
940     switch (choice)
941     {
942     default:
943     case NUM_BOOKS:
944     {
945         int total_weights = 0;
946 
947         // Pick a random spellbook according to unknown spells contained.
948         int weights[NUM_BOOKS] = { 0 };
949         for (int bk = 0; bk < NUM_BOOKS; bk++)
950         {
951             const auto bkt = static_cast<book_type>(bk);
952 
953             if (!book_exists(bkt))
954                 continue;
955 
956             weights[bk]    = _book_weight(bkt);
957             total_weights += weights[bk];
958         }
959 
960         if (total_weights > 0)
961         {
962             book.sub_type = choose_random_weighted(weights, end(weights));
963             break;
964         }
965         acquire_themed_randbook(book, agent);
966         break;
967     }
968 
969     case BOOK_RANDART_THEME:
970         acquire_themed_randbook(book, agent);
971         break;
972 
973     case BOOK_RANDART_LEVEL:
974     {
975         const int level = agent == GOD_XOM ?
976             random_range(1, 9) :
977             max(1, (_skill_rdiv(SK_SPELLCASTING) + 2) / 3);
978 
979         book.sub_type  = BOOK_RANDART_LEVEL;
980         if (!make_book_level_randart(book, level, agent == GOD_SIF_MUNA))
981             return false;
982         break;
983     }
984     } // switch book choice
985 
986     // If we couldn't make a useful book, try to make a manual instead.
987     // We have to temporarily identify the book for this.
988     if (agent != GOD_XOM && agent != GOD_SIF_MUNA)
989     {
990         bool useless = false;
991         {
992             unwind_var<iflags_t> oldflags{book.flags};
993             book.flags |= ISFLAG_KNOW_TYPE;
994             useless = is_useless_item(book);
995         }
996         if (useless)
997         {
998             destroy_item(book);
999             book.base_type = OBJ_BOOKS;
1000             book.quantity = 1;
1001             return _acquire_manual(book);
1002         }
1003     }
1004 
1005     return true;
1006 }
1007 
_failed_acquirement(bool quiet)1008 static int _failed_acquirement(bool quiet)
1009 {
1010     if (!quiet)
1011         mpr("The demon of the infinite void smiles upon you.");
1012     return NON_ITEM;
1013 }
1014 
_weapon_brand_quality(int brand,bool range)1015 static int _weapon_brand_quality(int brand, bool range)
1016 {
1017     switch (brand)
1018     {
1019     case SPWPN_SPEED:
1020         return range ? 3 : 5;
1021     case SPWPN_PENETRATION:
1022         return 4;
1023     case SPWPN_ELECTROCUTION:
1024     case SPWPN_DISTORTION:
1025     case SPWPN_HOLY_WRATH:
1026     case SPWPN_REAPING:
1027         return 3;
1028     case SPWPN_CHAOS:
1029         return 2;
1030     default:
1031         return 1;
1032     case SPWPN_NORMAL:
1033         return 0;
1034     case SPWPN_PAIN:
1035         return _skill_rdiv(SK_NECROMANCY) / 2;
1036     case SPWPN_VORPAL:
1037         return range ? 5 : 1;
1038     }
1039 }
1040 
_armour_slot_seen(armour_type arm)1041 static bool _armour_slot_seen(armour_type arm)
1042 {
1043     item_def item;
1044     item.base_type = OBJ_ARMOUR;
1045     item.quantity = 1;
1046 
1047     for (int i = 0; i < NUM_ARMOURS; i++)
1048     {
1049         if (get_armour_slot(arm) != get_armour_slot((armour_type)i))
1050             continue;
1051         item.sub_type = i;
1052 
1053         // having seen a helmet means nothing about your decision to go
1054         // bare-headed if you have horns
1055         if (!can_wear_armour(item, false, true))
1056             continue;
1057 
1058         if (you.seen_armour[i])
1059             return true;
1060     }
1061     return false;
1062 }
1063 
_is_armour_plain(const item_def & item)1064 static bool _is_armour_plain(const item_def &item)
1065 {
1066     ASSERT(item.base_type == OBJ_ARMOUR);
1067     if (is_artefact(item))
1068         return false;
1069 
1070     if (armour_is_special(item))
1071     {
1072         // These are always interesting, even with no brand.
1073         // May still be redundant, but that has another check.
1074         return false;
1075     }
1076 
1077     return get_armour_ego_type(item) == SPARM_NORMAL;
1078 }
1079 
1080 /**
1081  * Has the player already encountered an item with this brand?
1082  *
1083  * Only supports weapons & armour.
1084  *
1085  * @param item      The item in question.
1086  * @param           Whether the player has encountered another weapon or
1087  *                  piece of armour with the same ego.
1088  */
_brand_already_seen(const item_def & item)1089 static bool _brand_already_seen(const item_def &item)
1090 {
1091     switch (item.base_type)
1092     {
1093         case OBJ_WEAPONS:
1094             return you.seen_weapon[item.sub_type]
1095                    & (1<<get_weapon_brand(item));
1096         case OBJ_ARMOUR:
1097             return you.seen_armour[item.sub_type]
1098                    & (1<<get_armour_ego_type(item));
1099         default:
1100             die("Unsupported item type!");
1101     }
1102 }
1103 
1104 // ugh
1105 #define ITEM_LEVEL (divine ? ISPEC_GIFT : ISPEC_GOOD_ITEM)
1106 
1107 /**
1108  * Take a newly-generated acquirement item, and adjust its brand if we don't
1109  * like it.
1110  *
1111  * Specifically, when any of:
1112  *   - The god doesn't like the brand (for divine gifts)
1113  *   - We think the brand is too weak (for non-divine gifts)
1114  *   - Sometimes if we've seen the brand before.
1115  *
1116  * @param item      The item which may have its brand adjusted. Not necessarily
1117  *                  a weapon or piece of armour.
1118  * @param divine    Whether the item is a god gift, rather than from
1119  *                  acquirement proper.
1120  * @param agent     The source of the acquirement. For god gifts, it's equal to
1121  *                  the god.
1122  */
_adjust_brand(item_def & item,bool divine,int agent)1123 static void _adjust_brand(item_def &item, bool divine, int agent)
1124 {
1125     if (item.base_type != OBJ_WEAPONS && item.base_type != OBJ_ARMOUR)
1126         return; // don't reroll missile brands, I guess
1127 
1128     if (is_artefact(item))
1129         return; // their own kettle of fish
1130 
1131 
1132     // Trog has a restricted brand table.
1133     if (agent == GOD_TROG && item.base_type == OBJ_WEAPONS)
1134     {
1135         // 75% chance of a brand
1136         item.brand = random_choose(SPWPN_NORMAL, SPWPN_VORPAL,
1137                                    SPWPN_FLAMING, SPWPN_ANTIMAGIC);
1138         return;
1139     }
1140 
1141     // Not from a god, so we should prefer better brands.
1142     if (!divine && item.base_type == OBJ_WEAPONS)
1143     {
1144         while (_weapon_brand_quality(get_weapon_brand(item),
1145                                      is_range_weapon(item)) < random2(6))
1146         {
1147             reroll_brand(item, ITEM_LEVEL);
1148         }
1149     }
1150 
1151     // Try to not generate brands that were already seen, although unlike
1152     // jewellery and books, this is not absolute.
1153     while (_brand_already_seen(item) && !one_chance_in(5))
1154         reroll_brand(item, ITEM_LEVEL);
1155 }
1156 
1157 /**
1158  * Should the given item be rejected as an acquirement/god gift result &
1159  * rerolled? If so, why?
1160  *
1161  * @param item      The item in question.
1162  * @param agent     The entity creating the item; possibly a god.
1163  * @return          A reason why the item should be rejected, if it should be;
1164  *                  otherwise, the empty string.
1165  */
_why_reject(const item_def & item,int agent)1166 static string _why_reject(const item_def &item, int agent)
1167 {
1168     if (agent != GOD_XOM
1169         && (item.base_type == OBJ_WEAPONS
1170                 && !can_wield(&item, false, true)
1171             || item.base_type == OBJ_ARMOUR
1172                 && !can_wear_armour(item, false, true)))
1173     {
1174         return "Destroying unusable weapon or armour!";
1175     }
1176 
1177     // Trog does not gift the Wrath of Trog.
1178     if (agent == GOD_TROG && is_unrandom_artefact(item, UNRAND_TROG))
1179         return "Destroying Trog-gifted Wrath of Trog!";
1180 
1181     // Pain brand is useless if you've sacrificed Necromacy.
1182     if (you.get_mutation_level(MUT_NO_NECROMANCY_MAGIC)
1183         && get_weapon_brand(item) == SPWPN_PAIN)
1184     {
1185         return "Destroying pain weapon after Necro sac!";
1186     }
1187 
1188     return ""; // all OK
1189 }
1190 
acquirement_create_item(object_class_type class_wanted,int agent,bool quiet,const coord_def & pos)1191 int acquirement_create_item(object_class_type class_wanted,
1192                             int agent, bool quiet,
1193                             const coord_def &pos)
1194 {
1195     ASSERT(class_wanted != OBJ_RANDOM);
1196 
1197     const bool divine = (agent == GOD_OKAWARU || agent == GOD_XOM
1198                          || agent == GOD_TROG
1199 #if TAG_MAJOR_VERSION == 34
1200                          || agent == GOD_PAKELLAS
1201 #endif
1202                         );
1203     int thing_created = NON_ITEM;
1204     int quant = 1;
1205 #define MAX_ACQ_TRIES 40
1206     for (int item_tries = 0; item_tries < MAX_ACQ_TRIES; item_tries++)
1207     {
1208         int type_wanted = -1;
1209         if (agent == GOD_XOM && class_wanted == OBJ_ARMOUR && one_chance_in(20))
1210             type_wanted = _useless_armour_type();
1211         else
1212         {
1213             // This may clobber class_wanted (e.g. staves)
1214             type_wanted = _find_acquirement_subtype(class_wanted, quant,
1215                                                     divine, agent);
1216         }
1217         ASSERT(type_wanted != -1);
1218 
1219         // Don't generate randart books in items(), we do that
1220         // ourselves.
1221         bool want_arts = (class_wanted != OBJ_BOOKS);
1222         if (agent == GOD_TROG && !one_chance_in(3))
1223             want_arts = false;
1224 
1225         thing_created = items(want_arts, class_wanted, type_wanted,
1226                               ITEM_LEVEL, 0, agent);
1227 
1228         if (thing_created == NON_ITEM)
1229         {
1230             if (!quiet)
1231                 dprf("Failed to make thing!");
1232             continue;
1233         }
1234 
1235         item_def &acq_item(env.item[thing_created]);
1236         _adjust_brand(acq_item, divine, agent);
1237 
1238         // For plain armour, try to change the subtype to something
1239         // matching a currently unfilled equipment slot.
1240         if (acq_item.base_type == OBJ_ARMOUR && !is_artefact(acq_item))
1241         {
1242             const special_armour_type sparm = get_armour_ego_type(acq_item);
1243 
1244             if (agent != GOD_XOM
1245                 && you.seen_armour[acq_item.sub_type] & (1 << sparm)
1246                 && x_chance_in_y(MAX_ACQ_TRIES - item_tries, MAX_ACQ_TRIES + 5)
1247                 || !divine
1248                 && you.seen_armour[acq_item.sub_type]
1249                 && !one_chance_in(3)
1250                 && item_tries < 20)
1251             {
1252                 // We have seen the exact item already, it's very unlikely
1253                 // extras will do any good.
1254                 // For scroll acquirement, prefer base items not seen before
1255                 // as well, even if you didn't see the exact brand yet.
1256                 destroy_item(thing_created, true);
1257                 thing_created = NON_ITEM;
1258                 if (!quiet)
1259                     dprf("Destroying already-seen item!");
1260                 continue;
1261             }
1262 
1263             // Try to fill empty slots.
1264             if ((_is_armour_plain(acq_item)
1265                  || get_armour_slot(acq_item) == EQ_BODY_ARMOUR && coinflip())
1266                 && _armour_slot_seen((armour_type)acq_item.sub_type))
1267             {
1268                 armour_type at = _pick_unseen_armour();
1269                 if (at != NUM_ARMOURS)
1270                 {
1271                     destroy_item(thing_created, true);
1272                     thing_created = items(true, OBJ_ARMOUR, at,
1273                                           ITEM_LEVEL, 0, agent);
1274                 }
1275                 else if (agent != GOD_XOM && one_chance_in(3))
1276                 {
1277                     // If the item is plain and there aren't any
1278                     // unfilled slots, we might want to roll again.
1279                     destroy_item(thing_created, true);
1280                     thing_created = NON_ITEM;
1281                     if (!quiet)
1282                         dprf("Destroying plain item!");
1283                     continue;
1284                 }
1285             }
1286         }
1287 
1288         const string rejection_reason = _why_reject(acq_item, agent);
1289         if (!rejection_reason.empty())
1290         {
1291             if (!quiet)
1292                 dprf("%s", rejection_reason.c_str());
1293             destroy_item(acq_item);
1294             thing_created = NON_ITEM;
1295             continue;
1296         }
1297 
1298         ASSERT(acq_item.is_valid());
1299 
1300         if (class_wanted == OBJ_WANDS)
1301             acq_item.plus = max(static_cast<int>(acq_item.plus), 3 + random2(3));
1302         else if (class_wanted == OBJ_GOLD)
1303             acq_item.quantity = random_range(200, 1400, 2);
1304         else if (class_wanted == OBJ_MISSILES && !divine)
1305             acq_item.quantity *= 5;
1306         else if (quant > 1)
1307             acq_item.quantity = quant;
1308 
1309         if (acq_item.base_type == OBJ_BOOKS)
1310         {
1311             if (!_do_book_acquirement(acq_item, agent))
1312             {
1313                 destroy_item(acq_item, true);
1314                 return _failed_acquirement(quiet);
1315             }
1316             // That might have changed the item's subtype.
1317             item_colour(acq_item);
1318         }
1319         else if (acq_item.base_type == OBJ_JEWELLERY
1320                  && !is_unrandom_artefact(acq_item))
1321         {
1322             switch (acq_item.sub_type)
1323             {
1324             case RING_STRENGTH:
1325             case RING_INTELLIGENCE:
1326             case RING_DEXTERITY:
1327                 acq_item.plus = GOOD_STAT_RING_PLUS;
1328                 break;
1329             case RING_PROTECTION:
1330             case RING_EVASION:
1331             case RING_SLAYING:
1332                 acq_item.plus = GOOD_RING_PLUS;
1333                 break;
1334 
1335             default:
1336                 break;
1337             }
1338 
1339             // bump jewel acq power up a bit
1340             if (one_chance_in(2) && !is_artefact(acq_item))
1341                 make_item_randart(acq_item);
1342         }
1343         else if (acq_item.base_type == OBJ_WEAPONS
1344                  && !is_unrandom_artefact(acq_item))
1345         {
1346             // These can never get egos, and mundane versions are quite common,
1347             // so guarantee artefact status. Rarity is a bit low to compensate.
1348             // ...except actually, trog can give them antimagic brand, so...
1349             if (is_giant_club_type(acq_item.sub_type)
1350                 && get_weapon_brand(acq_item) == SPWPN_NORMAL
1351                 && !one_chance_in(25))
1352             {
1353                 make_item_randart(acq_item, true);
1354             }
1355 
1356             if (agent == GOD_TROG)
1357                 acq_item.plus += random2(3);
1358             // God gifts (except Xom's) never have a negative enchantment
1359             if (divine && agent != GOD_XOM)
1360                 acq_item.plus = max(static_cast<int>(acq_item.plus), 0);
1361         }
1362 
1363         // Last check: don't acquire items your god hates.
1364         // Temporarily mark the type as ID'd for the purpose of checking if
1365         // it is a hated brand (this addresses, e.g., Elyvilon followers
1366         // immediately identifying evil weapons).
1367         // Note that Xom will happily give useless items!
1368         int oldflags = acq_item.flags;
1369         acq_item.flags |= ISFLAG_KNOW_TYPE;
1370         if ((is_useless_item(acq_item, false) && agent != GOD_XOM)
1371             || god_hates_item(acq_item))
1372         {
1373             if (!quiet)
1374                 dprf("destroying useless item");
1375             destroy_item(thing_created);
1376             thing_created = NON_ITEM;
1377             continue;
1378         }
1379         acq_item.flags = oldflags;
1380         break;
1381     }
1382 
1383     if (thing_created == NON_ITEM)
1384         return _failed_acquirement(quiet);
1385 
1386     item_set_appearance(env.item[thing_created]); // cleanup
1387 
1388     if (thing_created != NON_ITEM)
1389     {
1390         ASSERT(env.item[thing_created].is_valid());
1391         env.item[thing_created].props[ACQUIRE_KEY].get_int() = agent;
1392     }
1393 
1394     ASSERT(!is_useless_item(env.item[thing_created], false) || agent == GOD_XOM);
1395     ASSERT(!god_hates_item(env.item[thing_created]));
1396 
1397     // If we have a zero coord_def, don't move the item to the grid. Used for
1398     // generating scroll of acquirement items.
1399     if (pos.origin())
1400         return thing_created;
1401 
1402     // Moving this above the move since it might not exist after falling.
1403     if (thing_created != NON_ITEM && !quiet)
1404         canned_msg(MSG_SOMETHING_APPEARS);
1405 
1406     // If a god wants to give you something but the floor doesn't want it,
1407     // it counts as a failed acquirement - no piety, etc cost.
1408     if (feat_destroys_items(env.grid(pos))
1409         && agent > GOD_NO_GOD
1410         && agent < NUM_GODS)
1411     {
1412         if (!quiet && agent == GOD_XOM)
1413             simple_god_message(" snickers.", GOD_XOM);
1414         else
1415             return _failed_acquirement(quiet);
1416     }
1417 
1418     move_item_to_grid(&thing_created, pos, quiet);
1419 
1420     return thing_created;
1421 }
1422 
1423 class AcquireMenu : public InvMenu
1424 {
1425     friend class AcquireEntry;
1426 
1427     CrawlVector &acq_items;
1428 
1429     void init_entries();
1430     void update_help();
1431     bool acquire_selected();
1432 
1433     virtual bool process_key(int keyin) override;
1434 
1435 public:
1436     AcquireMenu(CrawlVector &aitems);
1437 };
1438 
1439 class AcquireEntry : public InvEntry
1440 {
get_text(bool need_cursor=false) const1441     string get_text(bool need_cursor = false) const override
1442     {
1443         need_cursor = need_cursor && show_cursor;
1444         const colour_t keycol = LIGHTCYAN;
1445         const string keystr = colour_to_str(keycol);
1446         const string itemstr =
1447             colour_to_str(menu_colour(text, item_prefix(*item), tag));
1448         const string gold_text = item->base_type == OBJ_GOLD
1449             ? make_stringf(" (you have %d gold)", you.gold) : "";
1450         return make_stringf(" <%s>%c%c%c%c</%s><%s>%s%s</%s>",
1451                             keystr.c_str(),
1452                             hotkeys[0],
1453                             need_cursor ? '[' : ' ',
1454                             selected() ? '+' : '-',
1455                             need_cursor ? ']' : ' ',
1456                             keystr.c_str(),
1457                             itemstr.c_str(),
1458                             text.c_str(),
1459                             gold_text.c_str(),
1460                             itemstr.c_str());
1461     }
1462 
1463 public:
AcquireEntry(const item_def & i)1464     AcquireEntry(const item_def& i) : InvEntry(i)
1465     {
1466         show_background = false;
1467     }
1468 };
1469 
AcquireMenu(CrawlVector & aitems)1470 AcquireMenu::AcquireMenu(CrawlVector &aitems)
1471     : InvMenu(MF_SINGLESELECT | MF_NO_SELECT_QTY | MF_QUIET_SELECT
1472               | MF_ALWAYS_SHOW_MORE | MF_ALLOW_FORMATTING),
1473       acq_items(aitems)
1474 {
1475     menu_action = ACT_EXECUTE;
1476     set_flags(get_flags() & ~MF_USE_TWO_COLUMNS);
1477 
1478     set_tag("acquirement");
1479 
1480     init_entries();
1481 
1482     update_help();
1483 
1484     set_title("Choose an item to acquire.");
1485 }
1486 
init_entries()1487 void AcquireMenu::init_entries()
1488 {
1489     menu_letter ckey = 'a';
1490     for (item_def& item : acq_items)
1491     {
1492         auto newentry = make_unique<AcquireEntry>(item);
1493         newentry->hotkeys.clear();
1494         newentry->add_hotkey(ckey++);
1495         add_entry(move(newentry));
1496     }
1497 }
1498 
_hyphenated_letters(int how_many,char first)1499 static string _hyphenated_letters(int how_many, char first)
1500 {
1501     string s = "<w>";
1502     s += first;
1503     s += "</w>";
1504     if (how_many > 1)
1505     {
1506         s += "-<w>";
1507         s += first + how_many - 1;
1508         s += "</w>";
1509     }
1510     return s;
1511 }
1512 
update_help()1513 void AcquireMenu::update_help()
1514 {
1515     string top_line = string(80, ' ') + '\n';
1516 
1517     set_more(formatted_string::parse_string(top_line + make_stringf(
1518         //[!] acquire|examine item  [a-i] select item to acquire
1519         //[Esc/R-Click] exit
1520         "%s  [%s] %s\n"
1521         "[Esc/R-Click] exit",
1522         menu_action == ACT_EXECUTE ? "[<w>!</w>] <w>acquire</w>|examine items" :
1523                                      "[<w>!</w>] acquire|<w>examine</w> items",
1524         _hyphenated_letters(item_count(), 'a').c_str(),
1525         menu_action == ACT_EXECUTE ? "select item for acquirement"
1526                                    : "examine item")));
1527 }
1528 
_create_acquirement_item(item_def & item)1529 static void _create_acquirement_item(item_def &item)
1530 {
1531     auto &acq_items = you.props[ACQUIRE_ITEMS_KEY].get_vector();
1532 
1533     // Now that we have a selection, mark any generated unrands as not having
1534     // been generated, so they go back in circulation. Exclude the selected
1535     // item from this, if it's an unrand.
1536     for (auto aitem : acq_items)
1537     {
1538         if (is_unrandom_artefact(aitem)
1539             && (!is_unrandom_artefact(item)
1540                 || !is_unrandom_artefact(aitem, item.unrand_idx)))
1541         {
1542             set_unique_item_status(aitem, UNIQ_NOT_EXISTS);
1543         }
1544     }
1545 
1546     take_note(Note(NOTE_ACQUIRE_ITEM, 0, 0, item.name(DESC_A),
1547               origin_desc(item)));
1548     item.flags |= (ISFLAG_NOTED_ID | ISFLAG_NOTED_GET);
1549 
1550     set_ident_type(item, true);
1551 
1552     if (copy_item_to_grid(item, you.pos()))
1553         canned_msg(MSG_SOMETHING_APPEARS);
1554     else
1555         canned_msg(MSG_NOTHING_HAPPENS);
1556 
1557     acq_items.clear();
1558     you.props.erase(ACQUIRE_ITEMS_KEY);
1559 }
1560 
acquire_selected()1561 bool AcquireMenu::acquire_selected()
1562 {
1563     vector<MenuEntry*> selected = selected_entries();
1564     ASSERT(selected.size() == 1);
1565     auto& entry = *selected[0];
1566 
1567     const string col = colour_to_str(channel_to_colour(MSGCH_PROMPT));
1568     update_help();
1569     const formatted_string old_more = more;
1570     more = formatted_string::parse_string(make_stringf(
1571                "<%s>Acquire %s? (%s/N)</%s>\n",
1572                col.c_str(),
1573                entry.text.c_str(),
1574                Options.easy_confirm == easy_confirm_type::none ? "Y" : "y",
1575                col.c_str()));
1576     more += old_more;
1577     update_more();
1578 
1579     if (!yesno(nullptr, true, 'n', false, false, true))
1580     {
1581         deselect_all();
1582         more = old_more;
1583         update_more();
1584         return true;
1585     }
1586 
1587     item_def &acq_item = *static_cast<item_def*>(entry.data);
1588     _create_acquirement_item(acq_item);
1589 
1590     return false;
1591 }
1592 
process_key(int keyin)1593 bool AcquireMenu::process_key(int keyin)
1594 {
1595     switch (keyin)
1596     {
1597     case '!':
1598     case '?':
1599         if (menu_action == ACT_EXECUTE)
1600             menu_action = ACT_EXAMINE;
1601         else
1602             menu_action = ACT_EXECUTE;
1603         update_help();
1604         update_more();
1605         return true;
1606     default:
1607         break;
1608     }
1609 
1610     if (keyin - 'a' >= 0 && keyin - 'a' < (int)items.size())
1611     {
1612         if (menu_action == ACT_EXAMINE)
1613         {
1614             // Use a copy to set flags that make the description better
1615             // See the similar code in shopping.cc for details about const
1616             // hygene
1617             item_def& item(*const_cast<item_def*>(dynamic_cast<AcquireEntry*>(
1618                 items[letter_to_index(keyin)])->item));
1619 
1620             item.flags |= (ISFLAG_IDENT_MASK | ISFLAG_NOTED_ID
1621                            | ISFLAG_NOTED_GET);
1622             describe_item_popup(item);
1623 
1624             return true;
1625         }
1626         else
1627         {
1628             const unsigned int i = keyin - 'a';
1629             select_item_index(i, 1, false);
1630             return acquire_selected();
1631         }
1632     }
1633 
1634     const bool ret = InvMenu::process_key(keyin);
1635     auto selected = selected_entries();
1636     if (selected.size() == 1)
1637         return acquire_selected();
1638     else
1639         return ret;
1640 }
1641 
_acquirement_item_def(object_class_type item_type)1642 static item_def _acquirement_item_def(object_class_type item_type)
1643 {
1644     item_def item;
1645 
1646     const int item_index = acquirement_create_item(item_type, AQ_SCROLL, true);
1647 
1648     if (item_index != NON_ITEM)
1649     {
1650         ASSERT(!god_hates_item(env.item[item_index]));
1651 
1652         // We make a copy of the item def, but we don't keep the real item.
1653         item = env.item[item_index];
1654         set_ident_flags(item,
1655                 // Act as if we've recieved this item already to prevent notes.
1656                 ISFLAG_IDENT_MASK | ISFLAG_NOTED_ID | ISFLAG_NOTED_GET);
1657         destroy_item(item_index);
1658     }
1659 
1660     return item;
1661 }
1662 
shuffled_acquirement_classes(bool scroll)1663 vector<object_class_type> shuffled_acquirement_classes(bool scroll)
1664 {
1665     vector<object_class_type> rand_classes;
1666 
1667     if (!you.has_mutation(MUT_NO_ARMOUR))
1668         rand_classes.emplace_back(OBJ_ARMOUR);
1669 
1670     if (!you.has_mutation(MUT_NO_GRASPING))
1671     {
1672         rand_classes.emplace_back(OBJ_WEAPONS);
1673         rand_classes.emplace_back(OBJ_STAVES);
1674     }
1675 
1676     rand_classes.emplace_back(OBJ_JEWELLERY);
1677     rand_classes.emplace_back(OBJ_BOOKS);
1678 
1679     // dungeon generation
1680     if (!scroll)
1681     {
1682         rand_classes.emplace_back(OBJ_MISCELLANY);
1683         rand_classes.emplace_back(OBJ_WANDS);
1684     }
1685     shuffle_array(rand_classes);
1686     return rand_classes;
1687 }
1688 
_make_acquirement_items()1689 static void _make_acquirement_items()
1690 {
1691     vector<object_class_type> rand_classes = shuffled_acquirement_classes(true);
1692     const int num_wanted = min(3, (int) rand_classes.size());
1693 
1694     CrawlVector &acq_items = you.props[ACQUIRE_ITEMS_KEY].get_vector();
1695     acq_items.empty();
1696 
1697     // Generate item defs until we have enough, skipping any random classes
1698     // that fail to generate an item.
1699     for (auto obj_type : rand_classes)
1700     {
1701         if (acq_items.size() == num_wanted)
1702             break;
1703 
1704         auto item = _acquirement_item_def(obj_type);
1705         if (item.defined())
1706             acq_items.push_back(item);
1707     }
1708 
1709     // Gold is guaranteed.
1710     auto gold_item = _acquirement_item_def(OBJ_GOLD);
1711     if (gold_item.defined())
1712             acq_items.push_back(gold_item);
1713 }
1714 
1715 /*
1716  * Handle scroll of acquirement.
1717  *
1718  * Generate acquirement choices as items in a prop if these don't already exist
1719  * (because a scroll was read and canceled. Then either get the acquirement
1720  * choice from the c_choose_acquirement lua handler if one exists or present a
1721  * menu for the player to choose an item.
1722  *
1723  * returns True if the scroll was used, false if it was canceled.
1724 */
acquirement_menu()1725 bool acquirement_menu()
1726 {
1727     ASSERT(!crawl_state.game_is_arena());
1728 
1729     if (!you.props.exists(ACQUIRE_ITEMS_KEY))
1730         _make_acquirement_items();
1731 
1732     auto &acq_items = you.props[ACQUIRE_ITEMS_KEY].get_vector();
1733 
1734     int index = 0;
1735     if (!clua.callfn("c_choose_acquirement", ">d", &index))
1736     {
1737         if (!clua.error.empty())
1738             mprf(MSGCH_ERROR, "Lua error: %s", clua.error.c_str());
1739     }
1740     else if (index >= 1 && index <= acq_items.size())
1741     {
1742         _create_acquirement_item(acq_items[index - 1]);
1743         return true;
1744     }
1745 
1746     AcquireMenu acq_menu(acq_items);
1747     acq_menu.show();
1748 
1749     return !you.props.exists(ACQUIRE_ITEMS_KEY);
1750 }
1751