OSDN Git Service

a0b7f0e5c0a8c7a0d2d4ee2b226dfc4ce9777468
[hengband/hengband.git] / src / autopick / autopick.c
1 /*!
2  * @file autopick.c
3  * @brief 自動拾い機能の実装 / Object Auto-picker/Destroyer
4  * @date 2014/01/02
5  * @author
6  * Copyright (c) 2002  Mogami\n
7  *\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
12  */
13
14 #include "angband.h"
15 #include "util.h"
16 #include "autopick/autopick-commands-table.h"
17 #include "autopick/autopick-dirty-flags.h"
18 #include "autopick/autopick-flags-table.h"
19 #include "autopick/autopick-initializer.h"
20 #include "autopick/autopick-key-flag-process.h"
21 #include "autopick/autopick-matcher.h"
22 #include "autopick/autopick-menu-data-table.h"
23 #include "autopick/autopick-methods-table.h"
24 #include "autopick/autopick-keys-table.h"
25 #include "autopick/autopick-entry.h"
26 #include "gameterm.h"
27 #include "autopick/autopick.h"
28 #include "core.h"
29 #include "core/show-file.h"
30 #include "cmd/cmd-save.h"
31 #include "io/read-pref-file.h"
32
33 #include "mind.h"
34
35 #include "market/store.h"
36 #include "player-status.h"
37 #include "player-move.h"
38 #include "player-class.h"
39 #include "player-race.h"
40 #include "player-inventory.h"
41 #include "view/display-player.h"
42 #include "object/object-kind.h"
43 #include "object-ego.h"
44 #include "object-flavor.h"
45 #include "object-hook.h"
46
47 #include "files.h"
48 #include "floor.h"
49 #include "world.h"
50 #include "monster.h"
51 #include "monsterrace.h"
52 #include "view-mainwindow.h" // 暫定。後で消す
53
54 /*
55  * Automatically destroy an item if it is to be destroyed
56  *
57  * When always_pickup is 'yes', we disable auto-destroyer function of
58  * auto-picker/destroyer, and do only easy-auto-destroyer.
59  */
60 static object_type autopick_last_destroyed_object;
61
62 /*
63  *  Get file name for autopick preference
64  */
65 static concptr pickpref_filename(player_type *player_ptr, int filename_mode)
66 {
67         static const char namebase[] = _("picktype", "pickpref");
68
69         switch (filename_mode)
70         {
71         case PT_DEFAULT:
72                 return format("%s.prf", namebase);
73
74         case PT_WITH_PNAME:
75                 return format("%s-%s.prf", namebase, player_ptr->base_name);
76
77         default:
78                 return NULL;
79         }
80 }
81
82
83 /*
84  * Load an autopick preference file
85  */
86 void autopick_load_pref(player_type *player_ptr, bool disp_mes)
87 {
88         GAME_TEXT buf[80];
89         init_autopick();
90         my_strcpy(buf, pickpref_filename(player_ptr, PT_WITH_PNAME), sizeof(buf));
91         errr err = process_autopick_file(player_ptr, buf);
92         if (err == 0 && disp_mes)
93         {
94                 msg_format(_("%sを読み込みました。", "Loaded '%s'."), buf);
95         }
96
97         if (err < 0)
98         {
99                 my_strcpy(buf, pickpref_filename(player_ptr, PT_DEFAULT), sizeof(buf));
100                 err = process_autopick_file(player_ptr, buf);
101                 if (err == 0 && disp_mes)
102                 {
103                         msg_format(_("%sを読み込みました。", "Loaded '%s'."), buf);
104                 }
105         }
106
107         if (err && disp_mes)
108         {
109                 msg_print(_("自動拾い設定ファイルの読み込みに失敗しました。", "Failed to reload autopick preference."));
110         }
111 }
112
113
114 /*
115  * Add one line to autopick_list[]
116  */
117 static void add_autopick_list(autopick_type *entry)
118 {
119         if (max_autopick >= max_max_autopick)
120         {
121                 int old_max_max_autopick = max_max_autopick;
122                 autopick_type *old_autopick_list = autopick_list;
123                 max_max_autopick += MAX_AUTOPICK_DEFAULT;
124                 C_MAKE(autopick_list, max_max_autopick, autopick_type);
125                 (void)C_COPY(autopick_list, old_autopick_list, old_max_max_autopick, autopick_type);
126                 C_KILL(old_autopick_list, old_max_max_autopick, autopick_type);
127         }
128
129         autopick_list[max_autopick] = *entry;
130         max_autopick++;
131 }
132
133
134 /*
135  *  Process line for auto picker/destroyer.
136  */
137 void process_autopick_file_command(char *buf)
138 {
139         autopick_type an_entry, *entry = &an_entry;
140         int i;
141         for (i = 0; buf[i]; i++)
142         {
143 #ifdef JP
144                 if (iskanji(buf[i]))
145                 {
146                         i++;
147                         continue;
148                 }
149 #endif
150                 if (iswspace(buf[i]) && buf[i] != ' ')
151                         break;
152         }
153
154         buf[i] = 0;
155         if (!autopick_new_entry(entry, buf, FALSE)) return;
156
157         for (i = 0; i < max_autopick; i++)
158         {
159                 if (!strcmp(entry->name, autopick_list[i].name)
160                         && entry->flag[0] == autopick_list[i].flag[0]
161                         && entry->flag[1] == autopick_list[i].flag[1]
162                         && entry->dice == autopick_list[i].dice
163                         && entry->bonus == autopick_list[i].bonus)
164                 {
165                         autopick_free_entry(entry);
166                         return;
167                 }
168         }
169
170         add_autopick_list(entry);
171         return;
172 }
173
174
175 /*
176  * A function for Auto-picker/destroyer
177  * Examine whether the object matches to the list of keywords or not.
178  */
179 int is_autopick(player_type *player_ptr, object_type *o_ptr)
180 {
181         GAME_TEXT o_name[MAX_NLEN];
182         if (o_ptr->tval == TV_GOLD) return -1;
183
184         object_desc(player_ptr, o_name, o_ptr, (OD_NO_FLAVOR | OD_OMIT_PREFIX | OD_NO_PLURAL));
185         str_tolower(o_name);
186         for (int i = 0; i < max_autopick; i++)
187         {
188                 autopick_type *entry = &autopick_list[i];
189                 if (is_autopick_match(player_ptr, o_ptr, entry, o_name))
190                         return i;
191         }
192
193         return -1;
194 }
195
196
197 /*
198  *  Auto inscription
199  */
200 static void auto_inscribe_item(player_type *player_ptr, object_type *o_ptr, int idx)
201 {
202         if (idx < 0 || !autopick_list[idx].insc) return;
203
204         if (!o_ptr->inscription)
205                 o_ptr->inscription = quark_add(autopick_list[idx].insc);
206
207         player_ptr->window |= (PW_EQUIP | PW_INVEN);
208         player_ptr->update |= (PU_BONUS);
209 }
210
211
212 /*
213  * Automatically destroy items in this grid.
214  */
215 static bool is_opt_confirm_destroy(player_type *player_ptr, object_type *o_ptr)
216 {
217         if (!destroy_items) return FALSE;
218
219         if (leave_worth)
220                 if (object_value(o_ptr) > 0) return FALSE;
221
222         if (leave_equip)
223                 if (object_is_weapon_armour_ammo(o_ptr)) return FALSE;
224
225         if (leave_chest)
226                 if ((o_ptr->tval == TV_CHEST) && o_ptr->pval) return FALSE;
227
228         if (leave_wanted)
229         {
230                 if (object_is_bounty(o_ptr)) return FALSE;
231         }
232
233         if (leave_corpse)
234                 if (o_ptr->tval == TV_CORPSE) return FALSE;
235
236         if (leave_junk)
237                 if ((o_ptr->tval == TV_SKELETON) || (o_ptr->tval == TV_BOTTLE) || (o_ptr->tval == TV_JUNK) || (o_ptr->tval == TV_STATUE)) return FALSE;
238
239         if (leave_special)
240         {
241                 if (player_ptr->prace == RACE_DEMON)
242                 {
243                         if (o_ptr->tval == TV_CORPSE &&
244                                 o_ptr->sval == SV_CORPSE &&
245                                 my_strchr("pht", r_info[o_ptr->pval].d_char))
246                                 return FALSE;
247                 }
248
249                 if (player_ptr->pclass == CLASS_ARCHER)
250                 {
251                         if (o_ptr->tval == TV_SKELETON ||
252                                 (o_ptr->tval == TV_CORPSE && o_ptr->sval == SV_SKELETON))
253                                 return FALSE;
254                 }
255                 else if (player_ptr->pclass == CLASS_NINJA)
256                 {
257                         if (o_ptr->tval == TV_LITE &&
258                                 o_ptr->name2 == EGO_LITE_DARKNESS && object_is_known(o_ptr))
259                                 return FALSE;
260                 }
261                 else if (player_ptr->pclass == CLASS_BEASTMASTER ||
262                         player_ptr->pclass == CLASS_CAVALRY)
263                 {
264                         if (o_ptr->tval == TV_WAND &&
265                                 o_ptr->sval == SV_WAND_HEAL_MONSTER && object_is_aware(o_ptr))
266                                 return FALSE;
267                 }
268         }
269
270         if (o_ptr->tval == TV_GOLD) return FALSE;
271
272         return TRUE;
273 }
274
275
276 static void auto_destroy_item(player_type *player_ptr, object_type *o_ptr, int autopick_idx)
277 {
278         bool destroy = FALSE;
279         if (is_opt_confirm_destroy(player_ptr, o_ptr)) destroy = TRUE;
280
281         if (autopick_idx >= 0 &&
282                 !(autopick_list[autopick_idx].action & DO_AUTODESTROY))
283                 destroy = FALSE;
284
285         if (!always_pickup)
286         {
287                 if (autopick_idx >= 0 &&
288                         (autopick_list[autopick_idx].action & DO_AUTODESTROY))
289                         destroy = TRUE;
290         }
291
292         if (!destroy) return;
293
294         disturb(player_ptr, FALSE, FALSE);
295         if (!can_player_destroy_object(o_ptr))
296         {
297                 GAME_TEXT o_name[MAX_NLEN];
298                 object_desc(player_ptr, o_name, o_ptr, 0);
299                 msg_format(_("%sは破壊不能だ。", "You cannot auto-destroy %s."), o_name);
300                 return;
301         }
302
303         (void)COPY(&autopick_last_destroyed_object, o_ptr, object_type);
304         o_ptr->marked |= OM_AUTODESTROY;
305         player_ptr->update |= PU_AUTODESTROY;
306 }
307
308
309 /*
310  *  Auto-destroy marked item
311  */
312 static void autopick_delayed_alter_aux(player_type *player_ptr, INVENTORY_IDX item)
313 {
314         object_type *o_ptr;
315         o_ptr = REF_ITEM(player_ptr, player_ptr->current_floor_ptr, item);
316
317         if (o_ptr->k_idx == 0 || !(o_ptr->marked & OM_AUTODESTROY)) return;
318
319         GAME_TEXT o_name[MAX_NLEN];
320         object_desc(player_ptr, o_name, o_ptr, 0);
321         if (item >= 0)
322         {
323                 inven_item_increase(player_ptr, item, -(o_ptr->number));
324                 inven_item_optimize(player_ptr, item);
325         }
326         else
327         {
328                 delete_object_idx(player_ptr, 0 - item);
329         }
330
331         msg_format(_("%sを自動破壊します。", "Auto-destroying %s."), o_name);
332 }
333
334
335 /*
336  *  Auto-destroy marked items in inventry and on floor
337  */
338 void autopick_delayed_alter(player_type *owner_ptr)
339 {
340         INVENTORY_IDX item;
341
342         /*
343          * Scan inventry in reverse order to prevent
344          * skipping after inven_item_optimize()
345          */
346         for (item = INVEN_TOTAL - 1; item >= 0; item--)
347                 autopick_delayed_alter_aux(owner_ptr, item);
348
349         floor_type *floor_ptr = owner_ptr->current_floor_ptr;
350         item = floor_ptr->grid_array[owner_ptr->y][owner_ptr->x].o_idx;
351         while (item)
352         {
353                 OBJECT_IDX next = floor_ptr->o_list[item].next_o_idx;
354                 autopick_delayed_alter_aux(owner_ptr, -item);
355                 item = next;
356         }
357 }
358
359
360 /*
361  * Auto-inscription and/or destroy
362  *
363  * Auto-destroyer works only on inventory or on floor stack only when
364  * requested.
365  */
366 void autopick_alter_item(player_type *player_ptr, INVENTORY_IDX item, bool destroy)
367 {
368         object_type *o_ptr;
369         o_ptr = REF_ITEM(player_ptr, player_ptr->current_floor_ptr, item);
370         int idx = is_autopick(player_ptr, o_ptr);
371         auto_inscribe_item(player_ptr, o_ptr, idx);
372         if (destroy && item <= INVEN_PACK)
373                 auto_destroy_item(player_ptr, o_ptr, idx);
374 }
375
376
377 /*
378  * Automatically pickup/destroy items in this grid.
379  */
380 void autopick_pickup_items(player_type* player_ptr, grid_type *g_ptr)
381 {
382         OBJECT_IDX this_o_idx, next_o_idx = 0;
383         for (this_o_idx = g_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx)
384         {
385                 object_type *o_ptr = &player_ptr->current_floor_ptr->o_list[this_o_idx];
386                 next_o_idx = o_ptr->next_o_idx;
387                 int idx = is_autopick(player_ptr, o_ptr);
388                 auto_inscribe_item(player_ptr, o_ptr, idx);
389                 bool is_auto_pickup = idx >= 0;
390                 is_auto_pickup &= (autopick_list[idx].action & (DO_AUTOPICK | DO_QUERY_AUTOPICK)) != 0;
391                 if (!is_auto_pickup)
392                 {
393                         auto_destroy_item(player_ptr, o_ptr, idx);
394                         continue;
395                 }
396
397                 disturb(player_ptr, FALSE, FALSE);
398                 if (!inven_carry_okay(o_ptr))
399                 {
400                         GAME_TEXT o_name[MAX_NLEN];
401                         object_desc(player_ptr, o_name, o_ptr, 0);
402                         msg_format(_("ザックには%sを入れる隙間がない。", "You have no room for %s."), o_name);
403                         o_ptr->marked |= OM_NOMSG;
404                         continue;
405                 }
406
407                 if (!(autopick_list[idx].action & DO_QUERY_AUTOPICK))
408                 {
409                         py_pickup_aux(player_ptr, this_o_idx);
410                         continue;
411                 }
412
413                 char out_val[MAX_NLEN + 20];
414                 GAME_TEXT o_name[MAX_NLEN];
415                 if (o_ptr->marked & OM_NO_QUERY)
416                 {
417                         continue;
418                 }
419
420                 object_desc(player_ptr, o_name, o_ptr, 0);
421                 sprintf(out_val, _("%sを拾いますか? ", "Pick up %s? "), o_name);
422                 if (!get_check(out_val))
423                 {
424                         o_ptr->marked |= OM_NOMSG | OM_NO_QUERY;
425                         continue;
426                 }
427
428                 py_pickup_aux(player_ptr, this_o_idx);
429         }
430 }
431
432
433 static const char autoregister_header[] = "?:$AUTOREGISTER";
434
435 /*
436  *  Clear auto registered lines in the picktype.prf .
437  */
438 static bool clear_auto_register(player_type *player_ptr)
439 {
440         char tmp_file[1024];
441         char pref_file[1024];
442         char buf[1024];
443         FILE *pref_fff;
444         FILE *tmp_fff;
445         int num = 0;
446         bool autoregister = FALSE;
447         bool okay = TRUE;
448
449         path_build(pref_file, sizeof(pref_file), ANGBAND_DIR_USER, pickpref_filename(player_ptr, PT_WITH_PNAME));
450         pref_fff = my_fopen(pref_file, "r");
451
452         if (!pref_fff)
453         {
454                 path_build(pref_file, sizeof(pref_file), ANGBAND_DIR_USER, pickpref_filename(player_ptr, PT_DEFAULT));
455                 pref_fff = my_fopen(pref_file, "r");
456         }
457
458         if (!pref_fff)
459         {
460                 return TRUE;
461         }
462
463         tmp_fff = my_fopen_temp(tmp_file, sizeof(tmp_file));
464         if (!tmp_fff)
465         {
466                 fclose(pref_fff);
467                 msg_format(_("一時ファイル %s を作成できませんでした。", "Failed to create temporary file %s."), tmp_file);
468                 msg_print(NULL);
469                 return FALSE;
470         }
471
472         while (TRUE)
473         {
474                 if (my_fgets(pref_fff, buf, sizeof(buf))) break;
475
476                 if (autoregister)
477                 {
478                         if (buf[0] != '#' && buf[0] != '?') num++;
479                         continue;
480                 }
481
482                 if (streq(buf, autoregister_header))
483                 {
484                         autoregister = TRUE;
485                 }
486                 else
487                 {
488                         fprintf(tmp_fff, "%s\n", buf);
489                 }
490         }
491
492         my_fclose(pref_fff);
493         my_fclose(tmp_fff);
494
495         if (num)
496         {
497                 msg_format(_("以前のキャラクター用の自動設定(%d行)が残っています。",
498                         "Auto registered lines (%d lines) for previous character are remaining."), num);
499                 strcpy(buf, _("古い設定行は削除します。よろしいですか?", "These lines will be deleted.  Are you sure? "));
500
501                 if (!get_check(buf))
502                 {
503                         okay = FALSE;
504                         autoregister = FALSE;
505
506                         msg_print(_("エディタのカット&ペースト等を使って必要な行を避難してください。",
507                                 "Use cut & paste of auto picker editor (_) to keep old prefs."));
508                 }
509         }
510
511         if (autoregister)
512         {
513                 tmp_fff = my_fopen(tmp_file, "r");
514                 pref_fff = my_fopen(pref_file, "w");
515
516                 while (!my_fgets(tmp_fff, buf, sizeof(buf)))
517                         fprintf(pref_fff, "%s\n", buf);
518
519                 my_fclose(pref_fff);
520                 my_fclose(tmp_fff);
521         }
522
523         fd_kill(tmp_file);
524         return okay;
525 }
526
527
528 /*
529  *  Automatically register an auto-destroy preference line
530  */
531 bool autopick_autoregister(player_type *player_ptr, object_type *o_ptr)
532 {
533         char buf[1024];
534         char pref_file[1024];
535         FILE *pref_fff;
536         autopick_type an_entry, *entry = &an_entry;
537         int match_autopick = is_autopick(player_ptr, o_ptr);
538         if (match_autopick != -1)
539         {
540                 concptr what;
541                 byte act = autopick_list[match_autopick].action;
542                 if (act & DO_AUTOPICK) what = _("自動で拾う", "auto-pickup");
543                 else if (act & DO_AUTODESTROY) what = _("自動破壊する", "auto-destroy");
544                 else if (act & DONT_AUTOPICK) what = _("放置する", "leave on floor");
545                 else what = _("確認して拾う", "query auto-pickup");
546
547                 msg_format(_("そのアイテムは既に%sように設定されています。", "The object is already registered to %s."), what);
548                 return FALSE;
549         }
550
551         if ((object_is_known(o_ptr) && object_is_artifact(o_ptr)) ||
552                 ((o_ptr->ident & IDENT_SENSE) &&
553                 (o_ptr->feeling == FEEL_TERRIBLE || o_ptr->feeling == FEEL_SPECIAL)))
554         {
555                 GAME_TEXT o_name[MAX_NLEN];
556                 object_desc(player_ptr, o_name, o_ptr, 0);
557                 msg_format(_("%sは破壊不能だ。", "You cannot auto-destroy %s."), o_name);
558                 return FALSE;
559         }
560
561         if (!player_ptr->autopick_autoregister)
562         {
563                 if (!clear_auto_register(player_ptr)) return FALSE;
564         }
565
566         path_build(pref_file, sizeof(pref_file), ANGBAND_DIR_USER, pickpref_filename(player_ptr, PT_WITH_PNAME));
567         pref_fff = my_fopen(pref_file, "r");
568
569         if (!pref_fff)
570         {
571                 path_build(pref_file, sizeof(pref_file), ANGBAND_DIR_USER, pickpref_filename(player_ptr, PT_DEFAULT));
572                 pref_fff = my_fopen(pref_file, "r");
573         }
574
575         if (pref_fff)
576         {
577                 while (TRUE)
578                 {
579                         if (my_fgets(pref_fff, buf, sizeof(buf)))
580                         {
581                                 player_ptr->autopick_autoregister = FALSE;
582                                 break;
583                         }
584
585                         if (streq(buf, autoregister_header))
586                         {
587                                 player_ptr->autopick_autoregister = TRUE;
588                                 break;
589                         }
590                 }
591
592                 fclose(pref_fff);
593         }
594         else
595         {
596                 /*
597                  * File could not be opened for reading.  Assume header not
598                  * present.
599                  */
600                 player_ptr->autopick_autoregister = FALSE;
601         }
602
603         pref_fff = my_fopen(pref_file, "a");
604         if (!pref_fff)
605         {
606                 msg_format(_("%s を開くことができませんでした。", "Failed to open %s."), pref_file);
607                 msg_print(NULL);
608                 return FALSE;
609         }
610
611         if (!player_ptr->autopick_autoregister)
612         {
613                 fprintf(pref_fff, "%s\n", autoregister_header);
614
615                 fprintf(pref_fff, "%s\n", _("# *警告!!* 以降の行は自動登録されたものです。",
616                         "# *Warning!* The lines below will be deleted later."));
617                 fprintf(pref_fff, "%s\n", _("# 後で自動的に削除されますので、必要な行は上の方へ移動しておいてください。",
618                         "# Keep it by cut & paste if you need these lines for future characters."));
619                 player_ptr->autopick_autoregister = TRUE;
620         }
621
622         autopick_entry_from_object(player_ptr, entry, o_ptr);
623         entry->action = DO_AUTODESTROY;
624         add_autopick_list(entry);
625
626         concptr tmp = autopick_line_from_entry(entry);
627         fprintf(pref_fff, "%s\n", tmp);
628         string_free(tmp);
629         fclose(pref_fff);
630         return TRUE;
631 }
632
633
634 /*
635  * Describe which kind of object is Auto-picked/destroyed
636  */
637 static void describe_autopick(char *buff, autopick_type *entry)
638 {
639         concptr str = entry->name;
640         byte act = entry->action;
641         concptr insc = entry->insc;
642         int i;
643
644         bool top = FALSE;
645
646 #ifdef JP
647         concptr before_str[100], body_str;
648         int before_n = 0;
649
650         body_str = "アイテム";
651         if (IS_FLG(FLG_COLLECTING))
652                 before_str[before_n++] = "収集中で既に持っているスロットにまとめられる";
653
654         if (IS_FLG(FLG_UNAWARE))
655                 before_str[before_n++] = "未鑑定でその効果も判明していない";
656
657         if (IS_FLG(FLG_UNIDENTIFIED))
658                 before_str[before_n++] = "未鑑定の";
659
660         if (IS_FLG(FLG_IDENTIFIED))
661                 before_str[before_n++] = "鑑定済みの";
662
663         if (IS_FLG(FLG_STAR_IDENTIFIED))
664                 before_str[before_n++] = "完全に鑑定済みの";
665
666         if (IS_FLG(FLG_BOOSTED))
667         {
668                 before_str[before_n++] = "ダメージダイスが通常より大きい";
669                 body_str = "武器";
670         }
671
672         if (IS_FLG(FLG_MORE_DICE))
673         {
674                 static char more_than_desc_str[] = "___";
675                 before_str[before_n++] = "ダメージダイスの最大値が";
676                 body_str = "武器";
677
678                 sprintf(more_than_desc_str, "%d", entry->dice);
679                 before_str[before_n++] = more_than_desc_str;
680                 before_str[before_n++] = "以上の";
681         }
682
683         if (IS_FLG(FLG_MORE_BONUS))
684         {
685                 static char more_bonus_desc_str[] = "___";
686                 before_str[before_n++] = "修正値が(+";
687
688                 sprintf(more_bonus_desc_str, "%d", entry->bonus);
689                 before_str[before_n++] = more_bonus_desc_str;
690                 before_str[before_n++] = ")以上の";
691         }
692
693         if (IS_FLG(FLG_WORTHLESS))
694                 before_str[before_n++] = "店で無価値と判定される";
695
696         if (IS_FLG(FLG_ARTIFACT))
697         {
698                 before_str[before_n++] = "アーティファクトの";
699                 body_str = "装備";
700         }
701
702         if (IS_FLG(FLG_EGO))
703         {
704                 before_str[before_n++] = "エゴアイテムの";
705                 body_str = "装備";
706         }
707
708         if (IS_FLG(FLG_GOOD))
709         {
710                 before_str[before_n++] = "上質の";
711                 body_str = "装備";
712         }
713
714         if (IS_FLG(FLG_NAMELESS))
715         {
716                 before_str[before_n++] = "エゴでもアーティファクトでもない";
717                 body_str = "装備";
718         }
719
720         if (IS_FLG(FLG_AVERAGE))
721         {
722                 before_str[before_n++] = "並の";
723                 body_str = "装備";
724         }
725
726         if (IS_FLG(FLG_RARE))
727         {
728                 before_str[before_n++] = "ドラゴン装備やカオス・ブレード等を含む珍しい";
729                 body_str = "装備";
730         }
731
732         if (IS_FLG(FLG_COMMON))
733         {
734                 before_str[before_n++] = "ありふれた(ドラゴン装備やカオス・ブレード等の珍しい物ではない)";
735                 body_str = "装備";
736         }
737
738         if (IS_FLG(FLG_WANTED))
739         {
740                 before_str[before_n++] = "ハンター事務所で賞金首とされている";
741                 body_str = "死体や骨";
742         }
743
744         if (IS_FLG(FLG_HUMAN))
745         {
746                 before_str[before_n++] = "悪魔魔法で使うための人間やヒューマノイドの";
747                 body_str = "死体や骨";
748         }
749
750         if (IS_FLG(FLG_UNIQUE))
751         {
752                 before_str[before_n++] = "ユニークモンスターの";
753                 body_str = "死体や骨";
754         }
755
756         if (IS_FLG(FLG_UNREADABLE))
757         {
758                 before_str[before_n++] = "あなたが読めない領域の";
759                 body_str = "魔法書";
760         }
761
762         if (IS_FLG(FLG_REALM1))
763         {
764                 before_str[before_n++] = "第一領域の";
765                 body_str = "魔法書";
766         }
767
768         if (IS_FLG(FLG_REALM2))
769         {
770                 before_str[before_n++] = "第二領域の";
771                 body_str = "魔法書";
772         }
773
774         if (IS_FLG(FLG_FIRST))
775         {
776                 before_str[before_n++] = "全4冊の内の1冊目の";
777                 body_str = "魔法書";
778         }
779
780         if (IS_FLG(FLG_SECOND))
781         {
782                 before_str[before_n++] = "全4冊の内の2冊目の";
783                 body_str = "魔法書";
784         }
785
786         if (IS_FLG(FLG_THIRD))
787         {
788                 before_str[before_n++] = "全4冊の内の3冊目の";
789                 body_str = "魔法書";
790         }
791
792         if (IS_FLG(FLG_FOURTH))
793         {
794                 before_str[before_n++] = "全4冊の内の4冊目の";
795                 body_str = "魔法書";
796         }
797
798         if (IS_FLG(FLG_ITEMS))
799                 ; /* Nothing to do */
800         else if (IS_FLG(FLG_WEAPONS))
801                 body_str = "武器";
802         else if (IS_FLG(FLG_FAVORITE_WEAPONS))
803                 body_str = "得意武器";
804         else if (IS_FLG(FLG_ARMORS))
805                 body_str = "防具";
806         else if (IS_FLG(FLG_MISSILES))
807                 body_str = "弾や矢やクロスボウの矢";
808         else if (IS_FLG(FLG_DEVICES))
809                 body_str = "巻物や魔法棒や杖やロッド";
810         else if (IS_FLG(FLG_LIGHTS))
811                 body_str = "光源用のアイテム";
812         else if (IS_FLG(FLG_JUNKS))
813                 body_str = "折れた棒等のガラクタ";
814         else if (IS_FLG(FLG_CORPSES))
815                 body_str = "死体や骨";
816         else if (IS_FLG(FLG_SPELLBOOKS))
817                 body_str = "魔法書";
818         else if (IS_FLG(FLG_HAFTED))
819                 body_str = "鈍器";
820         else if (IS_FLG(FLG_SHIELDS))
821                 body_str = "盾";
822         else if (IS_FLG(FLG_BOWS))
823                 body_str = "スリングや弓やクロスボウ";
824         else if (IS_FLG(FLG_RINGS))
825                 body_str = "指輪";
826         else if (IS_FLG(FLG_AMULETS))
827                 body_str = "アミュレット";
828         else if (IS_FLG(FLG_SUITS))
829                 body_str = "鎧";
830         else if (IS_FLG(FLG_CLOAKS))
831                 body_str = "クローク";
832         else if (IS_FLG(FLG_HELMS))
833                 body_str = "ヘルメットや冠";
834         else if (IS_FLG(FLG_GLOVES))
835                 body_str = "籠手";
836         else if (IS_FLG(FLG_BOOTS))
837                 body_str = "ブーツ";
838
839         *buff = '\0';
840         if (!before_n)
841                 strcat(buff, "全ての");
842         else for (i = 0; i < before_n && before_str[i]; i++)
843                 strcat(buff, before_str[i]);
844
845         strcat(buff, body_str);
846
847         if (*str)
848         {
849                 if (*str == '^')
850                 {
851                         str++;
852                         top = TRUE;
853                 }
854
855                 strcat(buff, "で、名前が「");
856                 strncat(buff, str, 80);
857                 if (top)
858                         strcat(buff, "」で始まるもの");
859                 else
860                         strcat(buff, "」を含むもの");
861         }
862
863         if (insc)
864         {
865                 strncat(buff, format("に「%s」", insc), 80);
866
867                 if (my_strstr(insc, "%%all"))
868                         strcat(buff, "(%%allは全能力を表す英字の記号で置換)");
869                 else if (my_strstr(insc, "%all"))
870                         strcat(buff, "(%allは全能力を表す記号で置換)");
871                 else if (my_strstr(insc, "%%"))
872                         strcat(buff, "(%%は追加能力を表す英字の記号で置換)");
873                 else if (my_strstr(insc, "%"))
874                         strcat(buff, "(%は追加能力を表す記号で置換)");
875
876                 strcat(buff, "と刻んで");
877         }
878         else
879                 strcat(buff, "を");
880
881         if (act & DONT_AUTOPICK)
882                 strcat(buff, "放置する。");
883         else if (act & DO_AUTODESTROY)
884                 strcat(buff, "破壊する。");
885         else if (act & DO_QUERY_AUTOPICK)
886                 strcat(buff, "確認の後に拾う。");
887         else
888                 strcat(buff, "拾う。");
889
890         if (act & DO_DISPLAY)
891         {
892                 if (act & DONT_AUTOPICK)
893                         strcat(buff, "全体マップ('M')で'N'を押したときに表示する。");
894                 else if (act & DO_AUTODESTROY)
895                         strcat(buff, "全体マップ('M')で'K'を押したときに表示する。");
896                 else
897                         strcat(buff, "全体マップ('M')で'M'を押したときに表示する。");
898         }
899         else
900                 strcat(buff, "全体マップには表示しない。");
901
902 #else /* JP */
903
904         concptr before_str[20], after_str[20], which_str[20], whose_str[20], body_str;
905         int before_n = 0, after_n = 0, which_n = 0, whose_n = 0;
906         body_str = "items";
907         if (IS_FLG(FLG_COLLECTING))
908                 which_str[which_n++] = "can be absorbed into an existing inventory list slot";
909
910         if (IS_FLG(FLG_UNAWARE))
911         {
912                 before_str[before_n++] = "unidentified";
913                 whose_str[whose_n++] = "basic abilities are not known";
914         }
915
916         if (IS_FLG(FLG_UNIDENTIFIED))
917                 before_str[before_n++] = "unidentified";
918
919         if (IS_FLG(FLG_IDENTIFIED))
920                 before_str[before_n++] = "identified";
921
922         if (IS_FLG(FLG_STAR_IDENTIFIED))
923                 before_str[before_n++] = "fully identified";
924
925         if (IS_FLG(FLG_RARE))
926         {
927                 before_str[before_n++] = "very rare";
928                 body_str = "equipments";
929                 after_str[after_n++] = "such as Dragon armor, Blades of Chaos, etc.";
930         }
931
932         if (IS_FLG(FLG_COMMON))
933         {
934                 before_str[before_n++] = "relatively common";
935                 body_str = "equipments";
936                 after_str[after_n++] = "compared to very rare Dragon armor, Blades of Chaos, etc.";
937         }
938
939         if (IS_FLG(FLG_WORTHLESS))
940         {
941                 before_str[before_n++] = "worthless";
942                 which_str[which_n++] = "can not be sold at stores";
943         }
944
945         if (IS_FLG(FLG_ARTIFACT))
946         {
947                 before_str[before_n++] = "artifact";
948         }
949
950         if (IS_FLG(FLG_EGO))
951         {
952                 before_str[before_n++] = "ego";
953         }
954
955         if (IS_FLG(FLG_GOOD))
956         {
957                 body_str = "equipment";
958                 which_str[which_n++] = "have good quality";
959         }
960
961         if (IS_FLG(FLG_NAMELESS))
962         {
963                 body_str = "equipment";
964                 which_str[which_n++] = "is neither ego-item nor artifact";
965         }
966
967         if (IS_FLG(FLG_AVERAGE))
968         {
969                 body_str = "equipment";
970                 which_str[which_n++] = "have average quality";
971         }
972
973         if (IS_FLG(FLG_BOOSTED))
974         {
975                 body_str = "weapons";
976                 whose_str[whose_n++] = "damage dice is bigger than normal";
977         }
978
979         if (IS_FLG(FLG_MORE_DICE))
980         {
981                 static char more_than_desc_str[] =
982                         "maximum damage from dice is bigger than __";
983                 body_str = "weapons";
984
985                 sprintf(more_than_desc_str + sizeof(more_than_desc_str) - 3,
986                         "%d", entry->dice);
987                 whose_str[whose_n++] = more_than_desc_str;
988         }
989
990         if (IS_FLG(FLG_MORE_BONUS))
991         {
992                 static char more_bonus_desc_str[] =
993                         "magical bonus is bigger than (+__)";
994
995                 sprintf(more_bonus_desc_str + sizeof(more_bonus_desc_str) - 4,
996                         "%d)", entry->bonus);
997                 whose_str[whose_n++] = more_bonus_desc_str;
998         }
999
1000         if (IS_FLG(FLG_WANTED))
1001         {
1002                 body_str = "corpse or skeletons";
1003                 which_str[which_n++] = "is wanted at the Hunter's Office";
1004         }
1005
1006         if (IS_FLG(FLG_HUMAN))
1007         {
1008                 before_str[before_n++] = "humanoid";
1009                 body_str = "corpse or skeletons";
1010                 which_str[which_n++] = "can be used for Daemon magic";
1011         }
1012
1013         if (IS_FLG(FLG_UNIQUE))
1014         {
1015                 before_str[before_n++] = "unique monster's";
1016                 body_str = "corpse or skeletons";
1017         }
1018
1019         if (IS_FLG(FLG_UNREADABLE))
1020         {
1021                 body_str = "spellbooks";
1022                 after_str[after_n++] = "of different realms from yours";
1023         }
1024
1025         if (IS_FLG(FLG_REALM1))
1026         {
1027                 body_str = "spellbooks";
1028                 after_str[after_n++] = "of your first realm";
1029         }
1030
1031         if (IS_FLG(FLG_REALM2))
1032         {
1033                 body_str = "spellbooks";
1034                 after_str[after_n++] = "of your second realm";
1035         }
1036
1037         if (IS_FLG(FLG_FIRST))
1038         {
1039                 before_str[before_n++] = "first one of four";
1040                 body_str = "spellbooks";
1041         }
1042
1043         if (IS_FLG(FLG_SECOND))
1044         {
1045                 before_str[before_n++] = "second one of four";
1046                 body_str = "spellbooks";
1047         }
1048
1049         if (IS_FLG(FLG_THIRD))
1050         {
1051                 before_str[before_n++] = "third one of four";
1052                 body_str = "spellbooks";
1053         }
1054
1055         if (IS_FLG(FLG_FOURTH))
1056         {
1057                 before_str[before_n++] = "fourth one of four";
1058                 body_str = "spellbooks";
1059         }
1060
1061         if (IS_FLG(FLG_ITEMS))
1062                 ; /* Nothing to do */
1063         else if (IS_FLG(FLG_WEAPONS))
1064                 body_str = "weapons";
1065         else if (IS_FLG(FLG_FAVORITE_WEAPONS))
1066                 body_str = "favorite weapons";
1067         else if (IS_FLG(FLG_ARMORS))
1068                 body_str = "armors";
1069         else if (IS_FLG(FLG_MISSILES))
1070                 body_str = "shots, arrows or crossbow bolts";
1071         else if (IS_FLG(FLG_DEVICES))
1072                 body_str = "scrolls, wands, staffs or rods";
1073         else if (IS_FLG(FLG_LIGHTS))
1074                 body_str = "light sources";
1075         else if (IS_FLG(FLG_JUNKS))
1076                 body_str = "junk such as broken sticks";
1077         else if (IS_FLG(FLG_CORPSES))
1078                 body_str = "corpses or skeletons";
1079         else if (IS_FLG(FLG_SPELLBOOKS))
1080                 body_str = "spellbooks";
1081         else if (IS_FLG(FLG_HAFTED))
1082                 body_str = "hafted weapons";
1083         else if (IS_FLG(FLG_SHIELDS))
1084                 body_str = "shields";
1085         else if (IS_FLG(FLG_BOWS))
1086                 body_str = "slings, bows or crossbows";
1087         else if (IS_FLG(FLG_RINGS))
1088                 body_str = "rings";
1089         else if (IS_FLG(FLG_AMULETS))
1090                 body_str = "amulets";
1091         else if (IS_FLG(FLG_SUITS))
1092                 body_str = "body armors";
1093         else if (IS_FLG(FLG_CLOAKS))
1094                 body_str = "cloaks";
1095         else if (IS_FLG(FLG_HELMS))
1096                 body_str = "helms or crowns";
1097         else if (IS_FLG(FLG_GLOVES))
1098                 body_str = "gloves";
1099         else if (IS_FLG(FLG_BOOTS))
1100                 body_str = "boots";
1101
1102         if (*str)
1103         {
1104                 if (*str == '^')
1105                 {
1106                         str++;
1107                         top = TRUE;
1108                         whose_str[whose_n++] = "name begins with \"";
1109                 }
1110                 else
1111                         which_str[which_n++] = "have \"";
1112         }
1113
1114
1115         if (act & DONT_AUTOPICK)
1116                 strcpy(buff, "Leave on floor ");
1117         else if (act & DO_AUTODESTROY)
1118                 strcpy(buff, "Destroy ");
1119         else if (act & DO_QUERY_AUTOPICK)
1120                 strcpy(buff, "Ask to pick up ");
1121         else
1122                 strcpy(buff, "Pickup ");
1123
1124         if (insc)
1125         {
1126                 strncat(buff, format("and inscribe \"%s\"", insc), 80);
1127
1128                 if (my_strstr(insc, "%all"))
1129                         strcat(buff, ", replacing %all with code string representing all abilities,");
1130                 else if (my_strstr(insc, "%"))
1131                         strcat(buff, ", replacing % with code string representing extra random abilities,");
1132
1133                 strcat(buff, " on ");
1134         }
1135
1136         if (!before_n)
1137                 strcat(buff, "all ");
1138         else for (i = 0; i < before_n && before_str[i]; i++)
1139         {
1140                 strcat(buff, before_str[i]);
1141                 strcat(buff, " ");
1142         }
1143
1144         strcat(buff, body_str);
1145
1146         for (i = 0; i < after_n && after_str[i]; i++)
1147         {
1148                 strcat(buff, " ");
1149                 strcat(buff, after_str[i]);
1150         }
1151
1152         for (i = 0; i < whose_n && whose_str[i]; i++)
1153         {
1154                 if (i == 0)
1155                         strcat(buff, " whose ");
1156                 else
1157                         strcat(buff, ", and ");
1158
1159                 strcat(buff, whose_str[i]);
1160         }
1161
1162         if (*str && top)
1163         {
1164                 strcat(buff, str);
1165                 strcat(buff, "\"");
1166         }
1167
1168         if (whose_n && which_n)
1169                 strcat(buff, ", and ");
1170
1171         for (i = 0; i < which_n && which_str[i]; i++)
1172         {
1173                 if (i == 0)
1174                         strcat(buff, " which ");
1175                 else
1176                         strcat(buff, ", and ");
1177
1178                 strcat(buff, which_str[i]);
1179         }
1180
1181         if (*str && !top)
1182         {
1183                 strncat(buff, str, 80);
1184                 strcat(buff, "\" as part of its name");
1185         }
1186         strcat(buff, ".");
1187
1188         if (act & DO_DISPLAY)
1189         {
1190                 if (act & DONT_AUTOPICK)
1191                         strcat(buff, "  Display these items when you press the N key in the full 'M'ap.");
1192                 else if (act & DO_AUTODESTROY)
1193                         strcat(buff, "  Display these items when you press the K key in the full 'M'ap.");
1194                 else
1195                         strcat(buff, "  Display these items when you press the M key in the full 'M'ap.");
1196         }
1197         else
1198                 strcat(buff, " Not displayed in the full map.");
1199 #endif /* JP */
1200 }
1201
1202
1203 /*
1204  * Read whole lines of a file to memory
1205  */
1206 static concptr *read_text_lines(concptr filename)
1207 {
1208         concptr *lines_list = NULL;
1209         FILE *fff;
1210
1211         int lines = 0;
1212         char buf[1024];
1213
1214         path_build(buf, sizeof(buf), ANGBAND_DIR_USER, filename);
1215         fff = my_fopen(buf, "r");
1216         if (!fff) return NULL;
1217
1218         C_MAKE(lines_list, MAX_LINES, concptr);
1219         while (my_fgets(fff, buf, sizeof(buf)) == 0)
1220         {
1221                 lines_list[lines++] = string_make(buf);
1222                 if (lines >= MAX_LINES - 1) break;
1223         }
1224
1225         if (lines == 0)
1226                 lines_list[0] = string_make("");
1227
1228         my_fclose(fff);
1229         return lines_list;
1230 }
1231
1232
1233 /*
1234  * Copy the default autopick file to the user directory
1235  */
1236 static void prepare_default_pickpref(player_type *player_ptr)
1237 {
1238         const concptr messages[] = {
1239                 _("あなたは「自動拾いエディタ」を初めて起動しました。", "You have activated the Auto-Picker Editor for the first time."),
1240                 _("自動拾いのユーザー設定ファイルがまだ書かれていないので、", "Since user pref file for autopick is not yet created,"),
1241                 _("基本的な自動拾い設定ファイルをlib/pref/picktype.prfからコピーします。", "the default setting is loaded from lib/pref/pickpref.prf ."),
1242                 NULL
1243         };
1244
1245         concptr filename = pickpref_filename(player_ptr, PT_DEFAULT);
1246         for (int i = 0; messages[i]; i++)
1247         {
1248                 msg_print(messages[i]);
1249         }
1250
1251         msg_print(NULL);
1252         char buf[1024];
1253         path_build(buf, sizeof(buf), ANGBAND_DIR_USER, filename);
1254         FILE *user_fp;
1255         user_fp = my_fopen(buf, "w");
1256         if (!user_fp) return;
1257
1258         fprintf(user_fp, "#***\n");
1259         for (int i = 0; messages[i]; i++)
1260         {
1261                 fprintf(user_fp, "#***  %s\n", messages[i]);
1262         }
1263
1264         fprintf(user_fp, "#***\n\n\n");
1265         path_build(buf, sizeof(buf), ANGBAND_DIR_PREF, filename);
1266         FILE *pref_fp;
1267         pref_fp = my_fopen(buf, "r");
1268
1269         if (!pref_fp)
1270         {
1271                 my_fclose(user_fp);
1272                 return;
1273         }
1274
1275         while (!my_fgets(pref_fp, buf, sizeof(buf)))
1276         {
1277                 fprintf(user_fp, "%s\n", buf);
1278         }
1279
1280         my_fclose(user_fp);
1281         my_fclose(pref_fp);
1282 }
1283
1284 /*
1285  * Read an autopick prefence file to memory
1286  * Prepare default if no user file is found
1287  */
1288 static concptr *read_pickpref_text_lines(player_type *player_ptr, int *filename_mode_p)
1289 {
1290         /* Try a filename with player name */
1291         *filename_mode_p = PT_WITH_PNAME;
1292         char buf[1024];
1293         strcpy(buf, pickpref_filename(player_ptr, *filename_mode_p));
1294         concptr *lines_list;
1295         lines_list = read_text_lines(buf);
1296
1297         if (!lines_list)
1298         {
1299                 *filename_mode_p = PT_DEFAULT;
1300                 strcpy(buf, pickpref_filename(player_ptr, *filename_mode_p));
1301                 lines_list = read_text_lines(buf);
1302         }
1303
1304         if (!lines_list)
1305         {
1306                 prepare_default_pickpref(player_ptr);
1307                 lines_list = read_text_lines(buf);
1308         }
1309
1310         if (!lines_list)
1311         {
1312                 C_MAKE(lines_list, MAX_LINES, concptr);
1313                 lines_list[0] = string_make("");
1314         }
1315
1316         return lines_list;
1317 }
1318
1319
1320 /*
1321  * Write whole lines of memory to a file.
1322  */
1323 static bool write_text_lines(concptr filename, concptr *lines_list)
1324 {
1325         char buf[1024];
1326         path_build(buf, sizeof(buf), ANGBAND_DIR_USER, filename);
1327         FILE *fff;
1328         fff = my_fopen(buf, "w");
1329         if (!fff) return FALSE;
1330
1331         for (int lines = 0; lines_list[lines]; lines++)
1332         {
1333                 my_fputs(fff, lines_list[lines], 1024);
1334         }
1335
1336         my_fclose(fff);
1337         return TRUE;
1338 }
1339
1340
1341 /*
1342  * Free memory of lines_list.
1343  */
1344 static void free_text_lines(concptr *lines_list)
1345 {
1346         for (int lines = 0; lines_list[lines]; lines++)
1347         {
1348                 string_free(lines_list[lines]);
1349         }
1350
1351         /* free list of pointers */
1352         C_KILL(lines_list, MAX_LINES, concptr);
1353 }
1354
1355
1356 /*
1357  * Delete or insert string
1358  */
1359 static void toggle_keyword(text_body_type *tb, BIT_FLAGS flg)
1360 {
1361         int by1, by2;
1362         bool add = TRUE;
1363         bool fixed = FALSE;
1364         if (tb->mark)
1365         {
1366                 by1 = MIN(tb->my, tb->cy);
1367                 by2 = MAX(tb->my, tb->cy);
1368         }
1369         else /* if (!tb->mark) */
1370         {
1371                 by1 = by2 = tb->cy;
1372         }
1373
1374         for (int y = by1; y <= by2; y++)
1375         {
1376                 autopick_type an_entry, *entry = &an_entry;
1377                 if (!autopick_new_entry(entry, tb->lines_list[y], !fixed)) continue;
1378
1379                 string_free(tb->lines_list[y]);
1380                 if (!fixed)
1381                 {
1382                         if (!IS_FLG(flg)) add = TRUE;
1383                         else add = FALSE;
1384
1385                         fixed = TRUE;
1386                 }
1387
1388                 if (FLG_NOUN_BEGIN <= flg && flg <= FLG_NOUN_END)
1389                 {
1390                         int i;
1391                         for (i = FLG_NOUN_BEGIN; i <= FLG_NOUN_END; i++)
1392                                 REM_FLG(i);
1393                 }
1394                 else if (FLG_UNAWARE <= flg && flg <= FLG_STAR_IDENTIFIED)
1395                 {
1396                         int i;
1397                         for (i = FLG_UNAWARE; i <= FLG_STAR_IDENTIFIED; i++)
1398                                 REM_FLG(i);
1399                 }
1400                 else if (FLG_ARTIFACT <= flg && flg <= FLG_AVERAGE)
1401                 {
1402                         int i;
1403                         for (i = FLG_ARTIFACT; i <= FLG_AVERAGE; i++)
1404                                 REM_FLG(i);
1405                 }
1406                 else if (FLG_RARE <= flg && flg <= FLG_COMMON)
1407                 {
1408                         int i;
1409                         for (i = FLG_RARE; i <= FLG_COMMON; i++)
1410                                 REM_FLG(i);
1411                 }
1412
1413                 if (add) ADD_FLG(flg);
1414                 else REM_FLG(flg);
1415
1416                 tb->lines_list[y] = autopick_line_from_entry_kill(entry);
1417                 tb->dirty_flags |= DIRTY_ALL;
1418                 tb->changed = TRUE;
1419         }
1420 }
1421
1422
1423 /*
1424  * Change command letter
1425  */
1426 static void toggle_command_letter(text_body_type *tb, byte flg)
1427 {
1428         autopick_type an_entry, *entry = &an_entry;
1429         int by1, by2, y;
1430         bool add = TRUE;
1431         bool fixed = FALSE;
1432         if (tb->mark)
1433         {
1434                 by1 = MIN(tb->my, tb->cy);
1435                 by2 = MAX(tb->my, tb->cy);
1436         }
1437         else /* if (!tb->mark) */
1438         {
1439                 by1 = by2 = tb->cy;
1440         }
1441
1442         for (y = by1; y <= by2; y++)
1443         {
1444                 int wid = 0;
1445
1446                 if (!autopick_new_entry(entry, tb->lines_list[y], FALSE)) continue;
1447
1448                 string_free(tb->lines_list[y]);
1449
1450                 if (!fixed)
1451                 {
1452                         if (!(entry->action & flg)) add = TRUE;
1453                         else add = FALSE;
1454
1455                         fixed = TRUE;
1456                 }
1457
1458                 if (entry->action & DONT_AUTOPICK) wid--;
1459                 else if (entry->action & DO_AUTODESTROY) wid--;
1460                 else if (entry->action & DO_QUERY_AUTOPICK) wid--;
1461                 if (!(entry->action & DO_DISPLAY)) wid--;
1462
1463                 if (flg != DO_DISPLAY)
1464                 {
1465                         entry->action &= ~(DO_AUTOPICK | DONT_AUTOPICK | DO_AUTODESTROY | DO_QUERY_AUTOPICK);
1466                         if (add) entry->action |= flg;
1467                         else entry->action |= DO_AUTOPICK;
1468                 }
1469                 else
1470                 {
1471                         entry->action &= ~(DO_DISPLAY);
1472                         if (add) entry->action |= flg;
1473                 }
1474
1475                 if (tb->cy == y)
1476                 {
1477                         if (entry->action & DONT_AUTOPICK) wid++;
1478                         else if (entry->action & DO_AUTODESTROY) wid++;
1479                         else if (entry->action & DO_QUERY_AUTOPICK) wid++;
1480                         if (!(entry->action & DO_DISPLAY)) wid++;
1481
1482                         if (wid > 0) tb->cx++;
1483                         if (wid < 0 && tb->cx > 0) tb->cx--;
1484                 }
1485
1486                 tb->lines_list[y] = autopick_line_from_entry_kill(entry);
1487                 tb->dirty_flags |= DIRTY_ALL;
1488                 tb->changed = TRUE;
1489         }
1490 }
1491
1492
1493 /*
1494  * Delete or insert string
1495  */
1496 static void add_keyword(text_body_type *tb, BIT_FLAGS flg)
1497 {
1498         int by1, by2;
1499         if (tb->mark)
1500         {
1501                 by1 = MIN(tb->my, tb->cy);
1502                 by2 = MAX(tb->my, tb->cy);
1503         }
1504         else
1505         {
1506                 by1 = by2 = tb->cy;
1507         }
1508
1509         for (int y = by1; y <= by2; y++)
1510         {
1511                 autopick_type an_entry, *entry = &an_entry;
1512                 if (!autopick_new_entry(entry, tb->lines_list[y], FALSE)) continue;
1513
1514                 if (IS_FLG(flg))
1515                 {
1516                         autopick_free_entry(entry);
1517                         continue;
1518                 }
1519
1520                 string_free(tb->lines_list[y]);
1521                 if (FLG_NOUN_BEGIN <= flg && flg <= FLG_NOUN_END)
1522                 {
1523                         int i;
1524                         for (i = FLG_NOUN_BEGIN; i <= FLG_NOUN_END; i++)
1525                                 REM_FLG(i);
1526                 }
1527
1528                 ADD_FLG(flg);
1529                 tb->lines_list[y] = autopick_line_from_entry_kill(entry);
1530                 tb->dirty_flags |= DIRTY_ALL;
1531                 tb->changed = TRUE;
1532         }
1533 }
1534
1535
1536 /*
1537  * Check if this line is expression or not.
1538  * And update it if it is.
1539  */
1540 static void check_expression_line(text_body_type *tb, int y)
1541 {
1542         concptr s = tb->lines_list[y];
1543
1544         if ((s[0] == '?' && s[1] == ':') ||
1545                 (tb->states[y] & LSTAT_BYPASS))
1546         {
1547                 tb->dirty_flags |= DIRTY_EXPRESSION;
1548         }
1549 }
1550
1551
1552 /*
1553  * Add an empty line at the last of the file
1554  */
1555 static bool add_empty_line(text_body_type *tb)
1556 {
1557         int num_lines;
1558         for (num_lines = 0; tb->lines_list[num_lines]; num_lines++);
1559
1560         if (num_lines >= MAX_LINES - 2) return FALSE;
1561         if (!tb->lines_list[num_lines - 1][0]) return FALSE;
1562
1563         tb->lines_list[num_lines] = string_make("");
1564         tb->dirty_flags |= DIRTY_EXPRESSION;
1565         tb->changed = TRUE;
1566         return TRUE;
1567 }
1568
1569
1570 /*
1571  * Insert return code and split the line
1572  */
1573 static bool insert_return_code(text_body_type *tb)
1574 {
1575         char buf[MAX_LINELEN];
1576         int i, j, num_lines;
1577
1578         for (num_lines = 0; tb->lines_list[num_lines]; num_lines++);
1579
1580         if (num_lines >= MAX_LINES - 2) return FALSE;
1581         num_lines--;
1582
1583         for (; tb->cy < num_lines; num_lines--)
1584         {
1585                 tb->lines_list[num_lines + 1] = tb->lines_list[num_lines];
1586                 tb->states[num_lines + 1] = tb->states[num_lines];
1587         }
1588
1589         for (i = j = 0; tb->lines_list[tb->cy][i] && i < tb->cx; i++)
1590         {
1591 #ifdef JP
1592                 if (iskanji(tb->lines_list[tb->cy][i]))
1593                         buf[j++] = tb->lines_list[tb->cy][i++];
1594 #endif
1595                 buf[j++] = tb->lines_list[tb->cy][i];
1596         }
1597
1598         buf[j] = '\0';
1599         tb->lines_list[tb->cy + 1] = string_make(&tb->lines_list[tb->cy][i]);
1600         string_free(tb->lines_list[tb->cy]);
1601         tb->lines_list[tb->cy] = string_make(buf);
1602         tb->dirty_flags |= DIRTY_EXPRESSION;
1603         tb->changed = TRUE;
1604         return TRUE;
1605 }
1606
1607
1608 /*
1609  * Choose an item and get auto-picker entry from it.
1610  */
1611 static bool entry_from_choosed_object(player_type *player_ptr, autopick_type *entry)
1612 {
1613         concptr q = _("どのアイテムを登録しますか? ", "Enter which item? ");
1614         concptr s = _("アイテムを持っていない。", "You have nothing to enter.");
1615         object_type *o_ptr;
1616         o_ptr = choose_object(player_ptr, NULL, q, s, USE_INVEN | USE_FLOOR | USE_EQUIP, 0);
1617         if (!o_ptr) return FALSE;
1618
1619         autopick_entry_from_object(player_ptr, entry, o_ptr);
1620         return TRUE;
1621 }
1622
1623
1624 /*
1625  * Choose an item for search
1626  */
1627 static bool get_object_for_search(player_type *player_ptr, object_type **o_handle, concptr *search_strp)
1628 {
1629         concptr q = _("どのアイテムを検索しますか? ", "Enter which item? ");
1630         concptr s = _("アイテムを持っていない。", "You have nothing to enter.");
1631         object_type *o_ptr;
1632         o_ptr = choose_object(player_ptr, NULL, q, s, USE_INVEN | USE_FLOOR | USE_EQUIP, 0);
1633         if (!o_ptr) return FALSE;
1634
1635         *o_handle = o_ptr;
1636         string_free(*search_strp);
1637         char buf[MAX_NLEN + 20];
1638         object_desc(player_ptr, buf, *o_handle, (OD_NO_FLAVOR | OD_OMIT_PREFIX | OD_NO_PLURAL));
1639         *search_strp = string_make(format("<%s>", buf));
1640         return TRUE;
1641 }
1642
1643
1644 /*
1645  * Prepare for search by destroyed object
1646  */
1647 static bool get_destroyed_object_for_search(player_type *player_ptr, object_type **o_handle, concptr *search_strp)
1648 {
1649         if (!autopick_last_destroyed_object.k_idx) return FALSE;
1650
1651         *o_handle = &autopick_last_destroyed_object;
1652         string_free(*search_strp);
1653         char buf[MAX_NLEN + 20];
1654         object_desc(player_ptr, buf, *o_handle, (OD_NO_FLAVOR | OD_OMIT_PREFIX | OD_NO_PLURAL));
1655         *search_strp = string_make(format("<%s>", buf));
1656         return TRUE;
1657 }
1658
1659
1660 /*
1661  * Choose an item or string for search
1662  */
1663 static byte get_string_for_search(player_type *player_ptr, object_type **o_handle, concptr *search_strp)
1664 {
1665         /*
1666          * Text color
1667          * TERM_YELLOW : Overwrite mode
1668          * TERM_WHITE : Insert mode
1669          */
1670         byte color = TERM_YELLOW;
1671         char buf[MAX_NLEN + 20];
1672         const int len = 80;
1673         char prompt[] = _("検索(^I:持ち物 ^L:破壊された物): ", "Search key(^I:inven ^L:destroyed): ");
1674         int col = sizeof(prompt) - 1;
1675         if (*search_strp) strcpy(buf, *search_strp);
1676         else buf[0] = '\0';
1677
1678         if (*o_handle) color = TERM_L_GREEN;
1679
1680         prt(prompt, 0, 0);
1681         int pos = 0;
1682         while (TRUE)
1683         {
1684                 bool back = FALSE;
1685                 int skey;
1686
1687                 Term_erase(col, 0, 255);
1688                 Term_putstr(col, 0, -1, color, buf);
1689                 Term_gotoxy(col + pos, 0);
1690
1691                 skey = inkey_special(TRUE);
1692                 switch (skey)
1693                 {
1694                 case SKEY_LEFT:
1695                 case KTRL('b'):
1696                 {
1697                         int i = 0;
1698                         color = TERM_WHITE;
1699                         if (pos == 0) break;
1700
1701                         while (TRUE)
1702                         {
1703                                 int next_pos = i + 1;
1704
1705 #ifdef JP
1706                                 if (iskanji(buf[i])) next_pos++;
1707 #endif
1708                                 if (next_pos >= pos) break;
1709
1710                                 i = next_pos;
1711                         }
1712
1713                         pos = i;
1714                         break;
1715                 }
1716
1717                 case SKEY_RIGHT:
1718                 case KTRL('f'):
1719                         color = TERM_WHITE;
1720                         if ('\0' == buf[pos]) break;
1721
1722 #ifdef JP
1723                         if (iskanji(buf[pos])) pos += 2;
1724                         else pos++;
1725 #else
1726                         pos++;
1727 #endif
1728                         break;
1729
1730                 case ESCAPE:
1731                         return 0;
1732
1733                 case KTRL('r'):
1734                         back = TRUE;
1735                         /* Fall through */
1736
1737                 case '\n':
1738                 case '\r':
1739                 case KTRL('s'):
1740                         if (*o_handle) return (back ? -1 : 1);
1741                         string_free(*search_strp);
1742                         *search_strp = string_make(buf);
1743                         *o_handle = NULL;
1744                         return (back ? -1 : 1);
1745
1746                 case KTRL('i'):
1747                         return get_object_for_search(player_ptr, o_handle, search_strp);
1748
1749                 case KTRL('l'):
1750                         if (get_destroyed_object_for_search(player_ptr, o_handle, search_strp))
1751                                 return 1;
1752                         break;
1753
1754                 case '\010':
1755                 {
1756                         int i = 0;
1757                         color = TERM_WHITE;
1758                         if (pos == 0) break;
1759
1760                         while (TRUE)
1761                         {
1762                                 int next_pos = i + 1;
1763 #ifdef JP
1764                                 if (iskanji(buf[i])) next_pos++;
1765 #endif
1766                                 if (next_pos >= pos) break;
1767
1768                                 i = next_pos;
1769                         }
1770
1771                         pos = i;
1772                 }
1773                         /* Fall through */
1774
1775                 case 0x7F:
1776                 case KTRL('d'):
1777                 {
1778                         int dst, src;
1779                         color = TERM_WHITE;
1780                         if (buf[pos] == '\0') break;
1781
1782                         src = pos + 1;
1783 #ifdef JP
1784                         if (iskanji(buf[pos])) src++;
1785 #endif
1786                         dst = pos;
1787                         while ('\0' != (buf[dst++] = buf[src++]));
1788
1789                         break;
1790                 }
1791
1792                 default:
1793                 {
1794                         char tmp[100];
1795                         char c;
1796                         if (skey & SKEY_MASK) break;
1797
1798                         c = (char)skey;
1799                         if (color != TERM_WHITE)
1800                         {
1801                                 if (color == TERM_L_GREEN)
1802                                 {
1803                                         *o_handle = NULL;
1804                                         string_free(*search_strp);
1805                                         *search_strp = NULL;
1806                                 }
1807
1808                                 buf[0] = '\0';
1809                                 color = TERM_WHITE;
1810                         }
1811
1812                         strcpy(tmp, buf + pos);
1813 #ifdef JP
1814                         if (iskanji(c))
1815                         {
1816                                 char next;
1817                                 inkey_base = TRUE;
1818                                 next = inkey();
1819
1820                                 if (pos + 1 < len)
1821                                 {
1822                                         buf[pos++] = c;
1823                                         buf[pos++] = next;
1824                                 }
1825                                 else
1826                                 {
1827                                         bell();
1828                                 }
1829                         }
1830                         else
1831 #endif
1832                         {
1833 #ifdef JP
1834                                 if (pos < len && (isprint(c) || iskana(c)))
1835 #else
1836                                 if (pos < len && isprint(c))
1837 #endif
1838                                 {
1839                                         buf[pos++] = c;
1840                                 }
1841                                 else
1842                                 {
1843                                         bell();
1844                                 }
1845                         }
1846
1847                         buf[pos] = '\0';
1848                         my_strcat(buf, tmp, len + 1);
1849
1850                         break;
1851                 }
1852                 }
1853
1854                 if (*o_handle == NULL || color == TERM_L_GREEN) continue;
1855
1856                 *o_handle = NULL;
1857                 buf[0] = '\0';
1858                 string_free(*search_strp);
1859                 *search_strp = NULL;
1860         }
1861 }
1862
1863
1864 /*
1865  * Search next line matches for o_ptr
1866  */
1867 static void search_for_object(player_type *player_ptr, text_body_type *tb, object_type *o_ptr, bool forward)
1868 {
1869         autopick_type an_entry, *entry = &an_entry;
1870         GAME_TEXT o_name[MAX_NLEN];
1871         int bypassed_cy = -1;
1872         int i = tb->cy;
1873         object_desc(player_ptr, o_name, o_ptr, (OD_NO_FLAVOR | OD_OMIT_PREFIX | OD_NO_PLURAL));
1874         str_tolower(o_name);
1875
1876         while (TRUE)
1877         {
1878                 bool match;
1879                 if (forward)
1880                 {
1881                         if (!tb->lines_list[++i]) break;
1882                 }
1883                 else
1884                 {
1885                         if (--i < 0) break;
1886                 }
1887
1888                 if (!autopick_new_entry(entry, tb->lines_list[i], FALSE)) continue;
1889
1890                 match = is_autopick_match(player_ptr, o_ptr, entry, o_name);
1891                 autopick_free_entry(entry);
1892                 if (!match)     continue;
1893
1894                 if (tb->states[i] & LSTAT_BYPASS)
1895                 {
1896                         if (bypassed_cy == -1) bypassed_cy = i;
1897                         continue;
1898                 }
1899
1900                 tb->cx = 0;
1901                 tb->cy = i;
1902                 if (bypassed_cy != -1)
1903                 {
1904                         tb->dirty_flags |= DIRTY_SKIP_INACTIVE;
1905                 }
1906
1907                 return;
1908         }
1909
1910         if (bypassed_cy == -1)
1911         {
1912                 tb->dirty_flags |= DIRTY_NOT_FOUND;
1913                 return;
1914         }
1915
1916         tb->cx = 0;
1917         tb->cy = bypassed_cy;
1918         tb->dirty_flags |= DIRTY_INACTIVE;
1919 }
1920
1921
1922 /*
1923  * Search next line matches to the string
1924  */
1925 static void search_for_string(text_body_type *tb, concptr search_str, bool forward)
1926 {
1927         int bypassed_cy = -1;
1928         int bypassed_cx = 0;
1929
1930         int i = tb->cy;
1931         while (TRUE)
1932         {
1933                 concptr pos;
1934                 if (forward)
1935                 {
1936                         if (!tb->lines_list[++i]) break;
1937                 }
1938                 else
1939                 {
1940                         if (--i < 0) break;
1941                 }
1942
1943                 pos = my_strstr(tb->lines_list[i], search_str);
1944                 if (!pos) continue;
1945
1946                 if ((tb->states[i] & LSTAT_BYPASS) &&
1947                         !(tb->states[i] & LSTAT_EXPRESSION))
1948                 {
1949                         if (bypassed_cy == -1)
1950                         {
1951                                 bypassed_cy = i;
1952                                 bypassed_cx = (int)(pos - tb->lines_list[i]);
1953                         }
1954
1955                         continue;
1956                 }
1957
1958                 tb->cx = (int)(pos - tb->lines_list[i]);
1959                 tb->cy = i;
1960
1961                 if (bypassed_cy != -1)
1962                 {
1963                         tb->dirty_flags |= DIRTY_SKIP_INACTIVE;
1964                 }
1965
1966                 return;
1967         }
1968
1969         if (bypassed_cy == -1)
1970         {
1971                 tb->dirty_flags |= DIRTY_NOT_FOUND;
1972                 return;
1973         }
1974
1975         tb->cx = bypassed_cx;
1976         tb->cy = bypassed_cy;
1977         tb->dirty_flags |= DIRTY_INACTIVE;
1978 }
1979
1980
1981 /*
1982  * Find a command by 'key'.
1983  */
1984 static int get_com_id(char key)
1985 {
1986         for (int i = 0; menu_data[i].name; i++)
1987         {
1988                 if (menu_data[i].key == key)
1989                 {
1990                         return menu_data[i].com_id;
1991                 }
1992         }
1993
1994         return 0;
1995 }
1996
1997
1998 /*
1999  * Display the menu, and get a command
2000  */
2001 static int do_command_menu(int level, int start)
2002 {
2003         int max_len = 0;
2004         int col0 = 5 + level * 7;
2005         int row0 = 1 + level * 3;
2006         int menu_id_list[26];
2007         bool redraw = TRUE;
2008         char linestr[MAX_LINELEN];
2009
2010         byte menu_key = 0;
2011         for (int i = start; menu_data[i].level >= level; i++)
2012         {
2013                 int len;
2014
2015                 /* Ignore lower level sub menus */
2016                 if (menu_data[i].level > level) continue;
2017
2018                 len = strlen(menu_data[i].name);
2019                 if (len > max_len) max_len = len;
2020
2021                 menu_id_list[menu_key] = i;
2022                 menu_key++;
2023         }
2024
2025         while (menu_key < 26)
2026         {
2027                 menu_id_list[menu_key] = -1;
2028                 menu_key++;
2029         }
2030
2031         int max_menu_wid = max_len + 3 + 3;
2032
2033         /* Prepare box line */
2034         linestr[0] = '\0';
2035         strcat(linestr, "+");
2036         for (int i = 0; i < max_menu_wid + 2; i++)
2037         {
2038                 strcat(linestr, "-");
2039         }
2040
2041         strcat(linestr, "+");
2042
2043         while (TRUE)
2044         {
2045                 int com_id;
2046                 char key;
2047                 int menu_id;
2048
2049                 if (redraw)
2050                 {
2051                         int row1 = row0 + 1;
2052                         Term_putstr(col0, row0, -1, TERM_WHITE, linestr);
2053
2054                         menu_key = 0;
2055                         for (int i = start; menu_data[i].level >= level; i++)
2056                         {
2057                                 char com_key_str[3];
2058                                 concptr str;
2059                                 if (menu_data[i].level > level) continue;
2060
2061                                 if (menu_data[i].com_id == -1)
2062                                 {
2063                                         strcpy(com_key_str, _("▼", ">"));
2064                                 }
2065                                 else if (menu_data[i].key != -1)
2066                                 {
2067                                         com_key_str[0] = '^';
2068                                         com_key_str[1] = menu_data[i].key + '@';
2069                                         com_key_str[2] = '\0';
2070                                 }
2071                                 else
2072                                 {
2073                                         com_key_str[0] = '\0';
2074                                 }
2075
2076                                 str = format("| %c) %-*s %2s | ", menu_key + 'a', max_len, menu_data[i].name, com_key_str);
2077
2078                                 Term_putstr(col0, row1++, -1, TERM_WHITE, str);
2079
2080                                 menu_key++;
2081                         }
2082
2083                         Term_putstr(col0, row1, -1, TERM_WHITE, linestr);
2084                         redraw = FALSE;
2085                 }
2086
2087                 prt(format(_("(a-%c) コマンド:", "(a-%c) Command:"), menu_key + 'a' - 1), 0, 0);
2088                 key = inkey();
2089
2090                 if (key == ESCAPE) return 0;
2091
2092                 bool is_alphabet = key >= 'a' && key <= 'z';
2093                 if (!is_alphabet)
2094                 {
2095                         com_id = get_com_id(key);
2096                         if (com_id)
2097                         {
2098                                 return com_id;
2099                         }
2100
2101                         continue;
2102                 }
2103
2104                 menu_id = menu_id_list[key - 'a'];
2105
2106                 if (menu_id < 0) continue;
2107
2108                 com_id = menu_data[menu_id].com_id;
2109
2110                 if (com_id == -1)
2111                 {
2112                         com_id = do_command_menu(level + 1, menu_id + 1);
2113
2114                         if (com_id) return com_id;
2115                         else redraw = TRUE;
2116                 }
2117                 else if (com_id)
2118                 {
2119                         return com_id;
2120                 }
2121         }
2122 }
2123
2124
2125 static chain_str_type *new_chain_str(concptr str)
2126 {
2127         chain_str_type *chain;
2128         size_t len = strlen(str);
2129         chain = (chain_str_type *)ralloc(sizeof(chain_str_type) + len * sizeof(char));
2130         strcpy(chain->s, str);
2131         chain->next = NULL;
2132         return chain;
2133 }
2134
2135
2136 static void kill_yank_chain(text_body_type *tb)
2137 {
2138         chain_str_type *chain = tb->yank;
2139         tb->yank = NULL;
2140         tb->yank_eol = TRUE;
2141
2142         while (chain)
2143         {
2144                 chain_str_type *next = chain->next;
2145                 size_t len = strlen(chain->s);
2146
2147                 rnfree(chain, sizeof(chain_str_type) + len * sizeof(char));
2148
2149                 chain = next;
2150         }
2151 }
2152
2153
2154 static void add_str_to_yank(text_body_type *tb, concptr str)
2155 {
2156         tb->yank_eol = FALSE;
2157         if (NULL == tb->yank)
2158         {
2159                 tb->yank = new_chain_str(str);
2160                 return;
2161         }
2162
2163         chain_str_type *chain;
2164         chain = tb->yank;
2165
2166         while (TRUE)
2167         {
2168                 if (!chain->next)
2169                 {
2170                         chain->next = new_chain_str(str);
2171                         return;
2172                 }
2173
2174                 /* Go to next */
2175                 chain = chain->next;
2176         }
2177 }
2178
2179
2180 /*
2181  * Do work for the copy editor-command
2182  */
2183 static void copy_text_to_yank(text_body_type *tb)
2184 {
2185         int len = strlen(tb->lines_list[tb->cy]);
2186         if (tb->cx > len) tb->cx = len;
2187
2188         if (!tb->mark)
2189         {
2190                 tb->cx = 0;
2191                 tb->my = tb->cy;
2192                 tb->mx = len;
2193         }
2194
2195         kill_yank_chain(tb);
2196         if (tb->my != tb->cy)
2197         {
2198                 int by1 = MIN(tb->my, tb->cy);
2199                 int by2 = MAX(tb->my, tb->cy);
2200
2201                 for (int y = by1; y <= by2; y++)
2202                 {
2203                         add_str_to_yank(tb, tb->lines_list[y]);
2204                 }
2205
2206                 add_str_to_yank(tb, "");
2207                 tb->mark = 0;
2208                 tb->dirty_flags |= DIRTY_ALL;
2209                 return;
2210         }
2211
2212         char buf[MAX_LINELEN];
2213         int bx1 = MIN(tb->mx, tb->cx);
2214         int bx2 = MAX(tb->mx, tb->cx);
2215         if (bx2 > len) bx2 = len;
2216
2217         if (bx1 == 0 && bx2 == len)
2218         {
2219                 add_str_to_yank(tb, tb->lines_list[tb->cy]);
2220                 add_str_to_yank(tb, "");
2221         }
2222         else
2223         {
2224                 int end = bx2 - bx1;
2225                 for (int i = 0; i < bx2 - bx1; i++)
2226                 {
2227                         buf[i] = tb->lines_list[tb->cy][bx1 + i];
2228                 }
2229
2230                 buf[end] = '\0';
2231                 add_str_to_yank(tb, buf);
2232         }
2233
2234         tb->mark = 0;
2235         tb->dirty_flags |= DIRTY_ALL;
2236 }
2237
2238
2239 /*
2240  * Draw text
2241  */
2242 static void draw_text_editor(player_type *player_ptr, text_body_type *tb)
2243 {
2244         int i;
2245         int by1 = 0, by2 = 0;
2246
2247         Term_get_size(&tb->wid, &tb->hgt);
2248
2249         /*
2250          * Top line (-1), description line (-3), separator (-1)
2251          *  == -5
2252          */
2253         tb->hgt -= 2 + DESCRIPT_HGT;
2254
2255 #ifdef JP
2256         /* Don't let cursor at second byte of kanji */
2257         for (i = 0; tb->lines_list[tb->cy][i]; i++)
2258                 if (iskanji(tb->lines_list[tb->cy][i]))
2259                 {
2260                         i++;
2261                         if (i == tb->cx)
2262                         {
2263                                 /*
2264                                  * Move to a correct position in the
2265                                  * left or right
2266                                  */
2267                                 if (i & 1) tb->cx--;
2268                                 else tb->cx++;
2269                                 break;
2270                         }
2271                 }
2272 #endif
2273         if (tb->cy < tb->upper || tb->upper + tb->hgt <= tb->cy)
2274                 tb->upper = tb->cy - (tb->hgt) / 2;
2275         if (tb->upper < 0)
2276                 tb->upper = 0;
2277         if ((tb->cx < tb->left + 10 && tb->left > 0) || tb->left + tb->wid - 5 <= tb->cx)
2278                 tb->left = tb->cx - (tb->wid) * 2 / 3;
2279         if (tb->left < 0)
2280                 tb->left = 0;
2281
2282         if (tb->old_wid != tb->wid || tb->old_hgt != tb->hgt)
2283                 tb->dirty_flags |= DIRTY_SCREEN;
2284         else if (tb->old_upper != tb->upper || tb->old_left != tb->left)
2285                 tb->dirty_flags |= DIRTY_ALL;
2286
2287         if (tb->dirty_flags & DIRTY_SCREEN)
2288         {
2289                 tb->dirty_flags |= (DIRTY_ALL | DIRTY_MODE);
2290                 Term_clear();
2291         }
2292
2293         if (tb->dirty_flags & DIRTY_MODE)
2294         {
2295                 char buf[MAX_LINELEN];
2296                 int sepa_length = tb->wid;
2297                 for (i = 0; i < sepa_length; i++)
2298                         buf[i] = '-';
2299                 buf[i] = '\0';
2300                 Term_putstr(0, tb->hgt + 1, sepa_length, TERM_WHITE, buf);
2301         }
2302
2303         if (tb->dirty_flags & DIRTY_EXPRESSION)
2304         {
2305                 byte state = 0;
2306                 for (int y = 0; tb->lines_list[y]; y++)
2307                 {
2308                         char f;
2309                         concptr v;
2310                         concptr s = tb->lines_list[y];
2311                         char *ss, *s_keep;
2312                         int s_len;
2313
2314                         tb->states[y] = state;
2315
2316                         if (*s++ != '?') continue;
2317                         if (*s++ != ':') continue;
2318
2319                         if (streq(s, "$AUTOREGISTER"))
2320                                 state |= LSTAT_AUTOREGISTER;
2321
2322                         s_len = strlen(s);
2323                         ss = (char *)string_make(s);
2324                         s_keep = ss;
2325
2326                         v = process_pref_file_expr(player_ptr, &ss, &f);
2327
2328                         if (streq(v, "0")) state |= LSTAT_BYPASS;
2329                         else state &= ~LSTAT_BYPASS;
2330
2331                         C_KILL(s_keep, s_len + 1, char);
2332
2333                         tb->states[y] = state | LSTAT_EXPRESSION;
2334                 }
2335
2336                 tb->dirty_flags |= DIRTY_ALL;
2337         }
2338
2339         if (tb->mark)
2340         {
2341                 tb->dirty_flags |= DIRTY_ALL;
2342
2343                 by1 = MIN(tb->my, tb->cy);
2344                 by2 = MAX(tb->my, tb->cy);
2345         }
2346
2347         for (i = 0; i < tb->hgt; i++)
2348         {
2349                 int j;
2350                 int leftcol = 0;
2351                 concptr msg;
2352                 byte color;
2353                 int y = tb->upper + i;
2354
2355                 if (!(tb->dirty_flags & DIRTY_ALL) && (tb->dirty_line != y))
2356                         continue;
2357
2358                 msg = tb->lines_list[y];
2359                 if (!msg) break;
2360
2361                 for (j = 0; *msg; msg++, j++)
2362                 {
2363                         if (j == tb->left) break;
2364 #ifdef JP
2365                         if (j > tb->left)
2366                         {
2367                                 leftcol = 1;
2368                                 break;
2369                         }
2370                         if (iskanji(*msg))
2371                         {
2372                                 msg++;
2373                                 j++;
2374                         }
2375 #endif
2376                 }
2377
2378                 Term_erase(0, i + 1, tb->wid);
2379                 if (tb->states[y] & LSTAT_AUTOREGISTER)
2380                 {
2381                         color = TERM_L_RED;
2382                 }
2383                 else
2384                 {
2385                         if (tb->states[y] & LSTAT_BYPASS) color = TERM_SLATE;
2386                         else color = TERM_WHITE;
2387                 }
2388
2389                 if (!tb->mark || (y < by1 || by2 < y))
2390                 {
2391                         Term_putstr(leftcol, i + 1, tb->wid - 1, color, msg);
2392                 }
2393                 else if (by1 != by2)
2394                 {
2395                         Term_putstr(leftcol, i + 1, tb->wid - 1, TERM_YELLOW, msg);
2396                 }
2397                 else
2398                 {
2399                         int x0 = leftcol + tb->left;
2400                         int len = strlen(tb->lines_list[tb->cy]);
2401                         int bx1 = MIN(tb->mx, tb->cx);
2402                         int bx2 = MAX(tb->mx, tb->cx);
2403
2404                         if (bx2 > len) bx2 = len;
2405
2406                         Term_gotoxy(leftcol, i + 1);
2407                         if (x0 < bx1) Term_addstr(bx1 - x0, color, msg);
2408                         if (x0 < bx2) Term_addstr(bx2 - bx1, TERM_YELLOW, msg + (bx1 - x0));
2409                         Term_addstr(-1, color, msg + (bx2 - x0));
2410                 }
2411         }
2412
2413         for (; i < tb->hgt; i++)
2414         {
2415                 Term_erase(0, i + 1, tb->wid);
2416         }
2417
2418         bool is_dirty_diary = (tb->dirty_flags & (DIRTY_ALL | DIRTY_NOT_FOUND | DIRTY_NO_SEARCH)) != 0;
2419         bool is_updated = tb->old_cy != tb->cy || is_dirty_diary || tb->dirty_line == tb->cy;
2420         if (is_updated) return;
2421
2422         autopick_type an_entry, *entry = &an_entry;
2423         concptr str1 = NULL, str2 = NULL;
2424         for (i = 0; i < DESCRIPT_HGT; i++)
2425         {
2426                 Term_erase(0, tb->hgt + 2 + i, tb->wid);
2427         }
2428
2429         if (tb->dirty_flags & DIRTY_NOT_FOUND)
2430         {
2431                 str1 = format(_("パターンが見つかりません: %s", "Pattern not found: %s"), tb->search_str);
2432         }
2433         else if (tb->dirty_flags & DIRTY_SKIP_INACTIVE)
2434         {
2435                 str1 = format(_("無効状態の行をスキップしました。(%sを検索中)",
2436                         "Some inactive lines are skipped. (Searching %s)"), tb->search_str);
2437         }
2438         else if (tb->dirty_flags & DIRTY_INACTIVE)
2439         {
2440                 str1 = format(_("無効状態の行だけが見付かりました。(%sを検索中)",
2441                         "Found only an inactive line. (Searching %s)"), tb->search_str);
2442         }
2443         else if (tb->dirty_flags & DIRTY_NO_SEARCH)
2444         {
2445                 str1 = _("検索するパターンがありません(^S で検索)。", "No pattern to search. (Press ^S to search.)");
2446         }
2447         else if (tb->lines_list[tb->cy][0] == '#')
2448         {
2449                 str1 = _("この行はコメントです。", "This line is a comment.");
2450         }
2451         else if (tb->lines_list[tb->cy][0] && tb->lines_list[tb->cy][1] == ':')
2452         {
2453                 switch (tb->lines_list[tb->cy][0])
2454                 {
2455                 case '?':
2456                         str1 = _("この行は条件分岐式です。", "This line is a Conditional Expression.");
2457                         break;
2458                 case 'A':
2459                         str1 = _("この行はマクロの実行内容を定義します。", "This line defines a Macro action.");
2460                         break;
2461                 case 'P':
2462                         str1 = _("この行はマクロのトリガー・キーを定義します。", "This line defines a Macro trigger key.");
2463                         break;
2464                 case 'C':
2465                         str1 = _("この行はキー配置を定義します。", "This line defines a Keymap.");
2466                         break;
2467                 }
2468
2469                 switch (tb->lines_list[tb->cy][0])
2470                 {
2471                 case '?':
2472                         if (tb->states[tb->cy] & LSTAT_BYPASS)
2473                         {
2474                                 str2 = _("現在の式の値は「偽(=0)」です。", "The expression is 'False'(=0) currently.");
2475                         }
2476                         else
2477                         {
2478                                 str2 = _("現在の式の値は「真(=1)」です。", "The expression is 'True'(=1) currently.");
2479                         }
2480                         break;
2481
2482                 default:
2483                         if (tb->states[tb->cy] & LSTAT_AUTOREGISTER)
2484                         {
2485                                 str2 = _("この行は後で削除されます。", "This line will be delete later.");
2486                         }
2487
2488                         else if (tb->states[tb->cy] & LSTAT_BYPASS)
2489                         {
2490                                 str2 = _("この行は現在は無効な状態です。", "This line is bypassed currently.");
2491                         }
2492                         break;
2493                 }
2494         }
2495         else if (autopick_new_entry(entry, tb->lines_list[tb->cy], FALSE))
2496         {
2497                 char buf[MAX_LINELEN];
2498                 char temp[MAX_LINELEN];
2499                 concptr t;
2500
2501                 describe_autopick(buf, entry);
2502
2503                 if (tb->states[tb->cy] & LSTAT_AUTOREGISTER)
2504                 {
2505                         strcat(buf, _("この行は後で削除されます。", "  This line will be delete later."));
2506                 }
2507
2508                 if (tb->states[tb->cy] & LSTAT_BYPASS)
2509                 {
2510                         strcat(buf, _("この行は現在は無効な状態です。", "  This line is bypassed currently."));
2511                 }
2512
2513                 roff_to_buf(buf, 81, temp, sizeof(temp));
2514                 t = temp;
2515                 for (i = 0; i < 3; i++)
2516                 {
2517                         if (t[0] == 0)
2518                                 break;
2519                         else
2520                         {
2521                                 prt(t, tb->hgt + 1 + 1 + i, 0);
2522                                 t += strlen(t) + 1;
2523                         }
2524                 }
2525                 autopick_free_entry(entry);
2526         }
2527
2528         if (str1) prt(str1, tb->hgt + 1 + 1, 0);
2529         if (str2) prt(str2, tb->hgt + 1 + 2, 0);
2530 }
2531
2532
2533 /*
2534  * Kill segment of a line
2535  */
2536 static void kill_line_segment(text_body_type *tb, int y, int x0, int x1, bool whole)
2537 {
2538         concptr s = tb->lines_list[y];
2539         if (whole && x0 == 0 && s[x1] == '\0' && tb->lines_list[y + 1])
2540         {
2541                 string_free(tb->lines_list[y]);
2542
2543                 int i;
2544                 for (i = y; tb->lines_list[i + 1]; i++)
2545                         tb->lines_list[i] = tb->lines_list[i + 1];
2546                 tb->lines_list[i] = NULL;
2547
2548                 tb->dirty_flags |= DIRTY_EXPRESSION;
2549
2550                 return;
2551         }
2552
2553         if (x0 == x1) return;
2554
2555         char buf[MAX_LINELEN];
2556         char *d = buf;
2557         for (int x = 0; x < x0; x++)
2558                 *(d++) = s[x];
2559
2560         for (int x = x1; s[x]; x++)
2561                 *(d++) = s[x];
2562
2563         *d = '\0';
2564         string_free(tb->lines_list[y]);
2565         tb->lines_list[y] = string_make(buf);
2566         check_expression_line(tb, y);
2567         tb->changed = TRUE;
2568 }
2569
2570
2571 /*
2572  * Get a trigger key and insert ASCII string for the trigger
2573  */
2574 static bool insert_macro_line(text_body_type *tb)
2575 {
2576         int i, n = 0;
2577         flush();
2578         inkey_base = TRUE;
2579         i = inkey();
2580         char buf[1024];
2581         while (i)
2582         {
2583                 buf[n++] = (char)i;
2584                 inkey_base = TRUE;
2585                 inkey_scan = TRUE;
2586                 i = inkey();
2587         }
2588
2589         buf[n] = '\0';
2590         flush();
2591
2592         char tmp[1024];
2593         ascii_to_text(tmp, buf);
2594         if (!tmp[0]) return FALSE;
2595
2596         tb->cx = 0;
2597         insert_return_code(tb);
2598         string_free(tb->lines_list[tb->cy]);
2599         tb->lines_list[tb->cy] = string_make(format("P:%s", tmp));
2600
2601         i = macro_find_exact(buf);
2602         if (i == -1)
2603         {
2604                 tmp[0] = '\0';
2605         }
2606         else
2607         {
2608                 ascii_to_text(tmp, macro__act[i]);
2609         }
2610
2611         insert_return_code(tb);
2612         string_free(tb->lines_list[tb->cy]);
2613         tb->lines_list[tb->cy] = string_make(format("A:%s", tmp));
2614
2615         return TRUE;
2616 }
2617
2618
2619 /*
2620  * Get a command key and insert ASCII string for the key
2621  */
2622 static bool insert_keymap_line(text_body_type *tb)
2623 {
2624         BIT_FLAGS mode;
2625         if (rogue_like_commands)
2626         {
2627                 mode = KEYMAP_MODE_ROGUE;
2628         }
2629         else
2630         {
2631                 mode = KEYMAP_MODE_ORIG;
2632         }
2633
2634         flush();
2635         char buf[2];
2636         buf[0] = inkey();
2637         buf[1] = '\0';
2638
2639         flush();
2640         char tmp[1024];
2641         ascii_to_text(tmp, buf);
2642         if (!tmp[0]) return FALSE;
2643
2644         tb->cx = 0;
2645         insert_return_code(tb);
2646         string_free(tb->lines_list[tb->cy]);
2647         tb->lines_list[tb->cy] = string_make(format("C:%d:%s", mode, tmp));
2648
2649         concptr act = keymap_act[mode][(byte)(buf[0])];
2650         if (act)
2651         {
2652                 ascii_to_text(tmp, act);
2653         }
2654
2655         insert_return_code(tb);
2656         string_free(tb->lines_list[tb->cy]);
2657         tb->lines_list[tb->cy] = string_make(format("A:%s", tmp));
2658
2659         return TRUE;
2660 }
2661
2662
2663 /*
2664  * Execute a single editor command
2665  */
2666 static bool do_editor_command(player_type *player_ptr, text_body_type *tb, int com_id)
2667 {
2668         switch (com_id)
2669         {
2670         case EC_QUIT:
2671                 if (tb->changed)
2672                 {
2673                         if (!get_check(_("全ての変更を破棄してから終了します。よろしいですか? ",
2674                                 "Discard all changes and quit. Are you sure? "))) break;
2675                 }
2676
2677                 return QUIT_WITHOUT_SAVE;
2678
2679         case EC_SAVEQUIT:
2680                 return QUIT_AND_SAVE;
2681
2682         case EC_REVERT:
2683                 if (!get_check(_("全ての変更を破棄して元の状態に戻します。よろしいですか? ",
2684                         "Discard all changes and revert to original file. Are you sure? "))) break;
2685
2686                 free_text_lines(tb->lines_list);
2687                 tb->lines_list = read_pickpref_text_lines(player_ptr, &tb->filename_mode);
2688                 tb->dirty_flags |= DIRTY_ALL | DIRTY_MODE | DIRTY_EXPRESSION;
2689                 tb->cx = tb->cy = 0;
2690                 tb->mark = 0;
2691
2692                 tb->changed = FALSE;
2693                 break;
2694
2695         case EC_HELP:
2696                 (void)show_file(player_ptr, TRUE, _("jeditor.txt", "editor.txt"), NULL, 0, 0);
2697                 tb->dirty_flags |= DIRTY_SCREEN;
2698
2699                 break;
2700
2701         case EC_RETURN:
2702                 if (tb->mark)
2703                 {
2704                         tb->mark = 0;
2705                         tb->dirty_flags |= DIRTY_ALL;
2706                 }
2707
2708                 insert_return_code(tb);
2709                 tb->cy++;
2710                 tb->cx = 0;
2711
2712                 tb->dirty_flags |= DIRTY_ALL;
2713                 break;
2714
2715         case EC_LEFT:
2716         {
2717                 if (0 < tb->cx)
2718                 {
2719                         int len;
2720 #ifdef JP
2721                         int i;
2722 #endif
2723                         tb->cx--;
2724                         len = strlen(tb->lines_list[tb->cy]);
2725                         if (len < tb->cx) tb->cx = len;
2726 #ifdef JP
2727                         for (i = 0; tb->lines_list[tb->cy][i]; i++)
2728                         {
2729                                 if (iskanji(tb->lines_list[tb->cy][i]))
2730                                 {
2731                                         i++;
2732                                         if (i == tb->cx)
2733                                         {
2734                                                 tb->cx--;
2735                                                 break;
2736                                         }
2737                                 }
2738                         }
2739 #endif
2740                 }
2741                 else if (tb->cy > 0)
2742                 {
2743                         tb->cy--;
2744                         tb->cx = strlen(tb->lines_list[tb->cy]);
2745                 }
2746
2747                 break;
2748         }
2749         case EC_DOWN:
2750                 if (!tb->lines_list[tb->cy + 1])
2751                 {
2752                         if (!add_empty_line(tb)) break;
2753                 }
2754
2755                 tb->cy++;
2756                 break;
2757
2758         case EC_UP:
2759                 if (tb->cy > 0) tb->cy--;
2760                 break;
2761
2762         case EC_RIGHT:
2763         {
2764 #ifdef JP
2765                 if (iskanji(tb->lines_list[tb->cy][tb->cx])) tb->cx++;
2766 #endif
2767                 tb->cx++;
2768                 int len = strlen(tb->lines_list[tb->cy]);
2769                 if (len < tb->cx)
2770                 {
2771                         tb->cx = len;
2772                         if (!tb->lines_list[tb->cy + 1])
2773                         {
2774                                 if (!add_empty_line(tb)) break;
2775                         }
2776
2777                         tb->cy++;
2778                         tb->cx = 0;
2779                 }
2780
2781                 break;
2782         }
2783         case EC_BOL:
2784                 tb->cx = 0;
2785                 break;
2786
2787         case EC_EOL:
2788                 tb->cx = strlen(tb->lines_list[tb->cy]);
2789                 break;
2790
2791         case EC_PGUP:
2792                 while (0 < tb->cy && tb->upper <= tb->cy)
2793                         tb->cy--;
2794                 while (0 < tb->upper && tb->cy + 1 < tb->upper + tb->hgt)
2795                         tb->upper--;
2796                 break;
2797
2798         case EC_PGDOWN:
2799                 while (tb->cy < tb->upper + tb->hgt)
2800                 {
2801                         if (!tb->lines_list[tb->cy + 1])
2802                         {
2803                                 if (!add_empty_line(tb)) break;
2804                         }
2805
2806                         tb->cy++;
2807                 }
2808
2809                 tb->upper = tb->cy;
2810                 break;
2811
2812         case EC_TOP:
2813                 tb->cy = 0;
2814                 break;
2815
2816         case EC_BOTTOM:
2817                 while (TRUE)
2818                 {
2819                         if (!tb->lines_list[tb->cy + 1])
2820                         {
2821                                 if (!add_empty_line(tb)) break;
2822                         }
2823
2824                         tb->cy++;
2825                 }
2826
2827                 tb->cx = 0;
2828                 break;
2829
2830         case EC_CUT:
2831         {
2832                 copy_text_to_yank(tb);
2833                 if (tb->my == tb->cy)
2834                 {
2835                         int bx1 = MIN(tb->mx, tb->cx);
2836                         int bx2 = MAX(tb->mx, tb->cx);
2837                         int len = strlen(tb->lines_list[tb->cy]);
2838                         if (bx2 > len) bx2 = len;
2839
2840                         kill_line_segment(tb, tb->cy, bx1, bx2, TRUE);
2841                         tb->cx = bx1;
2842                 }
2843                 else
2844                 {
2845                         int by1 = MIN(tb->my, tb->cy);
2846                         int by2 = MAX(tb->my, tb->cy);
2847
2848                         for (int y = by2; y >= by1; y--)
2849                         {
2850                                 int len = strlen(tb->lines_list[y]);
2851
2852                                 kill_line_segment(tb, y, 0, len, TRUE);
2853                         }
2854
2855                         tb->cy = by1;
2856                         tb->cx = 0;
2857                 }
2858
2859                 tb->mark = 0;
2860                 tb->dirty_flags |= DIRTY_ALL;
2861                 tb->changed = TRUE;
2862                 break;
2863         }
2864         case EC_COPY:
2865                 copy_text_to_yank(tb);
2866
2867                 /*
2868                  * Move cursor position to the end of the selection
2869                  *
2870                  * Pressing ^C ^V correctly duplicates the selection.
2871                  */
2872                 if (tb->my != tb->cy)
2873                 {
2874                         tb->cy = MAX(tb->cy, tb->my);
2875                         if (!tb->lines_list[tb->cy + 1])
2876                         {
2877                                 if (!add_empty_line(tb)) break;
2878                         }
2879
2880                         tb->cy++;
2881                         break;
2882                 }
2883
2884                 tb->cx = MAX(tb->cx, tb->mx);
2885                 if (!tb->lines_list[tb->cy][tb->cx])
2886                 {
2887                         if (!tb->lines_list[tb->cy + 1])
2888                         {
2889                                 if (!add_empty_line(tb)) break;
2890                         }
2891
2892                         tb->cy++;
2893                         tb->cx = 0;
2894                 }
2895
2896                 break;
2897
2898         case EC_PASTE:
2899         {
2900                 chain_str_type *chain = tb->yank;
2901                 int len = strlen(tb->lines_list[tb->cy]);
2902                 if (!chain) break;
2903                 if (tb->cx > len) tb->cx = len;
2904
2905                 if (tb->mark)
2906                 {
2907                         tb->mark = 0;
2908                         tb->dirty_flags |= DIRTY_ALL;
2909                 }
2910
2911                 while (chain)
2912                 {
2913                         concptr yank_str = chain->s;
2914                         char buf[MAX_LINELEN];
2915                         int i;
2916                         char rest[MAX_LINELEN], *rest_ptr = rest;
2917                         for (i = 0; i < tb->cx; i++)
2918                                 buf[i] = tb->lines_list[tb->cy][i];
2919
2920                         strcpy(rest, &(tb->lines_list[tb->cy][i]));
2921                         while (*yank_str && i < MAX_LINELEN - 1)
2922                         {
2923                                 buf[i++] = *yank_str++;
2924                         }
2925
2926                         buf[i] = '\0';
2927                         chain = chain->next;
2928                         if (chain || tb->yank_eol)
2929                         {
2930                                 insert_return_code(tb);
2931                                 string_free(tb->lines_list[tb->cy]);
2932                                 tb->lines_list[tb->cy] = string_make(buf);
2933                                 tb->cx = 0;
2934                                 tb->cy++;
2935
2936                                 continue;
2937                         }
2938
2939                         tb->cx = strlen(buf);
2940                         while (*rest_ptr && i < MAX_LINELEN - 1)
2941                         {
2942                                 buf[i++] = *rest_ptr++;
2943                         }
2944
2945                         buf[i] = '\0';
2946                         string_free(tb->lines_list[tb->cy]);
2947                         tb->lines_list[tb->cy] = string_make(buf);
2948                         break;
2949                 }
2950
2951                 tb->dirty_flags |= DIRTY_ALL;
2952                 tb->dirty_flags |= DIRTY_EXPRESSION;
2953                 tb->changed = TRUE;
2954                 break;
2955         }
2956         case EC_BLOCK:
2957         {
2958                 if (tb->mark)
2959                 {
2960                         tb->mark = 0;
2961                         tb->dirty_flags |= DIRTY_ALL;
2962                         break;
2963                 }
2964
2965                 tb->mark = MARK_MARK;
2966                 if (com_id == tb->old_com_id)
2967                 {
2968                         int tmp = tb->cy;
2969                         tb->cy = tb->my;
2970                         tb->my = tmp;
2971                         tmp = tb->cx;
2972                         tb->cx = tb->mx;
2973                         tb->mx = tmp;
2974                         tb->dirty_flags |= DIRTY_ALL;
2975                         break;
2976                 }
2977
2978                 int len = strlen(tb->lines_list[tb->cy]);
2979
2980                 tb->my = tb->cy;
2981                 tb->mx = tb->cx;
2982                 if (tb->cx > len) tb->mx = len;
2983                 break;
2984         }
2985         case EC_KILL_LINE:
2986         {
2987                 int len = strlen(tb->lines_list[tb->cy]);
2988                 if (tb->cx > len) tb->cx = len;
2989
2990                 if (tb->mark)
2991                 {
2992                         tb->mark = 0;
2993                         tb->dirty_flags |= DIRTY_ALL;
2994                 }
2995
2996                 if (tb->old_com_id != com_id)
2997                 {
2998                         kill_yank_chain(tb);
2999                         tb->yank = NULL;
3000                 }
3001
3002                 if (tb->cx < len)
3003                 {
3004                         add_str_to_yank(tb, &(tb->lines_list[tb->cy][tb->cx]));
3005                         kill_line_segment(tb, tb->cy, tb->cx, len, FALSE);
3006                         tb->dirty_line = tb->cy;
3007                         break;
3008                 }
3009
3010                 if (tb->yank_eol) add_str_to_yank(tb, "");
3011
3012                 tb->yank_eol = TRUE;
3013                 do_editor_command(player_ptr, tb, EC_DELETE_CHAR);
3014                 break;
3015         }
3016         case EC_DELETE_CHAR:
3017         {
3018                 if (tb->mark)
3019                 {
3020                         tb->mark = 0;
3021                         tb->dirty_flags |= DIRTY_ALL;
3022                 }
3023
3024 #ifdef JP
3025                 if (iskanji(tb->lines_list[tb->cy][tb->cx])) tb->cx++;
3026 #endif
3027                 tb->cx++;
3028                 int len = strlen(tb->lines_list[tb->cy]);
3029                 if (len >= tb->cx)
3030                 {
3031                         do_editor_command(player_ptr, tb, EC_BACKSPACE);
3032                         break;
3033                 }
3034
3035                 if (tb->lines_list[tb->cy + 1])
3036                 {
3037                         tb->cy++;
3038                         tb->cx = 0;
3039                 }
3040                 else
3041                 {
3042                         tb->cx = len;
3043                         break;
3044                 }
3045
3046                 do_editor_command(player_ptr, tb, EC_BACKSPACE);
3047                 break;
3048         }
3049         case EC_BACKSPACE:
3050         {
3051                 int len, i, j, k;
3052                 char buf[MAX_LINELEN];
3053                 if (tb->mark)
3054                 {
3055                         tb->mark = 0;
3056                         tb->dirty_flags |= DIRTY_ALL;
3057                 }
3058
3059                 len = strlen(tb->lines_list[tb->cy]);
3060                 if (len < tb->cx) tb->cx = len;
3061
3062                 if (tb->cx == 0)
3063                 {
3064                         if (tb->cy == 0) break;
3065                         tb->cx = strlen(tb->lines_list[tb->cy - 1]);
3066                         strcpy(buf, tb->lines_list[tb->cy - 1]);
3067                         strcat(buf, tb->lines_list[tb->cy]);
3068                         string_free(tb->lines_list[tb->cy - 1]);
3069                         string_free(tb->lines_list[tb->cy]);
3070                         tb->lines_list[tb->cy - 1] = string_make(buf);
3071
3072                         for (i = tb->cy; tb->lines_list[i + 1]; i++)
3073                                 tb->lines_list[i] = tb->lines_list[i + 1];
3074
3075                         tb->lines_list[i] = NULL;
3076                         tb->cy--;
3077                         tb->dirty_flags |= DIRTY_ALL;
3078                         tb->dirty_flags |= DIRTY_EXPRESSION;
3079                         tb->changed = TRUE;
3080                         break;
3081                 }
3082
3083                 for (i = j = k = 0; tb->lines_list[tb->cy][i] && i < tb->cx; i++)
3084                 {
3085                         k = j;
3086 #ifdef JP
3087                         if (iskanji(tb->lines_list[tb->cy][i]))
3088                                 buf[j++] = tb->lines_list[tb->cy][i++];
3089 #endif
3090                         buf[j++] = tb->lines_list[tb->cy][i];
3091                 }
3092
3093                 while (j > k)
3094                 {
3095                         tb->cx--;
3096                         j--;
3097                 }
3098
3099                 for (; tb->lines_list[tb->cy][i]; i++)
3100                 {
3101                         buf[j++] = tb->lines_list[tb->cy][i];
3102                 }
3103
3104                 buf[j] = '\0';
3105                 string_free(tb->lines_list[tb->cy]);
3106                 tb->lines_list[tb->cy] = string_make(buf);
3107                 tb->dirty_line = tb->cy;
3108                 check_expression_line(tb, tb->cy);
3109                 tb->changed = TRUE;
3110                 break;
3111         }
3112         case EC_SEARCH_STR:
3113         {
3114                 byte search_dir;
3115                 tb->dirty_flags |= DIRTY_SCREEN;
3116                 search_dir = get_string_for_search(player_ptr, &tb->search_o_ptr, &tb->search_str);
3117
3118                 if (!search_dir) break;
3119
3120                 if (search_dir == 1) do_editor_command(player_ptr, tb, EC_SEARCH_FORW);
3121                 else do_editor_command(player_ptr, tb, EC_SEARCH_BACK);
3122                 break;
3123         }
3124         case EC_SEARCH_FORW:
3125                 if (tb->search_o_ptr)
3126                 {
3127                         search_for_object(player_ptr, tb, tb->search_o_ptr, TRUE);
3128                         break;
3129                 }
3130
3131                 if (tb->search_str && tb->search_str[0])
3132                 {
3133                         search_for_string(tb, tb->search_str, TRUE);
3134                         break;
3135                 }
3136
3137                 tb->dirty_flags |= DIRTY_NO_SEARCH;
3138                 break;
3139
3140         case EC_SEARCH_BACK:
3141                 if (tb->search_o_ptr)
3142                 {
3143                         search_for_object(player_ptr, tb, tb->search_o_ptr, FALSE);
3144                         break;
3145                 }
3146
3147                 if (tb->search_str && tb->search_str[0])
3148                 {
3149                         search_for_string(tb, tb->search_str, FALSE);
3150                         break;
3151                 }
3152
3153                 tb->dirty_flags |= DIRTY_NO_SEARCH;
3154                 break;
3155
3156         case EC_SEARCH_OBJ:
3157                 tb->dirty_flags |= DIRTY_SCREEN;
3158
3159                 if (!get_object_for_search(player_ptr, &tb->search_o_ptr, &tb->search_str)) break;
3160
3161                 do_editor_command(player_ptr, tb, EC_SEARCH_FORW);
3162                 break;
3163
3164         case EC_SEARCH_DESTROYED:
3165                 if (!get_destroyed_object_for_search(player_ptr, &tb->search_o_ptr, &tb->search_str))
3166                 {
3167                         tb->dirty_flags |= DIRTY_NO_SEARCH;
3168                         break;
3169                 }
3170
3171                 do_editor_command(player_ptr, tb, EC_SEARCH_FORW);
3172                 break;
3173
3174         case EC_INSERT_OBJECT:
3175         {
3176                 autopick_type an_entry, *entry = &an_entry;
3177                 if (!entry_from_choosed_object(player_ptr, entry))
3178                 {
3179                         tb->dirty_flags |= DIRTY_SCREEN;
3180                         break;
3181                 }
3182
3183                 tb->cx = 0;
3184                 insert_return_code(tb);
3185                 string_free(tb->lines_list[tb->cy]);
3186                 tb->lines_list[tb->cy] = autopick_line_from_entry_kill(entry);
3187                 tb->dirty_flags |= DIRTY_SCREEN;
3188                 break;
3189         }
3190         case EC_INSERT_DESTROYED:
3191                 if (!tb->last_destroyed) break;
3192
3193                 tb->cx = 0;
3194                 insert_return_code(tb);
3195                 string_free(tb->lines_list[tb->cy]);
3196                 tb->lines_list[tb->cy] = string_make(tb->last_destroyed);
3197                 tb->dirty_flags |= DIRTY_ALL;
3198                 tb->changed = TRUE;
3199                 break;
3200
3201         case EC_INSERT_BLOCK:
3202         {
3203                 char expression[80];
3204                 sprintf(expression, "?:[AND [EQU $RACE %s] [EQU $CLASS %s] [GEQ $LEVEL %02d]]",
3205 #ifdef JP
3206                         rp_ptr->E_title, cp_ptr->E_title,
3207 #else
3208                         rp_ptr->title, cp_ptr->title,
3209 #endif
3210                         player_ptr->lev);
3211                 tb->cx = 0;
3212                 insert_return_code(tb);
3213                 string_free(tb->lines_list[tb->cy]);
3214                 tb->lines_list[tb->cy] = string_make(expression);
3215                 tb->cy++;
3216                 insert_return_code(tb);
3217                 string_free(tb->lines_list[tb->cy]);
3218                 tb->lines_list[tb->cy] = string_make("?:1");
3219                 tb->dirty_flags |= DIRTY_ALL;
3220                 tb->changed = TRUE;
3221                 break;
3222         }
3223
3224         case EC_INSERT_MACRO:
3225                 draw_text_editor(player_ptr, tb);
3226                 Term_erase(0, tb->cy - tb->upper + 1, tb->wid);
3227                 Term_putstr(0, tb->cy - tb->upper + 1, tb->wid - 1, TERM_YELLOW, _("P:<トリガーキー>: ", "P:<Trigger key>: "));
3228                 if (!insert_macro_line(tb)) break;
3229
3230                 tb->cx = 2;
3231                 tb->dirty_flags |= DIRTY_ALL;
3232                 tb->changed = TRUE;
3233                 break;
3234
3235         case EC_INSERT_KEYMAP:
3236                 draw_text_editor(player_ptr, tb);
3237                 Term_erase(0, tb->cy - tb->upper + 1, tb->wid);
3238                 Term_putstr(0, tb->cy - tb->upper + 1, tb->wid - 1, TERM_YELLOW,
3239                         format(_("C:%d:<コマンドキー>: ", "C:%d:<Keypress>: "), (rogue_like_commands ? KEYMAP_MODE_ROGUE : KEYMAP_MODE_ORIG)));
3240
3241                 if (!insert_keymap_line(tb)) break;
3242
3243                 tb->cx = 2;
3244                 tb->dirty_flags |= DIRTY_ALL;
3245                 tb->changed = TRUE;
3246                 break;
3247
3248         case EC_CL_AUTOPICK: toggle_command_letter(tb, DO_AUTOPICK); break;
3249         case EC_CL_DESTROY: toggle_command_letter(tb, DO_AUTODESTROY); break;
3250         case EC_CL_LEAVE: toggle_command_letter(tb, DONT_AUTOPICK); break;
3251         case EC_CL_QUERY: toggle_command_letter(tb, DO_QUERY_AUTOPICK); break;
3252         case EC_CL_NO_DISP: toggle_command_letter(tb, DO_DISPLAY); break;
3253
3254         case EC_IK_UNAWARE: toggle_keyword(tb, FLG_UNAWARE); break;
3255         case EC_IK_UNIDENTIFIED: toggle_keyword(tb, FLG_UNIDENTIFIED); break;
3256         case EC_IK_IDENTIFIED: toggle_keyword(tb, FLG_IDENTIFIED); break;
3257         case EC_IK_STAR_IDENTIFIED: toggle_keyword(tb, FLG_STAR_IDENTIFIED); break;
3258         case EC_KK_WEAPONS: toggle_keyword(tb, FLG_WEAPONS); break;
3259         case EC_KK_FAVORITE_WEAPONS: toggle_keyword(tb, FLG_FAVORITE_WEAPONS); break;
3260         case EC_KK_ARMORS: toggle_keyword(tb, FLG_ARMORS); break;
3261         case EC_KK_MISSILES: toggle_keyword(tb, FLG_MISSILES); break;
3262         case EC_KK_DEVICES: toggle_keyword(tb, FLG_DEVICES); break;
3263         case EC_KK_LIGHTS: toggle_keyword(tb, FLG_LIGHTS); break;
3264         case EC_KK_JUNKS: toggle_keyword(tb, FLG_JUNKS); break;
3265         case EC_KK_CORPSES: toggle_keyword(tb, FLG_CORPSES); break;
3266         case EC_KK_SPELLBOOKS: toggle_keyword(tb, FLG_SPELLBOOKS); break;
3267         case EC_KK_SHIELDS: toggle_keyword(tb, FLG_SHIELDS); break;
3268         case EC_KK_BOWS: toggle_keyword(tb, FLG_BOWS); break;
3269         case EC_KK_RINGS: toggle_keyword(tb, FLG_RINGS); break;
3270         case EC_KK_AMULETS: toggle_keyword(tb, FLG_AMULETS); break;
3271         case EC_KK_SUITS: toggle_keyword(tb, FLG_SUITS); break;
3272         case EC_KK_CLOAKS: toggle_keyword(tb, FLG_CLOAKS); break;
3273         case EC_KK_HELMS: toggle_keyword(tb, FLG_HELMS); break;
3274         case EC_KK_GLOVES: toggle_keyword(tb, FLG_GLOVES); break;
3275         case EC_KK_BOOTS: toggle_keyword(tb, FLG_BOOTS); break;
3276         case EC_OK_COLLECTING: toggle_keyword(tb, FLG_COLLECTING); break;
3277         case EC_OK_BOOSTED: toggle_keyword(tb, FLG_BOOSTED); break;
3278         case EC_OK_MORE_DICE: toggle_keyword(tb, FLG_MORE_DICE); break;
3279         case EC_OK_MORE_BONUS: toggle_keyword(tb, FLG_MORE_BONUS); break;
3280         case EC_OK_WORTHLESS: toggle_keyword(tb, FLG_WORTHLESS); break;
3281         case EC_OK_ARTIFACT: toggle_keyword(tb, FLG_ARTIFACT); break;
3282         case EC_OK_EGO: toggle_keyword(tb, FLG_EGO); break;
3283         case EC_OK_GOOD: toggle_keyword(tb, FLG_GOOD); break;
3284         case EC_OK_NAMELESS: toggle_keyword(tb, FLG_NAMELESS); break;
3285         case EC_OK_AVERAGE: toggle_keyword(tb, FLG_AVERAGE); break;
3286         case EC_OK_RARE: toggle_keyword(tb, FLG_RARE); break;
3287         case EC_OK_COMMON: toggle_keyword(tb, FLG_COMMON); break;
3288         case EC_OK_WANTED: toggle_keyword(tb, FLG_WANTED); break;
3289         case EC_OK_UNIQUE: toggle_keyword(tb, FLG_UNIQUE); break;
3290         case EC_OK_HUMAN: toggle_keyword(tb, FLG_HUMAN); break;
3291         case EC_OK_UNREADABLE:
3292                 toggle_keyword(tb, FLG_UNREADABLE);
3293                 add_keyword(tb, FLG_SPELLBOOKS);
3294                 break;
3295         case EC_OK_REALM1:
3296                 toggle_keyword(tb, FLG_REALM1);
3297                 add_keyword(tb, FLG_SPELLBOOKS);
3298                 break;
3299         case EC_OK_REALM2:
3300                 toggle_keyword(tb, FLG_REALM2);
3301                 add_keyword(tb, FLG_SPELLBOOKS);
3302                 break;
3303         case EC_OK_FIRST:
3304                 toggle_keyword(tb, FLG_FIRST);
3305                 add_keyword(tb, FLG_SPELLBOOKS);
3306                 break;
3307         case EC_OK_SECOND:
3308                 toggle_keyword(tb, FLG_SECOND);
3309                 add_keyword(tb, FLG_SPELLBOOKS);
3310                 break;
3311         case EC_OK_THIRD:
3312                 toggle_keyword(tb, FLG_THIRD);
3313                 add_keyword(tb, FLG_SPELLBOOKS);
3314                 break;
3315         case EC_OK_FOURTH:
3316                 toggle_keyword(tb, FLG_FOURTH);
3317                 add_keyword(tb, FLG_SPELLBOOKS);
3318                 break;
3319         }
3320
3321         tb->old_com_id = com_id;
3322         return FALSE;
3323 }
3324
3325
3326 /*
3327  * Insert single letter at cursor position.
3328  */
3329 static void insert_single_letter(text_body_type *tb, int key)
3330 {
3331         int i, j, len;
3332         char buf[MAX_LINELEN];
3333
3334         for (i = j = 0; tb->lines_list[tb->cy][i] && i < tb->cx; i++)
3335         {
3336                 buf[j++] = tb->lines_list[tb->cy][i];
3337         }
3338
3339 #ifdef JP
3340         if (iskanji(key))
3341         {
3342                 int next;
3343
3344                 inkey_base = TRUE;
3345                 next = inkey();
3346                 if (j + 2 < MAX_LINELEN)
3347                 {
3348                         buf[j++] = (char)key;
3349                         buf[j++] = (char)next;
3350                         tb->cx += 2;
3351                 }
3352                 else
3353                         bell();
3354         }
3355         else
3356 #endif
3357         {
3358                 if (j + 1 < MAX_LINELEN)
3359                         buf[j++] = (char)key;
3360                 tb->cx++;
3361         }
3362
3363         for (; tb->lines_list[tb->cy][i] && j + 1 < MAX_LINELEN; i++)
3364                 buf[j++] = tb->lines_list[tb->cy][i];
3365         buf[j] = '\0';
3366
3367         string_free(tb->lines_list[tb->cy]);
3368         tb->lines_list[tb->cy] = string_make(buf);
3369         len = strlen(tb->lines_list[tb->cy]);
3370         if (len < tb->cx) tb->cx = len;
3371
3372         tb->dirty_line = tb->cy;
3373         check_expression_line(tb, tb->cy);
3374         tb->changed = TRUE;
3375 }
3376
3377
3378 /*
3379  * Check special key code and get a movement command id
3380  */
3381 static int analyze_move_key(text_body_type *tb, int skey)
3382 {
3383         int com_id;
3384         if (!(skey & SKEY_MASK)) return 0;
3385
3386         switch (skey & ~SKEY_MOD_MASK)
3387         {
3388         case SKEY_DOWN:   com_id = EC_DOWN;   break;
3389         case SKEY_LEFT:   com_id = EC_LEFT;   break;
3390         case SKEY_RIGHT:  com_id = EC_RIGHT;  break;
3391         case SKEY_UP:     com_id = EC_UP;     break;
3392         case SKEY_PGUP:   com_id = EC_PGUP;   break;
3393         case SKEY_PGDOWN: com_id = EC_PGDOWN; break;
3394         case SKEY_TOP:    com_id = EC_TOP;    break;
3395         case SKEY_BOTTOM: com_id = EC_BOTTOM; break;
3396         default:
3397                 return 0;
3398         }
3399
3400         if (!(skey & SKEY_MOD_SHIFT))
3401         {
3402                 /*
3403                  * Un-shifted cursor keys cancells
3404                  * selection created by shift+cursor.
3405                  */
3406                 if (tb->mark & MARK_BY_SHIFT)
3407                 {
3408                         tb->mark = 0;
3409                         tb->dirty_flags |= DIRTY_ALL;
3410                 }
3411
3412                 return com_id;
3413         }
3414
3415         if (tb->mark) return com_id;
3416
3417         int len = strlen(tb->lines_list[tb->cy]);
3418         tb->mark = MARK_MARK | MARK_BY_SHIFT;
3419         tb->my = tb->cy;
3420         tb->mx = tb->cx;
3421         if (tb->cx > len) tb->mx = len;
3422
3423         if (com_id == EC_UP || com_id == EC_DOWN)
3424         {
3425                 tb->dirty_flags |= DIRTY_ALL;
3426         }
3427         else
3428         {
3429                 tb->dirty_line = tb->cy;
3430         }
3431
3432         return com_id;
3433 }
3434
3435 /*
3436  * In-game editor of Object Auto-picker/Destoryer
3437  * @param player_ptr プレーヤーへの参照ポインタ
3438  */
3439 void do_cmd_edit_autopick(player_type *player_ptr)
3440 {
3441         static int cx_save = 0;
3442         static int cy_save = 0;
3443         text_body_type text_body, *tb = &text_body;
3444         autopick_type an_entry, *entry = &an_entry;
3445         char buf[MAX_LINELEN];
3446         int i;
3447         int key = -1;
3448         static s32b old_autosave_turn = 0L;
3449         byte quit = 0;
3450
3451         tb->changed = FALSE;
3452         tb->cx = cx_save;
3453         tb->cy = cy_save;
3454         tb->upper = tb->left = 0;
3455         tb->mark = 0;
3456         tb->mx = tb->my = 0;
3457         tb->old_cy = tb->old_upper = tb->old_left = -1;
3458         tb->old_wid = tb->old_hgt = -1;
3459         tb->old_com_id = 0;
3460
3461         tb->yank = NULL;
3462         tb->search_o_ptr = NULL;
3463         tb->search_str = NULL;
3464         tb->last_destroyed = NULL;
3465         tb->dirty_flags = DIRTY_ALL | DIRTY_MODE | DIRTY_EXPRESSION;
3466         tb->dirty_line = -1;
3467         tb->filename_mode = PT_DEFAULT;
3468
3469         if (current_world_ptr->game_turn < old_autosave_turn)
3470         {
3471                 while (old_autosave_turn > current_world_ptr->game_turn) old_autosave_turn -= TURNS_PER_TICK * TOWN_DAWN;
3472         }
3473
3474         if (current_world_ptr->game_turn > old_autosave_turn + 100L)
3475         {
3476                 do_cmd_save_game(player_ptr, TRUE);
3477                 old_autosave_turn = current_world_ptr->game_turn;
3478         }
3479
3480         update_playtime();
3481         init_autopick();
3482         if (autopick_last_destroyed_object.k_idx)
3483         {
3484                 autopick_entry_from_object(player_ptr, entry, &autopick_last_destroyed_object);
3485                 tb->last_destroyed = autopick_line_from_entry_kill(entry);
3486         }
3487
3488         tb->lines_list = read_pickpref_text_lines(player_ptr, &tb->filename_mode);
3489         for (i = 0; i < tb->cy; i++)
3490         {
3491                 if (!tb->lines_list[i])
3492                 {
3493                         tb->cy = tb->cx = 0;
3494                         break;
3495                 }
3496         }
3497
3498         screen_save();
3499         while (!quit)
3500         {
3501                 int com_id = 0;
3502                 draw_text_editor(player_ptr, tb);
3503                 prt(_("(^Q:終了 ^W:セーブして終了, ESC:メニュー, その他:入力)",
3504                         "(^Q:Quit, ^W:Save&Quit, ESC:Menu, Other:Input text)"), 0, 0);
3505                 if (!tb->mark)
3506                 {
3507                         prt(format("(%d,%d)", tb->cx, tb->cy), 0, 60);
3508                 }
3509                 else
3510                 {
3511                         prt(format("(%d,%d)-(%d,%d)", tb->mx, tb->my, tb->cx, tb->cy), 0, 60);
3512                 }
3513
3514                 Term_gotoxy(tb->cx - tb->left, tb->cy - tb->upper + 1);
3515                 tb->dirty_flags = 0;
3516                 tb->dirty_line = -1;
3517                 tb->old_cy = tb->cy;
3518                 tb->old_upper = tb->upper;
3519                 tb->old_left = tb->left;
3520                 tb->old_wid = tb->wid;
3521                 tb->old_hgt = tb->hgt;
3522
3523                 key = inkey_special(TRUE);
3524
3525                 if (key & SKEY_MASK)
3526                 {
3527                         com_id = analyze_move_key(tb, key);
3528                 }
3529                 else if (key == ESCAPE)
3530                 {
3531                         com_id = do_command_menu(0, 0);
3532                         tb->dirty_flags |= DIRTY_SCREEN;
3533                 }
3534                 else if (!iscntrl((unsigned char)key))
3535                 {
3536                         if (tb->mark)
3537                         {
3538                                 tb->mark = 0;
3539                                 tb->dirty_flags |= DIRTY_ALL;
3540                         }
3541
3542                         insert_single_letter(tb, key);
3543                         continue;
3544                 }
3545                 else
3546                 {
3547                         com_id = get_com_id((char)key);
3548                 }
3549
3550                 if (com_id) quit = do_editor_command(player_ptr, tb, com_id);
3551         }
3552
3553         screen_load();
3554         strcpy(buf, pickpref_filename(player_ptr, tb->filename_mode));
3555
3556         if (quit == QUIT_AND_SAVE)
3557                 write_text_lines(buf, tb->lines_list);
3558
3559         free_text_lines(tb->lines_list);
3560         string_free(tb->search_str);
3561         string_free(tb->last_destroyed);
3562         kill_yank_chain(tb);
3563
3564         process_autopick_file(player_ptr, buf);
3565         current_world_ptr->start_time = (u32b)time(NULL);
3566         cx_save = tb->cx;
3567         cy_save = tb->cy;
3568 }