OSDN Git Service

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