OSDN Git Service

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