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