3 * @brief 自動拾い機能の実装 / Object Auto-picker/Destroyer
6 * Copyright (c) 2002 Mogami\n
8 * This software may be copied and distributed for educational, research, and\n
9 * not for profit purposes provided that this copyright and statement are\n
10 * included in all such copies.\n
11 * 2014 Deskull rearranged comment for Doxygen.\n
16 #include "autopick/autopick-commands-table.h"
17 #include "autopick/autopick-dirty-flags.h"
18 #include "autopick/autopick-editor-table.h"
19 #include "autopick/autopick-flags-table.h"
20 #include "autopick/autopick-key-flag-process.h"
21 #include "autopick/autopick-menu-data-table.h"
22 #include "autopick/autopick-keys-table.h"
23 #include "autopick/autopick-util.h"
25 #include "autopick/autopick.h"
27 #include "core/show-file.h"
28 #include "cmd/cmd-save.h"
29 #include "io/read-pref-file.h"
33 #include "market/store.h"
34 #include "player-status.h"
35 #include "player-move.h"
36 #include "player-class.h"
37 #include "player-race.h"
38 #include "player-inventory.h"
39 #include "view/display-player.h"
40 #include "object/object-kind.h"
41 #include "object-ego.h"
42 #include "object-flavor.h"
43 #include "object-hook.h"
49 #include "monsterrace.h"
50 #include "view-mainwindow.h" // 暫定。後で消す
53 static char kanji_colon[] = ":";
57 * 自動拾い/破壊設定のリストに関する変数 / List for auto-picker/destroyer entries
59 int max_autopick = 0; /*!< 現在登録している自動拾い/破壊設定の数 */
60 int max_max_autopick = 0; /*!< 自動拾い/破壊設定の限界数 */
61 autopick_type *autopick_list = NULL; /*!< 自動拾い/破壊設定構造体のポインタ配列 */
64 * Automatically destroy an item if it is to be destroyed
66 * When always_pickup is 'yes', we disable auto-destroyer function of
67 * auto-picker/destroyer, and do only easy-auto-destroyer.
69 static object_type autopick_last_destroyed_object;
72 * A function to create new entry
74 static bool autopick_new_entry(autopick_type *entry, concptr str, bool allow_default)
76 if (str[0] && str[1] == ':') switch (str[0])
79 case 'A': case 'P': case 'C':
83 entry->flag[0] = entry->flag[1] = 0L;
87 byte act = DO_AUTOPICK | DO_DISPLAY;
90 if ((act & DO_AUTOPICK) && *str == '!')
93 act |= DO_AUTODESTROY;
98 if ((act & DO_AUTOPICK) && *str == '~')
101 act |= DONT_AUTOPICK;
106 if ((act & DO_AUTOPICK) && *str == ';')
109 act |= DO_QUERY_AUTOPICK;
114 if ((act & DO_DISPLAY) && *str == '(')
125 char buf[MAX_LINELEN];
127 for (i = 0; *str; i++)
145 if (isupper(c)) c = (char)tolower(c);
151 if (!allow_default && *buf == 0) return FALSE;
152 if (*buf == 0 && insc) return FALSE;
154 concptr prev_ptr, ptr;
155 ptr = prev_ptr = buf;
156 concptr old_ptr = NULL;
157 while (old_ptr != ptr)
160 if (MATCH_KEY(KEY_ALL)) ADD_FLG(FLG_ALL);
161 if (MATCH_KEY(KEY_COLLECTING)) ADD_FLG(FLG_COLLECTING);
162 if (MATCH_KEY(KEY_UNAWARE)) ADD_FLG(FLG_UNAWARE);
163 if (MATCH_KEY(KEY_UNIDENTIFIED)) ADD_FLG(FLG_UNIDENTIFIED);
164 if (MATCH_KEY(KEY_IDENTIFIED)) ADD_FLG(FLG_IDENTIFIED);
165 if (MATCH_KEY(KEY_STAR_IDENTIFIED)) ADD_FLG(FLG_STAR_IDENTIFIED);
166 if (MATCH_KEY(KEY_BOOSTED)) ADD_FLG(FLG_BOOSTED);
168 /*** Weapons whose dd*ds is more than nn ***/
169 if (MATCH_KEY2(KEY_MORE_THAN))
174 while (' ' == *ptr) ptr++;
176 while ('0' <= *ptr && *ptr <= '9')
178 entry->dice = 10 * entry->dice + (*ptr - '0');
185 (void)MATCH_KEY(KEY_DICE);
186 ADD_FLG(FLG_MORE_DICE);
192 /*** Items whose magical bonus is more than n ***/
193 if (MATCH_KEY2(KEY_MORE_BONUS))
198 while (' ' == *ptr) ptr++;
200 while ('0' <= *ptr && *ptr <= '9')
202 entry->bonus = 10 * entry->bonus + (*ptr - '0');
210 (void)MATCH_KEY(KEY_MORE_BONUS2);
212 if (' ' == *ptr) ptr++;
214 ADD_FLG(FLG_MORE_BONUS);
220 if (MATCH_KEY(KEY_WORTHLESS)) ADD_FLG(FLG_WORTHLESS);
221 if (MATCH_KEY(KEY_EGO)) ADD_FLG(FLG_EGO);
222 if (MATCH_KEY(KEY_GOOD)) ADD_FLG(FLG_GOOD);
223 if (MATCH_KEY(KEY_NAMELESS)) ADD_FLG(FLG_NAMELESS);
224 if (MATCH_KEY(KEY_AVERAGE)) ADD_FLG(FLG_AVERAGE);
225 if (MATCH_KEY(KEY_RARE)) ADD_FLG(FLG_RARE);
226 if (MATCH_KEY(KEY_COMMON)) ADD_FLG(FLG_COMMON);
227 if (MATCH_KEY(KEY_WANTED)) ADD_FLG(FLG_WANTED);
228 if (MATCH_KEY(KEY_UNIQUE)) ADD_FLG(FLG_UNIQUE);
229 if (MATCH_KEY(KEY_HUMAN)) ADD_FLG(FLG_HUMAN);
230 if (MATCH_KEY(KEY_UNREADABLE)) ADD_FLG(FLG_UNREADABLE);
231 if (MATCH_KEY(KEY_REALM1)) ADD_FLG(FLG_REALM1);
232 if (MATCH_KEY(KEY_REALM2)) ADD_FLG(FLG_REALM2);
233 if (MATCH_KEY(KEY_FIRST)) ADD_FLG(FLG_FIRST);
234 if (MATCH_KEY(KEY_SECOND)) ADD_FLG(FLG_SECOND);
235 if (MATCH_KEY(KEY_THIRD)) ADD_FLG(FLG_THIRD);
236 if (MATCH_KEY(KEY_FOURTH)) ADD_FLG(FLG_FOURTH);
240 if (MATCH_KEY2(KEY_ARTIFACT)) ADD_FLG_NOUN(FLG_ARTIFACT);
242 if (MATCH_KEY2(KEY_ITEMS)) ADD_FLG_NOUN(FLG_ITEMS);
243 else if (MATCH_KEY2(KEY_WEAPONS)) ADD_FLG_NOUN(FLG_WEAPONS);
244 else if (MATCH_KEY2(KEY_FAVORITE_WEAPONS)) ADD_FLG_NOUN(FLG_FAVORITE_WEAPONS);
245 else if (MATCH_KEY2(KEY_ARMORS)) ADD_FLG_NOUN(FLG_ARMORS);
246 else if (MATCH_KEY2(KEY_MISSILES)) ADD_FLG_NOUN(FLG_MISSILES);
247 else if (MATCH_KEY2(KEY_DEVICES)) ADD_FLG_NOUN(FLG_DEVICES);
248 else if (MATCH_KEY2(KEY_LIGHTS)) ADD_FLG_NOUN(FLG_LIGHTS);
249 else if (MATCH_KEY2(KEY_JUNKS)) ADD_FLG_NOUN(FLG_JUNKS);
250 else if (MATCH_KEY2(KEY_CORPSES)) ADD_FLG_NOUN(FLG_CORPSES);
251 else if (MATCH_KEY2(KEY_SPELLBOOKS)) ADD_FLG_NOUN(FLG_SPELLBOOKS);
252 else if (MATCH_KEY2(KEY_HAFTED)) ADD_FLG_NOUN(FLG_HAFTED);
253 else if (MATCH_KEY2(KEY_SHIELDS)) ADD_FLG_NOUN(FLG_SHIELDS);
254 else if (MATCH_KEY2(KEY_BOWS)) ADD_FLG_NOUN(FLG_BOWS);
255 else if (MATCH_KEY2(KEY_RINGS)) ADD_FLG_NOUN(FLG_RINGS);
256 else if (MATCH_KEY2(KEY_AMULETS)) ADD_FLG_NOUN(FLG_AMULETS);
257 else if (MATCH_KEY2(KEY_SUITS)) ADD_FLG_NOUN(FLG_SUITS);
258 else if (MATCH_KEY2(KEY_CLOAKS)) ADD_FLG_NOUN(FLG_CLOAKS);
259 else if (MATCH_KEY2(KEY_HELMS)) ADD_FLG_NOUN(FLG_HELMS);
260 else if (MATCH_KEY2(KEY_GLOVES)) ADD_FLG_NOUN(FLG_GLOVES);
261 else if (MATCH_KEY2(KEY_BOOTS)) ADD_FLG_NOUN(FLG_BOOTS);
266 else if (ptr[0] == kanji_colon[0] && ptr[1] == kanji_colon[1])
269 else if (*ptr == '\0')
272 ADD_FLG_NOUN(FLG_ITEMS);
278 entry->flag[prev_flg / 32] &= ~(1L << (prev_flg % 32));
283 entry->name = string_make(ptr);
285 entry->insc = string_make(insc);
292 * Get auto-picker entry from o_ptr.
294 static void autopick_entry_from_object(player_type *player_ptr, autopick_type *entry, object_type *o_ptr)
296 /* Assume that object name is to be added */
300 /* エゴ銘が邪魔かもしれないので、デフォルトで「^」は付けない */
301 bool bol_mark = FALSE;
303 /* We can always use the ^ mark in English */
304 bool bol_mark = TRUE;
307 GAME_TEXT name_str[MAX_NLEN];
310 entry->insc = string_make(quark_str(o_ptr->inscription));
311 entry->action = DO_AUTOPICK | DO_DISPLAY;
312 entry->flag[0] = entry->flag[1] = 0L;
315 if (!object_is_aware(o_ptr))
317 ADD_FLG(FLG_UNAWARE);
320 else if (!object_is_known(o_ptr))
322 if (!(o_ptr->ident & IDENT_SENSE))
324 ADD_FLG(FLG_UNIDENTIFIED);
329 switch (o_ptr->feeling)
333 ADD_FLG(FLG_NAMELESS);
339 ADD_FLG(FLG_NAMELESS);
340 ADD_FLG(FLG_WORTHLESS);
346 ADD_FLG(FLG_WORTHLESS);
363 if (object_is_ego(o_ptr))
365 if (object_is_weapon_armour_ammo(o_ptr))
368 * Base name of ego weapons and armors
369 * are almost meaningless.
370 * Register the ego type only.
372 ego_item_type *e_ptr = &e_info[o_ptr->name2];
374 /* エゴ銘には「^」マークが使える */
375 sprintf(name_str, "^%s", e_name + e_ptr->name);
377 /* We ommit the basename and cannot use the ^ mark */
378 strcpy(name_str, e_name + e_ptr->name);
381 if (!object_is_rare(o_ptr)) ADD_FLG(FLG_COMMON);
386 else if (object_is_artifact(o_ptr))
387 ADD_FLG(FLG_ARTIFACT);
390 if (object_is_equipment(o_ptr))
391 ADD_FLG(FLG_NAMELESS);
398 if (object_is_melee_weapon(o_ptr))
400 object_kind *k_ptr = &k_info[o_ptr->k_idx];
402 if ((o_ptr->dd != k_ptr->dd) || (o_ptr->ds != k_ptr->ds))
403 ADD_FLG(FLG_BOOSTED);
406 if (object_is_bounty(o_ptr))
408 REM_FLG(FLG_WORTHLESS);
412 if ((o_ptr->tval == TV_CORPSE || o_ptr->tval == TV_STATUE)
413 && (r_info[o_ptr->pval].flags1 & RF1_UNIQUE))
418 if (o_ptr->tval == TV_CORPSE && my_strchr("pht", r_info[o_ptr->pval].d_char))
423 if (o_ptr->tval >= TV_LIFE_BOOK &&
424 !check_book_realm(player_ptr, o_ptr->tval, o_ptr->sval))
426 ADD_FLG(FLG_UNREADABLE);
427 if (o_ptr->tval != TV_ARCANE_BOOK) name = FALSE;
430 if (REALM1_BOOK == o_ptr->tval &&
431 player_ptr->pclass != CLASS_SORCERER &&
432 player_ptr->pclass != CLASS_RED_MAGE)
438 if (REALM2_BOOK == o_ptr->tval &&
439 player_ptr->pclass != CLASS_SORCERER &&
440 player_ptr->pclass != CLASS_RED_MAGE)
446 if (o_ptr->tval >= TV_LIFE_BOOK && 0 == o_ptr->sval)
448 if (o_ptr->tval >= TV_LIFE_BOOK && 1 == o_ptr->sval)
450 if (o_ptr->tval >= TV_LIFE_BOOK && 2 == o_ptr->sval)
452 if (o_ptr->tval >= TV_LIFE_BOOK && 3 == o_ptr->sval)
455 if (object_is_ammo(o_ptr))
456 ADD_FLG(FLG_MISSILES);
457 else if (o_ptr->tval == TV_SCROLL || o_ptr->tval == TV_STAFF
458 || o_ptr->tval == TV_WAND || o_ptr->tval == TV_ROD)
459 ADD_FLG(FLG_DEVICES);
460 else if (o_ptr->tval == TV_LITE)
462 else if (o_ptr->tval == TV_SKELETON || o_ptr->tval == TV_BOTTLE
463 || o_ptr->tval == TV_JUNK || o_ptr->tval == TV_STATUE)
465 else if (o_ptr->tval == TV_CORPSE)
466 ADD_FLG(FLG_CORPSES);
467 else if (o_ptr->tval >= TV_LIFE_BOOK)
468 ADD_FLG(FLG_SPELLBOOKS);
469 else if (o_ptr->tval == TV_POLEARM || o_ptr->tval == TV_SWORD
470 || o_ptr->tval == TV_DIGGING || o_ptr->tval == TV_HAFTED)
471 ADD_FLG(FLG_WEAPONS);
472 else if (o_ptr->tval == TV_SHIELD)
473 ADD_FLG(FLG_SHIELDS);
474 else if (o_ptr->tval == TV_BOW)
476 else if (o_ptr->tval == TV_RING)
478 else if (o_ptr->tval == TV_AMULET)
479 ADD_FLG(FLG_AMULETS);
480 else if (o_ptr->tval == TV_DRAG_ARMOR || o_ptr->tval == TV_HARD_ARMOR ||
481 o_ptr->tval == TV_SOFT_ARMOR)
483 else if (o_ptr->tval == TV_CLOAK)
485 else if (o_ptr->tval == TV_HELM)
487 else if (o_ptr->tval == TV_GLOVES)
489 else if (o_ptr->tval == TV_BOOTS)
494 str_tolower(name_str);
495 entry->name = string_make(name_str);
499 GAME_TEXT o_name[MAX_NLEN];
500 object_desc(player_ptr, o_name, o_ptr, (OD_NO_FLAVOR | OD_OMIT_PREFIX | OD_NO_PLURAL | OD_NAME_ONLY));
503 * If necessary, add a '^' which indicates the
506 sprintf(name_str, "%s%s", bol_mark ? "^" : "", o_name);
507 str_tolower(name_str);
508 entry->name = string_make(name_str);
513 * A function to delete entry
515 static void autopick_free_entry(autopick_type *entry)
517 string_free(entry->name);
518 string_free(entry->insc);
525 * Initialize the autopick
527 static void init_autopick(void)
529 static const char easy_autopick_inscription[] = "(:=g";
535 max_max_autopick = MAX_AUTOPICK_DEFAULT;
536 C_MAKE(autopick_list, max_max_autopick, autopick_type);
540 for (i = 0; i < max_autopick; i++)
541 autopick_free_entry(&autopick_list[i]);
544 autopick_new_entry(&entry, easy_autopick_inscription, TRUE);
545 autopick_list[max_autopick++] = entry;
550 * Get file name for autopick preference
552 static concptr pickpref_filename(player_type *player_ptr, int filename_mode)
554 static const char namebase[] = _("picktype", "pickpref");
556 switch (filename_mode)
559 return format("%s.prf", namebase);
562 return format("%s-%s.prf", namebase, player_ptr->base_name);
571 * Load an autopick preference file
573 void autopick_load_pref(player_type *player_ptr, bool disp_mes)
577 my_strcpy(buf, pickpref_filename(player_ptr, PT_WITH_PNAME), sizeof(buf));
578 errr err = process_autopick_file(player_ptr, buf);
579 if (err == 0 && disp_mes)
581 msg_format(_("%sを読み込みました。", "Loaded '%s'."), buf);
586 my_strcpy(buf, pickpref_filename(player_ptr, PT_DEFAULT), sizeof(buf));
587 err = process_autopick_file(player_ptr, buf);
588 if (err == 0 && disp_mes)
590 msg_format(_("%sを読み込みました。", "Loaded '%s'."), buf);
596 msg_print(_("自動拾い設定ファイルの読み込みに失敗しました。", "Failed to reload autopick preference."));
602 * Add one line to autopick_list[]
604 static void add_autopick_list(autopick_type *entry)
606 if (max_autopick >= max_max_autopick)
608 int old_max_max_autopick = max_max_autopick;
609 autopick_type *old_autopick_list = autopick_list;
610 max_max_autopick += MAX_AUTOPICK_DEFAULT;
611 C_MAKE(autopick_list, max_max_autopick, autopick_type);
612 (void)C_COPY(autopick_list, old_autopick_list, old_max_max_autopick, autopick_type);
613 C_KILL(old_autopick_list, old_max_max_autopick, autopick_type);
616 autopick_list[max_autopick] = *entry;
622 * Process line for auto picker/destroyer.
624 void process_autopick_file_command(char *buf)
626 autopick_type an_entry, *entry = &an_entry;
628 for (i = 0; buf[i]; i++)
637 if (iswspace(buf[i]) && buf[i] != ' ')
642 if (!autopick_new_entry(entry, buf, FALSE)) return;
644 for (i = 0; i < max_autopick; i++)
646 if (!strcmp(entry->name, autopick_list[i].name)
647 && entry->flag[0] == autopick_list[i].flag[0]
648 && entry->flag[1] == autopick_list[i].flag[1]
649 && entry->dice == autopick_list[i].dice
650 && entry->bonus == autopick_list[i].bonus)
652 autopick_free_entry(entry);
657 add_autopick_list(entry);
663 * Reconstruct preference line from entry
665 concptr autopick_line_from_entry(autopick_type *entry)
667 char buf[MAX_LINELEN];
669 if (!(entry->action & DO_DISPLAY)) strcat(buf, "(");
670 if (entry->action & DO_QUERY_AUTOPICK) strcat(buf, ";");
671 if (entry->action & DO_AUTODESTROY) strcat(buf, "!");
672 if (entry->action & DONT_AUTOPICK) strcat(buf, "~");
676 if (IS_FLG(FLG_ALL)) ADD_KEY(KEY_ALL);
677 if (IS_FLG(FLG_COLLECTING)) ADD_KEY(KEY_COLLECTING);
678 if (IS_FLG(FLG_UNAWARE)) ADD_KEY(KEY_UNAWARE);
679 if (IS_FLG(FLG_UNIDENTIFIED)) ADD_KEY(KEY_UNIDENTIFIED);
680 if (IS_FLG(FLG_IDENTIFIED)) ADD_KEY(KEY_IDENTIFIED);
681 if (IS_FLG(FLG_STAR_IDENTIFIED)) ADD_KEY(KEY_STAR_IDENTIFIED);
682 if (IS_FLG(FLG_BOOSTED)) ADD_KEY(KEY_BOOSTED);
684 if (IS_FLG(FLG_MORE_DICE))
686 ADD_KEY(KEY_MORE_THAN);
687 strcat(ptr, format("%d", entry->dice));
691 if (IS_FLG(FLG_MORE_BONUS))
693 ADD_KEY(KEY_MORE_BONUS);
694 strcat(ptr, format("%d", entry->bonus));
695 ADD_KEY(KEY_MORE_BONUS2);
698 if (IS_FLG(FLG_UNREADABLE)) ADD_KEY(KEY_UNREADABLE);
699 if (IS_FLG(FLG_REALM1)) ADD_KEY(KEY_REALM1);
700 if (IS_FLG(FLG_REALM2)) ADD_KEY(KEY_REALM2);
701 if (IS_FLG(FLG_FIRST)) ADD_KEY(KEY_FIRST);
702 if (IS_FLG(FLG_SECOND)) ADD_KEY(KEY_SECOND);
703 if (IS_FLG(FLG_THIRD)) ADD_KEY(KEY_THIRD);
704 if (IS_FLG(FLG_FOURTH)) ADD_KEY(KEY_FOURTH);
705 if (IS_FLG(FLG_WANTED)) ADD_KEY(KEY_WANTED);
706 if (IS_FLG(FLG_UNIQUE)) ADD_KEY(KEY_UNIQUE);
707 if (IS_FLG(FLG_HUMAN)) ADD_KEY(KEY_HUMAN);
708 if (IS_FLG(FLG_WORTHLESS)) ADD_KEY(KEY_WORTHLESS);
709 if (IS_FLG(FLG_GOOD)) ADD_KEY(KEY_GOOD);
710 if (IS_FLG(FLG_NAMELESS)) ADD_KEY(KEY_NAMELESS);
711 if (IS_FLG(FLG_AVERAGE)) ADD_KEY(KEY_AVERAGE);
712 if (IS_FLG(FLG_RARE)) ADD_KEY(KEY_RARE);
713 if (IS_FLG(FLG_COMMON)) ADD_KEY(KEY_COMMON);
714 if (IS_FLG(FLG_EGO)) ADD_KEY(KEY_EGO);
716 if (IS_FLG(FLG_ARTIFACT)) ADD_KEY(KEY_ARTIFACT);
718 bool sepa_flag = TRUE;
719 if (IS_FLG(FLG_ITEMS)) ADD_KEY2(KEY_ITEMS);
720 else if (IS_FLG(FLG_WEAPONS)) ADD_KEY2(KEY_WEAPONS);
721 else if (IS_FLG(FLG_FAVORITE_WEAPONS)) ADD_KEY2(KEY_FAVORITE_WEAPONS);
722 else if (IS_FLG(FLG_ARMORS)) ADD_KEY2(KEY_ARMORS);
723 else if (IS_FLG(FLG_MISSILES)) ADD_KEY2(KEY_MISSILES);
724 else if (IS_FLG(FLG_DEVICES)) ADD_KEY2(KEY_DEVICES);
725 else if (IS_FLG(FLG_LIGHTS)) ADD_KEY2(KEY_LIGHTS);
726 else if (IS_FLG(FLG_JUNKS)) ADD_KEY2(KEY_JUNKS);
727 else if (IS_FLG(FLG_CORPSES)) ADD_KEY2(KEY_CORPSES);
728 else if (IS_FLG(FLG_SPELLBOOKS)) ADD_KEY2(KEY_SPELLBOOKS);
729 else if (IS_FLG(FLG_HAFTED)) ADD_KEY2(KEY_HAFTED);
730 else if (IS_FLG(FLG_SHIELDS)) ADD_KEY2(KEY_SHIELDS);
731 else if (IS_FLG(FLG_BOWS)) ADD_KEY2(KEY_BOWS);
732 else if (IS_FLG(FLG_RINGS)) ADD_KEY2(KEY_RINGS);
733 else if (IS_FLG(FLG_AMULETS)) ADD_KEY2(KEY_AMULETS);
734 else if (IS_FLG(FLG_SUITS)) ADD_KEY2(KEY_SUITS);
735 else if (IS_FLG(FLG_CLOAKS)) ADD_KEY2(KEY_CLOAKS);
736 else if (IS_FLG(FLG_HELMS)) ADD_KEY2(KEY_HELMS);
737 else if (IS_FLG(FLG_GLOVES)) ADD_KEY2(KEY_GLOVES);
738 else if (IS_FLG(FLG_BOOTS)) ADD_KEY2(KEY_BOOTS);
739 else if (!IS_FLG(FLG_ARTIFACT))
742 if (entry->name && entry->name[0])
744 if (sepa_flag) strcat(buf, ":");
748 while (entry->name[j] && i < MAX_LINELEN - 2 - 1)
751 if (iskanji(entry->name[j]))
752 buf[i++] = entry->name[j++];
754 buf[i++] = entry->name[j++];
759 if (!entry->insc) return string_make(buf);
765 while (entry->insc[j] && i < MAX_LINELEN - 2)
768 if (iskanji(entry->insc[j]))
769 buf[i++] = entry->insc[j++];
771 buf[i++] = entry->insc[j++];
775 return string_make(buf);
780 * Reconstruct preference line from entry and kill entry
782 static concptr autopick_line_from_entry_kill(autopick_type *entry)
784 concptr ptr = autopick_line_from_entry(entry);
785 autopick_free_entry(entry);
791 * A function for Auto-picker/destroyer
792 * Examine whether the object matches to the entry
794 static bool is_autopick_aux(player_type *player_ptr, object_type *o_ptr, autopick_type *entry, concptr o_name)
796 concptr ptr = entry->name;
797 if (IS_FLG(FLG_UNAWARE) && object_is_aware(o_ptr))
800 if (IS_FLG(FLG_UNIDENTIFIED)
801 && (object_is_known(o_ptr) || (o_ptr->ident & IDENT_SENSE)))
804 if (IS_FLG(FLG_IDENTIFIED) && !object_is_known(o_ptr))
807 if (IS_FLG(FLG_STAR_IDENTIFIED) &&
808 (!object_is_known(o_ptr) || !OBJECT_IS_FULL_KNOWN(o_ptr)))
811 if (IS_FLG(FLG_BOOSTED))
813 object_kind *k_ptr = &k_info[o_ptr->k_idx];
814 if (!object_is_melee_weapon(o_ptr))
817 if ((o_ptr->dd == k_ptr->dd) && (o_ptr->ds == k_ptr->ds))
820 if (!object_is_known(o_ptr) && object_is_quest_target(o_ptr))
826 if (IS_FLG(FLG_MORE_DICE))
828 if (o_ptr->dd * o_ptr->ds < entry->dice)
832 if (IS_FLG(FLG_MORE_BONUS))
834 if (!object_is_known(o_ptr)) return FALSE;
838 if (o_ptr->pval < entry->bonus) return FALSE;
842 if (o_ptr->to_h < entry->bonus &&
843 o_ptr->to_d < entry->bonus &&
844 o_ptr->to_a < entry->bonus &&
845 o_ptr->pval < entry->bonus)
850 if (IS_FLG(FLG_WORTHLESS) && object_value(o_ptr) > 0)
853 if (IS_FLG(FLG_ARTIFACT))
855 if (!object_is_known(o_ptr) || !object_is_artifact(o_ptr))
861 if (!object_is_ego(o_ptr)) return FALSE;
862 if (!object_is_known(o_ptr) &&
863 !((o_ptr->ident & IDENT_SENSE) && o_ptr->feeling == FEEL_EXCELLENT))
867 if (IS_FLG(FLG_GOOD))
869 if (!object_is_equipment(o_ptr)) return FALSE;
870 if (object_is_known(o_ptr))
872 if (!object_is_nameless(o_ptr))
875 if (o_ptr->to_a <= 0 && (o_ptr->to_h + o_ptr->to_d) <= 0)
878 else if (o_ptr->ident & IDENT_SENSE)
880 switch (o_ptr->feeling)
895 if (IS_FLG(FLG_NAMELESS))
897 if (!object_is_equipment(o_ptr)) return FALSE;
898 if (object_is_known(o_ptr))
900 if (!object_is_nameless(o_ptr))
903 else if (o_ptr->ident & IDENT_SENSE)
905 switch (o_ptr->feeling)
923 if (IS_FLG(FLG_AVERAGE))
925 if (!object_is_equipment(o_ptr)) return FALSE;
926 if (object_is_known(o_ptr))
928 if (!object_is_nameless(o_ptr))
931 if (object_is_cursed(o_ptr) || object_is_broken(o_ptr))
934 if (o_ptr->to_a > 0 || (o_ptr->to_h + o_ptr->to_d) > 0)
937 else if (o_ptr->ident & IDENT_SENSE)
939 switch (o_ptr->feeling)
954 if (IS_FLG(FLG_RARE) && !object_is_rare(o_ptr))
957 if (IS_FLG(FLG_COMMON) && object_is_rare(o_ptr))
960 if (IS_FLG(FLG_WANTED) && !object_is_bounty(o_ptr))
963 if (IS_FLG(FLG_UNIQUE) &&
964 ((o_ptr->tval != TV_CORPSE && o_ptr->tval != TV_STATUE) ||
965 !(r_info[o_ptr->pval].flags1 & RF1_UNIQUE)))
968 if (IS_FLG(FLG_HUMAN) &&
969 (o_ptr->tval != TV_CORPSE ||
970 !my_strchr("pht", r_info[o_ptr->pval].d_char)))
973 if (IS_FLG(FLG_UNREADABLE) &&
974 (o_ptr->tval < TV_LIFE_BOOK ||
975 check_book_realm(player_ptr, o_ptr->tval, o_ptr->sval)))
978 if (IS_FLG(FLG_REALM1) &&
979 (REALM1_BOOK != o_ptr->tval ||
980 player_ptr->pclass == CLASS_SORCERER ||
981 player_ptr->pclass == CLASS_RED_MAGE))
984 if (IS_FLG(FLG_REALM2) &&
985 (REALM2_BOOK != o_ptr->tval ||
986 player_ptr->pclass == CLASS_SORCERER ||
987 player_ptr->pclass == CLASS_RED_MAGE))
990 if (IS_FLG(FLG_FIRST) &&
991 (o_ptr->tval < TV_LIFE_BOOK || 0 != o_ptr->sval))
994 if (IS_FLG(FLG_SECOND) &&
995 (o_ptr->tval < TV_LIFE_BOOK || 1 != o_ptr->sval))
998 if (IS_FLG(FLG_THIRD) &&
999 (o_ptr->tval < TV_LIFE_BOOK || 2 != o_ptr->sval))
1002 if (IS_FLG(FLG_FOURTH) &&
1003 (o_ptr->tval < TV_LIFE_BOOK || 3 != o_ptr->sval))
1006 if (IS_FLG(FLG_WEAPONS))
1008 if (!object_is_weapon(o_ptr))
1011 else if (IS_FLG(FLG_FAVORITE_WEAPONS))
1013 if (!object_is_favorite(o_ptr))
1016 else if (IS_FLG(FLG_ARMORS))
1018 if (!object_is_armour(o_ptr))
1021 else if (IS_FLG(FLG_MISSILES))
1023 if (!object_is_ammo(o_ptr)) return FALSE;
1025 else if (IS_FLG(FLG_DEVICES))
1027 switch (o_ptr->tval)
1029 case TV_SCROLL: case TV_STAFF: case TV_WAND: case TV_ROD:
1031 default: return FALSE;
1034 else if (IS_FLG(FLG_LIGHTS))
1036 if (!(o_ptr->tval == TV_LITE))
1039 else if (IS_FLG(FLG_JUNKS))
1041 switch (o_ptr->tval)
1043 case TV_SKELETON: case TV_BOTTLE:
1044 case TV_JUNK: case TV_STATUE:
1046 default: return FALSE;
1049 else if (IS_FLG(FLG_CORPSES))
1051 if (o_ptr->tval != TV_CORPSE && o_ptr->tval != TV_SKELETON)
1054 else if (IS_FLG(FLG_SPELLBOOKS))
1056 if (!(o_ptr->tval >= TV_LIFE_BOOK))
1059 else if (IS_FLG(FLG_HAFTED))
1061 if (!(o_ptr->tval == TV_HAFTED))
1064 else if (IS_FLG(FLG_SHIELDS))
1066 if (!(o_ptr->tval == TV_SHIELD))
1069 else if (IS_FLG(FLG_BOWS))
1071 if (!(o_ptr->tval == TV_BOW))
1074 else if (IS_FLG(FLG_RINGS))
1076 if (!(o_ptr->tval == TV_RING))
1079 else if (IS_FLG(FLG_AMULETS))
1081 if (!(o_ptr->tval == TV_AMULET))
1084 else if (IS_FLG(FLG_SUITS))
1086 if (!(o_ptr->tval == TV_DRAG_ARMOR ||
1087 o_ptr->tval == TV_HARD_ARMOR ||
1088 o_ptr->tval == TV_SOFT_ARMOR))
1091 else if (IS_FLG(FLG_CLOAKS))
1093 if (!(o_ptr->tval == TV_CLOAK))
1096 else if (IS_FLG(FLG_HELMS))
1098 if (!(o_ptr->tval == TV_CROWN || o_ptr->tval == TV_HELM))
1101 else if (IS_FLG(FLG_GLOVES))
1103 if (!(o_ptr->tval == TV_GLOVES))
1106 else if (IS_FLG(FLG_BOOTS))
1108 if (!(o_ptr->tval == TV_BOOTS))
1115 if (strncmp(o_name, ptr, strlen(ptr))) return FALSE;
1119 if (!my_strstr(o_name, ptr)) return FALSE;
1122 if (!IS_FLG(FLG_COLLECTING)) return TRUE;
1124 for (int j = 0; j < INVEN_PACK; j++)
1127 * 'Collecting' means the item must be absorbed
1128 * into an inventory slot.
1129 * But an item can not be absorbed into itself!
1131 if ((&player_ptr->inventory_list[j] != o_ptr) &&
1132 object_similar(&player_ptr->inventory_list[j], o_ptr))
1141 * A function for Auto-picker/destroyer
1142 * Examine whether the object matches to the list of keywords or not.
1144 int is_autopick(player_type *player_ptr, object_type *o_ptr)
1146 GAME_TEXT o_name[MAX_NLEN];
1147 if (o_ptr->tval == TV_GOLD) return -1;
1149 object_desc(player_ptr, o_name, o_ptr, (OD_NO_FLAVOR | OD_OMIT_PREFIX | OD_NO_PLURAL));
1150 str_tolower(o_name);
1151 for (int i = 0; i < max_autopick; i++)
1153 autopick_type *entry = &autopick_list[i];
1154 if (is_autopick_aux(player_ptr, o_ptr, entry, o_name))
1165 static void auto_inscribe_item(player_type *player_ptr, object_type *o_ptr, int idx)
1167 if (idx < 0 || !autopick_list[idx].insc) return;
1169 if (!o_ptr->inscription)
1170 o_ptr->inscription = quark_add(autopick_list[idx].insc);
1172 player_ptr->window |= (PW_EQUIP | PW_INVEN);
1173 player_ptr->update |= (PU_BONUS);
1178 * Automatically destroy items in this grid.
1180 static bool is_opt_confirm_destroy(player_type *player_ptr, object_type *o_ptr)
1182 if (!destroy_items) return FALSE;
1185 if (object_value(o_ptr) > 0) return FALSE;
1188 if (object_is_weapon_armour_ammo(o_ptr)) return FALSE;
1191 if ((o_ptr->tval == TV_CHEST) && o_ptr->pval) return FALSE;
1195 if (object_is_bounty(o_ptr)) return FALSE;
1199 if (o_ptr->tval == TV_CORPSE) return FALSE;
1202 if ((o_ptr->tval == TV_SKELETON) || (o_ptr->tval == TV_BOTTLE) || (o_ptr->tval == TV_JUNK) || (o_ptr->tval == TV_STATUE)) return FALSE;
1206 if (player_ptr->prace == RACE_DEMON)
1208 if (o_ptr->tval == TV_CORPSE &&
1209 o_ptr->sval == SV_CORPSE &&
1210 my_strchr("pht", r_info[o_ptr->pval].d_char))
1214 if (player_ptr->pclass == CLASS_ARCHER)
1216 if (o_ptr->tval == TV_SKELETON ||
1217 (o_ptr->tval == TV_CORPSE && o_ptr->sval == SV_SKELETON))
1220 else if (player_ptr->pclass == CLASS_NINJA)
1222 if (o_ptr->tval == TV_LITE &&
1223 o_ptr->name2 == EGO_LITE_DARKNESS && object_is_known(o_ptr))
1226 else if (player_ptr->pclass == CLASS_BEASTMASTER ||
1227 player_ptr->pclass == CLASS_CAVALRY)
1229 if (o_ptr->tval == TV_WAND &&
1230 o_ptr->sval == SV_WAND_HEAL_MONSTER && object_is_aware(o_ptr))
1235 if (o_ptr->tval == TV_GOLD) return FALSE;
1241 static void auto_destroy_item(player_type *player_ptr, object_type *o_ptr, int autopick_idx)
1243 bool destroy = FALSE;
1244 if (is_opt_confirm_destroy(player_ptr, o_ptr)) destroy = TRUE;
1246 if (autopick_idx >= 0 &&
1247 !(autopick_list[autopick_idx].action & DO_AUTODESTROY))
1252 if (autopick_idx >= 0 &&
1253 (autopick_list[autopick_idx].action & DO_AUTODESTROY))
1257 if (!destroy) return;
1259 disturb(player_ptr, FALSE, FALSE);
1260 if (!can_player_destroy_object(o_ptr))
1262 GAME_TEXT o_name[MAX_NLEN];
1263 object_desc(player_ptr, o_name, o_ptr, 0);
1264 msg_format(_("%sは破壊不能だ。", "You cannot auto-destroy %s."), o_name);
1268 (void)COPY(&autopick_last_destroyed_object, o_ptr, object_type);
1269 o_ptr->marked |= OM_AUTODESTROY;
1270 player_ptr->update |= PU_AUTODESTROY;
1275 * Auto-destroy marked item
1277 static void autopick_delayed_alter_aux(player_type *player_ptr, INVENTORY_IDX item)
1280 o_ptr = REF_ITEM(player_ptr, player_ptr->current_floor_ptr, item);
1282 if (o_ptr->k_idx == 0 || !(o_ptr->marked & OM_AUTODESTROY)) return;
1284 GAME_TEXT o_name[MAX_NLEN];
1285 object_desc(player_ptr, o_name, o_ptr, 0);
1288 inven_item_increase(player_ptr, item, -(o_ptr->number));
1289 inven_item_optimize(player_ptr, item);
1293 delete_object_idx(player_ptr, 0 - item);
1296 msg_format(_("%sを自動破壊します。", "Auto-destroying %s."), o_name);
1301 * Auto-destroy marked items in inventry and on floor
1303 void autopick_delayed_alter(player_type *owner_ptr)
1308 * Scan inventry in reverse order to prevent
1309 * skipping after inven_item_optimize()
1311 for (item = INVEN_TOTAL - 1; item >= 0; item--)
1312 autopick_delayed_alter_aux(owner_ptr, item);
1314 floor_type *floor_ptr = owner_ptr->current_floor_ptr;
1315 item = floor_ptr->grid_array[owner_ptr->y][owner_ptr->x].o_idx;
1318 OBJECT_IDX next = floor_ptr->o_list[item].next_o_idx;
1319 autopick_delayed_alter_aux(owner_ptr, -item);
1326 * Auto-inscription and/or destroy
1328 * Auto-destroyer works only on inventory or on floor stack only when
1331 void autopick_alter_item(player_type *player_ptr, INVENTORY_IDX item, bool destroy)
1334 o_ptr = REF_ITEM(player_ptr, player_ptr->current_floor_ptr, item);
1335 int idx = is_autopick(player_ptr, o_ptr);
1336 auto_inscribe_item(player_ptr, o_ptr, idx);
1337 if (destroy && item <= INVEN_PACK)
1338 auto_destroy_item(player_ptr, o_ptr, idx);
1343 * Automatically pickup/destroy items in this grid.
1345 void autopick_pickup_items(player_type* player_ptr, grid_type *g_ptr)
1347 OBJECT_IDX this_o_idx, next_o_idx = 0;
1348 for (this_o_idx = g_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx)
1350 object_type *o_ptr = &player_ptr->current_floor_ptr->o_list[this_o_idx];
1351 next_o_idx = o_ptr->next_o_idx;
1352 int idx = is_autopick(player_ptr, o_ptr);
1353 auto_inscribe_item(player_ptr, o_ptr, idx);
1354 bool is_auto_pickup = idx >= 0;
1355 is_auto_pickup &= (autopick_list[idx].action & (DO_AUTOPICK | DO_QUERY_AUTOPICK)) != 0;
1356 if (!is_auto_pickup)
1358 auto_destroy_item(player_ptr, o_ptr, idx);
1362 disturb(player_ptr, FALSE, FALSE);
1363 if (!inven_carry_okay(o_ptr))
1365 GAME_TEXT o_name[MAX_NLEN];
1366 object_desc(player_ptr, o_name, o_ptr, 0);
1367 msg_format(_("ザックには%sを入れる隙間がない。", "You have no room for %s."), o_name);
1368 o_ptr->marked |= OM_NOMSG;
1372 if (!(autopick_list[idx].action & DO_QUERY_AUTOPICK))
1374 py_pickup_aux(player_ptr, this_o_idx);
1378 char out_val[MAX_NLEN + 20];
1379 GAME_TEXT o_name[MAX_NLEN];
1380 if (o_ptr->marked & OM_NO_QUERY)
1385 object_desc(player_ptr, o_name, o_ptr, 0);
1386 sprintf(out_val, _("%sを拾いますか? ", "Pick up %s? "), o_name);
1387 if (!get_check(out_val))
1389 o_ptr->marked |= OM_NOMSG | OM_NO_QUERY;
1393 py_pickup_aux(player_ptr, this_o_idx);
1398 static const char autoregister_header[] = "?:$AUTOREGISTER";
1401 * Clear auto registered lines in the picktype.prf .
1403 static bool clear_auto_register(player_type *player_ptr)
1405 char tmp_file[1024];
1406 char pref_file[1024];
1411 bool autoregister = FALSE;
1414 path_build(pref_file, sizeof(pref_file), ANGBAND_DIR_USER, pickpref_filename(player_ptr, PT_WITH_PNAME));
1415 pref_fff = my_fopen(pref_file, "r");
1419 path_build(pref_file, sizeof(pref_file), ANGBAND_DIR_USER, pickpref_filename(player_ptr, PT_DEFAULT));
1420 pref_fff = my_fopen(pref_file, "r");
1428 tmp_fff = my_fopen_temp(tmp_file, sizeof(tmp_file));
1432 msg_format(_("一時ファイル %s を作成できませんでした。", "Failed to create temporary file %s."), tmp_file);
1439 if (my_fgets(pref_fff, buf, sizeof(buf))) break;
1443 if (buf[0] != '#' && buf[0] != '?') num++;
1447 if (streq(buf, autoregister_header))
1449 autoregister = TRUE;
1453 fprintf(tmp_fff, "%s\n", buf);
1457 my_fclose(pref_fff);
1462 msg_format(_("以前のキャラクター用の自動設定(%d行)が残っています。",
1463 "Auto registered lines (%d lines) for previous character are remaining."), num);
1464 strcpy(buf, _("古い設定行は削除します。よろしいですか?", "These lines will be deleted. Are you sure? "));
1466 if (!get_check(buf))
1469 autoregister = FALSE;
1471 msg_print(_("エディタのカット&ペースト等を使って必要な行を避難してください。",
1472 "Use cut & paste of auto picker editor (_) to keep old prefs."));
1478 tmp_fff = my_fopen(tmp_file, "r");
1479 pref_fff = my_fopen(pref_file, "w");
1481 while (!my_fgets(tmp_fff, buf, sizeof(buf)))
1482 fprintf(pref_fff, "%s\n", buf);
1484 my_fclose(pref_fff);
1494 * Automatically register an auto-destroy preference line
1496 bool autopick_autoregister(player_type *player_ptr, object_type *o_ptr)
1499 char pref_file[1024];
1501 autopick_type an_entry, *entry = &an_entry;
1502 int match_autopick = is_autopick(player_ptr, o_ptr);
1503 if (match_autopick != -1)
1506 byte act = autopick_list[match_autopick].action;
1507 if (act & DO_AUTOPICK) what = _("自動で拾う", "auto-pickup");
1508 else if (act & DO_AUTODESTROY) what = _("自動破壊する", "auto-destroy");
1509 else if (act & DONT_AUTOPICK) what = _("放置する", "leave on floor");
1510 else what = _("確認して拾う", "query auto-pickup");
1512 msg_format(_("そのアイテムは既に%sように設定されています。", "The object is already registered to %s."), what);
1516 if ((object_is_known(o_ptr) && object_is_artifact(o_ptr)) ||
1517 ((o_ptr->ident & IDENT_SENSE) &&
1518 (o_ptr->feeling == FEEL_TERRIBLE || o_ptr->feeling == FEEL_SPECIAL)))
1520 GAME_TEXT o_name[MAX_NLEN];
1521 object_desc(player_ptr, o_name, o_ptr, 0);
1522 msg_format(_("%sは破壊不能だ。", "You cannot auto-destroy %s."), o_name);
1526 if (!player_ptr->autopick_autoregister)
1528 if (!clear_auto_register(player_ptr)) return FALSE;
1531 path_build(pref_file, sizeof(pref_file), ANGBAND_DIR_USER, pickpref_filename(player_ptr, PT_WITH_PNAME));
1532 pref_fff = my_fopen(pref_file, "r");
1536 path_build(pref_file, sizeof(pref_file), ANGBAND_DIR_USER, pickpref_filename(player_ptr, PT_DEFAULT));
1537 pref_fff = my_fopen(pref_file, "r");
1544 if (my_fgets(pref_fff, buf, sizeof(buf)))
1546 player_ptr->autopick_autoregister = FALSE;
1550 if (streq(buf, autoregister_header))
1552 player_ptr->autopick_autoregister = TRUE;
1562 * File could not be opened for reading. Assume header not
1565 player_ptr->autopick_autoregister = FALSE;
1568 pref_fff = my_fopen(pref_file, "a");
1571 msg_format(_("%s を開くことができませんでした。", "Failed to open %s."), pref_file);
1576 if (!player_ptr->autopick_autoregister)
1578 fprintf(pref_fff, "%s\n", autoregister_header);
1580 fprintf(pref_fff, "%s\n", _("# *警告!!* 以降の行は自動登録されたものです。",
1581 "# *Warning!* The lines below will be deleted later."));
1582 fprintf(pref_fff, "%s\n", _("# 後で自動的に削除されますので、必要な行は上の方へ移動しておいてください。",
1583 "# Keep it by cut & paste if you need these lines for future characters."));
1584 player_ptr->autopick_autoregister = TRUE;
1587 autopick_entry_from_object(player_ptr, entry, o_ptr);
1588 entry->action = DO_AUTODESTROY;
1589 add_autopick_list(entry);
1591 concptr tmp = autopick_line_from_entry(entry);
1592 fprintf(pref_fff, "%s\n", tmp);
1600 * Describe which kind of object is Auto-picked/destroyed
1602 static void describe_autopick(char *buff, autopick_type *entry)
1604 concptr str = entry->name;
1605 byte act = entry->action;
1606 concptr insc = entry->insc;
1612 concptr before_str[100], body_str;
1616 if (IS_FLG(FLG_COLLECTING))
1617 before_str[before_n++] = "収集中で既に持っているスロットにまとめられる";
1619 if (IS_FLG(FLG_UNAWARE))
1620 before_str[before_n++] = "未鑑定でその効果も判明していない";
1622 if (IS_FLG(FLG_UNIDENTIFIED))
1623 before_str[before_n++] = "未鑑定の";
1625 if (IS_FLG(FLG_IDENTIFIED))
1626 before_str[before_n++] = "鑑定済みの";
1628 if (IS_FLG(FLG_STAR_IDENTIFIED))
1629 before_str[before_n++] = "完全に鑑定済みの";
1631 if (IS_FLG(FLG_BOOSTED))
1633 before_str[before_n++] = "ダメージダイスが通常より大きい";
1637 if (IS_FLG(FLG_MORE_DICE))
1639 static char more_than_desc_str[] = "___";
1640 before_str[before_n++] = "ダメージダイスの最大値が";
1643 sprintf(more_than_desc_str, "%d", entry->dice);
1644 before_str[before_n++] = more_than_desc_str;
1645 before_str[before_n++] = "以上の";
1648 if (IS_FLG(FLG_MORE_BONUS))
1650 static char more_bonus_desc_str[] = "___";
1651 before_str[before_n++] = "修正値が(+";
1653 sprintf(more_bonus_desc_str, "%d", entry->bonus);
1654 before_str[before_n++] = more_bonus_desc_str;
1655 before_str[before_n++] = ")以上の";
1658 if (IS_FLG(FLG_WORTHLESS))
1659 before_str[before_n++] = "店で無価値と判定される";
1661 if (IS_FLG(FLG_ARTIFACT))
1663 before_str[before_n++] = "アーティファクトの";
1667 if (IS_FLG(FLG_EGO))
1669 before_str[before_n++] = "エゴアイテムの";
1673 if (IS_FLG(FLG_GOOD))
1675 before_str[before_n++] = "上質の";
1679 if (IS_FLG(FLG_NAMELESS))
1681 before_str[before_n++] = "エゴでもアーティファクトでもない";
1685 if (IS_FLG(FLG_AVERAGE))
1687 before_str[before_n++] = "並の";
1691 if (IS_FLG(FLG_RARE))
1693 before_str[before_n++] = "ドラゴン装備やカオス・ブレード等を含む珍しい";
1697 if (IS_FLG(FLG_COMMON))
1699 before_str[before_n++] = "ありふれた(ドラゴン装備やカオス・ブレード等の珍しい物ではない)";
1703 if (IS_FLG(FLG_WANTED))
1705 before_str[before_n++] = "ハンター事務所で賞金首とされている";
1709 if (IS_FLG(FLG_HUMAN))
1711 before_str[before_n++] = "悪魔魔法で使うための人間やヒューマノイドの";
1715 if (IS_FLG(FLG_UNIQUE))
1717 before_str[before_n++] = "ユニークモンスターの";
1721 if (IS_FLG(FLG_UNREADABLE))
1723 before_str[before_n++] = "あなたが読めない領域の";
1727 if (IS_FLG(FLG_REALM1))
1729 before_str[before_n++] = "第一領域の";
1733 if (IS_FLG(FLG_REALM2))
1735 before_str[before_n++] = "第二領域の";
1739 if (IS_FLG(FLG_FIRST))
1741 before_str[before_n++] = "全4冊の内の1冊目の";
1745 if (IS_FLG(FLG_SECOND))
1747 before_str[before_n++] = "全4冊の内の2冊目の";
1751 if (IS_FLG(FLG_THIRD))
1753 before_str[before_n++] = "全4冊の内の3冊目の";
1757 if (IS_FLG(FLG_FOURTH))
1759 before_str[before_n++] = "全4冊の内の4冊目の";
1763 if (IS_FLG(FLG_ITEMS))
1764 ; /* Nothing to do */
1765 else if (IS_FLG(FLG_WEAPONS))
1767 else if (IS_FLG(FLG_FAVORITE_WEAPONS))
1769 else if (IS_FLG(FLG_ARMORS))
1771 else if (IS_FLG(FLG_MISSILES))
1772 body_str = "弾や矢やクロスボウの矢";
1773 else if (IS_FLG(FLG_DEVICES))
1774 body_str = "巻物や魔法棒や杖やロッド";
1775 else if (IS_FLG(FLG_LIGHTS))
1776 body_str = "光源用のアイテム";
1777 else if (IS_FLG(FLG_JUNKS))
1778 body_str = "折れた棒等のガラクタ";
1779 else if (IS_FLG(FLG_CORPSES))
1781 else if (IS_FLG(FLG_SPELLBOOKS))
1783 else if (IS_FLG(FLG_HAFTED))
1785 else if (IS_FLG(FLG_SHIELDS))
1787 else if (IS_FLG(FLG_BOWS))
1788 body_str = "スリングや弓やクロスボウ";
1789 else if (IS_FLG(FLG_RINGS))
1791 else if (IS_FLG(FLG_AMULETS))
1792 body_str = "アミュレット";
1793 else if (IS_FLG(FLG_SUITS))
1795 else if (IS_FLG(FLG_CLOAKS))
1797 else if (IS_FLG(FLG_HELMS))
1798 body_str = "ヘルメットや冠";
1799 else if (IS_FLG(FLG_GLOVES))
1801 else if (IS_FLG(FLG_BOOTS))
1806 strcat(buff, "全ての");
1807 else for (i = 0; i < before_n && before_str[i]; i++)
1808 strcat(buff, before_str[i]);
1810 strcat(buff, body_str);
1820 strcat(buff, "で、名前が「");
1821 strncat(buff, str, 80);
1823 strcat(buff, "」で始まるもの");
1825 strcat(buff, "」を含むもの");
1830 strncat(buff, format("に「%s」", insc), 80);
1832 if (my_strstr(insc, "%%all"))
1833 strcat(buff, "(%%allは全能力を表す英字の記号で置換)");
1834 else if (my_strstr(insc, "%all"))
1835 strcat(buff, "(%allは全能力を表す記号で置換)");
1836 else if (my_strstr(insc, "%%"))
1837 strcat(buff, "(%%は追加能力を表す英字の記号で置換)");
1838 else if (my_strstr(insc, "%"))
1839 strcat(buff, "(%は追加能力を表す記号で置換)");
1841 strcat(buff, "と刻んで");
1846 if (act & DONT_AUTOPICK)
1847 strcat(buff, "放置する。");
1848 else if (act & DO_AUTODESTROY)
1849 strcat(buff, "破壊する。");
1850 else if (act & DO_QUERY_AUTOPICK)
1851 strcat(buff, "確認の後に拾う。");
1853 strcat(buff, "拾う。");
1855 if (act & DO_DISPLAY)
1857 if (act & DONT_AUTOPICK)
1858 strcat(buff, "全体マップ('M')で'N'を押したときに表示する。");
1859 else if (act & DO_AUTODESTROY)
1860 strcat(buff, "全体マップ('M')で'K'を押したときに表示する。");
1862 strcat(buff, "全体マップ('M')で'M'を押したときに表示する。");
1865 strcat(buff, "全体マップには表示しない。");
1869 concptr before_str[20], after_str[20], which_str[20], whose_str[20], body_str;
1870 int before_n = 0, after_n = 0, which_n = 0, whose_n = 0;
1872 if (IS_FLG(FLG_COLLECTING))
1873 which_str[which_n++] = "can be absorbed into an existing inventory list slot";
1875 if (IS_FLG(FLG_UNAWARE))
1877 before_str[before_n++] = "unidentified";
1878 whose_str[whose_n++] = "basic abilities are not known";
1881 if (IS_FLG(FLG_UNIDENTIFIED))
1882 before_str[before_n++] = "unidentified";
1884 if (IS_FLG(FLG_IDENTIFIED))
1885 before_str[before_n++] = "identified";
1887 if (IS_FLG(FLG_STAR_IDENTIFIED))
1888 before_str[before_n++] = "fully identified";
1890 if (IS_FLG(FLG_RARE))
1892 before_str[before_n++] = "very rare";
1893 body_str = "equipments";
1894 after_str[after_n++] = "such as Dragon armor, Blades of Chaos, etc.";
1897 if (IS_FLG(FLG_COMMON))
1899 before_str[before_n++] = "relatively common";
1900 body_str = "equipments";
1901 after_str[after_n++] = "compared to very rare Dragon armor, Blades of Chaos, etc.";
1904 if (IS_FLG(FLG_WORTHLESS))
1906 before_str[before_n++] = "worthless";
1907 which_str[which_n++] = "can not be sold at stores";
1910 if (IS_FLG(FLG_ARTIFACT))
1912 before_str[before_n++] = "artifact";
1915 if (IS_FLG(FLG_EGO))
1917 before_str[before_n++] = "ego";
1920 if (IS_FLG(FLG_GOOD))
1922 body_str = "equipment";
1923 which_str[which_n++] = "have good quality";
1926 if (IS_FLG(FLG_NAMELESS))
1928 body_str = "equipment";
1929 which_str[which_n++] = "is neither ego-item nor artifact";
1932 if (IS_FLG(FLG_AVERAGE))
1934 body_str = "equipment";
1935 which_str[which_n++] = "have average quality";
1938 if (IS_FLG(FLG_BOOSTED))
1940 body_str = "weapons";
1941 whose_str[whose_n++] = "damage dice is bigger than normal";
1944 if (IS_FLG(FLG_MORE_DICE))
1946 static char more_than_desc_str[] =
1947 "maximum damage from dice is bigger than __";
1948 body_str = "weapons";
1950 sprintf(more_than_desc_str + sizeof(more_than_desc_str) - 3,
1952 whose_str[whose_n++] = more_than_desc_str;
1955 if (IS_FLG(FLG_MORE_BONUS))
1957 static char more_bonus_desc_str[] =
1958 "magical bonus is bigger than (+__)";
1960 sprintf(more_bonus_desc_str + sizeof(more_bonus_desc_str) - 4,
1961 "%d)", entry->bonus);
1962 whose_str[whose_n++] = more_bonus_desc_str;
1965 if (IS_FLG(FLG_WANTED))
1967 body_str = "corpse or skeletons";
1968 which_str[which_n++] = "is wanted at the Hunter's Office";
1971 if (IS_FLG(FLG_HUMAN))
1973 before_str[before_n++] = "humanoid";
1974 body_str = "corpse or skeletons";
1975 which_str[which_n++] = "can be used for Daemon magic";
1978 if (IS_FLG(FLG_UNIQUE))
1980 before_str[before_n++] = "unique monster's";
1981 body_str = "corpse or skeletons";
1984 if (IS_FLG(FLG_UNREADABLE))
1986 body_str = "spellbooks";
1987 after_str[after_n++] = "of different realms from yours";
1990 if (IS_FLG(FLG_REALM1))
1992 body_str = "spellbooks";
1993 after_str[after_n++] = "of your first realm";
1996 if (IS_FLG(FLG_REALM2))
1998 body_str = "spellbooks";
1999 after_str[after_n++] = "of your second realm";
2002 if (IS_FLG(FLG_FIRST))
2004 before_str[before_n++] = "first one of four";
2005 body_str = "spellbooks";
2008 if (IS_FLG(FLG_SECOND))
2010 before_str[before_n++] = "second one of four";
2011 body_str = "spellbooks";
2014 if (IS_FLG(FLG_THIRD))
2016 before_str[before_n++] = "third one of four";
2017 body_str = "spellbooks";
2020 if (IS_FLG(FLG_FOURTH))
2022 before_str[before_n++] = "fourth one of four";
2023 body_str = "spellbooks";
2026 if (IS_FLG(FLG_ITEMS))
2027 ; /* Nothing to do */
2028 else if (IS_FLG(FLG_WEAPONS))
2029 body_str = "weapons";
2030 else if (IS_FLG(FLG_FAVORITE_WEAPONS))
2031 body_str = "favorite weapons";
2032 else if (IS_FLG(FLG_ARMORS))
2033 body_str = "armors";
2034 else if (IS_FLG(FLG_MISSILES))
2035 body_str = "shots, arrows or crossbow bolts";
2036 else if (IS_FLG(FLG_DEVICES))
2037 body_str = "scrolls, wands, staffs or rods";
2038 else if (IS_FLG(FLG_LIGHTS))
2039 body_str = "light sources";
2040 else if (IS_FLG(FLG_JUNKS))
2041 body_str = "junk such as broken sticks";
2042 else if (IS_FLG(FLG_CORPSES))
2043 body_str = "corpses or skeletons";
2044 else if (IS_FLG(FLG_SPELLBOOKS))
2045 body_str = "spellbooks";
2046 else if (IS_FLG(FLG_HAFTED))
2047 body_str = "hafted weapons";
2048 else if (IS_FLG(FLG_SHIELDS))
2049 body_str = "shields";
2050 else if (IS_FLG(FLG_BOWS))
2051 body_str = "slings, bows or crossbows";
2052 else if (IS_FLG(FLG_RINGS))
2054 else if (IS_FLG(FLG_AMULETS))
2055 body_str = "amulets";
2056 else if (IS_FLG(FLG_SUITS))
2057 body_str = "body armors";
2058 else if (IS_FLG(FLG_CLOAKS))
2059 body_str = "cloaks";
2060 else if (IS_FLG(FLG_HELMS))
2061 body_str = "helms or crowns";
2062 else if (IS_FLG(FLG_GLOVES))
2063 body_str = "gloves";
2064 else if (IS_FLG(FLG_BOOTS))
2073 whose_str[whose_n++] = "name begins with \"";
2076 which_str[which_n++] = "have \"";
2080 if (act & DONT_AUTOPICK)
2081 strcpy(buff, "Leave on floor ");
2082 else if (act & DO_AUTODESTROY)
2083 strcpy(buff, "Destroy ");
2084 else if (act & DO_QUERY_AUTOPICK)
2085 strcpy(buff, "Ask to pick up ");
2087 strcpy(buff, "Pickup ");
2091 strncat(buff, format("and inscribe \"%s\"", insc), 80);
2093 if (my_strstr(insc, "%all"))
2094 strcat(buff, ", replacing %all with code string representing all abilities,");
2095 else if (my_strstr(insc, "%"))
2096 strcat(buff, ", replacing % with code string representing extra random abilities,");
2098 strcat(buff, " on ");
2102 strcat(buff, "all ");
2103 else for (i = 0; i < before_n && before_str[i]; i++)
2105 strcat(buff, before_str[i]);
2109 strcat(buff, body_str);
2111 for (i = 0; i < after_n && after_str[i]; i++)
2114 strcat(buff, after_str[i]);
2117 for (i = 0; i < whose_n && whose_str[i]; i++)
2120 strcat(buff, " whose ");
2122 strcat(buff, ", and ");
2124 strcat(buff, whose_str[i]);
2133 if (whose_n && which_n)
2134 strcat(buff, ", and ");
2136 for (i = 0; i < which_n && which_str[i]; i++)
2139 strcat(buff, " which ");
2141 strcat(buff, ", and ");
2143 strcat(buff, which_str[i]);
2148 strncat(buff, str, 80);
2149 strcat(buff, "\" as part of its name");
2153 if (act & DO_DISPLAY)
2155 if (act & DONT_AUTOPICK)
2156 strcat(buff, " Display these items when you press the N key in the full 'M'ap.");
2157 else if (act & DO_AUTODESTROY)
2158 strcat(buff, " Display these items when you press the K key in the full 'M'ap.");
2160 strcat(buff, " Display these items when you press the M key in the full 'M'ap.");
2163 strcat(buff, " Not displayed in the full map.");
2169 * Read whole lines of a file to memory
2171 static concptr *read_text_lines(concptr filename)
2173 concptr *lines_list = NULL;
2179 path_build(buf, sizeof(buf), ANGBAND_DIR_USER, filename);
2180 fff = my_fopen(buf, "r");
2181 if (!fff) return NULL;
2183 C_MAKE(lines_list, MAX_LINES, concptr);
2184 while (my_fgets(fff, buf, sizeof(buf)) == 0)
2186 lines_list[lines++] = string_make(buf);
2187 if (lines >= MAX_LINES - 1) break;
2191 lines_list[0] = string_make("");
2199 * Copy the default autopick file to the user directory
2201 static void prepare_default_pickpref(player_type *player_ptr)
2203 const concptr messages[] = {
2204 _("あなたは「自動拾いエディタ」を初めて起動しました。", "You have activated the Auto-Picker Editor for the first time."),
2205 _("自動拾いのユーザー設定ファイルがまだ書かれていないので、", "Since user pref file for autopick is not yet created,"),
2206 _("基本的な自動拾い設定ファイルをlib/pref/picktype.prfからコピーします。", "the default setting is loaded from lib/pref/pickpref.prf ."),
2210 concptr filename = pickpref_filename(player_ptr, PT_DEFAULT);
2211 for (int i = 0; messages[i]; i++)
2213 msg_print(messages[i]);
2218 path_build(buf, sizeof(buf), ANGBAND_DIR_USER, filename);
2220 user_fp = my_fopen(buf, "w");
2221 if (!user_fp) return;
2223 fprintf(user_fp, "#***\n");
2224 for (int i = 0; messages[i]; i++)
2226 fprintf(user_fp, "#*** %s\n", messages[i]);
2229 fprintf(user_fp, "#***\n\n\n");
2230 path_build(buf, sizeof(buf), ANGBAND_DIR_PREF, filename);
2232 pref_fp = my_fopen(buf, "r");
2240 while (!my_fgets(pref_fp, buf, sizeof(buf)))
2242 fprintf(user_fp, "%s\n", buf);
2250 * Read an autopick prefence file to memory
2251 * Prepare default if no user file is found
2253 static concptr *read_pickpref_text_lines(player_type *player_ptr, int *filename_mode_p)
2255 /* Try a filename with player name */
2256 *filename_mode_p = PT_WITH_PNAME;
2258 strcpy(buf, pickpref_filename(player_ptr, *filename_mode_p));
2259 concptr *lines_list;
2260 lines_list = read_text_lines(buf);
2264 *filename_mode_p = PT_DEFAULT;
2265 strcpy(buf, pickpref_filename(player_ptr, *filename_mode_p));
2266 lines_list = read_text_lines(buf);
2271 prepare_default_pickpref(player_ptr);
2272 lines_list = read_text_lines(buf);
2277 C_MAKE(lines_list, MAX_LINES, concptr);
2278 lines_list[0] = string_make("");
2286 * Write whole lines of memory to a file.
2288 static bool write_text_lines(concptr filename, concptr *lines_list)
2291 path_build(buf, sizeof(buf), ANGBAND_DIR_USER, filename);
2293 fff = my_fopen(buf, "w");
2294 if (!fff) return FALSE;
2296 for (int lines = 0; lines_list[lines]; lines++)
2298 my_fputs(fff, lines_list[lines], 1024);
2307 * Free memory of lines_list.
2309 static void free_text_lines(concptr *lines_list)
2311 for (int lines = 0; lines_list[lines]; lines++)
2313 string_free(lines_list[lines]);
2316 /* free list of pointers */
2317 C_KILL(lines_list, MAX_LINES, concptr);
2322 * Delete or insert string
2324 static void toggle_keyword(text_body_type *tb, BIT_FLAGS flg)
2331 by1 = MIN(tb->my, tb->cy);
2332 by2 = MAX(tb->my, tb->cy);
2334 else /* if (!tb->mark) */
2339 for (int y = by1; y <= by2; y++)
2341 autopick_type an_entry, *entry = &an_entry;
2342 if (!autopick_new_entry(entry, tb->lines_list[y], !fixed)) continue;
2344 string_free(tb->lines_list[y]);
2347 if (!IS_FLG(flg)) add = TRUE;
2353 if (FLG_NOUN_BEGIN <= flg && flg <= FLG_NOUN_END)
2356 for (i = FLG_NOUN_BEGIN; i <= FLG_NOUN_END; i++)
2359 else if (FLG_UNAWARE <= flg && flg <= FLG_STAR_IDENTIFIED)
2362 for (i = FLG_UNAWARE; i <= FLG_STAR_IDENTIFIED; i++)
2365 else if (FLG_ARTIFACT <= flg && flg <= FLG_AVERAGE)
2368 for (i = FLG_ARTIFACT; i <= FLG_AVERAGE; i++)
2371 else if (FLG_RARE <= flg && flg <= FLG_COMMON)
2374 for (i = FLG_RARE; i <= FLG_COMMON; i++)
2378 if (add) ADD_FLG(flg);
2381 tb->lines_list[y] = autopick_line_from_entry_kill(entry);
2382 tb->dirty_flags |= DIRTY_ALL;
2389 * Change command letter
2391 static void toggle_command_letter(text_body_type *tb, byte flg)
2393 autopick_type an_entry, *entry = &an_entry;
2399 by1 = MIN(tb->my, tb->cy);
2400 by2 = MAX(tb->my, tb->cy);
2402 else /* if (!tb->mark) */
2407 for (y = by1; y <= by2; y++)
2411 if (!autopick_new_entry(entry, tb->lines_list[y], FALSE)) continue;
2413 string_free(tb->lines_list[y]);
2417 if (!(entry->action & flg)) add = TRUE;
2423 if (entry->action & DONT_AUTOPICK) wid--;
2424 else if (entry->action & DO_AUTODESTROY) wid--;
2425 else if (entry->action & DO_QUERY_AUTOPICK) wid--;
2426 if (!(entry->action & DO_DISPLAY)) wid--;
2428 if (flg != DO_DISPLAY)
2430 entry->action &= ~(DO_AUTOPICK | DONT_AUTOPICK | DO_AUTODESTROY | DO_QUERY_AUTOPICK);
2431 if (add) entry->action |= flg;
2432 else entry->action |= DO_AUTOPICK;
2436 entry->action &= ~(DO_DISPLAY);
2437 if (add) entry->action |= flg;
2442 if (entry->action & DONT_AUTOPICK) wid++;
2443 else if (entry->action & DO_AUTODESTROY) wid++;
2444 else if (entry->action & DO_QUERY_AUTOPICK) wid++;
2445 if (!(entry->action & DO_DISPLAY)) wid++;
2447 if (wid > 0) tb->cx++;
2448 if (wid < 0 && tb->cx > 0) tb->cx--;
2451 tb->lines_list[y] = autopick_line_from_entry_kill(entry);
2452 tb->dirty_flags |= DIRTY_ALL;
2459 * Delete or insert string
2461 static void add_keyword(text_body_type *tb, BIT_FLAGS flg)
2466 by1 = MIN(tb->my, tb->cy);
2467 by2 = MAX(tb->my, tb->cy);
2474 for (int y = by1; y <= by2; y++)
2476 autopick_type an_entry, *entry = &an_entry;
2477 if (!autopick_new_entry(entry, tb->lines_list[y], FALSE)) continue;
2481 autopick_free_entry(entry);
2485 string_free(tb->lines_list[y]);
2486 if (FLG_NOUN_BEGIN <= flg && flg <= FLG_NOUN_END)
2489 for (i = FLG_NOUN_BEGIN; i <= FLG_NOUN_END; i++)
2494 tb->lines_list[y] = autopick_line_from_entry_kill(entry);
2495 tb->dirty_flags |= DIRTY_ALL;
2502 * Check if this line is expression or not.
2503 * And update it if it is.
2505 static void check_expression_line(text_body_type *tb, int y)
2507 concptr s = tb->lines_list[y];
2509 if ((s[0] == '?' && s[1] == ':') ||
2510 (tb->states[y] & LSTAT_BYPASS))
2512 tb->dirty_flags |= DIRTY_EXPRESSION;
2518 * Add an empty line at the last of the file
2520 static bool add_empty_line(text_body_type *tb)
2523 for (num_lines = 0; tb->lines_list[num_lines]; num_lines++);
2525 if (num_lines >= MAX_LINES - 2) return FALSE;
2526 if (!tb->lines_list[num_lines - 1][0]) return FALSE;
2528 tb->lines_list[num_lines] = string_make("");
2529 tb->dirty_flags |= DIRTY_EXPRESSION;
2536 * Insert return code and split the line
2538 static bool insert_return_code(text_body_type *tb)
2540 char buf[MAX_LINELEN];
2541 int i, j, num_lines;
2543 for (num_lines = 0; tb->lines_list[num_lines]; num_lines++);
2545 if (num_lines >= MAX_LINES - 2) return FALSE;
2548 for (; tb->cy < num_lines; num_lines--)
2550 tb->lines_list[num_lines + 1] = tb->lines_list[num_lines];
2551 tb->states[num_lines + 1] = tb->states[num_lines];
2554 for (i = j = 0; tb->lines_list[tb->cy][i] && i < tb->cx; i++)
2557 if (iskanji(tb->lines_list[tb->cy][i]))
2558 buf[j++] = tb->lines_list[tb->cy][i++];
2560 buf[j++] = tb->lines_list[tb->cy][i];
2564 tb->lines_list[tb->cy + 1] = string_make(&tb->lines_list[tb->cy][i]);
2565 string_free(tb->lines_list[tb->cy]);
2566 tb->lines_list[tb->cy] = string_make(buf);
2567 tb->dirty_flags |= DIRTY_EXPRESSION;
2574 * Choose an item and get auto-picker entry from it.
2576 static bool entry_from_choosed_object(player_type *player_ptr, autopick_type *entry)
2578 concptr q = _("どのアイテムを登録しますか? ", "Enter which item? ");
2579 concptr s = _("アイテムを持っていない。", "You have nothing to enter.");
2581 o_ptr = choose_object(player_ptr, NULL, q, s, USE_INVEN | USE_FLOOR | USE_EQUIP, 0);
2582 if (!o_ptr) return FALSE;
2584 autopick_entry_from_object(player_ptr, entry, o_ptr);
2590 * Choose an item for search
2592 static bool get_object_for_search(player_type *player_ptr, object_type **o_handle, concptr *search_strp)
2594 concptr q = _("どのアイテムを検索しますか? ", "Enter which item? ");
2595 concptr s = _("アイテムを持っていない。", "You have nothing to enter.");
2597 o_ptr = choose_object(player_ptr, NULL, q, s, USE_INVEN | USE_FLOOR | USE_EQUIP, 0);
2598 if (!o_ptr) return FALSE;
2601 string_free(*search_strp);
2602 char buf[MAX_NLEN + 20];
2603 object_desc(player_ptr, buf, *o_handle, (OD_NO_FLAVOR | OD_OMIT_PREFIX | OD_NO_PLURAL));
2604 *search_strp = string_make(format("<%s>", buf));
2610 * Prepare for search by destroyed object
2612 static bool get_destroyed_object_for_search(player_type *player_ptr, object_type **o_handle, concptr *search_strp)
2614 if (!autopick_last_destroyed_object.k_idx) return FALSE;
2616 *o_handle = &autopick_last_destroyed_object;
2617 string_free(*search_strp);
2618 char buf[MAX_NLEN + 20];
2619 object_desc(player_ptr, buf, *o_handle, (OD_NO_FLAVOR | OD_OMIT_PREFIX | OD_NO_PLURAL));
2620 *search_strp = string_make(format("<%s>", buf));
2626 * Choose an item or string for search
2628 static byte get_string_for_search(player_type *player_ptr, object_type **o_handle, concptr *search_strp)
2632 * TERM_YELLOW : Overwrite mode
2633 * TERM_WHITE : Insert mode
2635 byte color = TERM_YELLOW;
2636 char buf[MAX_NLEN + 20];
2638 char prompt[] = _("検索(^I:持ち物 ^L:破壊された物): ", "Search key(^I:inven ^L:destroyed): ");
2639 int col = sizeof(prompt) - 1;
2640 if (*search_strp) strcpy(buf, *search_strp);
2643 if (*o_handle) color = TERM_L_GREEN;
2652 Term_erase(col, 0, 255);
2653 Term_putstr(col, 0, -1, color, buf);
2654 Term_gotoxy(col + pos, 0);
2656 skey = inkey_special(TRUE);
2664 if (pos == 0) break;
2668 int next_pos = i + 1;
2671 if (iskanji(buf[i])) next_pos++;
2673 if (next_pos >= pos) break;
2685 if ('\0' == buf[pos]) break;
2688 if (iskanji(buf[pos])) pos += 2;
2705 if (*o_handle) return (back ? -1 : 1);
2706 string_free(*search_strp);
2707 *search_strp = string_make(buf);
2709 return (back ? -1 : 1);
2712 return get_object_for_search(player_ptr, o_handle, search_strp);
2715 if (get_destroyed_object_for_search(player_ptr, o_handle, search_strp))
2723 if (pos == 0) break;
2727 int next_pos = i + 1;
2729 if (iskanji(buf[i])) next_pos++;
2731 if (next_pos >= pos) break;
2745 if (buf[pos] == '\0') break;
2749 if (iskanji(buf[pos])) src++;
2752 while ('\0' != (buf[dst++] = buf[src++]));
2761 if (skey & SKEY_MASK) break;
2764 if (color != TERM_WHITE)
2766 if (color == TERM_L_GREEN)
2769 string_free(*search_strp);
2770 *search_strp = NULL;
2777 strcpy(tmp, buf + pos);
2799 if (pos < len && (isprint(c) || iskana(c)))
2801 if (pos < len && isprint(c))
2813 my_strcat(buf, tmp, len + 1);
2819 if (*o_handle == NULL || color == TERM_L_GREEN) continue;
2823 string_free(*search_strp);
2824 *search_strp = NULL;
2830 * Search next line matches for o_ptr
2832 static void search_for_object(player_type *player_ptr, text_body_type *tb, object_type *o_ptr, bool forward)
2834 autopick_type an_entry, *entry = &an_entry;
2835 GAME_TEXT o_name[MAX_NLEN];
2836 int bypassed_cy = -1;
2838 object_desc(player_ptr, o_name, o_ptr, (OD_NO_FLAVOR | OD_OMIT_PREFIX | OD_NO_PLURAL));
2839 str_tolower(o_name);
2846 if (!tb->lines_list[++i]) break;
2853 if (!autopick_new_entry(entry, tb->lines_list[i], FALSE)) continue;
2855 match = is_autopick_aux(player_ptr, o_ptr, entry, o_name);
2856 autopick_free_entry(entry);
2857 if (!match) continue;
2859 if (tb->states[i] & LSTAT_BYPASS)
2861 if (bypassed_cy == -1) bypassed_cy = i;
2867 if (bypassed_cy != -1)
2869 tb->dirty_flags |= DIRTY_SKIP_INACTIVE;
2875 if (bypassed_cy == -1)
2877 tb->dirty_flags |= DIRTY_NOT_FOUND;
2882 tb->cy = bypassed_cy;
2883 tb->dirty_flags |= DIRTY_INACTIVE;
2888 * Search next line matches to the string
2890 static void search_for_string(text_body_type *tb, concptr search_str, bool forward)
2892 int bypassed_cy = -1;
2893 int bypassed_cx = 0;
2901 if (!tb->lines_list[++i]) break;
2908 pos = my_strstr(tb->lines_list[i], search_str);
2911 if ((tb->states[i] & LSTAT_BYPASS) &&
2912 !(tb->states[i] & LSTAT_EXPRESSION))
2914 if (bypassed_cy == -1)
2917 bypassed_cx = (int)(pos - tb->lines_list[i]);
2923 tb->cx = (int)(pos - tb->lines_list[i]);
2926 if (bypassed_cy != -1)
2928 tb->dirty_flags |= DIRTY_SKIP_INACTIVE;
2934 if (bypassed_cy == -1)
2936 tb->dirty_flags |= DIRTY_NOT_FOUND;
2940 tb->cx = bypassed_cx;
2941 tb->cy = bypassed_cy;
2942 tb->dirty_flags |= DIRTY_INACTIVE;
2947 * Find a command by 'key'.
2949 static int get_com_id(char key)
2951 for (int i = 0; menu_data[i].name; i++)
2953 if (menu_data[i].key == key)
2955 return menu_data[i].com_id;
2964 * Display the menu, and get a command
2966 static int do_command_menu(int level, int start)
2969 int col0 = 5 + level * 7;
2970 int row0 = 1 + level * 3;
2971 int menu_id_list[26];
2973 char linestr[MAX_LINELEN];
2976 for (int i = start; menu_data[i].level >= level; i++)
2980 /* Ignore lower level sub menus */
2981 if (menu_data[i].level > level) continue;
2983 len = strlen(menu_data[i].name);
2984 if (len > max_len) max_len = len;
2986 menu_id_list[menu_key] = i;
2990 while (menu_key < 26)
2992 menu_id_list[menu_key] = -1;
2996 int max_menu_wid = max_len + 3 + 3;
2998 /* Prepare box line */
3000 strcat(linestr, "+");
3001 for (int i = 0; i < max_menu_wid + 2; i++)
3003 strcat(linestr, "-");
3006 strcat(linestr, "+");
3016 int row1 = row0 + 1;
3017 Term_putstr(col0, row0, -1, TERM_WHITE, linestr);
3020 for (int i = start; menu_data[i].level >= level; i++)
3022 char com_key_str[3];
3024 if (menu_data[i].level > level) continue;
3026 if (menu_data[i].com_id == -1)
3028 strcpy(com_key_str, _("▼", ">"));
3030 else if (menu_data[i].key != -1)
3032 com_key_str[0] = '^';
3033 com_key_str[1] = menu_data[i].key + '@';
3034 com_key_str[2] = '\0';
3038 com_key_str[0] = '\0';
3041 str = format("| %c) %-*s %2s | ", menu_key + 'a', max_len, menu_data[i].name, com_key_str);
3043 Term_putstr(col0, row1++, -1, TERM_WHITE, str);
3048 Term_putstr(col0, row1, -1, TERM_WHITE, linestr);
3052 prt(format(_("(a-%c) コマンド:", "(a-%c) Command:"), menu_key + 'a' - 1), 0, 0);
3055 if (key == ESCAPE) return 0;
3057 bool is_alphabet = key >= 'a' && key <= 'z';
3060 com_id = get_com_id(key);
3069 menu_id = menu_id_list[key - 'a'];
3071 if (menu_id < 0) continue;
3073 com_id = menu_data[menu_id].com_id;
3077 com_id = do_command_menu(level + 1, menu_id + 1);
3079 if (com_id) return com_id;
3090 static chain_str_type *new_chain_str(concptr str)
3092 chain_str_type *chain;
3093 size_t len = strlen(str);
3094 chain = (chain_str_type *)ralloc(sizeof(chain_str_type) + len * sizeof(char));
3095 strcpy(chain->s, str);
3101 static void kill_yank_chain(text_body_type *tb)
3103 chain_str_type *chain = tb->yank;
3105 tb->yank_eol = TRUE;
3109 chain_str_type *next = chain->next;
3110 size_t len = strlen(chain->s);
3112 rnfree(chain, sizeof(chain_str_type) + len * sizeof(char));
3119 static void add_str_to_yank(text_body_type *tb, concptr str)
3121 tb->yank_eol = FALSE;
3122 if (NULL == tb->yank)
3124 tb->yank = new_chain_str(str);
3128 chain_str_type *chain;
3135 chain->next = new_chain_str(str);
3140 chain = chain->next;
3146 * Do work for the copy editor-command
3148 static void copy_text_to_yank(text_body_type *tb)
3150 int len = strlen(tb->lines_list[tb->cy]);
3151 if (tb->cx > len) tb->cx = len;
3160 kill_yank_chain(tb);
3161 if (tb->my != tb->cy)
3163 int by1 = MIN(tb->my, tb->cy);
3164 int by2 = MAX(tb->my, tb->cy);
3166 for (int y = by1; y <= by2; y++)
3168 add_str_to_yank(tb, tb->lines_list[y]);
3171 add_str_to_yank(tb, "");
3173 tb->dirty_flags |= DIRTY_ALL;
3177 char buf[MAX_LINELEN];
3178 int bx1 = MIN(tb->mx, tb->cx);
3179 int bx2 = MAX(tb->mx, tb->cx);
3180 if (bx2 > len) bx2 = len;
3182 if (bx1 == 0 && bx2 == len)
3184 add_str_to_yank(tb, tb->lines_list[tb->cy]);
3185 add_str_to_yank(tb, "");
3189 int end = bx2 - bx1;
3190 for (int i = 0; i < bx2 - bx1; i++)
3192 buf[i] = tb->lines_list[tb->cy][bx1 + i];
3196 add_str_to_yank(tb, buf);
3200 tb->dirty_flags |= DIRTY_ALL;
3207 static void draw_text_editor(player_type *player_ptr, text_body_type *tb)
3210 int by1 = 0, by2 = 0;
3212 Term_get_size(&tb->wid, &tb->hgt);
3215 * Top line (-1), description line (-3), separator (-1)
3218 tb->hgt -= 2 + DESCRIPT_HGT;
3221 /* Don't let cursor at second byte of kanji */
3222 for (i = 0; tb->lines_list[tb->cy][i]; i++)
3223 if (iskanji(tb->lines_list[tb->cy][i]))
3229 * Move to a correct position in the
3232 if (i & 1) tb->cx--;
3238 if (tb->cy < tb->upper || tb->upper + tb->hgt <= tb->cy)
3239 tb->upper = tb->cy - (tb->hgt) / 2;
3242 if ((tb->cx < tb->left + 10 && tb->left > 0) || tb->left + tb->wid - 5 <= tb->cx)
3243 tb->left = tb->cx - (tb->wid) * 2 / 3;
3247 if (tb->old_wid != tb->wid || tb->old_hgt != tb->hgt)
3248 tb->dirty_flags |= DIRTY_SCREEN;
3249 else if (tb->old_upper != tb->upper || tb->old_left != tb->left)
3250 tb->dirty_flags |= DIRTY_ALL;
3252 if (tb->dirty_flags & DIRTY_SCREEN)
3254 tb->dirty_flags |= (DIRTY_ALL | DIRTY_MODE);
3258 if (tb->dirty_flags & DIRTY_MODE)
3260 char buf[MAX_LINELEN];
3261 int sepa_length = tb->wid;
3262 for (i = 0; i < sepa_length; i++)
3265 Term_putstr(0, tb->hgt + 1, sepa_length, TERM_WHITE, buf);
3268 if (tb->dirty_flags & DIRTY_EXPRESSION)
3271 for (int y = 0; tb->lines_list[y]; y++)
3275 concptr s = tb->lines_list[y];
3279 tb->states[y] = state;
3281 if (*s++ != '?') continue;
3282 if (*s++ != ':') continue;
3284 if (streq(s, "$AUTOREGISTER"))
3285 state |= LSTAT_AUTOREGISTER;
3288 ss = (char *)string_make(s);
3291 v = process_pref_file_expr(player_ptr, &ss, &f);
3293 if (streq(v, "0")) state |= LSTAT_BYPASS;
3294 else state &= ~LSTAT_BYPASS;
3296 C_KILL(s_keep, s_len + 1, char);
3298 tb->states[y] = state | LSTAT_EXPRESSION;
3301 tb->dirty_flags |= DIRTY_ALL;
3306 tb->dirty_flags |= DIRTY_ALL;
3308 by1 = MIN(tb->my, tb->cy);
3309 by2 = MAX(tb->my, tb->cy);
3312 for (i = 0; i < tb->hgt; i++)
3318 int y = tb->upper + i;
3320 if (!(tb->dirty_flags & DIRTY_ALL) && (tb->dirty_line != y))
3323 msg = tb->lines_list[y];
3326 for (j = 0; *msg; msg++, j++)
3328 if (j == tb->left) break;
3343 Term_erase(0, i + 1, tb->wid);
3344 if (tb->states[y] & LSTAT_AUTOREGISTER)
3350 if (tb->states[y] & LSTAT_BYPASS) color = TERM_SLATE;
3351 else color = TERM_WHITE;
3354 if (!tb->mark || (y < by1 || by2 < y))
3356 Term_putstr(leftcol, i + 1, tb->wid - 1, color, msg);
3358 else if (by1 != by2)
3360 Term_putstr(leftcol, i + 1, tb->wid - 1, TERM_YELLOW, msg);
3364 int x0 = leftcol + tb->left;
3365 int len = strlen(tb->lines_list[tb->cy]);
3366 int bx1 = MIN(tb->mx, tb->cx);
3367 int bx2 = MAX(tb->mx, tb->cx);
3369 if (bx2 > len) bx2 = len;
3371 Term_gotoxy(leftcol, i + 1);
3372 if (x0 < bx1) Term_addstr(bx1 - x0, color, msg);
3373 if (x0 < bx2) Term_addstr(bx2 - bx1, TERM_YELLOW, msg + (bx1 - x0));
3374 Term_addstr(-1, color, msg + (bx2 - x0));
3378 for (; i < tb->hgt; i++)
3380 Term_erase(0, i + 1, tb->wid);
3383 bool is_dirty_diary = (tb->dirty_flags & (DIRTY_ALL | DIRTY_NOT_FOUND | DIRTY_NO_SEARCH)) != 0;
3384 bool is_updated = tb->old_cy != tb->cy || is_dirty_diary || tb->dirty_line == tb->cy;
3385 if (is_updated) return;
3387 autopick_type an_entry, *entry = &an_entry;
3388 concptr str1 = NULL, str2 = NULL;
3389 for (i = 0; i < DESCRIPT_HGT; i++)
3391 Term_erase(0, tb->hgt + 2 + i, tb->wid);
3394 if (tb->dirty_flags & DIRTY_NOT_FOUND)
3396 str1 = format(_("パターンが見つかりません: %s", "Pattern not found: %s"), tb->search_str);
3398 else if (tb->dirty_flags & DIRTY_SKIP_INACTIVE)
3400 str1 = format(_("無効状態の行をスキップしました。(%sを検索中)",
3401 "Some inactive lines are skipped. (Searching %s)"), tb->search_str);
3403 else if (tb->dirty_flags & DIRTY_INACTIVE)
3405 str1 = format(_("無効状態の行だけが見付かりました。(%sを検索中)",
3406 "Found only an inactive line. (Searching %s)"), tb->search_str);
3408 else if (tb->dirty_flags & DIRTY_NO_SEARCH)
3410 str1 = _("検索するパターンがありません(^S で検索)。", "No pattern to search. (Press ^S to search.)");
3412 else if (tb->lines_list[tb->cy][0] == '#')
3414 str1 = _("この行はコメントです。", "This line is a comment.");
3416 else if (tb->lines_list[tb->cy][0] && tb->lines_list[tb->cy][1] == ':')
3418 switch (tb->lines_list[tb->cy][0])
3421 str1 = _("この行は条件分岐式です。", "This line is a Conditional Expression.");
3424 str1 = _("この行はマクロの実行内容を定義します。", "This line defines a Macro action.");
3427 str1 = _("この行はマクロのトリガー・キーを定義します。", "This line defines a Macro trigger key.");
3430 str1 = _("この行はキー配置を定義します。", "This line defines a Keymap.");
3434 switch (tb->lines_list[tb->cy][0])
3437 if (tb->states[tb->cy] & LSTAT_BYPASS)
3439 str2 = _("現在の式の値は「偽(=0)」です。", "The expression is 'False'(=0) currently.");
3443 str2 = _("現在の式の値は「真(=1)」です。", "The expression is 'True'(=1) currently.");
3448 if (tb->states[tb->cy] & LSTAT_AUTOREGISTER)
3450 str2 = _("この行は後で削除されます。", "This line will be delete later.");
3453 else if (tb->states[tb->cy] & LSTAT_BYPASS)
3455 str2 = _("この行は現在は無効な状態です。", "This line is bypassed currently.");
3460 else if (autopick_new_entry(entry, tb->lines_list[tb->cy], FALSE))
3462 char buf[MAX_LINELEN];
3463 char temp[MAX_LINELEN];
3466 describe_autopick(buf, entry);
3468 if (tb->states[tb->cy] & LSTAT_AUTOREGISTER)
3470 strcat(buf, _("この行は後で削除されます。", " This line will be delete later."));
3473 if (tb->states[tb->cy] & LSTAT_BYPASS)
3475 strcat(buf, _("この行は現在は無効な状態です。", " This line is bypassed currently."));
3478 roff_to_buf(buf, 81, temp, sizeof(temp));
3480 for (i = 0; i < 3; i++)
3486 prt(t, tb->hgt + 1 + 1 + i, 0);
3490 autopick_free_entry(entry);
3493 if (str1) prt(str1, tb->hgt + 1 + 1, 0);
3494 if (str2) prt(str2, tb->hgt + 1 + 2, 0);
3499 * Kill segment of a line
3501 static void kill_line_segment(text_body_type *tb, int y, int x0, int x1, bool whole)
3503 concptr s = tb->lines_list[y];
3504 if (whole && x0 == 0 && s[x1] == '\0' && tb->lines_list[y + 1])
3506 string_free(tb->lines_list[y]);
3509 for (i = y; tb->lines_list[i + 1]; i++)
3510 tb->lines_list[i] = tb->lines_list[i + 1];
3511 tb->lines_list[i] = NULL;
3513 tb->dirty_flags |= DIRTY_EXPRESSION;
3518 if (x0 == x1) return;
3520 char buf[MAX_LINELEN];
3522 for (int x = 0; x < x0; x++)
3525 for (int x = x1; s[x]; x++)
3529 string_free(tb->lines_list[y]);
3530 tb->lines_list[y] = string_make(buf);
3531 check_expression_line(tb, y);
3537 * Get a trigger key and insert ASCII string for the trigger
3539 static bool insert_macro_line(text_body_type *tb)
3558 ascii_to_text(tmp, buf);
3559 if (!tmp[0]) return FALSE;
3562 insert_return_code(tb);
3563 string_free(tb->lines_list[tb->cy]);
3564 tb->lines_list[tb->cy] = string_make(format("P:%s", tmp));
3566 i = macro_find_exact(buf);
3573 ascii_to_text(tmp, macro__act[i]);
3576 insert_return_code(tb);
3577 string_free(tb->lines_list[tb->cy]);
3578 tb->lines_list[tb->cy] = string_make(format("A:%s", tmp));
3585 * Get a command key and insert ASCII string for the key
3587 static bool insert_keymap_line(text_body_type *tb)
3590 if (rogue_like_commands)
3592 mode = KEYMAP_MODE_ROGUE;
3596 mode = KEYMAP_MODE_ORIG;
3606 ascii_to_text(tmp, buf);
3607 if (!tmp[0]) return FALSE;
3610 insert_return_code(tb);
3611 string_free(tb->lines_list[tb->cy]);
3612 tb->lines_list[tb->cy] = string_make(format("C:%d:%s", mode, tmp));
3614 concptr act = keymap_act[mode][(byte)(buf[0])];
3617 ascii_to_text(tmp, act);
3620 insert_return_code(tb);
3621 string_free(tb->lines_list[tb->cy]);
3622 tb->lines_list[tb->cy] = string_make(format("A:%s", tmp));
3629 * Execute a single editor command
3631 static bool do_editor_command(player_type *player_ptr, text_body_type *tb, int com_id)
3638 if (!get_check(_("全ての変更を破棄してから終了します。よろしいですか? ",
3639 "Discard all changes and quit. Are you sure? "))) break;
3642 return QUIT_WITHOUT_SAVE;
3645 return QUIT_AND_SAVE;
3648 if (!get_check(_("全ての変更を破棄して元の状態に戻します。よろしいですか? ",
3649 "Discard all changes and revert to original file. Are you sure? "))) break;
3651 free_text_lines(tb->lines_list);
3652 tb->lines_list = read_pickpref_text_lines(player_ptr, &tb->filename_mode);
3653 tb->dirty_flags |= DIRTY_ALL | DIRTY_MODE | DIRTY_EXPRESSION;
3654 tb->cx = tb->cy = 0;
3657 tb->changed = FALSE;
3661 (void)show_file(player_ptr, TRUE, _("jeditor.txt", "editor.txt"), NULL, 0, 0);
3662 tb->dirty_flags |= DIRTY_SCREEN;
3670 tb->dirty_flags |= DIRTY_ALL;
3673 insert_return_code(tb);
3677 tb->dirty_flags |= DIRTY_ALL;
3689 len = strlen(tb->lines_list[tb->cy]);
3690 if (len < tb->cx) tb->cx = len;
3692 for (i = 0; tb->lines_list[tb->cy][i]; i++)
3694 if (iskanji(tb->lines_list[tb->cy][i]))
3706 else if (tb->cy > 0)
3709 tb->cx = strlen(tb->lines_list[tb->cy]);
3715 if (!tb->lines_list[tb->cy + 1])
3717 if (!add_empty_line(tb)) break;
3724 if (tb->cy > 0) tb->cy--;
3730 if (iskanji(tb->lines_list[tb->cy][tb->cx])) tb->cx++;
3733 int len = strlen(tb->lines_list[tb->cy]);
3737 if (!tb->lines_list[tb->cy + 1])
3739 if (!add_empty_line(tb)) break;
3753 tb->cx = strlen(tb->lines_list[tb->cy]);
3757 while (0 < tb->cy && tb->upper <= tb->cy)
3759 while (0 < tb->upper && tb->cy + 1 < tb->upper + tb->hgt)
3764 while (tb->cy < tb->upper + tb->hgt)
3766 if (!tb->lines_list[tb->cy + 1])
3768 if (!add_empty_line(tb)) break;
3784 if (!tb->lines_list[tb->cy + 1])
3786 if (!add_empty_line(tb)) break;
3797 copy_text_to_yank(tb);
3798 if (tb->my == tb->cy)
3800 int bx1 = MIN(tb->mx, tb->cx);
3801 int bx2 = MAX(tb->mx, tb->cx);
3802 int len = strlen(tb->lines_list[tb->cy]);
3803 if (bx2 > len) bx2 = len;
3805 kill_line_segment(tb, tb->cy, bx1, bx2, TRUE);
3810 int by1 = MIN(tb->my, tb->cy);
3811 int by2 = MAX(tb->my, tb->cy);
3813 for (int y = by2; y >= by1; y--)
3815 int len = strlen(tb->lines_list[y]);
3817 kill_line_segment(tb, y, 0, len, TRUE);
3825 tb->dirty_flags |= DIRTY_ALL;
3830 copy_text_to_yank(tb);
3833 * Move cursor position to the end of the selection
3835 * Pressing ^C ^V correctly duplicates the selection.
3837 if (tb->my != tb->cy)
3839 tb->cy = MAX(tb->cy, tb->my);
3840 if (!tb->lines_list[tb->cy + 1])
3842 if (!add_empty_line(tb)) break;
3849 tb->cx = MAX(tb->cx, tb->mx);
3850 if (!tb->lines_list[tb->cy][tb->cx])
3852 if (!tb->lines_list[tb->cy + 1])
3854 if (!add_empty_line(tb)) break;
3865 chain_str_type *chain = tb->yank;
3866 int len = strlen(tb->lines_list[tb->cy]);
3868 if (tb->cx > len) tb->cx = len;
3873 tb->dirty_flags |= DIRTY_ALL;
3878 concptr yank_str = chain->s;
3879 char buf[MAX_LINELEN];
3881 char rest[MAX_LINELEN], *rest_ptr = rest;
3882 for (i = 0; i < tb->cx; i++)
3883 buf[i] = tb->lines_list[tb->cy][i];
3885 strcpy(rest, &(tb->lines_list[tb->cy][i]));
3886 while (*yank_str && i < MAX_LINELEN - 1)
3888 buf[i++] = *yank_str++;
3892 chain = chain->next;
3893 if (chain || tb->yank_eol)
3895 insert_return_code(tb);
3896 string_free(tb->lines_list[tb->cy]);
3897 tb->lines_list[tb->cy] = string_make(buf);
3904 tb->cx = strlen(buf);
3905 while (*rest_ptr && i < MAX_LINELEN - 1)
3907 buf[i++] = *rest_ptr++;
3911 string_free(tb->lines_list[tb->cy]);
3912 tb->lines_list[tb->cy] = string_make(buf);
3916 tb->dirty_flags |= DIRTY_ALL;
3917 tb->dirty_flags |= DIRTY_EXPRESSION;
3926 tb->dirty_flags |= DIRTY_ALL;
3930 tb->mark = MARK_MARK;
3931 if (com_id == tb->old_com_id)
3939 tb->dirty_flags |= DIRTY_ALL;
3943 int len = strlen(tb->lines_list[tb->cy]);
3947 if (tb->cx > len) tb->mx = len;
3952 int len = strlen(tb->lines_list[tb->cy]);
3953 if (tb->cx > len) tb->cx = len;
3958 tb->dirty_flags |= DIRTY_ALL;
3961 if (tb->old_com_id != com_id)
3963 kill_yank_chain(tb);
3969 add_str_to_yank(tb, &(tb->lines_list[tb->cy][tb->cx]));
3970 kill_line_segment(tb, tb->cy, tb->cx, len, FALSE);
3971 tb->dirty_line = tb->cy;
3975 if (tb->yank_eol) add_str_to_yank(tb, "");
3977 tb->yank_eol = TRUE;
3978 do_editor_command(player_ptr, tb, EC_DELETE_CHAR);
3981 case EC_DELETE_CHAR:
3986 tb->dirty_flags |= DIRTY_ALL;
3990 if (iskanji(tb->lines_list[tb->cy][tb->cx])) tb->cx++;
3993 int len = strlen(tb->lines_list[tb->cy]);
3996 do_editor_command(player_ptr, tb, EC_BACKSPACE);
4000 if (tb->lines_list[tb->cy + 1])
4011 do_editor_command(player_ptr, tb, EC_BACKSPACE);
4017 char buf[MAX_LINELEN];
4021 tb->dirty_flags |= DIRTY_ALL;
4024 len = strlen(tb->lines_list[tb->cy]);
4025 if (len < tb->cx) tb->cx = len;
4029 if (tb->cy == 0) break;
4030 tb->cx = strlen(tb->lines_list[tb->cy - 1]);
4031 strcpy(buf, tb->lines_list[tb->cy - 1]);
4032 strcat(buf, tb->lines_list[tb->cy]);
4033 string_free(tb->lines_list[tb->cy - 1]);
4034 string_free(tb->lines_list[tb->cy]);
4035 tb->lines_list[tb->cy - 1] = string_make(buf);
4037 for (i = tb->cy; tb->lines_list[i + 1]; i++)
4038 tb->lines_list[i] = tb->lines_list[i + 1];
4040 tb->lines_list[i] = NULL;
4042 tb->dirty_flags |= DIRTY_ALL;
4043 tb->dirty_flags |= DIRTY_EXPRESSION;
4048 for (i = j = k = 0; tb->lines_list[tb->cy][i] && i < tb->cx; i++)
4052 if (iskanji(tb->lines_list[tb->cy][i]))
4053 buf[j++] = tb->lines_list[tb->cy][i++];
4055 buf[j++] = tb->lines_list[tb->cy][i];
4064 for (; tb->lines_list[tb->cy][i]; i++)
4066 buf[j++] = tb->lines_list[tb->cy][i];
4070 string_free(tb->lines_list[tb->cy]);
4071 tb->lines_list[tb->cy] = string_make(buf);
4072 tb->dirty_line = tb->cy;
4073 check_expression_line(tb, tb->cy);
4080 tb->dirty_flags |= DIRTY_SCREEN;
4081 search_dir = get_string_for_search(player_ptr, &tb->search_o_ptr, &tb->search_str);
4083 if (!search_dir) break;
4085 if (search_dir == 1) do_editor_command(player_ptr, tb, EC_SEARCH_FORW);
4086 else do_editor_command(player_ptr, tb, EC_SEARCH_BACK);
4089 case EC_SEARCH_FORW:
4090 if (tb->search_o_ptr)
4092 search_for_object(player_ptr, tb, tb->search_o_ptr, TRUE);
4096 if (tb->search_str && tb->search_str[0])
4098 search_for_string(tb, tb->search_str, TRUE);
4102 tb->dirty_flags |= DIRTY_NO_SEARCH;
4105 case EC_SEARCH_BACK:
4106 if (tb->search_o_ptr)
4108 search_for_object(player_ptr, tb, tb->search_o_ptr, FALSE);
4112 if (tb->search_str && tb->search_str[0])
4114 search_for_string(tb, tb->search_str, FALSE);
4118 tb->dirty_flags |= DIRTY_NO_SEARCH;
4122 tb->dirty_flags |= DIRTY_SCREEN;
4124 if (!get_object_for_search(player_ptr, &tb->search_o_ptr, &tb->search_str)) break;
4126 do_editor_command(player_ptr, tb, EC_SEARCH_FORW);
4129 case EC_SEARCH_DESTROYED:
4130 if (!get_destroyed_object_for_search(player_ptr, &tb->search_o_ptr, &tb->search_str))
4132 tb->dirty_flags |= DIRTY_NO_SEARCH;
4136 do_editor_command(player_ptr, tb, EC_SEARCH_FORW);
4139 case EC_INSERT_OBJECT:
4141 autopick_type an_entry, *entry = &an_entry;
4142 if (!entry_from_choosed_object(player_ptr, entry))
4144 tb->dirty_flags |= DIRTY_SCREEN;
4149 insert_return_code(tb);
4150 string_free(tb->lines_list[tb->cy]);
4151 tb->lines_list[tb->cy] = autopick_line_from_entry_kill(entry);
4152 tb->dirty_flags |= DIRTY_SCREEN;
4155 case EC_INSERT_DESTROYED:
4156 if (!tb->last_destroyed) break;
4159 insert_return_code(tb);
4160 string_free(tb->lines_list[tb->cy]);
4161 tb->lines_list[tb->cy] = string_make(tb->last_destroyed);
4162 tb->dirty_flags |= DIRTY_ALL;
4166 case EC_INSERT_BLOCK:
4168 char expression[80];
4169 sprintf(expression, "?:[AND [EQU $RACE %s] [EQU $CLASS %s] [GEQ $LEVEL %02d]]",
4171 rp_ptr->E_title, cp_ptr->E_title,
4173 rp_ptr->title, cp_ptr->title,
4177 insert_return_code(tb);
4178 string_free(tb->lines_list[tb->cy]);
4179 tb->lines_list[tb->cy] = string_make(expression);
4181 insert_return_code(tb);
4182 string_free(tb->lines_list[tb->cy]);
4183 tb->lines_list[tb->cy] = string_make("?:1");
4184 tb->dirty_flags |= DIRTY_ALL;
4189 case EC_INSERT_MACRO:
4190 draw_text_editor(player_ptr, tb);
4191 Term_erase(0, tb->cy - tb->upper + 1, tb->wid);
4192 Term_putstr(0, tb->cy - tb->upper + 1, tb->wid - 1, TERM_YELLOW, _("P:<トリガーキー>: ", "P:<Trigger key>: "));
4193 if (!insert_macro_line(tb)) break;
4196 tb->dirty_flags |= DIRTY_ALL;
4200 case EC_INSERT_KEYMAP:
4201 draw_text_editor(player_ptr, tb);
4202 Term_erase(0, tb->cy - tb->upper + 1, tb->wid);
4203 Term_putstr(0, tb->cy - tb->upper + 1, tb->wid - 1, TERM_YELLOW,
4204 format(_("C:%d:<コマンドキー>: ", "C:%d:<Keypress>: "), (rogue_like_commands ? KEYMAP_MODE_ROGUE : KEYMAP_MODE_ORIG)));
4206 if (!insert_keymap_line(tb)) break;
4209 tb->dirty_flags |= DIRTY_ALL;
4213 case EC_CL_AUTOPICK: toggle_command_letter(tb, DO_AUTOPICK); break;
4214 case EC_CL_DESTROY: toggle_command_letter(tb, DO_AUTODESTROY); break;
4215 case EC_CL_LEAVE: toggle_command_letter(tb, DONT_AUTOPICK); break;
4216 case EC_CL_QUERY: toggle_command_letter(tb, DO_QUERY_AUTOPICK); break;
4217 case EC_CL_NO_DISP: toggle_command_letter(tb, DO_DISPLAY); break;
4219 case EC_IK_UNAWARE: toggle_keyword(tb, FLG_UNAWARE); break;
4220 case EC_IK_UNIDENTIFIED: toggle_keyword(tb, FLG_UNIDENTIFIED); break;
4221 case EC_IK_IDENTIFIED: toggle_keyword(tb, FLG_IDENTIFIED); break;
4222 case EC_IK_STAR_IDENTIFIED: toggle_keyword(tb, FLG_STAR_IDENTIFIED); break;
4223 case EC_KK_WEAPONS: toggle_keyword(tb, FLG_WEAPONS); break;
4224 case EC_KK_FAVORITE_WEAPONS: toggle_keyword(tb, FLG_FAVORITE_WEAPONS); break;
4225 case EC_KK_ARMORS: toggle_keyword(tb, FLG_ARMORS); break;
4226 case EC_KK_MISSILES: toggle_keyword(tb, FLG_MISSILES); break;
4227 case EC_KK_DEVICES: toggle_keyword(tb, FLG_DEVICES); break;
4228 case EC_KK_LIGHTS: toggle_keyword(tb, FLG_LIGHTS); break;
4229 case EC_KK_JUNKS: toggle_keyword(tb, FLG_JUNKS); break;
4230 case EC_KK_CORPSES: toggle_keyword(tb, FLG_CORPSES); break;
4231 case EC_KK_SPELLBOOKS: toggle_keyword(tb, FLG_SPELLBOOKS); break;
4232 case EC_KK_SHIELDS: toggle_keyword(tb, FLG_SHIELDS); break;
4233 case EC_KK_BOWS: toggle_keyword(tb, FLG_BOWS); break;
4234 case EC_KK_RINGS: toggle_keyword(tb, FLG_RINGS); break;
4235 case EC_KK_AMULETS: toggle_keyword(tb, FLG_AMULETS); break;
4236 case EC_KK_SUITS: toggle_keyword(tb, FLG_SUITS); break;
4237 case EC_KK_CLOAKS: toggle_keyword(tb, FLG_CLOAKS); break;
4238 case EC_KK_HELMS: toggle_keyword(tb, FLG_HELMS); break;
4239 case EC_KK_GLOVES: toggle_keyword(tb, FLG_GLOVES); break;
4240 case EC_KK_BOOTS: toggle_keyword(tb, FLG_BOOTS); break;
4241 case EC_OK_COLLECTING: toggle_keyword(tb, FLG_COLLECTING); break;
4242 case EC_OK_BOOSTED: toggle_keyword(tb, FLG_BOOSTED); break;
4243 case EC_OK_MORE_DICE: toggle_keyword(tb, FLG_MORE_DICE); break;
4244 case EC_OK_MORE_BONUS: toggle_keyword(tb, FLG_MORE_BONUS); break;
4245 case EC_OK_WORTHLESS: toggle_keyword(tb, FLG_WORTHLESS); break;
4246 case EC_OK_ARTIFACT: toggle_keyword(tb, FLG_ARTIFACT); break;
4247 case EC_OK_EGO: toggle_keyword(tb, FLG_EGO); break;
4248 case EC_OK_GOOD: toggle_keyword(tb, FLG_GOOD); break;
4249 case EC_OK_NAMELESS: toggle_keyword(tb, FLG_NAMELESS); break;
4250 case EC_OK_AVERAGE: toggle_keyword(tb, FLG_AVERAGE); break;
4251 case EC_OK_RARE: toggle_keyword(tb, FLG_RARE); break;
4252 case EC_OK_COMMON: toggle_keyword(tb, FLG_COMMON); break;
4253 case EC_OK_WANTED: toggle_keyword(tb, FLG_WANTED); break;
4254 case EC_OK_UNIQUE: toggle_keyword(tb, FLG_UNIQUE); break;
4255 case EC_OK_HUMAN: toggle_keyword(tb, FLG_HUMAN); break;
4256 case EC_OK_UNREADABLE:
4257 toggle_keyword(tb, FLG_UNREADABLE);
4258 add_keyword(tb, FLG_SPELLBOOKS);
4261 toggle_keyword(tb, FLG_REALM1);
4262 add_keyword(tb, FLG_SPELLBOOKS);
4265 toggle_keyword(tb, FLG_REALM2);
4266 add_keyword(tb, FLG_SPELLBOOKS);
4269 toggle_keyword(tb, FLG_FIRST);
4270 add_keyword(tb, FLG_SPELLBOOKS);
4273 toggle_keyword(tb, FLG_SECOND);
4274 add_keyword(tb, FLG_SPELLBOOKS);
4277 toggle_keyword(tb, FLG_THIRD);
4278 add_keyword(tb, FLG_SPELLBOOKS);
4281 toggle_keyword(tb, FLG_FOURTH);
4282 add_keyword(tb, FLG_SPELLBOOKS);
4286 tb->old_com_id = com_id;
4292 * Insert single letter at cursor position.
4294 static void insert_single_letter(text_body_type *tb, int key)
4297 char buf[MAX_LINELEN];
4299 for (i = j = 0; tb->lines_list[tb->cy][i] && i < tb->cx; i++)
4301 buf[j++] = tb->lines_list[tb->cy][i];
4311 if (j + 2 < MAX_LINELEN)
4313 buf[j++] = (char)key;
4314 buf[j++] = (char)next;
4323 if (j + 1 < MAX_LINELEN)
4324 buf[j++] = (char)key;
4328 for (; tb->lines_list[tb->cy][i] && j + 1 < MAX_LINELEN; i++)
4329 buf[j++] = tb->lines_list[tb->cy][i];
4332 string_free(tb->lines_list[tb->cy]);
4333 tb->lines_list[tb->cy] = string_make(buf);
4334 len = strlen(tb->lines_list[tb->cy]);
4335 if (len < tb->cx) tb->cx = len;
4337 tb->dirty_line = tb->cy;
4338 check_expression_line(tb, tb->cy);
4344 * Check special key code and get a movement command id
4346 static int analyze_move_key(text_body_type *tb, int skey)
4349 if (!(skey & SKEY_MASK)) return 0;
4351 switch (skey & ~SKEY_MOD_MASK)
4353 case SKEY_DOWN: com_id = EC_DOWN; break;
4354 case SKEY_LEFT: com_id = EC_LEFT; break;
4355 case SKEY_RIGHT: com_id = EC_RIGHT; break;
4356 case SKEY_UP: com_id = EC_UP; break;
4357 case SKEY_PGUP: com_id = EC_PGUP; break;
4358 case SKEY_PGDOWN: com_id = EC_PGDOWN; break;
4359 case SKEY_TOP: com_id = EC_TOP; break;
4360 case SKEY_BOTTOM: com_id = EC_BOTTOM; break;
4365 if (!(skey & SKEY_MOD_SHIFT))
4368 * Un-shifted cursor keys cancells
4369 * selection created by shift+cursor.
4371 if (tb->mark & MARK_BY_SHIFT)
4374 tb->dirty_flags |= DIRTY_ALL;
4380 if (tb->mark) return com_id;
4382 int len = strlen(tb->lines_list[tb->cy]);
4383 tb->mark = MARK_MARK | MARK_BY_SHIFT;
4386 if (tb->cx > len) tb->mx = len;
4388 if (com_id == EC_UP || com_id == EC_DOWN)
4390 tb->dirty_flags |= DIRTY_ALL;
4394 tb->dirty_line = tb->cy;
4401 * In-game editor of Object Auto-picker/Destoryer
4402 * @param player_ptr プレーヤーへの参照ポインタ
4404 void do_cmd_edit_autopick(player_type *player_ptr)
4406 static int cx_save = 0;
4407 static int cy_save = 0;
4408 text_body_type text_body, *tb = &text_body;
4409 autopick_type an_entry, *entry = &an_entry;
4410 char buf[MAX_LINELEN];
4413 static s32b old_autosave_turn = 0L;
4416 tb->changed = FALSE;
4419 tb->upper = tb->left = 0;
4421 tb->mx = tb->my = 0;
4422 tb->old_cy = tb->old_upper = tb->old_left = -1;
4423 tb->old_wid = tb->old_hgt = -1;
4427 tb->search_o_ptr = NULL;
4428 tb->search_str = NULL;
4429 tb->last_destroyed = NULL;
4430 tb->dirty_flags = DIRTY_ALL | DIRTY_MODE | DIRTY_EXPRESSION;
4431 tb->dirty_line = -1;
4432 tb->filename_mode = PT_DEFAULT;
4434 if (current_world_ptr->game_turn < old_autosave_turn)
4436 while (old_autosave_turn > current_world_ptr->game_turn) old_autosave_turn -= TURNS_PER_TICK * TOWN_DAWN;
4439 if (current_world_ptr->game_turn > old_autosave_turn + 100L)
4441 do_cmd_save_game(player_ptr, TRUE);
4442 old_autosave_turn = current_world_ptr->game_turn;
4447 if (autopick_last_destroyed_object.k_idx)
4449 autopick_entry_from_object(player_ptr, entry, &autopick_last_destroyed_object);
4450 tb->last_destroyed = autopick_line_from_entry_kill(entry);
4453 tb->lines_list = read_pickpref_text_lines(player_ptr, &tb->filename_mode);
4454 for (i = 0; i < tb->cy; i++)
4456 if (!tb->lines_list[i])
4458 tb->cy = tb->cx = 0;
4467 draw_text_editor(player_ptr, tb);
4468 prt(_("(^Q:終了 ^W:セーブして終了, ESC:メニュー, その他:入力)",
4469 "(^Q:Quit, ^W:Save&Quit, ESC:Menu, Other:Input text)"), 0, 0);
4472 prt(format("(%d,%d)", tb->cx, tb->cy), 0, 60);
4476 prt(format("(%d,%d)-(%d,%d)", tb->mx, tb->my, tb->cx, tb->cy), 0, 60);
4479 Term_gotoxy(tb->cx - tb->left, tb->cy - tb->upper + 1);
4480 tb->dirty_flags = 0;
4481 tb->dirty_line = -1;
4482 tb->old_cy = tb->cy;
4483 tb->old_upper = tb->upper;
4484 tb->old_left = tb->left;
4485 tb->old_wid = tb->wid;
4486 tb->old_hgt = tb->hgt;
4488 key = inkey_special(TRUE);
4490 if (key & SKEY_MASK)
4492 com_id = analyze_move_key(tb, key);
4494 else if (key == ESCAPE)
4496 com_id = do_command_menu(0, 0);
4497 tb->dirty_flags |= DIRTY_SCREEN;
4499 else if (!iscntrl((unsigned char)key))
4504 tb->dirty_flags |= DIRTY_ALL;
4507 insert_single_letter(tb, key);
4512 com_id = get_com_id((char)key);
4515 if (com_id) quit = do_editor_command(player_ptr, tb, com_id);
4519 strcpy(buf, pickpref_filename(player_ptr, tb->filename_mode));
4521 if (quit == QUIT_AND_SAVE)
4522 write_text_lines(buf, tb->lines_list);
4524 free_text_lines(tb->lines_list);
4525 string_free(tb->search_str);
4526 string_free(tb->last_destroyed);
4527 kill_yank_chain(tb);
4529 process_autopick_file(player_ptr, buf);
4530 current_world_ptr->start_time = (u32b)time(NULL);