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 "perception/object-perception.h"
21 #include "player-base/player-class.h"
22 #include "player/player-realm.h"
23 #include "system/baseitem-info.h"
24 #include "system/item-entity.h"
25 #include "system/monster-race-info.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, ItemEntity *o_ptr)
329 /* Assume that object name is to be added */
331 auto insc = quark_str(o_ptr->inscription);
333 entry->insc = insc != nullptr ? insc : "";
334 entry->action = DO_AUTOPICK | DO_DISPLAY;
335 entry->flag[0] = entry->flag[1] = 0L;
338 // エゴ銘が邪魔かもしれないので、デフォルトで「^」は付けない.
339 // We can always use the ^ mark in English.
340 bool is_hat_added = _(false, true);
341 if (!o_ptr->is_aware()) {
342 ADD_FLG(FLG_UNAWARE);
344 } else if (!o_ptr->is_known()) {
345 if (!(o_ptr->ident & IDENT_SENSE)) {
346 ADD_FLG(FLG_UNIDENTIFIED);
349 switch (o_ptr->feeling) {
352 ADD_FLG(FLG_NAMELESS);
358 ADD_FLG(FLG_NAMELESS);
359 ADD_FLG(FLG_WORTHLESS);
365 ADD_FLG(FLG_WORTHLESS);
380 if (o_ptr->is_ego()) {
381 if (o_ptr->is_weapon_armour_ammo()) {
383 * Base name of ego weapons and armors
384 * are almost meaningless.
385 * Register the ego type only.
387 auto *e_ptr = &egos_info[o_ptr->ego_idx];
389 /* エゴ銘には「^」マークが使える */
391 entry->name.append(e_ptr->name);
393 /* We omit the basename and cannot use the ^ mark */
394 entry->name = e_ptr->name;
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 const auto &baseitem = baseitems_info[o_ptr->bi_id];
416 if ((o_ptr->dd != baseitem.dd) || (o_ptr->ds != baseitem.ds)) {
417 ADD_FLG(FLG_BOOSTED);
421 if (object_is_bounty(player_ptr, o_ptr)) {
422 REM_FLG(FLG_WORTHLESS);
426 const auto r_idx = i2enum<MonsterRaceId>(o_ptr->pval);
427 const auto &bi_key = o_ptr->bi_key;
428 const auto tval = bi_key.tval();
429 if ((tval == ItemKindType::CORPSE || tval == ItemKindType::STATUE) && monraces_info[r_idx].kind_flags.has(MonsterKindType::UNIQUE)) {
433 if (tval == ItemKindType::CORPSE && angband_strchr("pht", monraces_info[r_idx].d_char)) {
437 if (o_ptr->is_spell_book() && !check_book_realm(player_ptr, bi_key)) {
438 ADD_FLG(FLG_UNREADABLE);
439 if (tval != ItemKindType::ARCANE_BOOK) {
444 PlayerClass pc(player_ptr);
445 auto realm_except_class = pc.equals(PlayerClassType::SORCERER) || pc.equals(PlayerClassType::RED_MAGE);
447 if ((get_realm1_book(player_ptr) == tval) && !realm_except_class) {
452 if ((get_realm2_book(player_ptr) == tval) && !realm_except_class) {
457 const auto sval = bi_key.sval();
458 if (o_ptr->is_spell_book() && (sval == 0)) {
461 if (o_ptr->is_spell_book() && (sval == 1)) {
464 if (o_ptr->is_spell_book() && (sval == 2)) {
467 if (o_ptr->is_spell_book() && (sval == 3)) {
471 if (o_ptr->is_ammo()) {
472 ADD_FLG(FLG_MISSILES);
473 } else if (tval == ItemKindType::SCROLL || o_ptr->is_wand_staff() || o_ptr->is_wand_rod()) {
474 ADD_FLG(FLG_DEVICES);
475 } else if (tval == ItemKindType::LITE) {
477 } else if (o_ptr->is_junk()) {
479 } else if (tval == ItemKindType::CORPSE) {
480 ADD_FLG(FLG_CORPSES);
481 } else if (o_ptr->is_spell_book()) {
482 ADD_FLG(FLG_SPELLBOOKS);
483 } else if (o_ptr->is_melee_weapon()) {
484 ADD_FLG(FLG_WEAPONS);
485 } else if (tval == ItemKindType::SHIELD) {
486 ADD_FLG(FLG_SHIELDS);
487 } else if (tval == ItemKindType::BOW) {
489 } else if (tval == ItemKindType::RING) {
491 } else if (tval == ItemKindType::AMULET) {
492 ADD_FLG(FLG_AMULETS);
493 } else if (o_ptr->is_armour()) {
495 } else if (tval == ItemKindType::CLOAK) {
497 } else if (tval == ItemKindType::HELM) {
499 } else if (tval == ItemKindType::GLOVES) {
501 } else if (tval == ItemKindType::BOOTS) {
506 str_tolower(entry->name.data());
510 GAME_TEXT o_name[MAX_NLEN];
511 describe_flavor(player_ptr, o_name, o_ptr, (OD_NO_FLAVOR | OD_OMIT_PREFIX | OD_NO_PLURAL | OD_NAME_ONLY));
514 * If necessary, add a '^' which indicates the
517 entry->name = std::string(is_hat_added ? "^" : "").append(o_name);
518 str_tolower(entry->name.data());
522 * @brief Reconstruct preference line from entry
524 concptr autopick_line_from_entry(autopick_type *entry)
526 char buf[MAX_LINELEN];
528 if (!(entry->action & DO_DISPLAY)) {
531 if (entry->action & DO_QUERY_AUTOPICK) {
534 if (entry->action & DO_AUTODESTROY) {
537 if (entry->action & DONT_AUTOPICK) {
543 if (IS_FLG(FLG_ALL)) {
546 if (IS_FLG(FLG_COLLECTING)) {
547 ADD_KEY(KEY_COLLECTING);
549 if (IS_FLG(FLG_UNAWARE)) {
550 ADD_KEY(KEY_UNAWARE);
552 if (IS_FLG(FLG_UNIDENTIFIED)) {
553 ADD_KEY(KEY_UNIDENTIFIED);
555 if (IS_FLG(FLG_IDENTIFIED)) {
556 ADD_KEY(KEY_IDENTIFIED);
558 if (IS_FLG(FLG_STAR_IDENTIFIED)) {
559 ADD_KEY(KEY_STAR_IDENTIFIED);
561 if (IS_FLG(FLG_BOOSTED)) {
562 ADD_KEY(KEY_BOOSTED);
565 if (IS_FLG(FLG_MORE_DICE)) {
566 ADD_KEY(KEY_MORE_THAN);
567 strcat(ptr, format("%d", entry->dice));
571 if (IS_FLG(FLG_MORE_BONUS)) {
572 ADD_KEY(KEY_MORE_BONUS);
573 strcat(ptr, format("%d", entry->bonus));
574 ADD_KEY(KEY_MORE_BONUS2);
577 if (IS_FLG(FLG_UNREADABLE)) {
578 ADD_KEY(KEY_UNREADABLE);
580 if (IS_FLG(FLG_REALM1)) {
583 if (IS_FLG(FLG_REALM2)) {
586 if (IS_FLG(FLG_FIRST)) {
589 if (IS_FLG(FLG_SECOND)) {
592 if (IS_FLG(FLG_THIRD)) {
595 if (IS_FLG(FLG_FOURTH)) {
598 if (IS_FLG(FLG_WANTED)) {
601 if (IS_FLG(FLG_UNIQUE)) {
604 if (IS_FLG(FLG_HUMAN)) {
607 if (IS_FLG(FLG_WORTHLESS)) {
608 ADD_KEY(KEY_WORTHLESS);
610 if (IS_FLG(FLG_GOOD)) {
613 if (IS_FLG(FLG_NAMELESS)) {
614 ADD_KEY(KEY_NAMELESS);
616 if (IS_FLG(FLG_AVERAGE)) {
617 ADD_KEY(KEY_AVERAGE);
619 if (IS_FLG(FLG_RARE)) {
622 if (IS_FLG(FLG_COMMON)) {
625 if (IS_FLG(FLG_EGO)) {
629 if (IS_FLG(FLG_ARTIFACT)) {
630 ADD_KEY(KEY_ARTIFACT);
633 bool sepa_flag = true;
634 if (IS_FLG(FLG_ITEMS)) {
636 } else if (IS_FLG(FLG_WEAPONS)) {
637 ADD_KEY2(KEY_WEAPONS);
638 } else if (IS_FLG(FLG_FAVORITE_WEAPONS)) {
639 ADD_KEY2(KEY_FAVORITE_WEAPONS);
640 } else if (IS_FLG(FLG_ARMORS)) {
641 ADD_KEY2(KEY_ARMORS);
642 } else if (IS_FLG(FLG_MISSILES)) {
643 ADD_KEY2(KEY_MISSILES);
644 } else if (IS_FLG(FLG_DEVICES)) {
645 ADD_KEY2(KEY_DEVICES);
646 } else if (IS_FLG(FLG_LIGHTS)) {
647 ADD_KEY2(KEY_LIGHTS);
648 } else if (IS_FLG(FLG_JUNKS)) {
650 } else if (IS_FLG(FLG_CORPSES)) {
651 ADD_KEY2(KEY_CORPSES);
652 } else if (IS_FLG(FLG_SPELLBOOKS)) {
653 ADD_KEY2(KEY_SPELLBOOKS);
654 } else if (IS_FLG(FLG_HAFTED)) {
655 ADD_KEY2(KEY_HAFTED);
656 } else if (IS_FLG(FLG_SHIELDS)) {
657 ADD_KEY2(KEY_SHIELDS);
658 } else if (IS_FLG(FLG_BOWS)) {
660 } else if (IS_FLG(FLG_RINGS)) {
662 } else if (IS_FLG(FLG_AMULETS)) {
663 ADD_KEY2(KEY_AMULETS);
664 } else if (IS_FLG(FLG_SUITS)) {
666 } else if (IS_FLG(FLG_CLOAKS)) {
667 ADD_KEY2(KEY_CLOAKS);
668 } else if (IS_FLG(FLG_HELMS)) {
670 } else if (IS_FLG(FLG_GLOVES)) {
671 ADD_KEY2(KEY_GLOVES);
672 } else if (IS_FLG(FLG_BOOTS)) {
674 } else if (!IS_FLG(FLG_ARTIFACT)) {
678 if (!entry->name.empty()) {
685 while (entry->name[j] && i < MAX_LINELEN - 2 - 1) {
687 if (iskanji(entry->name[j])) {
688 buf[i++] = entry->name[j++];
691 buf[i++] = entry->name[j++];
696 if (entry->insc.empty()) {
697 return string_make(buf);
704 while (entry->insc[j] && i < MAX_LINELEN - 2) {
706 if (iskanji(entry->insc[j])) {
707 buf[i++] = entry->insc[j++];
710 buf[i++] = entry->insc[j++];
714 return string_make(buf);
718 * @brief Reconstruct preference line from entry and kill entry
720 concptr autopick_line_from_entry_kill(autopick_type *entry)
722 concptr ptr = autopick_line_from_entry(entry);
727 * @brief Choose an item and get auto-picker entry from it.
729 bool entry_from_choosed_object(PlayerType *player_ptr, autopick_type *entry)
731 concptr q = _("どのアイテムを登録しますか? ", "Enter which item? ");
732 concptr s = _("アイテムを持っていない。", "You have nothing to enter.");
734 o_ptr = choose_object(player_ptr, nullptr, q, s, USE_INVEN | USE_FLOOR | USE_EQUIP);
739 autopick_entry_from_object(player_ptr, entry, o_ptr);