3 * @brief 自動拾い機能の実装 / Object Auto-picker/Destroyer
6 * Copyright (c) 2002 Mogami\n
8 * This software may be copied and distributed for educational, research, and\n
9 * not for profit purposes provided that this copyright and statement are\n
10 * included in all such copies.\n
11 * 2014 Deskull rearranged comment for Doxygen.\n
16 #include "autopick/autopick-commands-table.h"
17 #include "autopick/autopick-dirty-flags.h"
18 #include "autopick/autopick-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"
32 #include "autopick/autopick.h"
33 #include "core/show-file.h"
34 #include "cmd/cmd-save.h"
35 #include "io/read-pref-file.h"
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"
49 #include "view/display-main-window.h" // 暫定。後で消す.
54 static void auto_inscribe_item(player_type *player_ptr, object_type *o_ptr, int idx)
56 if (idx < 0 || !autopick_list[idx].insc) return;
58 if (!o_ptr->inscription)
59 o_ptr->inscription = quark_add(autopick_list[idx].insc);
61 player_ptr->window |= (PW_EQUIP | PW_INVEN);
62 player_ptr->update |= (PU_BONUS);
67 * Auto-destroy marked item
69 static void autopick_delayed_alter_aux(player_type *player_ptr, INVENTORY_IDX item)
72 o_ptr = REF_ITEM(player_ptr, player_ptr->current_floor_ptr, item);
74 if (o_ptr->k_idx == 0 || !(o_ptr->marked & OM_AUTODESTROY)) return;
76 GAME_TEXT o_name[MAX_NLEN];
77 object_desc(player_ptr, o_name, o_ptr, 0);
80 inven_item_increase(player_ptr, item, -(o_ptr->number));
81 inven_item_optimize(player_ptr, item);
85 delete_object_idx(player_ptr, 0 - item);
88 msg_format(_("%sを自動破壊します。", "Auto-destroying %s."), o_name);
93 * Auto-destroy marked items in inventry and on floor
95 void autopick_delayed_alter(player_type *owner_ptr)
100 * Scan inventry in reverse order to prevent
101 * skipping after inven_item_optimize()
103 for (item = INVEN_TOTAL - 1; item >= 0; item--)
104 autopick_delayed_alter_aux(owner_ptr, item);
106 floor_type *floor_ptr = owner_ptr->current_floor_ptr;
107 item = floor_ptr->grid_array[owner_ptr->y][owner_ptr->x].o_idx;
110 OBJECT_IDX next = floor_ptr->o_list[item].next_o_idx;
111 autopick_delayed_alter_aux(owner_ptr, -item);
118 * Auto-inscription and/or destroy
120 * Auto-destroyer works only on inventory or on floor stack only when
123 void autopick_alter_item(player_type *player_ptr, INVENTORY_IDX item, bool destroy)
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);
135 * Automatically pickup/destroy items in this grid.
137 void autopick_pickup_items(player_type* player_ptr, grid_type *g_ptr)
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)
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;
150 auto_destroy_item(player_ptr, o_ptr, idx);
154 disturb(player_ptr, FALSE, FALSE);
155 if (!inven_carry_okay(o_ptr))
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;
164 if (!(autopick_list[idx].action & DO_QUERY_AUTOPICK))
166 py_pickup_aux(player_ptr, this_o_idx);
170 char out_val[MAX_NLEN + 20];
171 GAME_TEXT o_name[MAX_NLEN];
172 if (o_ptr->marked & OM_NO_QUERY)
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))
181 o_ptr->marked |= OM_NOMSG | OM_NO_QUERY;
185 py_pickup_aux(player_ptr, this_o_idx);
190 static const char autoregister_header[] = "?:$AUTOREGISTER";
193 * Clear auto registered lines in the picktype.prf .
195 static bool clear_auto_register(player_type *player_ptr)
197 char pref_file[1024];
198 path_build(pref_file, sizeof(pref_file), ANGBAND_DIR_USER, pickpref_filename(player_ptr, PT_WITH_PNAME));
200 pref_fff = my_fopen(pref_file, "r");
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");
215 tmp_fff = my_fopen_temp(tmp_file, sizeof(tmp_file));
219 msg_format(_("一時ファイル %s を作成できませんでした。", "Failed to create temporary file %s."), tmp_file);
224 bool autoregister = FALSE;
229 if (my_fgets(pref_fff, buf, sizeof(buf))) break;
233 if (buf[0] != '#' && buf[0] != '?') num++;
237 if (streq(buf, autoregister_header))
243 fprintf(tmp_fff, "%s\n", buf);
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? "));
260 autoregister = FALSE;
262 msg_print(_("エディタのカット&ペースト等を使って必要な行を避難してください。",
263 "Use cut & paste of auto picker editor (_) to keep old prefs."));
269 tmp_fff = my_fopen(tmp_file, "r");
270 pref_fff = my_fopen(pref_file, "w");
272 while (!my_fgets(tmp_fff, buf, sizeof(buf)))
273 fprintf(pref_fff, "%s\n", buf);
285 * Automatically register an auto-destroy preference line
287 bool autopick_autoregister(player_type *player_ptr, object_type *o_ptr)
290 char pref_file[1024];
292 autopick_type an_entry, *entry = &an_entry;
293 int match_autopick = find_autopick_list(player_ptr, o_ptr);
294 if (match_autopick != -1)
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");
303 msg_format(_("そのアイテムは既に%sように設定されています。", "The object is already registered to %s."), what);
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)))
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);
317 if (!player_ptr->autopick_autoregister)
319 if (!clear_auto_register(player_ptr)) return FALSE;
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");
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");
335 if (my_fgets(pref_fff, buf, sizeof(buf)))
337 player_ptr->autopick_autoregister = FALSE;
341 if (streq(buf, autoregister_header))
343 player_ptr->autopick_autoregister = TRUE;
353 * File could not be opened for reading. Assume header not
356 player_ptr->autopick_autoregister = FALSE;
359 pref_fff = my_fopen(pref_file, "a");
362 msg_format(_("%s を開くことができませんでした。", "Failed to open %s."), pref_file);
367 if (!player_ptr->autopick_autoregister)
369 fprintf(pref_fff, "%s\n", autoregister_header);
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;
378 autopick_entry_from_object(player_ptr, entry, o_ptr);
379 entry->action = DO_AUTODESTROY;
380 add_autopick_list(entry);
382 concptr tmp = autopick_line_from_entry(entry);
383 fprintf(pref_fff, "%s\n", tmp);
391 * Delete or insert string
393 static void toggle_keyword(text_body_type *tb, BIT_FLAGS flg)
400 by1 = MIN(tb->my, tb->cy);
401 by2 = MAX(tb->my, tb->cy);
403 else /* if (!tb->mark) */
408 for (int y = by1; y <= by2; y++)
410 autopick_type an_entry, *entry = &an_entry;
411 if (!autopick_new_entry(entry, tb->lines_list[y], !fixed)) continue;
413 string_free(tb->lines_list[y]);
416 if (!IS_FLG(flg)) add = TRUE;
422 if (FLG_NOUN_BEGIN <= flg && flg <= FLG_NOUN_END)
425 for (i = FLG_NOUN_BEGIN; i <= FLG_NOUN_END; i++)
428 else if (FLG_UNAWARE <= flg && flg <= FLG_STAR_IDENTIFIED)
431 for (i = FLG_UNAWARE; i <= FLG_STAR_IDENTIFIED; i++)
434 else if (FLG_ARTIFACT <= flg && flg <= FLG_AVERAGE)
437 for (i = FLG_ARTIFACT; i <= FLG_AVERAGE; i++)
440 else if (FLG_RARE <= flg && flg <= FLG_COMMON)
443 for (i = FLG_RARE; i <= FLG_COMMON; i++)
447 if (add) ADD_FLG(flg);
450 tb->lines_list[y] = autopick_line_from_entry_kill(entry);
451 tb->dirty_flags |= DIRTY_ALL;
458 * Change command letter
460 static void toggle_command_letter(text_body_type *tb, byte flg)
462 autopick_type an_entry;
463 autopick_type *entry = &an_entry;
469 by1 = MIN(tb->my, tb->cy);
470 by2 = MAX(tb->my, tb->cy);
472 else /* if (!tb->mark) */
477 for (int y = by1; y <= by2; y++)
481 if (!autopick_new_entry(entry, tb->lines_list[y], FALSE)) continue;
483 string_free(tb->lines_list[y]);
487 if (!(entry->action & flg)) add = TRUE;
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--;
498 if (flg != DO_DISPLAY)
500 entry->action &= ~(DO_AUTOPICK | DONT_AUTOPICK | DO_AUTODESTROY | DO_QUERY_AUTOPICK);
501 if (add) entry->action |= flg;
502 else entry->action |= DO_AUTOPICK;
506 entry->action &= ~(DO_DISPLAY);
507 if (add) entry->action |= flg;
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++;
517 if (wid > 0) tb->cx++;
518 if (wid < 0 && tb->cx > 0) tb->cx--;
521 tb->lines_list[y] = autopick_line_from_entry_kill(entry);
522 tb->dirty_flags |= DIRTY_ALL;
529 * Delete or insert string
531 static void add_keyword(text_body_type *tb, BIT_FLAGS flg)
536 by1 = MIN(tb->my, tb->cy);
537 by2 = MAX(tb->my, tb->cy);
544 for (int y = by1; y <= by2; y++)
546 autopick_type an_entry, *entry = &an_entry;
547 if (!autopick_new_entry(entry, tb->lines_list[y], FALSE)) continue;
551 autopick_free_entry(entry);
555 string_free(tb->lines_list[y]);
556 if (FLG_NOUN_BEGIN <= flg && flg <= FLG_NOUN_END)
559 for (i = FLG_NOUN_BEGIN; i <= FLG_NOUN_END; i++)
564 tb->lines_list[y] = autopick_line_from_entry_kill(entry);
565 tb->dirty_flags |= DIRTY_ALL;
572 * Add an empty line at the last of the file
574 static bool add_empty_line(text_body_type *tb)
577 for (num_lines = 0; tb->lines_list[num_lines]; num_lines++);
579 if (num_lines >= MAX_LINES - 2) return FALSE;
580 if (!tb->lines_list[num_lines - 1][0]) return FALSE;
582 tb->lines_list[num_lines] = string_make("");
583 tb->dirty_flags |= DIRTY_EXPRESSION;
590 * Display the menu, and get a command
592 static int do_command_menu(int level, int start)
595 int col0 = 5 + level * 7;
596 int row0 = 1 + level * 3;
597 int menu_id_list[26];
599 char linestr[MAX_LINELEN];
602 for (int i = start; menu_data[i].level >= level; i++)
604 /* Ignore lower level sub menus */
605 if (menu_data[i].level > level) continue;
607 int len = strlen(menu_data[i].name);
608 if (len > max_len) max_len = len;
610 menu_id_list[menu_key] = i;
614 while (menu_key < 26)
616 menu_id_list[menu_key] = -1;
620 int max_menu_wid = max_len + 3 + 3;
622 /* Prepare box line */
624 strcat(linestr, "+");
625 for (int i = 0; i < max_menu_wid + 2; i++)
627 strcat(linestr, "-");
630 strcat(linestr, "+");
637 Term_putstr(col0, row0, -1, TERM_WHITE, linestr);
640 for (int i = start; menu_data[i].level >= level; i++)
644 if (menu_data[i].level > level) continue;
646 if (menu_data[i].com_id == -1)
648 strcpy(com_key_str, _("▼", ">"));
650 else if (menu_data[i].key != -1)
652 com_key_str[0] = '^';
653 com_key_str[1] = menu_data[i].key + '@';
654 com_key_str[2] = '\0';
658 com_key_str[0] = '\0';
661 str = format("| %c) %-*s %2s | ", menu_key + 'a', max_len, menu_data[i].name, com_key_str);
663 Term_putstr(col0, row1++, -1, TERM_WHITE, str);
668 Term_putstr(col0, row1, -1, TERM_WHITE, linestr);
672 prt(format(_("(a-%c) コマンド:", "(a-%c) Command:"), menu_key + 'a' - 1), 0, 0);
675 if (key == ESCAPE) return 0;
678 bool is_alphabet = key >= 'a' && key <= 'z';
681 com_id = get_com_id(key);
690 int menu_id = menu_id_list[key - 'a'];
692 if (menu_id < 0) continue;
694 com_id = menu_data[menu_id].com_id;
698 com_id = do_command_menu(level + 1, menu_id + 1);
700 if (com_id) return com_id;
711 static chain_str_type *new_chain_str(concptr str)
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);
722 static void kill_yank_chain(text_body_type *tb)
724 chain_str_type *chain = tb->yank;
730 chain_str_type *next = chain->next;
731 size_t len = strlen(chain->s);
733 rnfree(chain, sizeof(chain_str_type) + len * sizeof(char));
740 static void add_str_to_yank(text_body_type *tb, concptr str)
742 tb->yank_eol = FALSE;
743 if (NULL == tb->yank)
745 tb->yank = new_chain_str(str);
749 chain_str_type *chain;
756 chain->next = new_chain_str(str);
767 * Do work for the copy editor-command
769 static void copy_text_to_yank(text_body_type *tb)
771 int len = strlen(tb->lines_list[tb->cy]);
772 if (tb->cx > len) tb->cx = len;
782 if (tb->my != tb->cy)
784 int by1 = MIN(tb->my, tb->cy);
785 int by2 = MAX(tb->my, tb->cy);
787 for (int y = by1; y <= by2; y++)
789 add_str_to_yank(tb, tb->lines_list[y]);
792 add_str_to_yank(tb, "");
794 tb->dirty_flags |= DIRTY_ALL;
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;
803 if (bx1 == 0 && bx2 == len)
805 add_str_to_yank(tb, tb->lines_list[tb->cy]);
806 add_str_to_yank(tb, "");
811 for (int i = 0; i < bx2 - bx1; i++)
813 buf[i] = tb->lines_list[tb->cy][bx1 + i];
817 add_str_to_yank(tb, buf);
821 tb->dirty_flags |= DIRTY_ALL;
826 * Execute a single editor command
828 static bool do_editor_command(player_type *player_ptr, text_body_type *tb, int com_id)
835 if (!get_check(_("全ての変更を破棄してから終了します。よろしいですか? ",
836 "Discard all changes and quit. Are you sure? "))) break;
839 return QUIT_WITHOUT_SAVE;
842 return QUIT_AND_SAVE;
845 if (!get_check(_("全ての変更を破棄して元の状態に戻します。よろしいですか? ",
846 "Discard all changes and revert to original file. Are you sure? "))) break;
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;
858 (void)show_file(player_ptr, TRUE, _("jeditor.txt", "editor.txt"), NULL, 0, 0);
859 tb->dirty_flags |= DIRTY_SCREEN;
867 tb->dirty_flags |= DIRTY_ALL;
870 insert_return_code(tb);
874 tb->dirty_flags |= DIRTY_ALL;
886 len = strlen(tb->lines_list[tb->cy]);
887 if (len < tb->cx) tb->cx = len;
889 for (i = 0; tb->lines_list[tb->cy][i]; i++)
891 if (iskanji(tb->lines_list[tb->cy][i]))
906 tb->cx = strlen(tb->lines_list[tb->cy]);
912 if (!tb->lines_list[tb->cy + 1])
914 if (!add_empty_line(tb)) break;
921 if (tb->cy > 0) tb->cy--;
927 if (iskanji(tb->lines_list[tb->cy][tb->cx])) tb->cx++;
930 int len = strlen(tb->lines_list[tb->cy]);
934 if (!tb->lines_list[tb->cy + 1])
936 if (!add_empty_line(tb)) break;
950 tb->cx = strlen(tb->lines_list[tb->cy]);
954 while (0 < tb->cy && tb->upper <= tb->cy)
956 while (0 < tb->upper && tb->cy + 1 < tb->upper + tb->hgt)
961 while (tb->cy < tb->upper + tb->hgt)
963 if (!tb->lines_list[tb->cy + 1])
965 if (!add_empty_line(tb)) break;
981 if (!tb->lines_list[tb->cy + 1])
983 if (!add_empty_line(tb)) break;
994 copy_text_to_yank(tb);
995 if (tb->my == tb->cy)
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;
1002 kill_line_segment(tb, tb->cy, bx1, bx2, TRUE);
1007 int by1 = MIN(tb->my, tb->cy);
1008 int by2 = MAX(tb->my, tb->cy);
1010 for (int y = by2; y >= by1; y--)
1012 int len = strlen(tb->lines_list[y]);
1014 kill_line_segment(tb, y, 0, len, TRUE);
1022 tb->dirty_flags |= DIRTY_ALL;
1027 copy_text_to_yank(tb);
1030 * Move cursor position to the end of the selection
1032 * Pressing ^C ^V correctly duplicates the selection.
1034 if (tb->my != tb->cy)
1036 tb->cy = MAX(tb->cy, tb->my);
1037 if (!tb->lines_list[tb->cy + 1])
1039 if (!add_empty_line(tb)) break;
1046 tb->cx = MAX(tb->cx, tb->mx);
1047 if (!tb->lines_list[tb->cy][tb->cx])
1049 if (!tb->lines_list[tb->cy + 1])
1051 if (!add_empty_line(tb)) break;
1062 chain_str_type *chain = tb->yank;
1063 int len = strlen(tb->lines_list[tb->cy]);
1065 if (tb->cx > len) tb->cx = len;
1070 tb->dirty_flags |= DIRTY_ALL;
1075 concptr yank_str = chain->s;
1076 char buf[MAX_LINELEN];
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];
1082 strcpy(rest, &(tb->lines_list[tb->cy][i]));
1083 while (*yank_str && i < MAX_LINELEN - 1)
1085 buf[i++] = *yank_str++;
1089 chain = chain->next;
1090 if (chain || tb->yank_eol)
1092 insert_return_code(tb);
1093 string_free(tb->lines_list[tb->cy]);
1094 tb->lines_list[tb->cy] = string_make(buf);
1101 tb->cx = strlen(buf);
1102 while (*rest_ptr && i < MAX_LINELEN - 1)
1104 buf[i++] = *rest_ptr++;
1108 string_free(tb->lines_list[tb->cy]);
1109 tb->lines_list[tb->cy] = string_make(buf);
1113 tb->dirty_flags |= DIRTY_ALL;
1114 tb->dirty_flags |= DIRTY_EXPRESSION;
1123 tb->dirty_flags |= DIRTY_ALL;
1127 tb->mark = MARK_MARK;
1128 if (com_id == tb->old_com_id)
1136 tb->dirty_flags |= DIRTY_ALL;
1140 int len = strlen(tb->lines_list[tb->cy]);
1144 if (tb->cx > len) tb->mx = len;
1149 int len = strlen(tb->lines_list[tb->cy]);
1150 if (tb->cx > len) tb->cx = len;
1155 tb->dirty_flags |= DIRTY_ALL;
1158 if (tb->old_com_id != com_id)
1160 kill_yank_chain(tb);
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;
1172 if (tb->yank_eol) add_str_to_yank(tb, "");
1174 tb->yank_eol = TRUE;
1175 do_editor_command(player_ptr, tb, EC_DELETE_CHAR);
1178 case EC_DELETE_CHAR:
1183 tb->dirty_flags |= DIRTY_ALL;
1187 if (iskanji(tb->lines_list[tb->cy][tb->cx])) tb->cx++;
1190 int len = strlen(tb->lines_list[tb->cy]);
1193 do_editor_command(player_ptr, tb, EC_BACKSPACE);
1197 if (tb->lines_list[tb->cy + 1])
1208 do_editor_command(player_ptr, tb, EC_BACKSPACE);
1214 char buf[MAX_LINELEN];
1218 tb->dirty_flags |= DIRTY_ALL;
1221 len = strlen(tb->lines_list[tb->cy]);
1222 if (len < tb->cx) tb->cx = len;
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);
1234 for (i = tb->cy; tb->lines_list[i + 1]; i++)
1235 tb->lines_list[i] = tb->lines_list[i + 1];
1237 tb->lines_list[i] = NULL;
1239 tb->dirty_flags |= DIRTY_ALL;
1240 tb->dirty_flags |= DIRTY_EXPRESSION;
1245 for (i = j = k = 0; tb->lines_list[tb->cy][i] && i < tb->cx; i++)
1249 if (iskanji(tb->lines_list[tb->cy][i]))
1250 buf[j++] = tb->lines_list[tb->cy][i++];
1252 buf[j++] = tb->lines_list[tb->cy][i];
1261 for (; tb->lines_list[tb->cy][i]; i++)
1263 buf[j++] = tb->lines_list[tb->cy][i];
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);
1277 tb->dirty_flags |= DIRTY_SCREEN;
1278 search_dir = get_string_for_search(player_ptr, &tb->search_o_ptr, &tb->search_str);
1280 if (!search_dir) break;
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);
1286 case EC_SEARCH_FORW:
1287 if (tb->search_o_ptr)
1289 search_for_object(player_ptr, tb, tb->search_o_ptr, TRUE);
1293 if (tb->search_str && tb->search_str[0])
1295 search_for_string(tb, tb->search_str, TRUE);
1299 tb->dirty_flags |= DIRTY_NO_SEARCH;
1302 case EC_SEARCH_BACK:
1303 if (tb->search_o_ptr)
1305 search_for_object(player_ptr, tb, tb->search_o_ptr, FALSE);
1309 if (tb->search_str && tb->search_str[0])
1311 search_for_string(tb, tb->search_str, FALSE);
1315 tb->dirty_flags |= DIRTY_NO_SEARCH;
1319 tb->dirty_flags |= DIRTY_SCREEN;
1321 if (!get_object_for_search(player_ptr, &tb->search_o_ptr, &tb->search_str)) break;
1323 do_editor_command(player_ptr, tb, EC_SEARCH_FORW);
1326 case EC_SEARCH_DESTROYED:
1327 if (!get_destroyed_object_for_search(player_ptr, &tb->search_o_ptr, &tb->search_str))
1329 tb->dirty_flags |= DIRTY_NO_SEARCH;
1333 do_editor_command(player_ptr, tb, EC_SEARCH_FORW);
1336 case EC_INSERT_OBJECT:
1338 autopick_type an_entry, *entry = &an_entry;
1339 if (!entry_from_choosed_object(player_ptr, entry))
1341 tb->dirty_flags |= DIRTY_SCREEN;
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;
1352 case EC_INSERT_DESTROYED:
1353 if (!tb->last_destroyed) break;
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;
1363 case EC_INSERT_BLOCK:
1365 char expression[80];
1366 sprintf(expression, "?:[AND [EQU $RACE %s] [EQU $CLASS %s] [GEQ $LEVEL %02d]]",
1368 rp_ptr->E_title, cp_ptr->E_title,
1370 rp_ptr->title, cp_ptr->title,
1374 insert_return_code(tb);
1375 string_free(tb->lines_list[tb->cy]);
1376 tb->lines_list[tb->cy] = string_make(expression);
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;
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;
1393 tb->dirty_flags |= DIRTY_ALL;
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)));
1403 if (!insert_keymap_line(tb)) break;
1406 tb->dirty_flags |= DIRTY_ALL;
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;
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);
1458 toggle_keyword(tb, FLG_REALM1);
1459 add_keyword(tb, FLG_SPELLBOOKS);
1462 toggle_keyword(tb, FLG_REALM2);
1463 add_keyword(tb, FLG_SPELLBOOKS);
1466 toggle_keyword(tb, FLG_FIRST);
1467 add_keyword(tb, FLG_SPELLBOOKS);
1470 toggle_keyword(tb, FLG_SECOND);
1471 add_keyword(tb, FLG_SPELLBOOKS);
1474 toggle_keyword(tb, FLG_THIRD);
1475 add_keyword(tb, FLG_SPELLBOOKS);
1478 toggle_keyword(tb, FLG_FOURTH);
1479 add_keyword(tb, FLG_SPELLBOOKS);
1483 tb->old_com_id = com_id;
1489 * Check special key code and get a movement command id
1491 static int analyze_move_key(text_body_type *tb, int skey)
1494 if (!(skey & SKEY_MASK)) return 0;
1496 switch (skey & ~SKEY_MOD_MASK)
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;
1510 if (!(skey & SKEY_MOD_SHIFT))
1513 * Un-shifted cursor keys cancells
1514 * selection created by shift+cursor.
1516 if (tb->mark & MARK_BY_SHIFT)
1519 tb->dirty_flags |= DIRTY_ALL;
1525 if (tb->mark) return com_id;
1527 int len = strlen(tb->lines_list[tb->cy]);
1528 tb->mark = MARK_MARK | MARK_BY_SHIFT;
1531 if (tb->cx > len) tb->mx = len;
1533 if (com_id == EC_UP || com_id == EC_DOWN)
1535 tb->dirty_flags |= DIRTY_ALL;
1539 tb->dirty_line = tb->cy;
1546 * In-game editor of Object Auto-picker/Destoryer
1547 * @param player_ptr プレーヤーへの参照ポインタ
1549 void do_cmd_edit_autopick(player_type *player_ptr)
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];
1557 static s32b old_autosave_turn = 0L;
1560 text_body_type text_body;
1561 text_body_type *tb = &text_body;
1562 tb->changed = FALSE;
1565 tb->upper = tb->left = 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;
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;
1580 if (current_world_ptr->game_turn < old_autosave_turn)
1582 while (old_autosave_turn > current_world_ptr->game_turn) old_autosave_turn -= TURNS_PER_TICK * TOWN_DAWN;
1585 if (current_world_ptr->game_turn > old_autosave_turn + 100L)
1587 do_cmd_save_game(player_ptr, TRUE);
1588 old_autosave_turn = current_world_ptr->game_turn;
1593 if (autopick_last_destroyed_object.k_idx)
1595 autopick_entry_from_object(player_ptr, entry, &autopick_last_destroyed_object);
1596 tb->last_destroyed = autopick_line_from_entry_kill(entry);
1599 tb->lines_list = read_pickpref_text_lines(player_ptr, &tb->filename_mode);
1600 for (i = 0; i < tb->cy; i++)
1602 if (!tb->lines_list[i])
1604 tb->cy = tb->cx = 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);
1618 prt(format("(%d,%d)", tb->cx, tb->cy), 0, 60);
1622 prt(format("(%d,%d)-(%d,%d)", tb->mx, tb->my, tb->cx, tb->cy), 0, 60);
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;
1634 key = inkey_special(TRUE);
1636 if (key & SKEY_MASK)
1638 com_id = analyze_move_key(tb, key);
1640 else if (key == ESCAPE)
1642 com_id = do_command_menu(0, 0);
1643 tb->dirty_flags |= DIRTY_SCREEN;
1645 else if (!iscntrl((unsigned char)key))
1650 tb->dirty_flags |= DIRTY_ALL;
1653 insert_single_letter(tb, key);
1658 com_id = get_com_id((char)key);
1661 if (com_id) quit = do_editor_command(player_ptr, tb, com_id);
1665 strcpy(buf, pickpref_filename(player_ptr, tb->filename_mode));
1667 if (quit == QUIT_AND_SAVE)
1668 write_text_lines(buf, tb->lines_list);
1670 free_text_lines(tb->lines_list);
1671 string_free(tb->search_str);
1672 string_free(tb->last_destroyed);
1673 kill_yank_chain(tb);
1675 process_autopick_file(player_ptr, buf);
1676 current_world_ptr->start_time = (u32b)time(NULL);