OSDN Git Service

dfdc74a1b858f7d37f32eda3424d63b8a787fff0
[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-menu-data-table.h"
22 #include "autopick/autopick-methods-table.h"
23 #include "autopick/autopick-destroyer.h"
24 #include "autopick/autopick-entry.h"
25 #include "autopick/autopick-reader-writer.h"
26 #include "autopick/autopick-finder.h"
27 #include "autopick/autopick-adder.h"
28 #include "autopick/autopick-drawer.h"
29 #include "autopick/autopick-searcher.h"
30 #include "autopick/autopick-inserter-killer.h"
31 #include "gameterm.h"
32 #include "autopick/autopick.h"
33 #include "core/show-file.h"
34 #include "cmd/cmd-save.h"
35 #include "io/read-pref-file.h"
36
37 #include "mind.h"
38
39 #include "market/store.h"
40 #include "player-move.h"
41 #include "player-class.h"
42 #include "player-race.h"
43 #include "view/display-player.h" // 暫定。後で消す.
44 #include "object/object-kind.h"
45 #include "object-flavor.h"
46 #include "object-hook.h"
47
48 #include "world.h"
49 #include "view/display-main-window.h" // 暫定。後で消す.
50
51 /*
52  *  Auto-destroy marked item
53  */
54 static void autopick_delayed_alter_aux(player_type *player_ptr, INVENTORY_IDX item)
55 {
56         object_type *o_ptr;
57         o_ptr = REF_ITEM(player_ptr, player_ptr->current_floor_ptr, item);
58
59         if (o_ptr->k_idx == 0 || !(o_ptr->marked & OM_AUTODESTROY)) return;
60
61         GAME_TEXT o_name[MAX_NLEN];
62         object_desc(player_ptr, o_name, o_ptr, 0);
63         if (item >= 0)
64         {
65                 inven_item_increase(player_ptr, item, -(o_ptr->number));
66                 inven_item_optimize(player_ptr, item);
67         }
68         else
69         {
70                 delete_object_idx(player_ptr, 0 - item);
71         }
72
73         msg_format(_("%sを自動破壊します。", "Auto-destroying %s."), o_name);
74 }
75
76
77 /*
78  *  Auto-destroy marked items in inventry and on floor
79  */
80 void autopick_delayed_alter(player_type *owner_ptr)
81 {
82         INVENTORY_IDX item;
83
84         /*
85          * Scan inventry in reverse order to prevent
86          * skipping after inven_item_optimize()
87          */
88         for (item = INVEN_TOTAL - 1; item >= 0; item--)
89                 autopick_delayed_alter_aux(owner_ptr, item);
90
91         floor_type *floor_ptr = owner_ptr->current_floor_ptr;
92         item = floor_ptr->grid_array[owner_ptr->y][owner_ptr->x].o_idx;
93         while (item)
94         {
95                 OBJECT_IDX next = floor_ptr->o_list[item].next_o_idx;
96                 autopick_delayed_alter_aux(owner_ptr, -item);
97                 item = next;
98         }
99 }
100
101
102 /*
103  * Auto-inscription and/or destroy
104  *
105  * Auto-destroyer works only on inventory or on floor stack only when
106  * requested.
107  */
108 void autopick_alter_item(player_type *player_ptr, INVENTORY_IDX item, bool destroy)
109 {
110         object_type *o_ptr;
111         o_ptr = REF_ITEM(player_ptr, player_ptr->current_floor_ptr, item);
112         int idx = find_autopick_list(player_ptr, o_ptr);
113         auto_inscribe_item(player_ptr, o_ptr, idx);
114         if (destroy && item <= INVEN_PACK)
115                 auto_destroy_item(player_ptr, o_ptr, idx);
116 }
117
118
119 /*
120  * Automatically pickup/destroy items in this grid.
121  */
122 void autopick_pickup_items(player_type* player_ptr, grid_type *g_ptr)
123 {
124         OBJECT_IDX this_o_idx, next_o_idx = 0;
125         for (this_o_idx = g_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx)
126         {
127                 object_type *o_ptr = &player_ptr->current_floor_ptr->o_list[this_o_idx];
128                 next_o_idx = o_ptr->next_o_idx;
129                 int idx = find_autopick_list(player_ptr, o_ptr);
130                 auto_inscribe_item(player_ptr, o_ptr, idx);
131                 bool is_auto_pickup = idx >= 0;
132                 is_auto_pickup &= (autopick_list[idx].action & (DO_AUTOPICK | DO_QUERY_AUTOPICK)) != 0;
133                 if (!is_auto_pickup)
134                 {
135                         auto_destroy_item(player_ptr, o_ptr, idx);
136                         continue;
137                 }
138
139                 disturb(player_ptr, FALSE, FALSE);
140                 if (!inven_carry_okay(o_ptr))
141                 {
142                         GAME_TEXT o_name[MAX_NLEN];
143                         object_desc(player_ptr, o_name, o_ptr, 0);
144                         msg_format(_("ザックには%sを入れる隙間がない。", "You have no room for %s."), o_name);
145                         o_ptr->marked |= OM_NOMSG;
146                         continue;
147                 }
148
149                 if (!(autopick_list[idx].action & DO_QUERY_AUTOPICK))
150                 {
151                         py_pickup_aux(player_ptr, this_o_idx);
152                         continue;
153                 }
154
155                 char out_val[MAX_NLEN + 20];
156                 GAME_TEXT o_name[MAX_NLEN];
157                 if (o_ptr->marked & OM_NO_QUERY)
158                 {
159                         continue;
160                 }
161
162                 object_desc(player_ptr, o_name, o_ptr, 0);
163                 sprintf(out_val, _("%sを拾いますか? ", "Pick up %s? "), o_name);
164                 if (!get_check(out_val))
165                 {
166                         o_ptr->marked |= OM_NOMSG | OM_NO_QUERY;
167                         continue;
168                 }
169
170                 py_pickup_aux(player_ptr, this_o_idx);
171         }
172 }
173
174
175 static const char autoregister_header[] = "?:$AUTOREGISTER";
176
177 /*
178  *  Clear auto registered lines in the picktype.prf .
179  */
180 static bool clear_auto_register(player_type *player_ptr)
181 {
182         char pref_file[1024];
183         path_build(pref_file, sizeof(pref_file), ANGBAND_DIR_USER, pickpref_filename(player_ptr, PT_WITH_PNAME));
184         FILE *pref_fff;
185         pref_fff = my_fopen(pref_file, "r");
186
187         if (!pref_fff)
188         {
189                 path_build(pref_file, sizeof(pref_file), ANGBAND_DIR_USER, pickpref_filename(player_ptr, PT_DEFAULT));
190                 pref_fff = my_fopen(pref_file, "r");
191         }
192
193         if (!pref_fff)
194         {
195                 return TRUE;
196         }
197
198         char tmp_file[1024];
199         FILE *tmp_fff;
200         tmp_fff = my_fopen_temp(tmp_file, sizeof(tmp_file));
201         if (!tmp_fff)
202         {
203                 fclose(pref_fff);
204                 msg_format(_("一時ファイル %s を作成できませんでした。", "Failed to create temporary file %s."), tmp_file);
205                 msg_print(NULL);
206                 return FALSE;
207         }
208
209         bool autoregister = FALSE;
210         int num = 0;
211         char buf[1024];
212         while (TRUE)
213         {
214                 if (my_fgets(pref_fff, buf, sizeof(buf))) break;
215
216                 if (autoregister)
217                 {
218                         if (buf[0] != '#' && buf[0] != '?') num++;
219                         continue;
220                 }
221
222                 if (streq(buf, autoregister_header))
223                 {
224                         autoregister = TRUE;
225                 }
226                 else
227                 {
228                         fprintf(tmp_fff, "%s\n", buf);
229                 }
230         }
231
232         my_fclose(pref_fff);
233         my_fclose(tmp_fff);
234
235         bool okay = TRUE;
236         if (num)
237         {
238                 msg_format(_("以前のキャラクター用の自動設定(%d行)が残っています。",
239                         "Auto registered lines (%d lines) for previous character are remaining."), num);
240                 strcpy(buf, _("古い設定行は削除します。よろしいですか?", "These lines will be deleted.  Are you sure? "));
241
242                 if (!get_check(buf))
243                 {
244                         okay = FALSE;
245                         autoregister = FALSE;
246
247                         msg_print(_("エディタのカット&ペースト等を使って必要な行を避難してください。",
248                                 "Use cut & paste of auto picker editor (_) to keep old prefs."));
249                 }
250         }
251
252         if (autoregister)
253         {
254                 tmp_fff = my_fopen(tmp_file, "r");
255                 pref_fff = my_fopen(pref_file, "w");
256
257                 while (!my_fgets(tmp_fff, buf, sizeof(buf)))
258                         fprintf(pref_fff, "%s\n", buf);
259
260                 my_fclose(pref_fff);
261                 my_fclose(tmp_fff);
262         }
263
264         fd_kill(tmp_file);
265         return okay;
266 }
267
268
269 /*
270  *  Automatically register an auto-destroy preference line
271  */
272 bool autopick_autoregister(player_type *player_ptr, object_type *o_ptr)
273 {
274         char buf[1024];
275         char pref_file[1024];
276         FILE *pref_fff;
277         autopick_type an_entry, *entry = &an_entry;
278         int match_autopick = find_autopick_list(player_ptr, o_ptr);
279         if (match_autopick != -1)
280         {
281                 concptr what;
282                 byte act = autopick_list[match_autopick].action;
283                 if (act & DO_AUTOPICK) what = _("自動で拾う", "auto-pickup");
284                 else if (act & DO_AUTODESTROY) what = _("自動破壊する", "auto-destroy");
285                 else if (act & DONT_AUTOPICK) what = _("放置する", "leave on floor");
286                 else what = _("確認して拾う", "query auto-pickup");
287
288                 msg_format(_("そのアイテムは既に%sように設定されています。", "The object is already registered to %s."), what);
289                 return FALSE;
290         }
291
292         if ((object_is_known(o_ptr) && object_is_artifact(o_ptr)) ||
293                 ((o_ptr->ident & IDENT_SENSE) &&
294                 (o_ptr->feeling == FEEL_TERRIBLE || o_ptr->feeling == FEEL_SPECIAL)))
295         {
296                 GAME_TEXT o_name[MAX_NLEN];
297                 object_desc(player_ptr, o_name, o_ptr, 0);
298                 msg_format(_("%sは破壊不能だ。", "You cannot auto-destroy %s."), o_name);
299                 return FALSE;
300         }
301
302         if (!player_ptr->autopick_autoregister)
303         {
304                 if (!clear_auto_register(player_ptr)) return FALSE;
305         }
306
307         path_build(pref_file, sizeof(pref_file), ANGBAND_DIR_USER, pickpref_filename(player_ptr, PT_WITH_PNAME));
308         pref_fff = my_fopen(pref_file, "r");
309
310         if (!pref_fff)
311         {
312                 path_build(pref_file, sizeof(pref_file), ANGBAND_DIR_USER, pickpref_filename(player_ptr, PT_DEFAULT));
313                 pref_fff = my_fopen(pref_file, "r");
314         }
315
316         if (pref_fff)
317         {
318                 while (TRUE)
319                 {
320                         if (my_fgets(pref_fff, buf, sizeof(buf)))
321                         {
322                                 player_ptr->autopick_autoregister = FALSE;
323                                 break;
324                         }
325
326                         if (streq(buf, autoregister_header))
327                         {
328                                 player_ptr->autopick_autoregister = TRUE;
329                                 break;
330                         }
331                 }
332
333                 fclose(pref_fff);
334         }
335         else
336         {
337                 /*
338                  * File could not be opened for reading.  Assume header not
339                  * present.
340                  */
341                 player_ptr->autopick_autoregister = FALSE;
342         }
343
344         pref_fff = my_fopen(pref_file, "a");
345         if (!pref_fff)
346         {
347                 msg_format(_("%s を開くことができませんでした。", "Failed to open %s."), pref_file);
348                 msg_print(NULL);
349                 return FALSE;
350         }
351
352         if (!player_ptr->autopick_autoregister)
353         {
354                 fprintf(pref_fff, "%s\n", autoregister_header);
355
356                 fprintf(pref_fff, "%s\n", _("# *警告!!* 以降の行は自動登録されたものです。",
357                         "# *Warning!* The lines below will be deleted later."));
358                 fprintf(pref_fff, "%s\n", _("# 後で自動的に削除されますので、必要な行は上の方へ移動しておいてください。",
359                         "# Keep it by cut & paste if you need these lines for future characters."));
360                 player_ptr->autopick_autoregister = TRUE;
361         }
362
363         autopick_entry_from_object(player_ptr, entry, o_ptr);
364         entry->action = DO_AUTODESTROY;
365         add_autopick_list(entry);
366
367         concptr tmp = autopick_line_from_entry(entry);
368         fprintf(pref_fff, "%s\n", tmp);
369         string_free(tmp);
370         fclose(pref_fff);
371         return TRUE;
372 }
373
374
375 /*
376  * Delete or insert string
377  */
378 static void toggle_keyword(text_body_type *tb, BIT_FLAGS flg)
379 {
380         int by1, by2;
381         bool add = TRUE;
382         bool fixed = FALSE;
383         if (tb->mark)
384         {
385                 by1 = MIN(tb->my, tb->cy);
386                 by2 = MAX(tb->my, tb->cy);
387         }
388         else /* if (!tb->mark) */
389         {
390                 by1 = by2 = tb->cy;
391         }
392
393         for (int y = by1; y <= by2; y++)
394         {
395                 autopick_type an_entry, *entry = &an_entry;
396                 if (!autopick_new_entry(entry, tb->lines_list[y], !fixed)) continue;
397
398                 string_free(tb->lines_list[y]);
399                 if (!fixed)
400                 {
401                         if (!IS_FLG(flg)) add = TRUE;
402                         else add = FALSE;
403
404                         fixed = TRUE;
405                 }
406
407                 if (FLG_NOUN_BEGIN <= flg && flg <= FLG_NOUN_END)
408                 {
409                         int i;
410                         for (i = FLG_NOUN_BEGIN; i <= FLG_NOUN_END; i++)
411                                 REM_FLG(i);
412                 }
413                 else if (FLG_UNAWARE <= flg && flg <= FLG_STAR_IDENTIFIED)
414                 {
415                         int i;
416                         for (i = FLG_UNAWARE; i <= FLG_STAR_IDENTIFIED; i++)
417                                 REM_FLG(i);
418                 }
419                 else if (FLG_ARTIFACT <= flg && flg <= FLG_AVERAGE)
420                 {
421                         int i;
422                         for (i = FLG_ARTIFACT; i <= FLG_AVERAGE; i++)
423                                 REM_FLG(i);
424                 }
425                 else if (FLG_RARE <= flg && flg <= FLG_COMMON)
426                 {
427                         int i;
428                         for (i = FLG_RARE; i <= FLG_COMMON; i++)
429                                 REM_FLG(i);
430                 }
431
432                 if (add) ADD_FLG(flg);
433                 else REM_FLG(flg);
434
435                 tb->lines_list[y] = autopick_line_from_entry_kill(entry);
436                 tb->dirty_flags |= DIRTY_ALL;
437                 tb->changed = TRUE;
438         }
439 }
440
441
442 /*
443  * Change command letter
444  */
445 static void toggle_command_letter(text_body_type *tb, byte flg)
446 {
447         autopick_type an_entry;
448         autopick_type *entry = &an_entry;
449         int by1, by2;
450         bool add = TRUE;
451         bool fixed = FALSE;
452         if (tb->mark)
453         {
454                 by1 = MIN(tb->my, tb->cy);
455                 by2 = MAX(tb->my, tb->cy);
456         }
457         else /* if (!tb->mark) */
458         {
459                 by1 = by2 = tb->cy;
460         }
461
462         for (int y = by1; y <= by2; y++)
463         {
464                 int wid = 0;
465
466                 if (!autopick_new_entry(entry, tb->lines_list[y], FALSE)) continue;
467
468                 string_free(tb->lines_list[y]);
469
470                 if (!fixed)
471                 {
472                         if (!(entry->action & flg)) add = TRUE;
473                         else add = FALSE;
474
475                         fixed = TRUE;
476                 }
477
478                 if (entry->action & DONT_AUTOPICK) wid--;
479                 else if (entry->action & DO_AUTODESTROY) wid--;
480                 else if (entry->action & DO_QUERY_AUTOPICK) wid--;
481                 if (!(entry->action & DO_DISPLAY)) wid--;
482
483                 if (flg != DO_DISPLAY)
484                 {
485                         entry->action &= ~(DO_AUTOPICK | DONT_AUTOPICK | DO_AUTODESTROY | DO_QUERY_AUTOPICK);
486                         if (add) entry->action |= flg;
487                         else entry->action |= DO_AUTOPICK;
488                 }
489                 else
490                 {
491                         entry->action &= ~(DO_DISPLAY);
492                         if (add) entry->action |= flg;
493                 }
494
495                 if (tb->cy == y)
496                 {
497                         if (entry->action & DONT_AUTOPICK) wid++;
498                         else if (entry->action & DO_AUTODESTROY) wid++;
499                         else if (entry->action & DO_QUERY_AUTOPICK) wid++;
500                         if (!(entry->action & DO_DISPLAY)) wid++;
501
502                         if (wid > 0) tb->cx++;
503                         if (wid < 0 && tb->cx > 0) tb->cx--;
504                 }
505
506                 tb->lines_list[y] = autopick_line_from_entry_kill(entry);
507                 tb->dirty_flags |= DIRTY_ALL;
508                 tb->changed = TRUE;
509         }
510 }
511
512
513 /*
514  * Delete or insert string
515  */
516 static void add_keyword(text_body_type *tb, BIT_FLAGS flg)
517 {
518         int by1, by2;
519         if (tb->mark)
520         {
521                 by1 = MIN(tb->my, tb->cy);
522                 by2 = MAX(tb->my, tb->cy);
523         }
524         else
525         {
526                 by1 = by2 = tb->cy;
527         }
528
529         for (int y = by1; y <= by2; y++)
530         {
531                 autopick_type an_entry, *entry = &an_entry;
532                 if (!autopick_new_entry(entry, tb->lines_list[y], FALSE)) continue;
533
534                 if (IS_FLG(flg))
535                 {
536                         autopick_free_entry(entry);
537                         continue;
538                 }
539
540                 string_free(tb->lines_list[y]);
541                 if (FLG_NOUN_BEGIN <= flg && flg <= FLG_NOUN_END)
542                 {
543                         int i;
544                         for (i = FLG_NOUN_BEGIN; i <= FLG_NOUN_END; i++)
545                                 REM_FLG(i);
546                 }
547
548                 ADD_FLG(flg);
549                 tb->lines_list[y] = autopick_line_from_entry_kill(entry);
550                 tb->dirty_flags |= DIRTY_ALL;
551                 tb->changed = TRUE;
552         }
553 }
554
555
556 /*
557  * Add an empty line at the last of the file
558  */
559 static bool add_empty_line(text_body_type *tb)
560 {
561         int num_lines;
562         for (num_lines = 0; tb->lines_list[num_lines]; num_lines++);
563
564         if (num_lines >= MAX_LINES - 2) return FALSE;
565         if (!tb->lines_list[num_lines - 1][0]) return FALSE;
566
567         tb->lines_list[num_lines] = string_make("");
568         tb->dirty_flags |= DIRTY_EXPRESSION;
569         tb->changed = TRUE;
570         return TRUE;
571 }
572
573
574 /*
575  * Display the menu, and get a command
576  */
577 static int do_command_menu(int level, int start)
578 {
579         int max_len = 0;
580         int col0 = 5 + level * 7;
581         int row0 = 1 + level * 3;
582         int menu_id_list[26];
583         bool redraw = TRUE;
584         char linestr[MAX_LINELEN];
585
586         byte menu_key = 0;
587         for (int i = start; menu_data[i].level >= level; i++)
588         {
589                 /* Ignore lower level sub menus */
590                 if (menu_data[i].level > level) continue;
591
592                 int len = strlen(menu_data[i].name);
593                 if (len > max_len) max_len = len;
594
595                 menu_id_list[menu_key] = i;
596                 menu_key++;
597         }
598
599         while (menu_key < 26)
600         {
601                 menu_id_list[menu_key] = -1;
602                 menu_key++;
603         }
604
605         int max_menu_wid = max_len + 3 + 3;
606
607         /* Prepare box line */
608         linestr[0] = '\0';
609         strcat(linestr, "+");
610         for (int i = 0; i < max_menu_wid + 2; i++)
611         {
612                 strcat(linestr, "-");
613         }
614
615         strcat(linestr, "+");
616
617         while (TRUE)
618         {
619                 if (redraw)
620                 {
621                         int row1 = row0 + 1;
622                         Term_putstr(col0, row0, -1, TERM_WHITE, linestr);
623
624                         menu_key = 0;
625                         for (int i = start; menu_data[i].level >= level; i++)
626                         {
627                                 char com_key_str[3];
628                                 concptr str;
629                                 if (menu_data[i].level > level) continue;
630
631                                 if (menu_data[i].com_id == -1)
632                                 {
633                                         strcpy(com_key_str, _("▼", ">"));
634                                 }
635                                 else if (menu_data[i].key != -1)
636                                 {
637                                         com_key_str[0] = '^';
638                                         com_key_str[1] = menu_data[i].key + '@';
639                                         com_key_str[2] = '\0';
640                                 }
641                                 else
642                                 {
643                                         com_key_str[0] = '\0';
644                                 }
645
646                                 str = format("| %c) %-*s %2s | ", menu_key + 'a', max_len, menu_data[i].name, com_key_str);
647
648                                 Term_putstr(col0, row1++, -1, TERM_WHITE, str);
649
650                                 menu_key++;
651                         }
652
653                         Term_putstr(col0, row1, -1, TERM_WHITE, linestr);
654                         redraw = FALSE;
655                 }
656
657                 prt(format(_("(a-%c) コマンド:", "(a-%c) Command:"), menu_key + 'a' - 1), 0, 0);
658                 char key = inkey();
659
660                 if (key == ESCAPE) return 0;
661
662                 int com_id;
663                 bool is_alphabet = key >= 'a' && key <= 'z';
664                 if (!is_alphabet)
665                 {
666                         com_id = get_com_id(key);
667                         if (com_id)
668                         {
669                                 return com_id;
670                         }
671
672                         continue;
673                 }
674
675                 int menu_id = menu_id_list[key - 'a'];
676
677                 if (menu_id < 0) continue;
678
679                 com_id = menu_data[menu_id].com_id;
680
681                 if (com_id == -1)
682                 {
683                         com_id = do_command_menu(level + 1, menu_id + 1);
684
685                         if (com_id) return com_id;
686                         else redraw = TRUE;
687                 }
688                 else if (com_id)
689                 {
690                         return com_id;
691                 }
692         }
693 }
694
695
696 static chain_str_type *new_chain_str(concptr str)
697 {
698         chain_str_type *chain;
699         size_t len = strlen(str);
700         chain = (chain_str_type *)ralloc(sizeof(chain_str_type) + len * sizeof(char));
701         strcpy(chain->s, str);
702         chain->next = NULL;
703         return chain;
704 }
705
706
707 static void kill_yank_chain(text_body_type *tb)
708 {
709         chain_str_type *chain = tb->yank;
710         tb->yank = NULL;
711         tb->yank_eol = TRUE;
712
713         while (chain)
714         {
715                 chain_str_type *next = chain->next;
716                 size_t len = strlen(chain->s);
717
718                 rnfree(chain, sizeof(chain_str_type) + len * sizeof(char));
719
720                 chain = next;
721         }
722 }
723
724
725 static void add_str_to_yank(text_body_type *tb, concptr str)
726 {
727         tb->yank_eol = FALSE;
728         if (NULL == tb->yank)
729         {
730                 tb->yank = new_chain_str(str);
731                 return;
732         }
733
734         chain_str_type *chain;
735         chain = tb->yank;
736
737         while (TRUE)
738         {
739                 if (!chain->next)
740                 {
741                         chain->next = new_chain_str(str);
742                         return;
743                 }
744
745                 /* Go to next */
746                 chain = chain->next;
747         }
748 }
749
750
751 /*
752  * Do work for the copy editor-command
753  */
754 static void copy_text_to_yank(text_body_type *tb)
755 {
756         int len = strlen(tb->lines_list[tb->cy]);
757         if (tb->cx > len) tb->cx = len;
758
759         if (!tb->mark)
760         {
761                 tb->cx = 0;
762                 tb->my = tb->cy;
763                 tb->mx = len;
764         }
765
766         kill_yank_chain(tb);
767         if (tb->my != tb->cy)
768         {
769                 int by1 = MIN(tb->my, tb->cy);
770                 int by2 = MAX(tb->my, tb->cy);
771
772                 for (int y = by1; y <= by2; y++)
773                 {
774                         add_str_to_yank(tb, tb->lines_list[y]);
775                 }
776
777                 add_str_to_yank(tb, "");
778                 tb->mark = 0;
779                 tb->dirty_flags |= DIRTY_ALL;
780                 return;
781         }
782
783         char buf[MAX_LINELEN];
784         int bx1 = MIN(tb->mx, tb->cx);
785         int bx2 = MAX(tb->mx, tb->cx);
786         if (bx2 > len) bx2 = len;
787
788         if (bx1 == 0 && bx2 == len)
789         {
790                 add_str_to_yank(tb, tb->lines_list[tb->cy]);
791                 add_str_to_yank(tb, "");
792         }
793         else
794         {
795                 int end = bx2 - bx1;
796                 for (int i = 0; i < bx2 - bx1; i++)
797                 {
798                         buf[i] = tb->lines_list[tb->cy][bx1 + i];
799                 }
800
801                 buf[end] = '\0';
802                 add_str_to_yank(tb, buf);
803         }
804
805         tb->mark = 0;
806         tb->dirty_flags |= DIRTY_ALL;
807 }
808
809
810 /*
811  * Execute a single editor command
812  */
813 static bool do_editor_command(player_type *player_ptr, text_body_type *tb, int com_id)
814 {
815         switch (com_id)
816         {
817         case EC_QUIT:
818                 if (tb->changed)
819                 {
820                         if (!get_check(_("全ての変更を破棄してから終了します。よろしいですか? ",
821                                 "Discard all changes and quit. Are you sure? "))) break;
822                 }
823
824                 return QUIT_WITHOUT_SAVE;
825
826         case EC_SAVEQUIT:
827                 return QUIT_AND_SAVE;
828
829         case EC_REVERT:
830                 if (!get_check(_("全ての変更を破棄して元の状態に戻します。よろしいですか? ",
831                         "Discard all changes and revert to original file. Are you sure? "))) break;
832
833                 free_text_lines(tb->lines_list);
834                 tb->lines_list = read_pickpref_text_lines(player_ptr, &tb->filename_mode);
835                 tb->dirty_flags |= DIRTY_ALL | DIRTY_MODE | DIRTY_EXPRESSION;
836                 tb->cx = tb->cy = 0;
837                 tb->mark = 0;
838
839                 tb->changed = FALSE;
840                 break;
841
842         case EC_HELP:
843                 (void)show_file(player_ptr, TRUE, _("jeditor.txt", "editor.txt"), NULL, 0, 0);
844                 tb->dirty_flags |= DIRTY_SCREEN;
845
846                 break;
847
848         case EC_RETURN:
849                 if (tb->mark)
850                 {
851                         tb->mark = 0;
852                         tb->dirty_flags |= DIRTY_ALL;
853                 }
854
855                 insert_return_code(tb);
856                 tb->cy++;
857                 tb->cx = 0;
858
859                 tb->dirty_flags |= DIRTY_ALL;
860                 break;
861
862         case EC_LEFT:
863         {
864                 if (0 < tb->cx)
865                 {
866                         int len;
867 #ifdef JP
868                         int i;
869 #endif
870                         tb->cx--;
871                         len = strlen(tb->lines_list[tb->cy]);
872                         if (len < tb->cx) tb->cx = len;
873 #ifdef JP
874                         for (i = 0; tb->lines_list[tb->cy][i]; i++)
875                         {
876                                 if (iskanji(tb->lines_list[tb->cy][i]))
877                                 {
878                                         i++;
879                                         if (i == tb->cx)
880                                         {
881                                                 tb->cx--;
882                                                 break;
883                                         }
884                                 }
885                         }
886 #endif
887                 }
888                 else if (tb->cy > 0)
889                 {
890                         tb->cy--;
891                         tb->cx = strlen(tb->lines_list[tb->cy]);
892                 }
893
894                 break;
895         }
896         case EC_DOWN:
897                 if (!tb->lines_list[tb->cy + 1])
898                 {
899                         if (!add_empty_line(tb)) break;
900                 }
901
902                 tb->cy++;
903                 break;
904
905         case EC_UP:
906                 if (tb->cy > 0) tb->cy--;
907                 break;
908
909         case EC_RIGHT:
910         {
911 #ifdef JP
912                 if (iskanji(tb->lines_list[tb->cy][tb->cx])) tb->cx++;
913 #endif
914                 tb->cx++;
915                 int len = strlen(tb->lines_list[tb->cy]);
916                 if (len < tb->cx)
917                 {
918                         tb->cx = len;
919                         if (!tb->lines_list[tb->cy + 1])
920                         {
921                                 if (!add_empty_line(tb)) break;
922                         }
923
924                         tb->cy++;
925                         tb->cx = 0;
926                 }
927
928                 break;
929         }
930         case EC_BOL:
931                 tb->cx = 0;
932                 break;
933
934         case EC_EOL:
935                 tb->cx = strlen(tb->lines_list[tb->cy]);
936                 break;
937
938         case EC_PGUP:
939                 while (0 < tb->cy && tb->upper <= tb->cy)
940                         tb->cy--;
941                 while (0 < tb->upper && tb->cy + 1 < tb->upper + tb->hgt)
942                         tb->upper--;
943                 break;
944
945         case EC_PGDOWN:
946                 while (tb->cy < tb->upper + tb->hgt)
947                 {
948                         if (!tb->lines_list[tb->cy + 1])
949                         {
950                                 if (!add_empty_line(tb)) break;
951                         }
952
953                         tb->cy++;
954                 }
955
956                 tb->upper = tb->cy;
957                 break;
958
959         case EC_TOP:
960                 tb->cy = 0;
961                 break;
962
963         case EC_BOTTOM:
964                 while (TRUE)
965                 {
966                         if (!tb->lines_list[tb->cy + 1])
967                         {
968                                 if (!add_empty_line(tb)) break;
969                         }
970
971                         tb->cy++;
972                 }
973
974                 tb->cx = 0;
975                 break;
976
977         case EC_CUT:
978         {
979                 copy_text_to_yank(tb);
980                 if (tb->my == tb->cy)
981                 {
982                         int bx1 = MIN(tb->mx, tb->cx);
983                         int bx2 = MAX(tb->mx, tb->cx);
984                         int len = strlen(tb->lines_list[tb->cy]);
985                         if (bx2 > len) bx2 = len;
986
987                         kill_line_segment(tb, tb->cy, bx1, bx2, TRUE);
988                         tb->cx = bx1;
989                 }
990                 else
991                 {
992                         int by1 = MIN(tb->my, tb->cy);
993                         int by2 = MAX(tb->my, tb->cy);
994
995                         for (int y = by2; y >= by1; y--)
996                         {
997                                 int len = strlen(tb->lines_list[y]);
998
999                                 kill_line_segment(tb, y, 0, len, TRUE);
1000                         }
1001
1002                         tb->cy = by1;
1003                         tb->cx = 0;
1004                 }
1005
1006                 tb->mark = 0;
1007                 tb->dirty_flags |= DIRTY_ALL;
1008                 tb->changed = TRUE;
1009                 break;
1010         }
1011         case EC_COPY:
1012                 copy_text_to_yank(tb);
1013
1014                 /*
1015                  * Move cursor position to the end of the selection
1016                  *
1017                  * Pressing ^C ^V correctly duplicates the selection.
1018                  */
1019                 if (tb->my != tb->cy)
1020                 {
1021                         tb->cy = MAX(tb->cy, tb->my);
1022                         if (!tb->lines_list[tb->cy + 1])
1023                         {
1024                                 if (!add_empty_line(tb)) break;
1025                         }
1026
1027                         tb->cy++;
1028                         break;
1029                 }
1030
1031                 tb->cx = MAX(tb->cx, tb->mx);
1032                 if (!tb->lines_list[tb->cy][tb->cx])
1033                 {
1034                         if (!tb->lines_list[tb->cy + 1])
1035                         {
1036                                 if (!add_empty_line(tb)) break;
1037                         }
1038
1039                         tb->cy++;
1040                         tb->cx = 0;
1041                 }
1042
1043                 break;
1044
1045         case EC_PASTE:
1046         {
1047                 chain_str_type *chain = tb->yank;
1048                 int len = strlen(tb->lines_list[tb->cy]);
1049                 if (!chain) break;
1050                 if (tb->cx > len) tb->cx = len;
1051
1052                 if (tb->mark)
1053                 {
1054                         tb->mark = 0;
1055                         tb->dirty_flags |= DIRTY_ALL;
1056                 }
1057
1058                 while (chain)
1059                 {
1060                         concptr yank_str = chain->s;
1061                         char buf[MAX_LINELEN];
1062                         int i;
1063                         char rest[MAX_LINELEN], *rest_ptr = rest;
1064                         for (i = 0; i < tb->cx; i++)
1065                                 buf[i] = tb->lines_list[tb->cy][i];
1066
1067                         strcpy(rest, &(tb->lines_list[tb->cy][i]));
1068                         while (*yank_str && i < MAX_LINELEN - 1)
1069                         {
1070                                 buf[i++] = *yank_str++;
1071                         }
1072
1073                         buf[i] = '\0';
1074                         chain = chain->next;
1075                         if (chain || tb->yank_eol)
1076                         {
1077                                 insert_return_code(tb);
1078                                 string_free(tb->lines_list[tb->cy]);
1079                                 tb->lines_list[tb->cy] = string_make(buf);
1080                                 tb->cx = 0;
1081                                 tb->cy++;
1082
1083                                 continue;
1084                         }
1085
1086                         tb->cx = strlen(buf);
1087                         while (*rest_ptr && i < MAX_LINELEN - 1)
1088                         {
1089                                 buf[i++] = *rest_ptr++;
1090                         }
1091
1092                         buf[i] = '\0';
1093                         string_free(tb->lines_list[tb->cy]);
1094                         tb->lines_list[tb->cy] = string_make(buf);
1095                         break;
1096                 }
1097
1098                 tb->dirty_flags |= DIRTY_ALL;
1099                 tb->dirty_flags |= DIRTY_EXPRESSION;
1100                 tb->changed = TRUE;
1101                 break;
1102         }
1103         case EC_BLOCK:
1104         {
1105                 if (tb->mark)
1106                 {
1107                         tb->mark = 0;
1108                         tb->dirty_flags |= DIRTY_ALL;
1109                         break;
1110                 }
1111
1112                 tb->mark = MARK_MARK;
1113                 if (com_id == tb->old_com_id)
1114                 {
1115                         int tmp = tb->cy;
1116                         tb->cy = tb->my;
1117                         tb->my = tmp;
1118                         tmp = tb->cx;
1119                         tb->cx = tb->mx;
1120                         tb->mx = tmp;
1121                         tb->dirty_flags |= DIRTY_ALL;
1122                         break;
1123                 }
1124
1125                 int len = strlen(tb->lines_list[tb->cy]);
1126
1127                 tb->my = tb->cy;
1128                 tb->mx = tb->cx;
1129                 if (tb->cx > len) tb->mx = len;
1130                 break;
1131         }
1132         case EC_KILL_LINE:
1133         {
1134                 int len = strlen(tb->lines_list[tb->cy]);
1135                 if (tb->cx > len) tb->cx = len;
1136
1137                 if (tb->mark)
1138                 {
1139                         tb->mark = 0;
1140                         tb->dirty_flags |= DIRTY_ALL;
1141                 }
1142
1143                 if (tb->old_com_id != com_id)
1144                 {
1145                         kill_yank_chain(tb);
1146                         tb->yank = NULL;
1147                 }
1148
1149                 if (tb->cx < len)
1150                 {
1151                         add_str_to_yank(tb, &(tb->lines_list[tb->cy][tb->cx]));
1152                         kill_line_segment(tb, tb->cy, tb->cx, len, FALSE);
1153                         tb->dirty_line = tb->cy;
1154                         break;
1155                 }
1156
1157                 if (tb->yank_eol) add_str_to_yank(tb, "");
1158
1159                 tb->yank_eol = TRUE;
1160                 do_editor_command(player_ptr, tb, EC_DELETE_CHAR);
1161                 break;
1162         }
1163         case EC_DELETE_CHAR:
1164         {
1165                 if (tb->mark)
1166                 {
1167                         tb->mark = 0;
1168                         tb->dirty_flags |= DIRTY_ALL;
1169                 }
1170
1171 #ifdef JP
1172                 if (iskanji(tb->lines_list[tb->cy][tb->cx])) tb->cx++;
1173 #endif
1174                 tb->cx++;
1175                 int len = strlen(tb->lines_list[tb->cy]);
1176                 if (len >= tb->cx)
1177                 {
1178                         do_editor_command(player_ptr, tb, EC_BACKSPACE);
1179                         break;
1180                 }
1181
1182                 if (tb->lines_list[tb->cy + 1])
1183                 {
1184                         tb->cy++;
1185                         tb->cx = 0;
1186                 }
1187                 else
1188                 {
1189                         tb->cx = len;
1190                         break;
1191                 }
1192
1193                 do_editor_command(player_ptr, tb, EC_BACKSPACE);
1194                 break;
1195         }
1196         case EC_BACKSPACE:
1197         {
1198                 int len, i, j, k;
1199                 char buf[MAX_LINELEN];
1200                 if (tb->mark)
1201                 {
1202                         tb->mark = 0;
1203                         tb->dirty_flags |= DIRTY_ALL;
1204                 }
1205
1206                 len = strlen(tb->lines_list[tb->cy]);
1207                 if (len < tb->cx) tb->cx = len;
1208
1209                 if (tb->cx == 0)
1210                 {
1211                         if (tb->cy == 0) break;
1212                         tb->cx = strlen(tb->lines_list[tb->cy - 1]);
1213                         strcpy(buf, tb->lines_list[tb->cy - 1]);
1214                         strcat(buf, tb->lines_list[tb->cy]);
1215                         string_free(tb->lines_list[tb->cy - 1]);
1216                         string_free(tb->lines_list[tb->cy]);
1217                         tb->lines_list[tb->cy - 1] = string_make(buf);
1218
1219                         for (i = tb->cy; tb->lines_list[i + 1]; i++)
1220                                 tb->lines_list[i] = tb->lines_list[i + 1];
1221
1222                         tb->lines_list[i] = NULL;
1223                         tb->cy--;
1224                         tb->dirty_flags |= DIRTY_ALL;
1225                         tb->dirty_flags |= DIRTY_EXPRESSION;
1226                         tb->changed = TRUE;
1227                         break;
1228                 }
1229
1230                 for (i = j = k = 0; tb->lines_list[tb->cy][i] && i < tb->cx; i++)
1231                 {
1232                         k = j;
1233 #ifdef JP
1234                         if (iskanji(tb->lines_list[tb->cy][i]))
1235                                 buf[j++] = tb->lines_list[tb->cy][i++];
1236 #endif
1237                         buf[j++] = tb->lines_list[tb->cy][i];
1238                 }
1239
1240                 while (j > k)
1241                 {
1242                         tb->cx--;
1243                         j--;
1244                 }
1245
1246                 for (; tb->lines_list[tb->cy][i]; i++)
1247                 {
1248                         buf[j++] = tb->lines_list[tb->cy][i];
1249                 }
1250
1251                 buf[j] = '\0';
1252                 string_free(tb->lines_list[tb->cy]);
1253                 tb->lines_list[tb->cy] = string_make(buf);
1254                 tb->dirty_line = tb->cy;
1255                 check_expression_line(tb, tb->cy);
1256                 tb->changed = TRUE;
1257                 break;
1258         }
1259         case EC_SEARCH_STR:
1260         {
1261                 byte search_dir;
1262                 tb->dirty_flags |= DIRTY_SCREEN;
1263                 search_dir = get_string_for_search(player_ptr, &tb->search_o_ptr, &tb->search_str);
1264
1265                 if (!search_dir) break;
1266
1267                 if (search_dir == 1) do_editor_command(player_ptr, tb, EC_SEARCH_FORW);
1268                 else do_editor_command(player_ptr, tb, EC_SEARCH_BACK);
1269                 break;
1270         }
1271         case EC_SEARCH_FORW:
1272                 if (tb->search_o_ptr)
1273                 {
1274                         search_for_object(player_ptr, tb, tb->search_o_ptr, TRUE);
1275                         break;
1276                 }
1277
1278                 if (tb->search_str && tb->search_str[0])
1279                 {
1280                         search_for_string(tb, tb->search_str, TRUE);
1281                         break;
1282                 }
1283
1284                 tb->dirty_flags |= DIRTY_NO_SEARCH;
1285                 break;
1286
1287         case EC_SEARCH_BACK:
1288                 if (tb->search_o_ptr)
1289                 {
1290                         search_for_object(player_ptr, tb, tb->search_o_ptr, FALSE);
1291                         break;
1292                 }
1293
1294                 if (tb->search_str && tb->search_str[0])
1295                 {
1296                         search_for_string(tb, tb->search_str, FALSE);
1297                         break;
1298                 }
1299
1300                 tb->dirty_flags |= DIRTY_NO_SEARCH;
1301                 break;
1302
1303         case EC_SEARCH_OBJ:
1304                 tb->dirty_flags |= DIRTY_SCREEN;
1305
1306                 if (!get_object_for_search(player_ptr, &tb->search_o_ptr, &tb->search_str)) break;
1307
1308                 do_editor_command(player_ptr, tb, EC_SEARCH_FORW);
1309                 break;
1310
1311         case EC_SEARCH_DESTROYED:
1312                 if (!get_destroyed_object_for_search(player_ptr, &tb->search_o_ptr, &tb->search_str))
1313                 {
1314                         tb->dirty_flags |= DIRTY_NO_SEARCH;
1315                         break;
1316                 }
1317
1318                 do_editor_command(player_ptr, tb, EC_SEARCH_FORW);
1319                 break;
1320
1321         case EC_INSERT_OBJECT:
1322         {
1323                 autopick_type an_entry, *entry = &an_entry;
1324                 if (!entry_from_choosed_object(player_ptr, entry))
1325                 {
1326                         tb->dirty_flags |= DIRTY_SCREEN;
1327                         break;
1328                 }
1329
1330                 tb->cx = 0;
1331                 insert_return_code(tb);
1332                 string_free(tb->lines_list[tb->cy]);
1333                 tb->lines_list[tb->cy] = autopick_line_from_entry_kill(entry);
1334                 tb->dirty_flags |= DIRTY_SCREEN;
1335                 break;
1336         }
1337         case EC_INSERT_DESTROYED:
1338                 if (!tb->last_destroyed) break;
1339
1340                 tb->cx = 0;
1341                 insert_return_code(tb);
1342                 string_free(tb->lines_list[tb->cy]);
1343                 tb->lines_list[tb->cy] = string_make(tb->last_destroyed);
1344                 tb->dirty_flags |= DIRTY_ALL;
1345                 tb->changed = TRUE;
1346                 break;
1347
1348         case EC_INSERT_BLOCK:
1349         {
1350                 char expression[80];
1351                 sprintf(expression, "?:[AND [EQU $RACE %s] [EQU $CLASS %s] [GEQ $LEVEL %02d]]",
1352 #ifdef JP
1353                         rp_ptr->E_title, cp_ptr->E_title,
1354 #else
1355                         rp_ptr->title, cp_ptr->title,
1356 #endif
1357                         player_ptr->lev);
1358                 tb->cx = 0;
1359                 insert_return_code(tb);
1360                 string_free(tb->lines_list[tb->cy]);
1361                 tb->lines_list[tb->cy] = string_make(expression);
1362                 tb->cy++;
1363                 insert_return_code(tb);
1364                 string_free(tb->lines_list[tb->cy]);
1365                 tb->lines_list[tb->cy] = string_make("?:1");
1366                 tb->dirty_flags |= DIRTY_ALL;
1367                 tb->changed = TRUE;
1368                 break;
1369         }
1370
1371         case EC_INSERT_MACRO:
1372                 draw_text_editor(player_ptr, tb);
1373                 Term_erase(0, tb->cy - tb->upper + 1, tb->wid);
1374                 Term_putstr(0, tb->cy - tb->upper + 1, tb->wid - 1, TERM_YELLOW, _("P:<トリガーキー>: ", "P:<Trigger key>: "));
1375                 if (!insert_macro_line(tb)) break;
1376
1377                 tb->cx = 2;
1378                 tb->dirty_flags |= DIRTY_ALL;
1379                 tb->changed = TRUE;
1380                 break;
1381
1382         case EC_INSERT_KEYMAP:
1383                 draw_text_editor(player_ptr, tb);
1384                 Term_erase(0, tb->cy - tb->upper + 1, tb->wid);
1385                 Term_putstr(0, tb->cy - tb->upper + 1, tb->wid - 1, TERM_YELLOW,
1386                         format(_("C:%d:<コマンドキー>: ", "C:%d:<Keypress>: "), (rogue_like_commands ? KEYMAP_MODE_ROGUE : KEYMAP_MODE_ORIG)));
1387
1388                 if (!insert_keymap_line(tb)) break;
1389
1390                 tb->cx = 2;
1391                 tb->dirty_flags |= DIRTY_ALL;
1392                 tb->changed = TRUE;
1393                 break;
1394
1395         case EC_CL_AUTOPICK: toggle_command_letter(tb, DO_AUTOPICK); break;
1396         case EC_CL_DESTROY: toggle_command_letter(tb, DO_AUTODESTROY); break;
1397         case EC_CL_LEAVE: toggle_command_letter(tb, DONT_AUTOPICK); break;
1398         case EC_CL_QUERY: toggle_command_letter(tb, DO_QUERY_AUTOPICK); break;
1399         case EC_CL_NO_DISP: toggle_command_letter(tb, DO_DISPLAY); break;
1400
1401         case EC_IK_UNAWARE: toggle_keyword(tb, FLG_UNAWARE); break;
1402         case EC_IK_UNIDENTIFIED: toggle_keyword(tb, FLG_UNIDENTIFIED); break;
1403         case EC_IK_IDENTIFIED: toggle_keyword(tb, FLG_IDENTIFIED); break;
1404         case EC_IK_STAR_IDENTIFIED: toggle_keyword(tb, FLG_STAR_IDENTIFIED); break;
1405         case EC_KK_WEAPONS: toggle_keyword(tb, FLG_WEAPONS); break;
1406         case EC_KK_FAVORITE_WEAPONS: toggle_keyword(tb, FLG_FAVORITE_WEAPONS); break;
1407         case EC_KK_ARMORS: toggle_keyword(tb, FLG_ARMORS); break;
1408         case EC_KK_MISSILES: toggle_keyword(tb, FLG_MISSILES); break;
1409         case EC_KK_DEVICES: toggle_keyword(tb, FLG_DEVICES); break;
1410         case EC_KK_LIGHTS: toggle_keyword(tb, FLG_LIGHTS); break;
1411         case EC_KK_JUNKS: toggle_keyword(tb, FLG_JUNKS); break;
1412         case EC_KK_CORPSES: toggle_keyword(tb, FLG_CORPSES); break;
1413         case EC_KK_SPELLBOOKS: toggle_keyword(tb, FLG_SPELLBOOKS); break;
1414         case EC_KK_SHIELDS: toggle_keyword(tb, FLG_SHIELDS); break;
1415         case EC_KK_BOWS: toggle_keyword(tb, FLG_BOWS); break;
1416         case EC_KK_RINGS: toggle_keyword(tb, FLG_RINGS); break;
1417         case EC_KK_AMULETS: toggle_keyword(tb, FLG_AMULETS); break;
1418         case EC_KK_SUITS: toggle_keyword(tb, FLG_SUITS); break;
1419         case EC_KK_CLOAKS: toggle_keyword(tb, FLG_CLOAKS); break;
1420         case EC_KK_HELMS: toggle_keyword(tb, FLG_HELMS); break;
1421         case EC_KK_GLOVES: toggle_keyword(tb, FLG_GLOVES); break;
1422         case EC_KK_BOOTS: toggle_keyword(tb, FLG_BOOTS); break;
1423         case EC_OK_COLLECTING: toggle_keyword(tb, FLG_COLLECTING); break;
1424         case EC_OK_BOOSTED: toggle_keyword(tb, FLG_BOOSTED); break;
1425         case EC_OK_MORE_DICE: toggle_keyword(tb, FLG_MORE_DICE); break;
1426         case EC_OK_MORE_BONUS: toggle_keyword(tb, FLG_MORE_BONUS); break;
1427         case EC_OK_WORTHLESS: toggle_keyword(tb, FLG_WORTHLESS); break;
1428         case EC_OK_ARTIFACT: toggle_keyword(tb, FLG_ARTIFACT); break;
1429         case EC_OK_EGO: toggle_keyword(tb, FLG_EGO); break;
1430         case EC_OK_GOOD: toggle_keyword(tb, FLG_GOOD); break;
1431         case EC_OK_NAMELESS: toggle_keyword(tb, FLG_NAMELESS); break;
1432         case EC_OK_AVERAGE: toggle_keyword(tb, FLG_AVERAGE); break;
1433         case EC_OK_RARE: toggle_keyword(tb, FLG_RARE); break;
1434         case EC_OK_COMMON: toggle_keyword(tb, FLG_COMMON); break;
1435         case EC_OK_WANTED: toggle_keyword(tb, FLG_WANTED); break;
1436         case EC_OK_UNIQUE: toggle_keyword(tb, FLG_UNIQUE); break;
1437         case EC_OK_HUMAN: toggle_keyword(tb, FLG_HUMAN); break;
1438         case EC_OK_UNREADABLE:
1439                 toggle_keyword(tb, FLG_UNREADABLE);
1440                 add_keyword(tb, FLG_SPELLBOOKS);
1441                 break;
1442         case EC_OK_REALM1:
1443                 toggle_keyword(tb, FLG_REALM1);
1444                 add_keyword(tb, FLG_SPELLBOOKS);
1445                 break;
1446         case EC_OK_REALM2:
1447                 toggle_keyword(tb, FLG_REALM2);
1448                 add_keyword(tb, FLG_SPELLBOOKS);
1449                 break;
1450         case EC_OK_FIRST:
1451                 toggle_keyword(tb, FLG_FIRST);
1452                 add_keyword(tb, FLG_SPELLBOOKS);
1453                 break;
1454         case EC_OK_SECOND:
1455                 toggle_keyword(tb, FLG_SECOND);
1456                 add_keyword(tb, FLG_SPELLBOOKS);
1457                 break;
1458         case EC_OK_THIRD:
1459                 toggle_keyword(tb, FLG_THIRD);
1460                 add_keyword(tb, FLG_SPELLBOOKS);
1461                 break;
1462         case EC_OK_FOURTH:
1463                 toggle_keyword(tb, FLG_FOURTH);
1464                 add_keyword(tb, FLG_SPELLBOOKS);
1465                 break;
1466         }
1467
1468         tb->old_com_id = com_id;
1469         return FALSE;
1470 }
1471
1472
1473 /*
1474  * Check special key code and get a movement command id
1475  */
1476 static int analyze_move_key(text_body_type *tb, int skey)
1477 {
1478         int com_id;
1479         if (!(skey & SKEY_MASK)) return 0;
1480
1481         switch (skey & ~SKEY_MOD_MASK)
1482         {
1483         case SKEY_DOWN:   com_id = EC_DOWN;   break;
1484         case SKEY_LEFT:   com_id = EC_LEFT;   break;
1485         case SKEY_RIGHT:  com_id = EC_RIGHT;  break;
1486         case SKEY_UP:     com_id = EC_UP;     break;
1487         case SKEY_PGUP:   com_id = EC_PGUP;   break;
1488         case SKEY_PGDOWN: com_id = EC_PGDOWN; break;
1489         case SKEY_TOP:    com_id = EC_TOP;    break;
1490         case SKEY_BOTTOM: com_id = EC_BOTTOM; break;
1491         default:
1492                 return 0;
1493         }
1494
1495         if (!(skey & SKEY_MOD_SHIFT))
1496         {
1497                 /*
1498                  * Un-shifted cursor keys cancells
1499                  * selection created by shift+cursor.
1500                  */
1501                 if (tb->mark & MARK_BY_SHIFT)
1502                 {
1503                         tb->mark = 0;
1504                         tb->dirty_flags |= DIRTY_ALL;
1505                 }
1506
1507                 return com_id;
1508         }
1509
1510         if (tb->mark) return com_id;
1511
1512         int len = strlen(tb->lines_list[tb->cy]);
1513         tb->mark = MARK_MARK | MARK_BY_SHIFT;
1514         tb->my = tb->cy;
1515         tb->mx = tb->cx;
1516         if (tb->cx > len) tb->mx = len;
1517
1518         if (com_id == EC_UP || com_id == EC_DOWN)
1519         {
1520                 tb->dirty_flags |= DIRTY_ALL;
1521         }
1522         else
1523         {
1524                 tb->dirty_line = tb->cy;
1525         }
1526
1527         return com_id;
1528 }
1529
1530 /*
1531  * In-game editor of Object Auto-picker/Destoryer
1532  * @param player_ptr プレーヤーへの参照ポインタ
1533  */
1534 void do_cmd_edit_autopick(player_type *player_ptr)
1535 {
1536         static int cx_save = 0;
1537         static int cy_save = 0;
1538         autopick_type an_entry, *entry = &an_entry;
1539         char buf[MAX_LINELEN];
1540         int i;
1541         int key = -1;
1542         static s32b old_autosave_turn = 0L;
1543         byte quit = 0;
1544
1545         text_body_type text_body;
1546         text_body_type *tb = &text_body;
1547         tb->changed = FALSE;
1548         tb->cx = cx_save;
1549         tb->cy = cy_save;
1550         tb->upper = tb->left = 0;
1551         tb->mark = 0;
1552         tb->mx = tb->my = 0;
1553         tb->old_cy = tb->old_upper = tb->old_left = -1;
1554         tb->old_wid = tb->old_hgt = -1;
1555         tb->old_com_id = 0;
1556
1557         tb->yank = NULL;
1558         tb->search_o_ptr = NULL;
1559         tb->search_str = NULL;
1560         tb->last_destroyed = NULL;
1561         tb->dirty_flags = DIRTY_ALL | DIRTY_MODE | DIRTY_EXPRESSION;
1562         tb->dirty_line = -1;
1563         tb->filename_mode = PT_DEFAULT;
1564
1565         if (current_world_ptr->game_turn < old_autosave_turn)
1566         {
1567                 while (old_autosave_turn > current_world_ptr->game_turn) old_autosave_turn -= TURNS_PER_TICK * TOWN_DAWN;
1568         }
1569
1570         if (current_world_ptr->game_turn > old_autosave_turn + 100L)
1571         {
1572                 do_cmd_save_game(player_ptr, TRUE);
1573                 old_autosave_turn = current_world_ptr->game_turn;
1574         }
1575
1576         update_playtime();
1577         init_autopick();
1578         if (autopick_last_destroyed_object.k_idx)
1579         {
1580                 autopick_entry_from_object(player_ptr, entry, &autopick_last_destroyed_object);
1581                 tb->last_destroyed = autopick_line_from_entry_kill(entry);
1582         }
1583
1584         tb->lines_list = read_pickpref_text_lines(player_ptr, &tb->filename_mode);
1585         for (i = 0; i < tb->cy; i++)
1586         {
1587                 if (!tb->lines_list[i])
1588                 {
1589                         tb->cy = tb->cx = 0;
1590                         break;
1591                 }
1592         }
1593
1594         screen_save();
1595         while (!quit)
1596         {
1597                 int com_id = 0;
1598                 draw_text_editor(player_ptr, tb);
1599                 prt(_("(^Q:終了 ^W:セーブして終了, ESC:メニュー, その他:入力)",
1600                         "(^Q:Quit, ^W:Save&Quit, ESC:Menu, Other:Input text)"), 0, 0);
1601                 if (!tb->mark)
1602                 {
1603                         prt(format("(%d,%d)", tb->cx, tb->cy), 0, 60);
1604                 }
1605                 else
1606                 {
1607                         prt(format("(%d,%d)-(%d,%d)", tb->mx, tb->my, tb->cx, tb->cy), 0, 60);
1608                 }
1609
1610                 Term_gotoxy(tb->cx - tb->left, tb->cy - tb->upper + 1);
1611                 tb->dirty_flags = 0;
1612                 tb->dirty_line = -1;
1613                 tb->old_cy = tb->cy;
1614                 tb->old_upper = tb->upper;
1615                 tb->old_left = tb->left;
1616                 tb->old_wid = tb->wid;
1617                 tb->old_hgt = tb->hgt;
1618
1619                 key = inkey_special(TRUE);
1620
1621                 if (key & SKEY_MASK)
1622                 {
1623                         com_id = analyze_move_key(tb, key);
1624                 }
1625                 else if (key == ESCAPE)
1626                 {
1627                         com_id = do_command_menu(0, 0);
1628                         tb->dirty_flags |= DIRTY_SCREEN;
1629                 }
1630                 else if (!iscntrl((unsigned char)key))
1631                 {
1632                         if (tb->mark)
1633                         {
1634                                 tb->mark = 0;
1635                                 tb->dirty_flags |= DIRTY_ALL;
1636                         }
1637
1638                         insert_single_letter(tb, key);
1639                         continue;
1640                 }
1641                 else
1642                 {
1643                         com_id = get_com_id((char)key);
1644                 }
1645
1646                 if (com_id) quit = do_editor_command(player_ptr, tb, com_id);
1647         }
1648
1649         screen_load();
1650         strcpy(buf, pickpref_filename(player_ptr, tb->filename_mode));
1651
1652         if (quit == QUIT_AND_SAVE)
1653                 write_text_lines(buf, tb->lines_list);
1654
1655         free_text_lines(tb->lines_list);
1656         string_free(tb->search_str);
1657         string_free(tb->last_destroyed);
1658         kill_yank_chain(tb);
1659
1660         process_autopick_file(player_ptr, buf);
1661         current_world_ptr->start_time = (u32b)time(NULL);
1662         cx_save = tb->cx;
1663         cy_save = tb->cy;
1664 }