1 #include "autopick/autopick-entry.h"
2 #include "autopick/autopick-flags-table.h"
3 #include "autopick/autopick-key-flag-process.h"
4 #include "autopick/autopick-keys-table.h"
5 #include "autopick/autopick-methods-table.h"
6 #include "autopick/autopick-util.h"
7 #include "core/show-file.h"
8 #include "flavor/flavor-describer.h"
9 #include "flavor/object-flavor-types.h"
10 #include "floor/floor-object.h"
11 #include "monster-race/monster-race.h"
12 #include "monster-race/race-flags1.h"
13 #include "object-enchant/item-feeling.h"
14 #include "object-enchant/object-ego.h"
15 #include "object-enchant/special-object-flags.h"
16 #include "object-hook/hook-quest.h"
17 #include "object-hook/hook-weapon.h"
18 #include "object/item-use-flags.h"
19 #include "object/object-info.h"
20 #include "object/object-kind.h"
21 #include "perception/object-perception.h"
22 #include "player-base/player-class.h"
23 #include "player/player-realm.h"
24 #include "system/monster-race-definition.h"
25 #include "system/object-type-definition.h"
26 #include "system/player-type-definition.h"
27 #include "util/quarks.h"
28 #include "util/string-processor.h"
31 static char kanji_colon[] = ":";
35 * @brief A function to create new entry
37 bool autopick_new_entry(autopick_type *entry, concptr str, bool allow_default)
39 if (str[0] && str[1] == ':') {
50 entry->flag[0] = entry->flag[1] = 0L;
54 byte act = DO_AUTOPICK | DO_DISPLAY;
56 if ((act & DO_AUTOPICK) && *str == '!') {
58 act |= DO_AUTODESTROY;
63 if ((act & DO_AUTOPICK) && *str == '~') {
70 if ((act & DO_AUTOPICK) && *str == ';') {
72 act |= DO_QUERY_AUTOPICK;
77 if ((act & DO_DISPLAY) && *str == '(') {
86 concptr insc = nullptr;
87 char buf[MAX_LINELEN];
89 for (i = 0; *str; i++) {
105 c = (char)tolower(c);
112 if (!allow_default && *buf == 0) {
115 if (*buf == 0 && insc) {
119 concptr prev_ptr, ptr;
120 ptr = prev_ptr = buf;
121 concptr old_ptr = nullptr;
122 while (old_ptr != ptr) {
124 if (MATCH_KEY(KEY_ALL)) {
127 if (MATCH_KEY(KEY_COLLECTING)) {
128 ADD_FLG(FLG_COLLECTING);
130 if (MATCH_KEY(KEY_UNAWARE)) {
131 ADD_FLG(FLG_UNAWARE);
133 if (MATCH_KEY(KEY_UNIDENTIFIED)) {
134 ADD_FLG(FLG_UNIDENTIFIED);
136 if (MATCH_KEY(KEY_IDENTIFIED)) {
137 ADD_FLG(FLG_IDENTIFIED);
139 if (MATCH_KEY(KEY_STAR_IDENTIFIED)) {
140 ADD_FLG(FLG_STAR_IDENTIFIED);
142 if (MATCH_KEY(KEY_BOOSTED)) {
143 ADD_FLG(FLG_BOOSTED);
146 /*** Weapons whose dd*ds is more than nn ***/
147 if (MATCH_KEY2(KEY_MORE_THAN)) {
151 while (' ' == *ptr) {
155 while ('0' <= *ptr && *ptr <= '9') {
156 entry->dice = 10 * entry->dice + (*ptr - '0');
161 if (k > 0 && k <= 2) {
162 (void)MATCH_KEY(KEY_DICE);
163 ADD_FLG(FLG_MORE_DICE);
169 /*** Items whose magical bonus is more than n ***/
170 if (MATCH_KEY2(KEY_MORE_BONUS)) {
174 while (' ' == *ptr) {
178 while ('0' <= *ptr && *ptr <= '9') {
179 entry->bonus = 10 * entry->bonus + (*ptr - '0');
184 if (k > 0 && k <= 2) {
186 (void)MATCH_KEY(KEY_MORE_BONUS2);
192 ADD_FLG(FLG_MORE_BONUS);
198 if (MATCH_KEY(KEY_WORTHLESS)) {
199 ADD_FLG(FLG_WORTHLESS);
201 if (MATCH_KEY(KEY_EGO)) {
204 if (MATCH_KEY(KEY_GOOD)) {
207 if (MATCH_KEY(KEY_NAMELESS)) {
208 ADD_FLG(FLG_NAMELESS);
210 if (MATCH_KEY(KEY_AVERAGE)) {
211 ADD_FLG(FLG_AVERAGE);
213 if (MATCH_KEY(KEY_RARE)) {
216 if (MATCH_KEY(KEY_COMMON)) {
219 if (MATCH_KEY(KEY_WANTED)) {
222 if (MATCH_KEY(KEY_UNIQUE)) {
225 if (MATCH_KEY(KEY_HUMAN)) {
228 if (MATCH_KEY(KEY_UNREADABLE)) {
229 ADD_FLG(FLG_UNREADABLE);
231 if (MATCH_KEY(KEY_REALM1)) {
234 if (MATCH_KEY(KEY_REALM2)) {
237 if (MATCH_KEY(KEY_FIRST)) {
240 if (MATCH_KEY(KEY_SECOND)) {
243 if (MATCH_KEY(KEY_THIRD)) {
246 if (MATCH_KEY(KEY_FOURTH)) {
252 if (MATCH_KEY2(KEY_ARTIFACT)) {
253 ADD_FLG_NOUN(FLG_ARTIFACT);
256 if (MATCH_KEY2(KEY_ITEMS)) {
257 ADD_FLG_NOUN(FLG_ITEMS);
258 } else if (MATCH_KEY2(KEY_WEAPONS)) {
259 ADD_FLG_NOUN(FLG_WEAPONS);
260 } else if (MATCH_KEY2(KEY_FAVORITE_WEAPONS)) {
261 ADD_FLG_NOUN(FLG_FAVORITE_WEAPONS);
262 } else if (MATCH_KEY2(KEY_ARMORS)) {
263 ADD_FLG_NOUN(FLG_ARMORS);
264 } else if (MATCH_KEY2(KEY_MISSILES)) {
265 ADD_FLG_NOUN(FLG_MISSILES);
266 } else if (MATCH_KEY2(KEY_DEVICES)) {
267 ADD_FLG_NOUN(FLG_DEVICES);
268 } else if (MATCH_KEY2(KEY_LIGHTS)) {
269 ADD_FLG_NOUN(FLG_LIGHTS);
270 } else if (MATCH_KEY2(KEY_JUNKS)) {
271 ADD_FLG_NOUN(FLG_JUNKS);
272 } else if (MATCH_KEY2(KEY_CORPSES)) {
273 ADD_FLG_NOUN(FLG_CORPSES);
274 } else if (MATCH_KEY2(KEY_SPELLBOOKS)) {
275 ADD_FLG_NOUN(FLG_SPELLBOOKS);
276 } else if (MATCH_KEY2(KEY_HAFTED)) {
277 ADD_FLG_NOUN(FLG_HAFTED);
278 } else if (MATCH_KEY2(KEY_SHIELDS)) {
279 ADD_FLG_NOUN(FLG_SHIELDS);
280 } else if (MATCH_KEY2(KEY_BOWS)) {
281 ADD_FLG_NOUN(FLG_BOWS);
282 } else if (MATCH_KEY2(KEY_RINGS)) {
283 ADD_FLG_NOUN(FLG_RINGS);
284 } else if (MATCH_KEY2(KEY_AMULETS)) {
285 ADD_FLG_NOUN(FLG_AMULETS);
286 } else if (MATCH_KEY2(KEY_SUITS)) {
287 ADD_FLG_NOUN(FLG_SUITS);
288 } else if (MATCH_KEY2(KEY_CLOAKS)) {
289 ADD_FLG_NOUN(FLG_CLOAKS);
290 } else if (MATCH_KEY2(KEY_HELMS)) {
291 ADD_FLG_NOUN(FLG_HELMS);
292 } else if (MATCH_KEY2(KEY_GLOVES)) {
293 ADD_FLG_NOUN(FLG_GLOVES);
294 } else if (MATCH_KEY2(KEY_BOOTS)) {
295 ADD_FLG_NOUN(FLG_BOOTS);
302 else if (ptr[0] == kanji_colon[0] && ptr[1] == kanji_colon[1]) {
306 else if (*ptr == '\0') {
307 if (prev_flg == -1) {
308 ADD_FLG_NOUN(FLG_ITEMS);
311 if (prev_flg != -1) {
312 entry->flag[prev_flg / 32] &= ~(1UL << (prev_flg % 32));
319 entry->insc = insc != nullptr ? insc : "";
325 * @brief Get auto-picker entry from o_ptr.
327 void autopick_entry_from_object(PlayerType *player_ptr, autopick_type *entry, ObjectType *o_ptr)
329 /* Assume that object name is to be added */
331 GAME_TEXT name_str[MAX_NLEN + 32];
333 auto insc = quark_str(o_ptr->inscription);
334 entry->insc = insc != nullptr ? insc : "";
335 entry->action = DO_AUTOPICK | DO_DISPLAY;
336 entry->flag[0] = entry->flag[1] = 0L;
339 // エゴ銘が邪魔かもしれないので、デフォルトで「^」は付けない.
340 // We can always use the ^ mark in English.
341 bool is_hat_added = _(false, true);
342 if (!o_ptr->is_aware()) {
343 ADD_FLG(FLG_UNAWARE);
345 } else if (!o_ptr->is_known()) {
346 if (!(o_ptr->ident & IDENT_SENSE)) {
347 ADD_FLG(FLG_UNIDENTIFIED);
350 switch (o_ptr->feeling) {
353 ADD_FLG(FLG_NAMELESS);
359 ADD_FLG(FLG_NAMELESS);
360 ADD_FLG(FLG_WORTHLESS);
366 ADD_FLG(FLG_WORTHLESS);
381 if (o_ptr->is_ego()) {
382 if (o_ptr->is_weapon_armour_ammo()) {
384 * Base name of ego weapons and armors
385 * are almost meaningless.
386 * Register the ego type only.
388 auto *e_ptr = &e_info[o_ptr->ego_idx];
390 /* エゴ銘には「^」マークが使える */
391 sprintf(name_str, "^%s", e_ptr->name.c_str());
393 /* We ommit the basename and cannot use the ^ mark */
394 strcpy(name_str, e_ptr->name.c_str());
397 if (!o_ptr->is_rare()) {
403 } else if (o_ptr->is_artifact()) {
404 ADD_FLG(FLG_ARTIFACT);
406 if (o_ptr->is_equipment()) {
407 ADD_FLG(FLG_NAMELESS);
414 if (o_ptr->is_melee_weapon()) {
415 auto *k_ptr = &k_info[o_ptr->k_idx];
417 if ((o_ptr->dd != k_ptr->dd) || (o_ptr->ds != k_ptr->ds)) {
418 ADD_FLG(FLG_BOOSTED);
422 if (object_is_bounty(player_ptr, o_ptr)) {
423 REM_FLG(FLG_WORTHLESS);
427 if ((o_ptr->tval == ItemKindType::CORPSE || o_ptr->tval == ItemKindType::STATUE) && r_info[o_ptr->pval].kind_flags.has(MonsterKindType::UNIQUE)) {
431 if (o_ptr->tval == ItemKindType::CORPSE && angband_strchr("pht", r_info[o_ptr->pval].d_char)) {
435 if (o_ptr->tval >= ItemKindType::LIFE_BOOK && !check_book_realm(player_ptr, o_ptr->tval, o_ptr->sval)) {
436 ADD_FLG(FLG_UNREADABLE);
437 if (o_ptr->tval != ItemKindType::ARCANE_BOOK) {
442 PlayerClass pc(player_ptr);
443 auto realm_except_class = pc.equals(PlayerClassType::SORCERER) || pc.equals(PlayerClassType::RED_MAGE);
445 if ((get_realm1_book(player_ptr) == o_ptr->tval) && !realm_except_class) {
450 if ((get_realm2_book(player_ptr) == o_ptr->tval) && !realm_except_class) {
455 if (o_ptr->tval >= ItemKindType::LIFE_BOOK && 0 == o_ptr->sval) {
458 if (o_ptr->tval >= ItemKindType::LIFE_BOOK && 1 == o_ptr->sval) {
461 if (o_ptr->tval >= ItemKindType::LIFE_BOOK && 2 == o_ptr->sval) {
464 if (o_ptr->tval >= ItemKindType::LIFE_BOOK && 3 == o_ptr->sval) {
468 if (o_ptr->is_ammo()) {
469 ADD_FLG(FLG_MISSILES);
470 } else if (o_ptr->tval == ItemKindType::SCROLL || o_ptr->tval == ItemKindType::STAFF || o_ptr->tval == ItemKindType::WAND || o_ptr->tval == ItemKindType::ROD) {
471 ADD_FLG(FLG_DEVICES);
472 } else if (o_ptr->tval == ItemKindType::LITE) {
474 } else if (o_ptr->tval == ItemKindType::SKELETON || o_ptr->tval == ItemKindType::BOTTLE || o_ptr->tval == ItemKindType::JUNK || o_ptr->tval == ItemKindType::STATUE) {
476 } else if (o_ptr->tval == ItemKindType::CORPSE) {
477 ADD_FLG(FLG_CORPSES);
478 } else if (o_ptr->tval >= ItemKindType::LIFE_BOOK) {
479 ADD_FLG(FLG_SPELLBOOKS);
480 } else if (o_ptr->tval == ItemKindType::POLEARM || o_ptr->tval == ItemKindType::SWORD || o_ptr->tval == ItemKindType::DIGGING || o_ptr->tval == ItemKindType::HAFTED) {
481 ADD_FLG(FLG_WEAPONS);
482 } else if (o_ptr->tval == ItemKindType::SHIELD) {
483 ADD_FLG(FLG_SHIELDS);
484 } else if (o_ptr->tval == ItemKindType::BOW) {
486 } else if (o_ptr->tval == ItemKindType::RING) {
488 } else if (o_ptr->tval == ItemKindType::AMULET) {
489 ADD_FLG(FLG_AMULETS);
490 } else if (o_ptr->tval == ItemKindType::DRAG_ARMOR || o_ptr->tval == ItemKindType::HARD_ARMOR || o_ptr->tval == ItemKindType::SOFT_ARMOR) {
492 } else if (o_ptr->tval == ItemKindType::CLOAK) {
494 } else if (o_ptr->tval == ItemKindType::HELM) {
496 } else if (o_ptr->tval == ItemKindType::GLOVES) {
498 } else if (o_ptr->tval == ItemKindType::BOOTS) {
503 str_tolower(name_str);
504 entry->name = name_str;
508 GAME_TEXT o_name[MAX_NLEN];
509 describe_flavor(player_ptr, o_name, o_ptr, (OD_NO_FLAVOR | OD_OMIT_PREFIX | OD_NO_PLURAL | OD_NAME_ONLY));
512 * If necessary, add a '^' which indicates the
515 sprintf(name_str, "%s%s", is_hat_added ? "^" : "", o_name);
516 str_tolower(name_str);
517 entry->name = name_str;
521 * @brief Reconstruct preference line from entry
523 concptr autopick_line_from_entry(autopick_type *entry)
525 char buf[MAX_LINELEN];
527 if (!(entry->action & DO_DISPLAY)) {
530 if (entry->action & DO_QUERY_AUTOPICK) {
533 if (entry->action & DO_AUTODESTROY) {
536 if (entry->action & DONT_AUTOPICK) {
542 if (IS_FLG(FLG_ALL)) {
545 if (IS_FLG(FLG_COLLECTING)) {
546 ADD_KEY(KEY_COLLECTING);
548 if (IS_FLG(FLG_UNAWARE)) {
549 ADD_KEY(KEY_UNAWARE);
551 if (IS_FLG(FLG_UNIDENTIFIED)) {
552 ADD_KEY(KEY_UNIDENTIFIED);
554 if (IS_FLG(FLG_IDENTIFIED)) {
555 ADD_KEY(KEY_IDENTIFIED);
557 if (IS_FLG(FLG_STAR_IDENTIFIED)) {
558 ADD_KEY(KEY_STAR_IDENTIFIED);
560 if (IS_FLG(FLG_BOOSTED)) {
561 ADD_KEY(KEY_BOOSTED);
564 if (IS_FLG(FLG_MORE_DICE)) {
565 ADD_KEY(KEY_MORE_THAN);
566 strcat(ptr, format("%d", entry->dice));
570 if (IS_FLG(FLG_MORE_BONUS)) {
571 ADD_KEY(KEY_MORE_BONUS);
572 strcat(ptr, format("%d", entry->bonus));
573 ADD_KEY(KEY_MORE_BONUS2);
576 if (IS_FLG(FLG_UNREADABLE)) {
577 ADD_KEY(KEY_UNREADABLE);
579 if (IS_FLG(FLG_REALM1)) {
582 if (IS_FLG(FLG_REALM2)) {
585 if (IS_FLG(FLG_FIRST)) {
588 if (IS_FLG(FLG_SECOND)) {
591 if (IS_FLG(FLG_THIRD)) {
594 if (IS_FLG(FLG_FOURTH)) {
597 if (IS_FLG(FLG_WANTED)) {
600 if (IS_FLG(FLG_UNIQUE)) {
603 if (IS_FLG(FLG_HUMAN)) {
606 if (IS_FLG(FLG_WORTHLESS)) {
607 ADD_KEY(KEY_WORTHLESS);
609 if (IS_FLG(FLG_GOOD)) {
612 if (IS_FLG(FLG_NAMELESS)) {
613 ADD_KEY(KEY_NAMELESS);
615 if (IS_FLG(FLG_AVERAGE)) {
616 ADD_KEY(KEY_AVERAGE);
618 if (IS_FLG(FLG_RARE)) {
621 if (IS_FLG(FLG_COMMON)) {
624 if (IS_FLG(FLG_EGO)) {
628 if (IS_FLG(FLG_ARTIFACT)) {
629 ADD_KEY(KEY_ARTIFACT);
632 bool sepa_flag = true;
633 if (IS_FLG(FLG_ITEMS)) {
635 } else if (IS_FLG(FLG_WEAPONS)) {
636 ADD_KEY2(KEY_WEAPONS);
637 } else if (IS_FLG(FLG_FAVORITE_WEAPONS)) {
638 ADD_KEY2(KEY_FAVORITE_WEAPONS);
639 } else if (IS_FLG(FLG_ARMORS)) {
640 ADD_KEY2(KEY_ARMORS);
641 } else if (IS_FLG(FLG_MISSILES)) {
642 ADD_KEY2(KEY_MISSILES);
643 } else if (IS_FLG(FLG_DEVICES)) {
644 ADD_KEY2(KEY_DEVICES);
645 } else if (IS_FLG(FLG_LIGHTS)) {
646 ADD_KEY2(KEY_LIGHTS);
647 } else if (IS_FLG(FLG_JUNKS)) {
649 } else if (IS_FLG(FLG_CORPSES)) {
650 ADD_KEY2(KEY_CORPSES);
651 } else if (IS_FLG(FLG_SPELLBOOKS)) {
652 ADD_KEY2(KEY_SPELLBOOKS);
653 } else if (IS_FLG(FLG_HAFTED)) {
654 ADD_KEY2(KEY_HAFTED);
655 } else if (IS_FLG(FLG_SHIELDS)) {
656 ADD_KEY2(KEY_SHIELDS);
657 } else if (IS_FLG(FLG_BOWS)) {
659 } else if (IS_FLG(FLG_RINGS)) {
661 } else if (IS_FLG(FLG_AMULETS)) {
662 ADD_KEY2(KEY_AMULETS);
663 } else if (IS_FLG(FLG_SUITS)) {
665 } else if (IS_FLG(FLG_CLOAKS)) {
666 ADD_KEY2(KEY_CLOAKS);
667 } else if (IS_FLG(FLG_HELMS)) {
669 } else if (IS_FLG(FLG_GLOVES)) {
670 ADD_KEY2(KEY_GLOVES);
671 } else if (IS_FLG(FLG_BOOTS)) {
673 } else if (!IS_FLG(FLG_ARTIFACT)) {
677 if (!entry->name.empty()) {
684 while (entry->name[j] && i < MAX_LINELEN - 2 - 1) {
686 if (iskanji(entry->name[j])) {
687 buf[i++] = entry->name[j++];
690 buf[i++] = entry->name[j++];
695 if (entry->insc.empty()) {
696 return string_make(buf);
703 while (entry->insc[j] && i < MAX_LINELEN - 2) {
705 if (iskanji(entry->insc[j])) {
706 buf[i++] = entry->insc[j++];
709 buf[i++] = entry->insc[j++];
713 return string_make(buf);
717 * @brief Reconstruct preference line from entry and kill entry
719 concptr autopick_line_from_entry_kill(autopick_type *entry)
721 concptr ptr = autopick_line_from_entry(entry);
726 * @brief Choose an item and get auto-picker entry from it.
728 bool entry_from_choosed_object(PlayerType *player_ptr, autopick_type *entry)
730 concptr q = _("どのアイテムを登録しますか? ", "Enter which item? ");
731 concptr s = _("アイテムを持っていない。", "You have nothing to enter.");
733 o_ptr = choose_object(player_ptr, nullptr, q, s, USE_INVEN | USE_FLOOR | USE_EQUIP);
738 autopick_entry_from_object(player_ptr, entry, o_ptr);