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] == ':')
49 entry->flag[0] = entry->flag[1] = 0L;
53 byte act = DO_AUTOPICK | DO_DISPLAY;
55 if ((act & DO_AUTOPICK) && *str == '!') {
57 act |= DO_AUTODESTROY;
62 if ((act & DO_AUTOPICK) && *str == '~') {
69 if ((act & DO_AUTOPICK) && *str == ';') {
71 act |= DO_QUERY_AUTOPICK;
76 if ((act & DO_DISPLAY) && *str == '(') {
85 concptr insc = nullptr;
86 char buf[MAX_LINELEN];
88 for (i = 0; *str; i++) {
104 c = (char)tolower(c);
110 if (!allow_default && *buf == 0)
112 if (*buf == 0 && insc)
115 concptr prev_ptr, ptr;
116 ptr = prev_ptr = buf;
117 concptr old_ptr = nullptr;
118 while (old_ptr != ptr) {
120 if (MATCH_KEY(KEY_ALL))
122 if (MATCH_KEY(KEY_COLLECTING))
123 ADD_FLG(FLG_COLLECTING);
124 if (MATCH_KEY(KEY_UNAWARE))
125 ADD_FLG(FLG_UNAWARE);
126 if (MATCH_KEY(KEY_UNIDENTIFIED))
127 ADD_FLG(FLG_UNIDENTIFIED);
128 if (MATCH_KEY(KEY_IDENTIFIED))
129 ADD_FLG(FLG_IDENTIFIED);
130 if (MATCH_KEY(KEY_STAR_IDENTIFIED))
131 ADD_FLG(FLG_STAR_IDENTIFIED);
132 if (MATCH_KEY(KEY_BOOSTED))
133 ADD_FLG(FLG_BOOSTED);
135 /*** Weapons whose dd*ds is more than nn ***/
136 if (MATCH_KEY2(KEY_MORE_THAN)) {
143 while ('0' <= *ptr && *ptr <= '9') {
144 entry->dice = 10 * entry->dice + (*ptr - '0');
149 if (k > 0 && k <= 2) {
150 (void)MATCH_KEY(KEY_DICE);
151 ADD_FLG(FLG_MORE_DICE);
156 /*** Items whose magical bonus is more than n ***/
157 if (MATCH_KEY2(KEY_MORE_BONUS)) {
164 while ('0' <= *ptr && *ptr <= '9') {
165 entry->bonus = 10 * entry->bonus + (*ptr - '0');
170 if (k > 0 && k <= 2) {
172 (void)MATCH_KEY(KEY_MORE_BONUS2);
177 ADD_FLG(FLG_MORE_BONUS);
182 if (MATCH_KEY(KEY_WORTHLESS))
183 ADD_FLG(FLG_WORTHLESS);
184 if (MATCH_KEY(KEY_EGO))
186 if (MATCH_KEY(KEY_GOOD))
188 if (MATCH_KEY(KEY_NAMELESS))
189 ADD_FLG(FLG_NAMELESS);
190 if (MATCH_KEY(KEY_AVERAGE))
191 ADD_FLG(FLG_AVERAGE);
192 if (MATCH_KEY(KEY_RARE))
194 if (MATCH_KEY(KEY_COMMON))
196 if (MATCH_KEY(KEY_WANTED))
198 if (MATCH_KEY(KEY_UNIQUE))
200 if (MATCH_KEY(KEY_HUMAN))
202 if (MATCH_KEY(KEY_UNREADABLE))
203 ADD_FLG(FLG_UNREADABLE);
204 if (MATCH_KEY(KEY_REALM1))
206 if (MATCH_KEY(KEY_REALM2))
208 if (MATCH_KEY(KEY_FIRST))
210 if (MATCH_KEY(KEY_SECOND))
212 if (MATCH_KEY(KEY_THIRD))
214 if (MATCH_KEY(KEY_FOURTH))
219 if (MATCH_KEY2(KEY_ARTIFACT))
220 ADD_FLG_NOUN(FLG_ARTIFACT);
222 if (MATCH_KEY2(KEY_ITEMS))
223 ADD_FLG_NOUN(FLG_ITEMS);
224 else if (MATCH_KEY2(KEY_WEAPONS))
225 ADD_FLG_NOUN(FLG_WEAPONS);
226 else if (MATCH_KEY2(KEY_FAVORITE_WEAPONS))
227 ADD_FLG_NOUN(FLG_FAVORITE_WEAPONS);
228 else if (MATCH_KEY2(KEY_ARMORS))
229 ADD_FLG_NOUN(FLG_ARMORS);
230 else if (MATCH_KEY2(KEY_MISSILES))
231 ADD_FLG_NOUN(FLG_MISSILES);
232 else if (MATCH_KEY2(KEY_DEVICES))
233 ADD_FLG_NOUN(FLG_DEVICES);
234 else if (MATCH_KEY2(KEY_LIGHTS))
235 ADD_FLG_NOUN(FLG_LIGHTS);
236 else if (MATCH_KEY2(KEY_JUNKS))
237 ADD_FLG_NOUN(FLG_JUNKS);
238 else if (MATCH_KEY2(KEY_CORPSES))
239 ADD_FLG_NOUN(FLG_CORPSES);
240 else if (MATCH_KEY2(KEY_SPELLBOOKS))
241 ADD_FLG_NOUN(FLG_SPELLBOOKS);
242 else if (MATCH_KEY2(KEY_HAFTED))
243 ADD_FLG_NOUN(FLG_HAFTED);
244 else if (MATCH_KEY2(KEY_SHIELDS))
245 ADD_FLG_NOUN(FLG_SHIELDS);
246 else if (MATCH_KEY2(KEY_BOWS))
247 ADD_FLG_NOUN(FLG_BOWS);
248 else if (MATCH_KEY2(KEY_RINGS))
249 ADD_FLG_NOUN(FLG_RINGS);
250 else if (MATCH_KEY2(KEY_AMULETS))
251 ADD_FLG_NOUN(FLG_AMULETS);
252 else if (MATCH_KEY2(KEY_SUITS))
253 ADD_FLG_NOUN(FLG_SUITS);
254 else if (MATCH_KEY2(KEY_CLOAKS))
255 ADD_FLG_NOUN(FLG_CLOAKS);
256 else if (MATCH_KEY2(KEY_HELMS))
257 ADD_FLG_NOUN(FLG_HELMS);
258 else if (MATCH_KEY2(KEY_GLOVES))
259 ADD_FLG_NOUN(FLG_GLOVES);
260 else if (MATCH_KEY2(KEY_BOOTS))
261 ADD_FLG_NOUN(FLG_BOOTS);
266 else if (ptr[0] == kanji_colon[0] && ptr[1] == kanji_colon[1])
269 else if (*ptr == '\0') {
271 ADD_FLG_NOUN(FLG_ITEMS);
273 if (prev_flg != -1) {
274 entry->flag[prev_flg / 32] &= ~(1UL << (prev_flg % 32));
281 entry->insc = insc != nullptr ? insc : "";
287 * @brief Get auto-picker entry from o_ptr.
289 void autopick_entry_from_object(PlayerType *player_ptr, autopick_type *entry, ObjectType *o_ptr)
291 /* Assume that object name is to be added */
293 GAME_TEXT name_str[MAX_NLEN + 32];
295 auto insc = quark_str(o_ptr->inscription);
296 entry->insc = insc != nullptr ? insc : "";
297 entry->action = DO_AUTOPICK | DO_DISPLAY;
298 entry->flag[0] = entry->flag[1] = 0L;
301 // エゴ銘が邪魔かもしれないので、デフォルトで「^」は付けない.
302 // We can always use the ^ mark in English.
303 bool is_hat_added = _(false, true);
304 if (!o_ptr->is_aware()) {
305 ADD_FLG(FLG_UNAWARE);
307 } else if (!o_ptr->is_known()) {
308 if (!(o_ptr->ident & IDENT_SENSE)) {
309 ADD_FLG(FLG_UNIDENTIFIED);
312 switch (o_ptr->feeling) {
315 ADD_FLG(FLG_NAMELESS);
321 ADD_FLG(FLG_NAMELESS);
322 ADD_FLG(FLG_WORTHLESS);
328 ADD_FLG(FLG_WORTHLESS);
343 if (o_ptr->is_ego()) {
344 if (o_ptr->is_weapon_armour_ammo()) {
346 * Base name of ego weapons and armors
347 * are almost meaningless.
348 * Register the ego type only.
350 auto *e_ptr = &e_info[o_ptr->ego_idx];
352 /* エゴ銘には「^」マークが使える */
353 sprintf(name_str, "^%s", e_ptr->name.c_str());
355 /* We ommit the basename and cannot use the ^ mark */
356 strcpy(name_str, e_ptr->name.c_str());
359 if (!o_ptr->is_rare())
364 } else if (o_ptr->is_artifact())
365 ADD_FLG(FLG_ARTIFACT);
367 if (o_ptr->is_equipment())
368 ADD_FLG(FLG_NAMELESS);
374 if (o_ptr->is_melee_weapon()) {
375 auto *k_ptr = &k_info[o_ptr->k_idx];
377 if ((o_ptr->dd != k_ptr->dd) || (o_ptr->ds != k_ptr->ds))
378 ADD_FLG(FLG_BOOSTED);
381 if (object_is_bounty(player_ptr, o_ptr)) {
382 REM_FLG(FLG_WORTHLESS);
386 if ((o_ptr->tval == ItemKindType::CORPSE || o_ptr->tval == ItemKindType::STATUE) && r_info[o_ptr->pval].kind_flags.has(MonsterKindType::UNIQUE)) {
390 if (o_ptr->tval == ItemKindType::CORPSE && angband_strchr("pht", r_info[o_ptr->pval].d_char)) {
394 if (o_ptr->tval >= ItemKindType::LIFE_BOOK && !check_book_realm(player_ptr, o_ptr->tval, o_ptr->sval)) {
395 ADD_FLG(FLG_UNREADABLE);
396 if (o_ptr->tval != ItemKindType::ARCANE_BOOK)
400 PlayerClass pc(player_ptr);
401 auto realm_except_class = pc.equals(PlayerClassType::SORCERER) || pc.equals(PlayerClassType::RED_MAGE);
403 if ((get_realm1_book(player_ptr) == o_ptr->tval) && !realm_except_class) {
408 if ((get_realm2_book(player_ptr) == o_ptr->tval) && !realm_except_class) {
413 if (o_ptr->tval >= ItemKindType::LIFE_BOOK && 0 == o_ptr->sval)
415 if (o_ptr->tval >= ItemKindType::LIFE_BOOK && 1 == o_ptr->sval)
417 if (o_ptr->tval >= ItemKindType::LIFE_BOOK && 2 == o_ptr->sval)
419 if (o_ptr->tval >= ItemKindType::LIFE_BOOK && 3 == o_ptr->sval)
422 if (o_ptr->is_ammo())
423 ADD_FLG(FLG_MISSILES);
424 else if (o_ptr->tval == ItemKindType::SCROLL || o_ptr->tval == ItemKindType::STAFF || o_ptr->tval == ItemKindType::WAND || o_ptr->tval == ItemKindType::ROD)
425 ADD_FLG(FLG_DEVICES);
426 else if (o_ptr->tval == ItemKindType::LITE)
428 else if (o_ptr->tval == ItemKindType::SKELETON || o_ptr->tval == ItemKindType::BOTTLE || o_ptr->tval == ItemKindType::JUNK || o_ptr->tval == ItemKindType::STATUE)
430 else if (o_ptr->tval == ItemKindType::CORPSE)
431 ADD_FLG(FLG_CORPSES);
432 else if (o_ptr->tval >= ItemKindType::LIFE_BOOK)
433 ADD_FLG(FLG_SPELLBOOKS);
434 else if (o_ptr->tval == ItemKindType::POLEARM || o_ptr->tval == ItemKindType::SWORD || o_ptr->tval == ItemKindType::DIGGING || o_ptr->tval == ItemKindType::HAFTED)
435 ADD_FLG(FLG_WEAPONS);
436 else if (o_ptr->tval == ItemKindType::SHIELD)
437 ADD_FLG(FLG_SHIELDS);
438 else if (o_ptr->tval == ItemKindType::BOW)
440 else if (o_ptr->tval == ItemKindType::RING)
442 else if (o_ptr->tval == ItemKindType::AMULET)
443 ADD_FLG(FLG_AMULETS);
444 else if (o_ptr->tval == ItemKindType::DRAG_ARMOR || o_ptr->tval == ItemKindType::HARD_ARMOR || o_ptr->tval == ItemKindType::SOFT_ARMOR)
446 else if (o_ptr->tval == ItemKindType::CLOAK)
448 else if (o_ptr->tval == ItemKindType::HELM)
450 else if (o_ptr->tval == ItemKindType::GLOVES)
452 else if (o_ptr->tval == ItemKindType::BOOTS)
456 str_tolower(name_str);
457 entry->name = name_str;
461 GAME_TEXT o_name[MAX_NLEN];
462 describe_flavor(player_ptr, o_name, o_ptr, (OD_NO_FLAVOR | OD_OMIT_PREFIX | OD_NO_PLURAL | OD_NAME_ONLY));
465 * If necessary, add a '^' which indicates the
468 sprintf(name_str, "%s%s", is_hat_added ? "^" : "", o_name);
469 str_tolower(name_str);
470 entry->name = name_str;
474 * @brief Reconstruct preference line from entry
476 concptr autopick_line_from_entry(autopick_type *entry)
478 char buf[MAX_LINELEN];
480 if (!(entry->action & DO_DISPLAY))
482 if (entry->action & DO_QUERY_AUTOPICK)
484 if (entry->action & DO_AUTODESTROY)
486 if (entry->action & DONT_AUTOPICK)
493 if (IS_FLG(FLG_COLLECTING))
494 ADD_KEY(KEY_COLLECTING);
495 if (IS_FLG(FLG_UNAWARE))
496 ADD_KEY(KEY_UNAWARE);
497 if (IS_FLG(FLG_UNIDENTIFIED))
498 ADD_KEY(KEY_UNIDENTIFIED);
499 if (IS_FLG(FLG_IDENTIFIED))
500 ADD_KEY(KEY_IDENTIFIED);
501 if (IS_FLG(FLG_STAR_IDENTIFIED))
502 ADD_KEY(KEY_STAR_IDENTIFIED);
503 if (IS_FLG(FLG_BOOSTED))
504 ADD_KEY(KEY_BOOSTED);
506 if (IS_FLG(FLG_MORE_DICE)) {
507 ADD_KEY(KEY_MORE_THAN);
508 strcat(ptr, format("%d", entry->dice));
512 if (IS_FLG(FLG_MORE_BONUS)) {
513 ADD_KEY(KEY_MORE_BONUS);
514 strcat(ptr, format("%d", entry->bonus));
515 ADD_KEY(KEY_MORE_BONUS2);
518 if (IS_FLG(FLG_UNREADABLE))
519 ADD_KEY(KEY_UNREADABLE);
520 if (IS_FLG(FLG_REALM1))
522 if (IS_FLG(FLG_REALM2))
524 if (IS_FLG(FLG_FIRST))
526 if (IS_FLG(FLG_SECOND))
528 if (IS_FLG(FLG_THIRD))
530 if (IS_FLG(FLG_FOURTH))
532 if (IS_FLG(FLG_WANTED))
534 if (IS_FLG(FLG_UNIQUE))
536 if (IS_FLG(FLG_HUMAN))
538 if (IS_FLG(FLG_WORTHLESS))
539 ADD_KEY(KEY_WORTHLESS);
540 if (IS_FLG(FLG_GOOD))
542 if (IS_FLG(FLG_NAMELESS))
543 ADD_KEY(KEY_NAMELESS);
544 if (IS_FLG(FLG_AVERAGE))
545 ADD_KEY(KEY_AVERAGE);
546 if (IS_FLG(FLG_RARE))
548 if (IS_FLG(FLG_COMMON))
553 if (IS_FLG(FLG_ARTIFACT))
554 ADD_KEY(KEY_ARTIFACT);
556 bool sepa_flag = true;
557 if (IS_FLG(FLG_ITEMS))
559 else if (IS_FLG(FLG_WEAPONS))
560 ADD_KEY2(KEY_WEAPONS);
561 else if (IS_FLG(FLG_FAVORITE_WEAPONS))
562 ADD_KEY2(KEY_FAVORITE_WEAPONS);
563 else if (IS_FLG(FLG_ARMORS))
564 ADD_KEY2(KEY_ARMORS);
565 else if (IS_FLG(FLG_MISSILES))
566 ADD_KEY2(KEY_MISSILES);
567 else if (IS_FLG(FLG_DEVICES))
568 ADD_KEY2(KEY_DEVICES);
569 else if (IS_FLG(FLG_LIGHTS))
570 ADD_KEY2(KEY_LIGHTS);
571 else if (IS_FLG(FLG_JUNKS))
573 else if (IS_FLG(FLG_CORPSES))
574 ADD_KEY2(KEY_CORPSES);
575 else if (IS_FLG(FLG_SPELLBOOKS))
576 ADD_KEY2(KEY_SPELLBOOKS);
577 else if (IS_FLG(FLG_HAFTED))
578 ADD_KEY2(KEY_HAFTED);
579 else if (IS_FLG(FLG_SHIELDS))
580 ADD_KEY2(KEY_SHIELDS);
581 else if (IS_FLG(FLG_BOWS))
583 else if (IS_FLG(FLG_RINGS))
585 else if (IS_FLG(FLG_AMULETS))
586 ADD_KEY2(KEY_AMULETS);
587 else if (IS_FLG(FLG_SUITS))
589 else if (IS_FLG(FLG_CLOAKS))
590 ADD_KEY2(KEY_CLOAKS);
591 else if (IS_FLG(FLG_HELMS))
593 else if (IS_FLG(FLG_GLOVES))
594 ADD_KEY2(KEY_GLOVES);
595 else if (IS_FLG(FLG_BOOTS))
597 else if (!IS_FLG(FLG_ARTIFACT))
600 if (!entry->name.empty()) {
606 while (entry->name[j] && i < MAX_LINELEN - 2 - 1) {
608 if (iskanji(entry->name[j]))
609 buf[i++] = entry->name[j++];
611 buf[i++] = entry->name[j++];
616 if (entry->insc.empty())
617 return string_make(buf);
623 while (entry->insc[j] && i < MAX_LINELEN - 2) {
625 if (iskanji(entry->insc[j]))
626 buf[i++] = entry->insc[j++];
628 buf[i++] = entry->insc[j++];
632 return string_make(buf);
636 * @brief Reconstruct preference line from entry and kill entry
638 concptr autopick_line_from_entry_kill(autopick_type *entry)
640 concptr ptr = autopick_line_from_entry(entry);
645 * @brief Choose an item and get auto-picker entry from it.
647 bool entry_from_choosed_object(PlayerType *player_ptr, autopick_type *entry)
649 concptr q = _("どのアイテムを登録しますか? ", "Enter which item? ");
650 concptr s = _("アイテムを持っていない。", "You have nothing to enter.");
652 o_ptr = choose_object(player_ptr, nullptr, q, s, USE_INVEN | USE_FLOOR | USE_EQUIP);
656 autopick_entry_from_object(player_ptr, entry, o_ptr);