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-editor-table.h"
17 #include "autopick/autopick-flags-table.h"
18 #include "autopick/autopick-keys-table.h"
20 #include "autopick/autopick.h"
22 #include "core/show-file.h"
23 #include "cmd/cmd-save.h"
24 #include "io/read-pref-file.h"
28 #include "market/store.h"
29 #include "player-status.h"
30 #include "player-move.h"
31 #include "player-class.h"
32 #include "player-race.h"
33 #include "player-inventory.h"
34 #include "view/display-player.h"
35 #include "object/object-kind.h"
36 #include "object-ego.h"
37 #include "object-flavor.h"
38 #include "object-hook.h"
44 #include "monsterrace.h"
45 #include "view-mainwindow.h" // 暫定。後で消す
47 #define MAX_LINELEN 1024
49 #define MAX_AUTOPICK_DEFAULT 200
52 #define PT_WITH_PNAME 1
54 #define MAX_YANK MAX_LINELEN
55 #define MAX_LINES 3000
57 #define MARK_MARK 0x01
58 #define MARK_BY_SHIFT 0x02
60 #define LSTAT_BYPASS 0x01
61 #define LSTAT_EXPRESSION 0x02
62 #define LSTAT_AUTOREGISTER 0x04
64 #define QUIT_WITHOUT_SAVE 1
65 #define QUIT_AND_SAVE 2
68 * Dirty flag for text editor
70 #define DIRTY_ALL 0x0001
71 #define DIRTY_MODE 0x0004
72 #define DIRTY_SCREEN 0x0008
73 #define DIRTY_NOT_FOUND 0x0010
74 #define DIRTY_NO_SEARCH 0x0020
75 #define DIRTY_EXPRESSION 0x0040
76 #define DIRTY_SKIP_INACTIVE 0x0080
77 #define DIRTY_INACTIVE 0x0100
79 #define DESCRIPT_HGT 3
81 #define MATCH_KEY(KEY) (!strncmp(ptr, KEY, sizeof(KEY)-1)\
82 ? (ptr += sizeof(KEY)-1, (' '==*ptr) ? ptr++ : 0, TRUE) : FALSE)
83 #define MATCH_KEY2(KEY) (!strncmp(ptr, KEY, sizeof(KEY)-1)\
84 ? (prev_ptr = ptr, ptr += sizeof(KEY)-1, (' '==*ptr) ? ptr++ : 0, TRUE) : FALSE)
87 #define ADD_KEY(KEY) strcat(ptr, KEY)
89 #define ADD_KEY(KEY) (strcat(ptr, KEY), strcat(ptr, " "))
91 #define ADD_KEY2(KEY) strcat(ptr, KEY)
93 #define ADD_FLG(FLG) (entry->flag[FLG / 32] |= (1L << (FLG % 32)))
94 #define REM_FLG(FLG) (entry->flag[FLG / 32] &= ~(1L << (FLG % 32)))
95 #define ADD_FLG_NOUN(FLG) (ADD_FLG(FLG), prev_flg = FLG)
96 #define IS_FLG(FLG) (entry->flag[FLG / 32] & (1L << (FLG % 32)))
99 static char kanji_colon[] = ":";
103 * 自動拾い/破壊設定のリストに関する変数 / List for auto-picker/destroyer entries
105 int max_autopick = 0; /*!< 現在登録している自動拾い/破壊設定の数 */
106 int max_max_autopick = 0; /*!< 自動拾い/破壊設定の限界数 */
107 autopick_type *autopick_list = NULL; /*!< 自動拾い/破壊設定構造体のポインタ配列 */
110 * Automatically destroy an item if it is to be destroyed
112 * When always_pickup is 'yes', we disable auto-destroyer function of
113 * auto-picker/destroyer, and do only easy-auto-destroyer.
115 static object_type autopick_last_destroyed_object;
118 * Struct for yank buffer
120 typedef struct chain_str {
121 struct chain_str *next;
126 * Data struct for text editor
132 int old_wid, old_hgt;
134 int old_upper, old_left;
138 object_type *search_o_ptr;
140 concptr last_destroyed;
142 chain_str_type *yank;
146 byte states[MAX_LINES];
157 * Editor command id's
160 #define EC_SAVEQUIT 2
178 #define EC_KILL_LINE 20
179 #define EC_DELETE_CHAR 21
180 #define EC_BACKSPACE 22
181 #define EC_SEARCH_STR 23
182 #define EC_SEARCH_FORW 24
183 #define EC_SEARCH_BACK 25
184 #define EC_SEARCH_OBJ 26
185 #define EC_SEARCH_DESTROYED 27
186 #define EC_INSERT_OBJECT 28
187 #define EC_INSERT_DESTROYED 29
188 #define EC_INSERT_BLOCK 30
189 #define EC_INSERT_MACRO 31
190 #define EC_INSERT_KEYMAP 32
191 #define EC_CL_AUTOPICK 33
192 #define EC_CL_DESTROY 34
193 #define EC_CL_LEAVE 35
194 #define EC_CL_QUERY 36
195 #define EC_CL_NO_DISP 37
196 #define EC_OK_COLLECTING 38
197 #define EC_IK_UNAWARE 39
198 #define EC_IK_UNIDENTIFIED 40
199 #define EC_IK_IDENTIFIED 41
200 #define EC_IK_STAR_IDENTIFIED 42
201 #define EC_OK_BOOSTED 43
202 #define EC_OK_MORE_DICE 44
203 #define EC_OK_MORE_BONUS 45
204 #define EC_OK_WORTHLESS 46
205 #define EC_OK_ARTIFACT 47
207 #define EC_OK_GOOD 49
208 #define EC_OK_NAMELESS 50
209 #define EC_OK_AVERAGE 51
210 #define EC_OK_RARE 52
211 #define EC_OK_COMMON 53
212 #define EC_OK_WANTED 54
213 #define EC_OK_UNIQUE 55
214 #define EC_OK_HUMAN 56
215 #define EC_OK_UNREADABLE 57
216 #define EC_OK_REALM1 58
217 #define EC_OK_REALM2 59
218 #define EC_OK_FIRST 60
219 #define EC_OK_SECOND 61
220 #define EC_OK_THIRD 62
221 #define EC_OK_FOURTH 63
222 #define EC_KK_WEAPONS 64
223 #define EC_KK_FAVORITE_WEAPONS 65
224 #define EC_KK_ARMORS 66
225 #define EC_KK_MISSILES 67
226 #define EC_KK_DEVICES 68
227 #define EC_KK_LIGHTS 69
228 #define EC_KK_JUNKS 70
229 #define EC_KK_CORPSES 71
230 #define EC_KK_SPELLBOOKS 72
231 #define EC_KK_SHIELDS 73
232 #define EC_KK_BOWS 74
233 #define EC_KK_RINGS 75
234 #define EC_KK_AMULETS 76
235 #define EC_KK_SUITS 77
236 #define EC_KK_CLOAKS 78
237 #define EC_KK_HELMS 79
238 #define EC_KK_GLOVES 80
239 #define EC_KK_BOOTS 81
248 command_menu_type menu_data[] =
250 {MN_HELP, 0, -1, EC_HELP},
251 {MN_QUIT, 0, KTRL('q'), EC_QUIT},
252 {MN_SAVEQUIT, 0, KTRL('w'), EC_SAVEQUIT},
253 {MN_REVERT, 0, KTRL('z'), EC_REVERT},
255 {MN_EDIT, 0, -1, -1},
256 {MN_CUT, 1, KTRL('x'), EC_CUT},
257 {MN_COPY, 1, KTRL('c'), EC_COPY},
258 {MN_PASTE, 1, KTRL('v'), EC_PASTE},
259 {MN_BLOCK, 1, KTRL('g'), EC_BLOCK},
260 {MN_KILL_LINE, 1, KTRL('k'), EC_KILL_LINE},
261 {MN_DELETE_CHAR, 1, KTRL('d'), EC_DELETE_CHAR},
262 {MN_BACKSPACE, 1, KTRL('h'), EC_BACKSPACE},
263 {MN_RETURN, 1, KTRL('j'), EC_RETURN},
264 {MN_RETURN, 1, KTRL('m'), EC_RETURN},
266 {MN_SEARCH, 0, -1, -1},
267 {MN_SEARCH_STR, 1, KTRL('s'), EC_SEARCH_STR},
268 {MN_SEARCH_FORW, 1, -1, EC_SEARCH_FORW},
269 {MN_SEARCH_BACK, 1, KTRL('r'), EC_SEARCH_BACK},
270 {MN_SEARCH_OBJ, 1, KTRL('y'), EC_SEARCH_OBJ},
271 {MN_SEARCH_DESTROYED, 1, -1, EC_SEARCH_DESTROYED},
273 {MN_MOVE, 0, -1, -1},
274 {MN_LEFT, 1, KTRL('b'), EC_LEFT},
275 {MN_DOWN, 1, KTRL('n'), EC_DOWN},
276 {MN_UP, 1, KTRL('p'), EC_UP},
277 {MN_RIGHT, 1, KTRL('f'), EC_RIGHT},
278 {MN_BOL, 1, KTRL('a'), EC_BOL},
279 {MN_EOL, 1, KTRL('e'), EC_EOL},
280 {MN_PGUP, 1, KTRL('o'), EC_PGUP},
281 {MN_PGDOWN, 1, KTRL('l'), EC_PGDOWN},
282 {MN_TOP, 1, KTRL('t'), EC_TOP},
283 {MN_BOTTOM, 1, KTRL('u'), EC_BOTTOM},
285 {MN_INSERT, 0, -1, -1},
286 {MN_INSERT_OBJECT, 1, KTRL('i'), EC_INSERT_OBJECT},
287 {MN_INSERT_DESTROYED, 1, -1, EC_INSERT_DESTROYED},
288 {MN_INSERT_BLOCK, 1, -1, EC_INSERT_BLOCK},
289 {MN_INSERT_MACRO, 1, -1, EC_INSERT_MACRO},
290 {MN_INSERT_KEYMAP, 1, -1, EC_INSERT_KEYMAP},
292 {MN_ADJECTIVE_GEN, 0, -1, -1},
293 {KEY_UNAWARE, 1, -1, EC_IK_UNAWARE},
294 {KEY_UNIDENTIFIED, 1, -1, EC_IK_UNIDENTIFIED},
295 {KEY_IDENTIFIED, 1, -1, EC_IK_IDENTIFIED},
296 {KEY_STAR_IDENTIFIED, 1, -1, EC_IK_STAR_IDENTIFIED},
297 {KEY_COLLECTING, 1, -1, EC_OK_COLLECTING},
298 {KEY_ARTIFACT, 1, -1, EC_OK_ARTIFACT},
299 {KEY_EGO, 1, -1, EC_OK_EGO},
300 {KEY_GOOD, 1, -1, EC_OK_GOOD},
301 {KEY_NAMELESS, 1, -1, EC_OK_NAMELESS},
302 {KEY_AVERAGE, 1, -1, EC_OK_AVERAGE},
303 {KEY_WORTHLESS, 1, -1, EC_OK_WORTHLESS},
304 {MN_RARE, 1, -1, EC_OK_RARE},
305 {MN_COMMON, 1, -1, EC_OK_COMMON},
307 {MN_ADJECTIVE_SPECIAL, 0, -1, -1},
308 {MN_BOOSTED, 1, -1, EC_OK_BOOSTED},
309 {MN_MORE_DICE, 1, -1, EC_OK_MORE_DICE},
310 {MN_MORE_BONUS, 1, -1, EC_OK_MORE_BONUS},
311 {MN_WANTED, 1, -1, EC_OK_WANTED},
312 {MN_UNIQUE, 1, -1, EC_OK_UNIQUE},
313 {MN_HUMAN, 1, -1, EC_OK_HUMAN},
314 {MN_UNREADABLE, 1, -1, EC_OK_UNREADABLE},
315 {MN_REALM1, 1, -1, EC_OK_REALM1},
316 {MN_REALM2, 1, -1, EC_OK_REALM2},
317 {MN_FIRST, 1, -1, EC_OK_FIRST},
318 {MN_SECOND, 1, -1, EC_OK_SECOND},
319 {MN_THIRD, 1, -1, EC_OK_THIRD},
320 {MN_FOURTH, 1, -1, EC_OK_FOURTH},
322 {MN_NOUN, 0, -1, -1},
323 {KEY_WEAPONS, 1, -1, EC_KK_WEAPONS},
324 {KEY_FAVORITE_WEAPONS, 1, -1, EC_KK_FAVORITE_WEAPONS},
325 {KEY_ARMORS, 1, -1, EC_KK_ARMORS},
326 {KEY_MISSILES, 1, -1, EC_KK_MISSILES},
327 {KEY_DEVICES, 1, -1, EC_KK_DEVICES},
328 {KEY_LIGHTS, 1, -1, EC_KK_LIGHTS},
329 {KEY_JUNKS, 1, -1, EC_KK_JUNKS},
330 {KEY_CORPSES, 1, -1, EC_KK_CORPSES},
331 {KEY_SPELLBOOKS, 1, -1, EC_KK_SPELLBOOKS},
332 {KEY_SHIELDS, 1, -1, EC_KK_SHIELDS},
333 {KEY_BOWS, 1, -1, EC_KK_BOWS},
334 {KEY_RINGS, 1, -1, EC_KK_RINGS},
335 {KEY_AMULETS, 1, -1, EC_KK_AMULETS},
336 {KEY_SUITS, 1, -1, EC_KK_SUITS},
337 {KEY_CLOAKS, 1, -1, EC_KK_CLOAKS},
338 {KEY_HELMS, 1, -1, EC_KK_HELMS},
339 {KEY_GLOVES, 1, -1, EC_KK_GLOVES},
340 {KEY_BOOTS, 1, -1, EC_KK_BOOTS},
342 {MN_COMMAND_LETTER, 0, -1, -1},
343 {MN_CL_AUTOPICK, 1, -1, EC_CL_AUTOPICK},
344 {MN_CL_DESTROY, 1, -1, EC_CL_DESTROY},
345 {MN_CL_LEAVE, 1, -1, EC_CL_LEAVE},
346 {MN_CL_QUERY, 1, -1, EC_CL_QUERY},
347 {MN_CL_NO_DISP, 1, -1, EC_CL_NO_DISP},
349 {MN_DELETE_CHAR, -1, 0x7F, EC_DELETE_CHAR},
355 * A function to create new entry
357 static bool autopick_new_entry(autopick_type *entry, concptr str, bool allow_default)
359 if (str[0] && str[1] == ':') switch (str[0])
362 case 'A': case 'P': case 'C':
366 entry->flag[0] = entry->flag[1] = 0L;
370 byte act = DO_AUTOPICK | DO_DISPLAY;
373 if ((act & DO_AUTOPICK) && *str == '!')
376 act |= DO_AUTODESTROY;
381 if ((act & DO_AUTOPICK) && *str == '~')
384 act |= DONT_AUTOPICK;
389 if ((act & DO_AUTOPICK) && *str == ';')
392 act |= DO_QUERY_AUTOPICK;
397 if ((act & DO_DISPLAY) && *str == '(')
408 char buf[MAX_LINELEN];
410 for (i = 0; *str; i++)
428 if (isupper(c)) c = (char)tolower(c);
434 if (!allow_default && *buf == 0) return FALSE;
435 if (*buf == 0 && insc) return FALSE;
437 concptr prev_ptr, ptr;
438 ptr = prev_ptr = buf;
439 concptr old_ptr = NULL;
440 while (old_ptr != ptr)
443 if (MATCH_KEY(KEY_ALL)) ADD_FLG(FLG_ALL);
444 if (MATCH_KEY(KEY_COLLECTING)) ADD_FLG(FLG_COLLECTING);
445 if (MATCH_KEY(KEY_UNAWARE)) ADD_FLG(FLG_UNAWARE);
446 if (MATCH_KEY(KEY_UNIDENTIFIED)) ADD_FLG(FLG_UNIDENTIFIED);
447 if (MATCH_KEY(KEY_IDENTIFIED)) ADD_FLG(FLG_IDENTIFIED);
448 if (MATCH_KEY(KEY_STAR_IDENTIFIED)) ADD_FLG(FLG_STAR_IDENTIFIED);
449 if (MATCH_KEY(KEY_BOOSTED)) ADD_FLG(FLG_BOOSTED);
451 /*** Weapons whose dd*ds is more than nn ***/
452 if (MATCH_KEY2(KEY_MORE_THAN))
457 while (' ' == *ptr) ptr++;
459 while ('0' <= *ptr && *ptr <= '9')
461 entry->dice = 10 * entry->dice + (*ptr - '0');
468 (void)MATCH_KEY(KEY_DICE);
469 ADD_FLG(FLG_MORE_DICE);
475 /*** Items whose magical bonus is more than n ***/
476 if (MATCH_KEY2(KEY_MORE_BONUS))
481 while (' ' == *ptr) ptr++;
483 while ('0' <= *ptr && *ptr <= '9')
485 entry->bonus = 10 * entry->bonus + (*ptr - '0');
493 (void)MATCH_KEY(KEY_MORE_BONUS2);
495 if (' ' == *ptr) ptr++;
497 ADD_FLG(FLG_MORE_BONUS);
503 if (MATCH_KEY(KEY_WORTHLESS)) ADD_FLG(FLG_WORTHLESS);
504 if (MATCH_KEY(KEY_EGO)) ADD_FLG(FLG_EGO);
505 if (MATCH_KEY(KEY_GOOD)) ADD_FLG(FLG_GOOD);
506 if (MATCH_KEY(KEY_NAMELESS)) ADD_FLG(FLG_NAMELESS);
507 if (MATCH_KEY(KEY_AVERAGE)) ADD_FLG(FLG_AVERAGE);
508 if (MATCH_KEY(KEY_RARE)) ADD_FLG(FLG_RARE);
509 if (MATCH_KEY(KEY_COMMON)) ADD_FLG(FLG_COMMON);
510 if (MATCH_KEY(KEY_WANTED)) ADD_FLG(FLG_WANTED);
511 if (MATCH_KEY(KEY_UNIQUE)) ADD_FLG(FLG_UNIQUE);
512 if (MATCH_KEY(KEY_HUMAN)) ADD_FLG(FLG_HUMAN);
513 if (MATCH_KEY(KEY_UNREADABLE)) ADD_FLG(FLG_UNREADABLE);
514 if (MATCH_KEY(KEY_REALM1)) ADD_FLG(FLG_REALM1);
515 if (MATCH_KEY(KEY_REALM2)) ADD_FLG(FLG_REALM2);
516 if (MATCH_KEY(KEY_FIRST)) ADD_FLG(FLG_FIRST);
517 if (MATCH_KEY(KEY_SECOND)) ADD_FLG(FLG_SECOND);
518 if (MATCH_KEY(KEY_THIRD)) ADD_FLG(FLG_THIRD);
519 if (MATCH_KEY(KEY_FOURTH)) ADD_FLG(FLG_FOURTH);
523 if (MATCH_KEY2(KEY_ARTIFACT)) ADD_FLG_NOUN(FLG_ARTIFACT);
525 if (MATCH_KEY2(KEY_ITEMS)) ADD_FLG_NOUN(FLG_ITEMS);
526 else if (MATCH_KEY2(KEY_WEAPONS)) ADD_FLG_NOUN(FLG_WEAPONS);
527 else if (MATCH_KEY2(KEY_FAVORITE_WEAPONS)) ADD_FLG_NOUN(FLG_FAVORITE_WEAPONS);
528 else if (MATCH_KEY2(KEY_ARMORS)) ADD_FLG_NOUN(FLG_ARMORS);
529 else if (MATCH_KEY2(KEY_MISSILES)) ADD_FLG_NOUN(FLG_MISSILES);
530 else if (MATCH_KEY2(KEY_DEVICES)) ADD_FLG_NOUN(FLG_DEVICES);
531 else if (MATCH_KEY2(KEY_LIGHTS)) ADD_FLG_NOUN(FLG_LIGHTS);
532 else if (MATCH_KEY2(KEY_JUNKS)) ADD_FLG_NOUN(FLG_JUNKS);
533 else if (MATCH_KEY2(KEY_CORPSES)) ADD_FLG_NOUN(FLG_CORPSES);
534 else if (MATCH_KEY2(KEY_SPELLBOOKS)) ADD_FLG_NOUN(FLG_SPELLBOOKS);
535 else if (MATCH_KEY2(KEY_HAFTED)) ADD_FLG_NOUN(FLG_HAFTED);
536 else if (MATCH_KEY2(KEY_SHIELDS)) ADD_FLG_NOUN(FLG_SHIELDS);
537 else if (MATCH_KEY2(KEY_BOWS)) ADD_FLG_NOUN(FLG_BOWS);
538 else if (MATCH_KEY2(KEY_RINGS)) ADD_FLG_NOUN(FLG_RINGS);
539 else if (MATCH_KEY2(KEY_AMULETS)) ADD_FLG_NOUN(FLG_AMULETS);
540 else if (MATCH_KEY2(KEY_SUITS)) ADD_FLG_NOUN(FLG_SUITS);
541 else if (MATCH_KEY2(KEY_CLOAKS)) ADD_FLG_NOUN(FLG_CLOAKS);
542 else if (MATCH_KEY2(KEY_HELMS)) ADD_FLG_NOUN(FLG_HELMS);
543 else if (MATCH_KEY2(KEY_GLOVES)) ADD_FLG_NOUN(FLG_GLOVES);
544 else if (MATCH_KEY2(KEY_BOOTS)) ADD_FLG_NOUN(FLG_BOOTS);
549 else if (ptr[0] == kanji_colon[0] && ptr[1] == kanji_colon[1])
552 else if (*ptr == '\0')
555 ADD_FLG_NOUN(FLG_ITEMS);
561 entry->flag[prev_flg / 32] &= ~(1L << (prev_flg % 32));
566 entry->name = string_make(ptr);
568 entry->insc = string_make(insc);
575 * Get auto-picker entry from o_ptr.
577 static void autopick_entry_from_object(player_type *player_ptr, autopick_type *entry, object_type *o_ptr)
579 /* Assume that object name is to be added */
583 /* エゴ銘が邪魔かもしれないので、デフォルトで「^」は付けない */
584 bool bol_mark = FALSE;
586 /* We can always use the ^ mark in English */
587 bool bol_mark = TRUE;
590 GAME_TEXT name_str[MAX_NLEN];
593 entry->insc = string_make(quark_str(o_ptr->inscription));
594 entry->action = DO_AUTOPICK | DO_DISPLAY;
595 entry->flag[0] = entry->flag[1] = 0L;
598 if (!object_is_aware(o_ptr))
600 ADD_FLG(FLG_UNAWARE);
603 else if (!object_is_known(o_ptr))
605 if (!(o_ptr->ident & IDENT_SENSE))
607 ADD_FLG(FLG_UNIDENTIFIED);
612 switch (o_ptr->feeling)
616 ADD_FLG(FLG_NAMELESS);
622 ADD_FLG(FLG_NAMELESS);
623 ADD_FLG(FLG_WORTHLESS);
629 ADD_FLG(FLG_WORTHLESS);
646 if (object_is_ego(o_ptr))
648 if (object_is_weapon_armour_ammo(o_ptr))
651 * Base name of ego weapons and armors
652 * are almost meaningless.
653 * Register the ego type only.
655 ego_item_type *e_ptr = &e_info[o_ptr->name2];
657 /* エゴ銘には「^」マークが使える */
658 sprintf(name_str, "^%s", e_name + e_ptr->name);
660 /* We ommit the basename and cannot use the ^ mark */
661 strcpy(name_str, e_name + e_ptr->name);
664 if (!object_is_rare(o_ptr)) ADD_FLG(FLG_COMMON);
669 else if (object_is_artifact(o_ptr))
670 ADD_FLG(FLG_ARTIFACT);
673 if (object_is_equipment(o_ptr))
674 ADD_FLG(FLG_NAMELESS);
681 if (object_is_melee_weapon(o_ptr))
683 object_kind *k_ptr = &k_info[o_ptr->k_idx];
685 if ((o_ptr->dd != k_ptr->dd) || (o_ptr->ds != k_ptr->ds))
686 ADD_FLG(FLG_BOOSTED);
689 if (object_is_bounty(o_ptr))
691 REM_FLG(FLG_WORTHLESS);
695 if ((o_ptr->tval == TV_CORPSE || o_ptr->tval == TV_STATUE)
696 && (r_info[o_ptr->pval].flags1 & RF1_UNIQUE))
701 if (o_ptr->tval == TV_CORPSE && my_strchr("pht", r_info[o_ptr->pval].d_char))
706 if (o_ptr->tval >= TV_LIFE_BOOK &&
707 !check_book_realm(player_ptr, o_ptr->tval, o_ptr->sval))
709 ADD_FLG(FLG_UNREADABLE);
710 if (o_ptr->tval != TV_ARCANE_BOOK) name = FALSE;
713 if (REALM1_BOOK == o_ptr->tval &&
714 player_ptr->pclass != CLASS_SORCERER &&
715 player_ptr->pclass != CLASS_RED_MAGE)
721 if (REALM2_BOOK == o_ptr->tval &&
722 player_ptr->pclass != CLASS_SORCERER &&
723 player_ptr->pclass != CLASS_RED_MAGE)
729 if (o_ptr->tval >= TV_LIFE_BOOK && 0 == o_ptr->sval)
731 if (o_ptr->tval >= TV_LIFE_BOOK && 1 == o_ptr->sval)
733 if (o_ptr->tval >= TV_LIFE_BOOK && 2 == o_ptr->sval)
735 if (o_ptr->tval >= TV_LIFE_BOOK && 3 == o_ptr->sval)
738 if (object_is_ammo(o_ptr))
739 ADD_FLG(FLG_MISSILES);
740 else if (o_ptr->tval == TV_SCROLL || o_ptr->tval == TV_STAFF
741 || o_ptr->tval == TV_WAND || o_ptr->tval == TV_ROD)
742 ADD_FLG(FLG_DEVICES);
743 else if (o_ptr->tval == TV_LITE)
745 else if (o_ptr->tval == TV_SKELETON || o_ptr->tval == TV_BOTTLE
746 || o_ptr->tval == TV_JUNK || o_ptr->tval == TV_STATUE)
748 else if (o_ptr->tval == TV_CORPSE)
749 ADD_FLG(FLG_CORPSES);
750 else if (o_ptr->tval >= TV_LIFE_BOOK)
751 ADD_FLG(FLG_SPELLBOOKS);
752 else if (o_ptr->tval == TV_POLEARM || o_ptr->tval == TV_SWORD
753 || o_ptr->tval == TV_DIGGING || o_ptr->tval == TV_HAFTED)
754 ADD_FLG(FLG_WEAPONS);
755 else if (o_ptr->tval == TV_SHIELD)
756 ADD_FLG(FLG_SHIELDS);
757 else if (o_ptr->tval == TV_BOW)
759 else if (o_ptr->tval == TV_RING)
761 else if (o_ptr->tval == TV_AMULET)
762 ADD_FLG(FLG_AMULETS);
763 else if (o_ptr->tval == TV_DRAG_ARMOR || o_ptr->tval == TV_HARD_ARMOR ||
764 o_ptr->tval == TV_SOFT_ARMOR)
766 else if (o_ptr->tval == TV_CLOAK)
768 else if (o_ptr->tval == TV_HELM)
770 else if (o_ptr->tval == TV_GLOVES)
772 else if (o_ptr->tval == TV_BOOTS)
777 str_tolower(name_str);
778 entry->name = string_make(name_str);
782 GAME_TEXT o_name[MAX_NLEN];
783 object_desc(player_ptr, o_name, o_ptr, (OD_NO_FLAVOR | OD_OMIT_PREFIX | OD_NO_PLURAL | OD_NAME_ONLY));
786 * If necessary, add a '^' which indicates the
789 sprintf(name_str, "%s%s", bol_mark ? "^" : "", o_name);
790 str_tolower(name_str);
791 entry->name = string_make(name_str);
796 * A function to delete entry
798 static void autopick_free_entry(autopick_type *entry)
800 string_free(entry->name);
801 string_free(entry->insc);
808 * Initialize the autopick
810 static void init_autopick(void)
812 static const char easy_autopick_inscription[] = "(:=g";
818 max_max_autopick = MAX_AUTOPICK_DEFAULT;
819 C_MAKE(autopick_list, max_max_autopick, autopick_type);
823 for (i = 0; i < max_autopick; i++)
824 autopick_free_entry(&autopick_list[i]);
827 autopick_new_entry(&entry, easy_autopick_inscription, TRUE);
828 autopick_list[max_autopick++] = entry;
833 * Get file name for autopick preference
835 static concptr pickpref_filename(player_type *player_ptr, int filename_mode)
837 static const char namebase[] = _("picktype", "pickpref");
839 switch (filename_mode)
842 return format("%s.prf", namebase);
845 return format("%s-%s.prf", namebase, player_ptr->base_name);
854 * Load an autopick preference file
856 void autopick_load_pref(player_type *player_ptr, bool disp_mes)
860 my_strcpy(buf, pickpref_filename(player_ptr, PT_WITH_PNAME), sizeof(buf));
861 errr err = process_autopick_file(player_ptr, buf);
862 if (err == 0 && disp_mes)
864 msg_format(_("%sを読み込みました。", "Loaded '%s'."), buf);
869 my_strcpy(buf, pickpref_filename(player_ptr, PT_DEFAULT), sizeof(buf));
870 err = process_autopick_file(player_ptr, buf);
871 if (err == 0 && disp_mes)
873 msg_format(_("%sを読み込みました。", "Loaded '%s'."), buf);
879 msg_print(_("自動拾い設定ファイルの読み込みに失敗しました。", "Failed to reload autopick preference."));
885 * Add one line to autopick_list[]
887 static void add_autopick_list(autopick_type *entry)
889 if (max_autopick >= max_max_autopick)
891 int old_max_max_autopick = max_max_autopick;
892 autopick_type *old_autopick_list = autopick_list;
893 max_max_autopick += MAX_AUTOPICK_DEFAULT;
894 C_MAKE(autopick_list, max_max_autopick, autopick_type);
895 (void)C_COPY(autopick_list, old_autopick_list, old_max_max_autopick, autopick_type);
896 C_KILL(old_autopick_list, old_max_max_autopick, autopick_type);
899 autopick_list[max_autopick] = *entry;
905 * Process line for auto picker/destroyer.
907 void process_autopick_file_command(char *buf)
909 autopick_type an_entry, *entry = &an_entry;
911 for (i = 0; buf[i]; i++)
920 if (iswspace(buf[i]) && buf[i] != ' ')
925 if (!autopick_new_entry(entry, buf, FALSE)) return;
927 for (i = 0; i < max_autopick; i++)
929 if (!strcmp(entry->name, autopick_list[i].name)
930 && entry->flag[0] == autopick_list[i].flag[0]
931 && entry->flag[1] == autopick_list[i].flag[1]
932 && entry->dice == autopick_list[i].dice
933 && entry->bonus == autopick_list[i].bonus)
935 autopick_free_entry(entry);
940 add_autopick_list(entry);
946 * Reconstruct preference line from entry
948 concptr autopick_line_from_entry(autopick_type *entry)
950 char buf[MAX_LINELEN];
952 if (!(entry->action & DO_DISPLAY)) strcat(buf, "(");
953 if (entry->action & DO_QUERY_AUTOPICK) strcat(buf, ";");
954 if (entry->action & DO_AUTODESTROY) strcat(buf, "!");
955 if (entry->action & DONT_AUTOPICK) strcat(buf, "~");
959 if (IS_FLG(FLG_ALL)) ADD_KEY(KEY_ALL);
960 if (IS_FLG(FLG_COLLECTING)) ADD_KEY(KEY_COLLECTING);
961 if (IS_FLG(FLG_UNAWARE)) ADD_KEY(KEY_UNAWARE);
962 if (IS_FLG(FLG_UNIDENTIFIED)) ADD_KEY(KEY_UNIDENTIFIED);
963 if (IS_FLG(FLG_IDENTIFIED)) ADD_KEY(KEY_IDENTIFIED);
964 if (IS_FLG(FLG_STAR_IDENTIFIED)) ADD_KEY(KEY_STAR_IDENTIFIED);
965 if (IS_FLG(FLG_BOOSTED)) ADD_KEY(KEY_BOOSTED);
967 if (IS_FLG(FLG_MORE_DICE))
969 ADD_KEY(KEY_MORE_THAN);
970 strcat(ptr, format("%d", entry->dice));
974 if (IS_FLG(FLG_MORE_BONUS))
976 ADD_KEY(KEY_MORE_BONUS);
977 strcat(ptr, format("%d", entry->bonus));
978 ADD_KEY(KEY_MORE_BONUS2);
981 if (IS_FLG(FLG_UNREADABLE)) ADD_KEY(KEY_UNREADABLE);
982 if (IS_FLG(FLG_REALM1)) ADD_KEY(KEY_REALM1);
983 if (IS_FLG(FLG_REALM2)) ADD_KEY(KEY_REALM2);
984 if (IS_FLG(FLG_FIRST)) ADD_KEY(KEY_FIRST);
985 if (IS_FLG(FLG_SECOND)) ADD_KEY(KEY_SECOND);
986 if (IS_FLG(FLG_THIRD)) ADD_KEY(KEY_THIRD);
987 if (IS_FLG(FLG_FOURTH)) ADD_KEY(KEY_FOURTH);
988 if (IS_FLG(FLG_WANTED)) ADD_KEY(KEY_WANTED);
989 if (IS_FLG(FLG_UNIQUE)) ADD_KEY(KEY_UNIQUE);
990 if (IS_FLG(FLG_HUMAN)) ADD_KEY(KEY_HUMAN);
991 if (IS_FLG(FLG_WORTHLESS)) ADD_KEY(KEY_WORTHLESS);
992 if (IS_FLG(FLG_GOOD)) ADD_KEY(KEY_GOOD);
993 if (IS_FLG(FLG_NAMELESS)) ADD_KEY(KEY_NAMELESS);
994 if (IS_FLG(FLG_AVERAGE)) ADD_KEY(KEY_AVERAGE);
995 if (IS_FLG(FLG_RARE)) ADD_KEY(KEY_RARE);
996 if (IS_FLG(FLG_COMMON)) ADD_KEY(KEY_COMMON);
997 if (IS_FLG(FLG_EGO)) ADD_KEY(KEY_EGO);
999 if (IS_FLG(FLG_ARTIFACT)) ADD_KEY(KEY_ARTIFACT);
1001 bool sepa_flag = TRUE;
1002 if (IS_FLG(FLG_ITEMS)) ADD_KEY2(KEY_ITEMS);
1003 else if (IS_FLG(FLG_WEAPONS)) ADD_KEY2(KEY_WEAPONS);
1004 else if (IS_FLG(FLG_FAVORITE_WEAPONS)) ADD_KEY2(KEY_FAVORITE_WEAPONS);
1005 else if (IS_FLG(FLG_ARMORS)) ADD_KEY2(KEY_ARMORS);
1006 else if (IS_FLG(FLG_MISSILES)) ADD_KEY2(KEY_MISSILES);
1007 else if (IS_FLG(FLG_DEVICES)) ADD_KEY2(KEY_DEVICES);
1008 else if (IS_FLG(FLG_LIGHTS)) ADD_KEY2(KEY_LIGHTS);
1009 else if (IS_FLG(FLG_JUNKS)) ADD_KEY2(KEY_JUNKS);
1010 else if (IS_FLG(FLG_CORPSES)) ADD_KEY2(KEY_CORPSES);
1011 else if (IS_FLG(FLG_SPELLBOOKS)) ADD_KEY2(KEY_SPELLBOOKS);
1012 else if (IS_FLG(FLG_HAFTED)) ADD_KEY2(KEY_HAFTED);
1013 else if (IS_FLG(FLG_SHIELDS)) ADD_KEY2(KEY_SHIELDS);
1014 else if (IS_FLG(FLG_BOWS)) ADD_KEY2(KEY_BOWS);
1015 else if (IS_FLG(FLG_RINGS)) ADD_KEY2(KEY_RINGS);
1016 else if (IS_FLG(FLG_AMULETS)) ADD_KEY2(KEY_AMULETS);
1017 else if (IS_FLG(FLG_SUITS)) ADD_KEY2(KEY_SUITS);
1018 else if (IS_FLG(FLG_CLOAKS)) ADD_KEY2(KEY_CLOAKS);
1019 else if (IS_FLG(FLG_HELMS)) ADD_KEY2(KEY_HELMS);
1020 else if (IS_FLG(FLG_GLOVES)) ADD_KEY2(KEY_GLOVES);
1021 else if (IS_FLG(FLG_BOOTS)) ADD_KEY2(KEY_BOOTS);
1022 else if (!IS_FLG(FLG_ARTIFACT))
1025 if (entry->name && entry->name[0])
1027 if (sepa_flag) strcat(buf, ":");
1029 int i = strlen(buf);
1031 while (entry->name[j] && i < MAX_LINELEN - 2 - 1)
1034 if (iskanji(entry->name[j]))
1035 buf[i++] = entry->name[j++];
1037 buf[i++] = entry->name[j++];
1042 if (!entry->insc) return string_make(buf);
1048 while (entry->insc[j] && i < MAX_LINELEN - 2)
1051 if (iskanji(entry->insc[j]))
1052 buf[i++] = entry->insc[j++];
1054 buf[i++] = entry->insc[j++];
1058 return string_make(buf);
1063 * Reconstruct preference line from entry and kill entry
1065 static concptr autopick_line_from_entry_kill(autopick_type *entry)
1067 concptr ptr = autopick_line_from_entry(entry);
1068 autopick_free_entry(entry);
1074 * A function for Auto-picker/destroyer
1075 * Examine whether the object matches to the entry
1077 static bool is_autopick_aux(player_type *player_ptr, object_type *o_ptr, autopick_type *entry, concptr o_name)
1079 concptr ptr = entry->name;
1080 if (IS_FLG(FLG_UNAWARE) && object_is_aware(o_ptr))
1083 if (IS_FLG(FLG_UNIDENTIFIED)
1084 && (object_is_known(o_ptr) || (o_ptr->ident & IDENT_SENSE)))
1087 if (IS_FLG(FLG_IDENTIFIED) && !object_is_known(o_ptr))
1090 if (IS_FLG(FLG_STAR_IDENTIFIED) &&
1091 (!object_is_known(o_ptr) || !OBJECT_IS_FULL_KNOWN(o_ptr)))
1094 if (IS_FLG(FLG_BOOSTED))
1096 object_kind *k_ptr = &k_info[o_ptr->k_idx];
1097 if (!object_is_melee_weapon(o_ptr))
1100 if ((o_ptr->dd == k_ptr->dd) && (o_ptr->ds == k_ptr->ds))
1103 if (!object_is_known(o_ptr) && object_is_quest_target(o_ptr))
1109 if (IS_FLG(FLG_MORE_DICE))
1111 if (o_ptr->dd * o_ptr->ds < entry->dice)
1115 if (IS_FLG(FLG_MORE_BONUS))
1117 if (!object_is_known(o_ptr)) return FALSE;
1121 if (o_ptr->pval < entry->bonus) return FALSE;
1125 if (o_ptr->to_h < entry->bonus &&
1126 o_ptr->to_d < entry->bonus &&
1127 o_ptr->to_a < entry->bonus &&
1128 o_ptr->pval < entry->bonus)
1133 if (IS_FLG(FLG_WORTHLESS) && object_value(o_ptr) > 0)
1136 if (IS_FLG(FLG_ARTIFACT))
1138 if (!object_is_known(o_ptr) || !object_is_artifact(o_ptr))
1142 if (IS_FLG(FLG_EGO))
1144 if (!object_is_ego(o_ptr)) return FALSE;
1145 if (!object_is_known(o_ptr) &&
1146 !((o_ptr->ident & IDENT_SENSE) && o_ptr->feeling == FEEL_EXCELLENT))
1150 if (IS_FLG(FLG_GOOD))
1152 if (!object_is_equipment(o_ptr)) return FALSE;
1153 if (object_is_known(o_ptr))
1155 if (!object_is_nameless(o_ptr))
1158 if (o_ptr->to_a <= 0 && (o_ptr->to_h + o_ptr->to_d) <= 0)
1161 else if (o_ptr->ident & IDENT_SENSE)
1163 switch (o_ptr->feeling)
1178 if (IS_FLG(FLG_NAMELESS))
1180 if (!object_is_equipment(o_ptr)) return FALSE;
1181 if (object_is_known(o_ptr))
1183 if (!object_is_nameless(o_ptr))
1186 else if (o_ptr->ident & IDENT_SENSE)
1188 switch (o_ptr->feeling)
1206 if (IS_FLG(FLG_AVERAGE))
1208 if (!object_is_equipment(o_ptr)) return FALSE;
1209 if (object_is_known(o_ptr))
1211 if (!object_is_nameless(o_ptr))
1214 if (object_is_cursed(o_ptr) || object_is_broken(o_ptr))
1217 if (o_ptr->to_a > 0 || (o_ptr->to_h + o_ptr->to_d) > 0)
1220 else if (o_ptr->ident & IDENT_SENSE)
1222 switch (o_ptr->feeling)
1237 if (IS_FLG(FLG_RARE) && !object_is_rare(o_ptr))
1240 if (IS_FLG(FLG_COMMON) && object_is_rare(o_ptr))
1243 if (IS_FLG(FLG_WANTED) && !object_is_bounty(o_ptr))
1246 if (IS_FLG(FLG_UNIQUE) &&
1247 ((o_ptr->tval != TV_CORPSE && o_ptr->tval != TV_STATUE) ||
1248 !(r_info[o_ptr->pval].flags1 & RF1_UNIQUE)))
1251 if (IS_FLG(FLG_HUMAN) &&
1252 (o_ptr->tval != TV_CORPSE ||
1253 !my_strchr("pht", r_info[o_ptr->pval].d_char)))
1256 if (IS_FLG(FLG_UNREADABLE) &&
1257 (o_ptr->tval < TV_LIFE_BOOK ||
1258 check_book_realm(player_ptr, o_ptr->tval, o_ptr->sval)))
1261 if (IS_FLG(FLG_REALM1) &&
1262 (REALM1_BOOK != o_ptr->tval ||
1263 player_ptr->pclass == CLASS_SORCERER ||
1264 player_ptr->pclass == CLASS_RED_MAGE))
1267 if (IS_FLG(FLG_REALM2) &&
1268 (REALM2_BOOK != o_ptr->tval ||
1269 player_ptr->pclass == CLASS_SORCERER ||
1270 player_ptr->pclass == CLASS_RED_MAGE))
1273 if (IS_FLG(FLG_FIRST) &&
1274 (o_ptr->tval < TV_LIFE_BOOK || 0 != o_ptr->sval))
1277 if (IS_FLG(FLG_SECOND) &&
1278 (o_ptr->tval < TV_LIFE_BOOK || 1 != o_ptr->sval))
1281 if (IS_FLG(FLG_THIRD) &&
1282 (o_ptr->tval < TV_LIFE_BOOK || 2 != o_ptr->sval))
1285 if (IS_FLG(FLG_FOURTH) &&
1286 (o_ptr->tval < TV_LIFE_BOOK || 3 != o_ptr->sval))
1289 if (IS_FLG(FLG_WEAPONS))
1291 if (!object_is_weapon(o_ptr))
1294 else if (IS_FLG(FLG_FAVORITE_WEAPONS))
1296 if (!object_is_favorite(o_ptr))
1299 else if (IS_FLG(FLG_ARMORS))
1301 if (!object_is_armour(o_ptr))
1304 else if (IS_FLG(FLG_MISSILES))
1306 if (!object_is_ammo(o_ptr)) return FALSE;
1308 else if (IS_FLG(FLG_DEVICES))
1310 switch (o_ptr->tval)
1312 case TV_SCROLL: case TV_STAFF: case TV_WAND: case TV_ROD:
1314 default: return FALSE;
1317 else if (IS_FLG(FLG_LIGHTS))
1319 if (!(o_ptr->tval == TV_LITE))
1322 else if (IS_FLG(FLG_JUNKS))
1324 switch (o_ptr->tval)
1326 case TV_SKELETON: case TV_BOTTLE:
1327 case TV_JUNK: case TV_STATUE:
1329 default: return FALSE;
1332 else if (IS_FLG(FLG_CORPSES))
1334 if (o_ptr->tval != TV_CORPSE && o_ptr->tval != TV_SKELETON)
1337 else if (IS_FLG(FLG_SPELLBOOKS))
1339 if (!(o_ptr->tval >= TV_LIFE_BOOK))
1342 else if (IS_FLG(FLG_HAFTED))
1344 if (!(o_ptr->tval == TV_HAFTED))
1347 else if (IS_FLG(FLG_SHIELDS))
1349 if (!(o_ptr->tval == TV_SHIELD))
1352 else if (IS_FLG(FLG_BOWS))
1354 if (!(o_ptr->tval == TV_BOW))
1357 else if (IS_FLG(FLG_RINGS))
1359 if (!(o_ptr->tval == TV_RING))
1362 else if (IS_FLG(FLG_AMULETS))
1364 if (!(o_ptr->tval == TV_AMULET))
1367 else if (IS_FLG(FLG_SUITS))
1369 if (!(o_ptr->tval == TV_DRAG_ARMOR ||
1370 o_ptr->tval == TV_HARD_ARMOR ||
1371 o_ptr->tval == TV_SOFT_ARMOR))
1374 else if (IS_FLG(FLG_CLOAKS))
1376 if (!(o_ptr->tval == TV_CLOAK))
1379 else if (IS_FLG(FLG_HELMS))
1381 if (!(o_ptr->tval == TV_CROWN || o_ptr->tval == TV_HELM))
1384 else if (IS_FLG(FLG_GLOVES))
1386 if (!(o_ptr->tval == TV_GLOVES))
1389 else if (IS_FLG(FLG_BOOTS))
1391 if (!(o_ptr->tval == TV_BOOTS))
1398 if (strncmp(o_name, ptr, strlen(ptr))) return FALSE;
1402 if (!my_strstr(o_name, ptr)) return FALSE;
1405 if (!IS_FLG(FLG_COLLECTING)) return TRUE;
1407 for (int j = 0; j < INVEN_PACK; j++)
1410 * 'Collecting' means the item must be absorbed
1411 * into an inventory slot.
1412 * But an item can not be absorbed into itself!
1414 if ((&player_ptr->inventory_list[j] != o_ptr) &&
1415 object_similar(&player_ptr->inventory_list[j], o_ptr))
1424 * A function for Auto-picker/destroyer
1425 * Examine whether the object matches to the list of keywords or not.
1427 int is_autopick(player_type *player_ptr, object_type *o_ptr)
1429 GAME_TEXT o_name[MAX_NLEN];
1430 if (o_ptr->tval == TV_GOLD) return -1;
1432 object_desc(player_ptr, o_name, o_ptr, (OD_NO_FLAVOR | OD_OMIT_PREFIX | OD_NO_PLURAL));
1433 str_tolower(o_name);
1434 for (int i = 0; i < max_autopick; i++)
1436 autopick_type *entry = &autopick_list[i];
1437 if (is_autopick_aux(player_ptr, o_ptr, entry, o_name))
1448 static void auto_inscribe_item(player_type *player_ptr, object_type *o_ptr, int idx)
1450 if (idx < 0 || !autopick_list[idx].insc) return;
1452 if (!o_ptr->inscription)
1453 o_ptr->inscription = quark_add(autopick_list[idx].insc);
1455 player_ptr->window |= (PW_EQUIP | PW_INVEN);
1456 player_ptr->update |= (PU_BONUS);
1461 * Automatically destroy items in this grid.
1463 static bool is_opt_confirm_destroy(player_type *player_ptr, object_type *o_ptr)
1465 if (!destroy_items) return FALSE;
1468 if (object_value(o_ptr) > 0) return FALSE;
1471 if (object_is_weapon_armour_ammo(o_ptr)) return FALSE;
1474 if ((o_ptr->tval == TV_CHEST) && o_ptr->pval) return FALSE;
1478 if (object_is_bounty(o_ptr)) return FALSE;
1482 if (o_ptr->tval == TV_CORPSE) return FALSE;
1485 if ((o_ptr->tval == TV_SKELETON) || (o_ptr->tval == TV_BOTTLE) || (o_ptr->tval == TV_JUNK) || (o_ptr->tval == TV_STATUE)) return FALSE;
1489 if (player_ptr->prace == RACE_DEMON)
1491 if (o_ptr->tval == TV_CORPSE &&
1492 o_ptr->sval == SV_CORPSE &&
1493 my_strchr("pht", r_info[o_ptr->pval].d_char))
1497 if (player_ptr->pclass == CLASS_ARCHER)
1499 if (o_ptr->tval == TV_SKELETON ||
1500 (o_ptr->tval == TV_CORPSE && o_ptr->sval == SV_SKELETON))
1503 else if (player_ptr->pclass == CLASS_NINJA)
1505 if (o_ptr->tval == TV_LITE &&
1506 o_ptr->name2 == EGO_LITE_DARKNESS && object_is_known(o_ptr))
1509 else if (player_ptr->pclass == CLASS_BEASTMASTER ||
1510 player_ptr->pclass == CLASS_CAVALRY)
1512 if (o_ptr->tval == TV_WAND &&
1513 o_ptr->sval == SV_WAND_HEAL_MONSTER && object_is_aware(o_ptr))
1518 if (o_ptr->tval == TV_GOLD) return FALSE;
1524 static void auto_destroy_item(player_type *player_ptr, object_type *o_ptr, int autopick_idx)
1526 bool destroy = FALSE;
1527 if (is_opt_confirm_destroy(player_ptr, o_ptr)) destroy = TRUE;
1529 if (autopick_idx >= 0 &&
1530 !(autopick_list[autopick_idx].action & DO_AUTODESTROY))
1535 if (autopick_idx >= 0 &&
1536 (autopick_list[autopick_idx].action & DO_AUTODESTROY))
1540 if (!destroy) return;
1542 disturb(player_ptr, FALSE, FALSE);
1543 if (!can_player_destroy_object(o_ptr))
1545 GAME_TEXT o_name[MAX_NLEN];
1546 object_desc(player_ptr, o_name, o_ptr, 0);
1547 msg_format(_("%sは破壊不能だ。", "You cannot auto-destroy %s."), o_name);
1551 (void)COPY(&autopick_last_destroyed_object, o_ptr, object_type);
1552 o_ptr->marked |= OM_AUTODESTROY;
1553 player_ptr->update |= PU_AUTODESTROY;
1558 * Auto-destroy marked item
1560 static void autopick_delayed_alter_aux(player_type *player_ptr, INVENTORY_IDX item)
1563 o_ptr = REF_ITEM(player_ptr, player_ptr->current_floor_ptr, item);
1565 if (o_ptr->k_idx == 0 || !(o_ptr->marked & OM_AUTODESTROY)) return;
1567 GAME_TEXT o_name[MAX_NLEN];
1568 object_desc(player_ptr, o_name, o_ptr, 0);
1571 inven_item_increase(player_ptr, item, -(o_ptr->number));
1572 inven_item_optimize(player_ptr, item);
1576 delete_object_idx(player_ptr, 0 - item);
1579 msg_format(_("%sを自動破壊します。", "Auto-destroying %s."), o_name);
1584 * Auto-destroy marked items in inventry and on floor
1586 void autopick_delayed_alter(player_type *owner_ptr)
1591 * Scan inventry in reverse order to prevent
1592 * skipping after inven_item_optimize()
1594 for (item = INVEN_TOTAL - 1; item >= 0; item--)
1595 autopick_delayed_alter_aux(owner_ptr, item);
1597 floor_type *floor_ptr = owner_ptr->current_floor_ptr;
1598 item = floor_ptr->grid_array[owner_ptr->y][owner_ptr->x].o_idx;
1601 OBJECT_IDX next = floor_ptr->o_list[item].next_o_idx;
1602 autopick_delayed_alter_aux(owner_ptr, -item);
1609 * Auto-inscription and/or destroy
1611 * Auto-destroyer works only on inventory or on floor stack only when
1614 void autopick_alter_item(player_type *player_ptr, INVENTORY_IDX item, bool destroy)
1617 o_ptr = REF_ITEM(player_ptr, player_ptr->current_floor_ptr, item);
1618 int idx = is_autopick(player_ptr, o_ptr);
1619 auto_inscribe_item(player_ptr, o_ptr, idx);
1620 if (destroy && item <= INVEN_PACK)
1621 auto_destroy_item(player_ptr, o_ptr, idx);
1626 * Automatically pickup/destroy items in this grid.
1628 void autopick_pickup_items(player_type* player_ptr, grid_type *g_ptr)
1630 OBJECT_IDX this_o_idx, next_o_idx = 0;
1631 for (this_o_idx = g_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx)
1633 object_type *o_ptr = &player_ptr->current_floor_ptr->o_list[this_o_idx];
1634 next_o_idx = o_ptr->next_o_idx;
1635 int idx = is_autopick(player_ptr, o_ptr);
1636 auto_inscribe_item(player_ptr, o_ptr, idx);
1637 bool is_auto_pickup = idx >= 0;
1638 is_auto_pickup &= (autopick_list[idx].action & (DO_AUTOPICK | DO_QUERY_AUTOPICK)) != 0;
1639 if (!is_auto_pickup)
1641 auto_destroy_item(player_ptr, o_ptr, idx);
1645 disturb(player_ptr, FALSE, FALSE);
1646 if (!inven_carry_okay(o_ptr))
1648 GAME_TEXT o_name[MAX_NLEN];
1649 object_desc(player_ptr, o_name, o_ptr, 0);
1650 msg_format(_("ザックには%sを入れる隙間がない。", "You have no room for %s."), o_name);
1651 o_ptr->marked |= OM_NOMSG;
1655 if (!(autopick_list[idx].action & DO_QUERY_AUTOPICK))
1657 py_pickup_aux(player_ptr, this_o_idx);
1661 char out_val[MAX_NLEN + 20];
1662 GAME_TEXT o_name[MAX_NLEN];
1663 if (o_ptr->marked & OM_NO_QUERY)
1668 object_desc(player_ptr, o_name, o_ptr, 0);
1669 sprintf(out_val, _("%sを拾いますか? ", "Pick up %s? "), o_name);
1670 if (!get_check(out_val))
1672 o_ptr->marked |= OM_NOMSG | OM_NO_QUERY;
1676 py_pickup_aux(player_ptr, this_o_idx);
1681 static const char autoregister_header[] = "?:$AUTOREGISTER";
1684 * Clear auto registered lines in the picktype.prf .
1686 static bool clear_auto_register(player_type *player_ptr)
1688 char tmp_file[1024];
1689 char pref_file[1024];
1694 bool autoregister = FALSE;
1697 path_build(pref_file, sizeof(pref_file), ANGBAND_DIR_USER, pickpref_filename(player_ptr, PT_WITH_PNAME));
1698 pref_fff = my_fopen(pref_file, "r");
1702 path_build(pref_file, sizeof(pref_file), ANGBAND_DIR_USER, pickpref_filename(player_ptr, PT_DEFAULT));
1703 pref_fff = my_fopen(pref_file, "r");
1711 tmp_fff = my_fopen_temp(tmp_file, sizeof(tmp_file));
1715 msg_format(_("一時ファイル %s を作成できませんでした。", "Failed to create temporary file %s."), tmp_file);
1722 if (my_fgets(pref_fff, buf, sizeof(buf))) break;
1726 if (buf[0] != '#' && buf[0] != '?') num++;
1730 if (streq(buf, autoregister_header))
1732 autoregister = TRUE;
1736 fprintf(tmp_fff, "%s\n", buf);
1740 my_fclose(pref_fff);
1745 msg_format(_("以前のキャラクター用の自動設定(%d行)が残っています。",
1746 "Auto registered lines (%d lines) for previous character are remaining."), num);
1747 strcpy(buf, _("古い設定行は削除します。よろしいですか?", "These lines will be deleted. Are you sure? "));
1749 if (!get_check(buf))
1752 autoregister = FALSE;
1754 msg_print(_("エディタのカット&ペースト等を使って必要な行を避難してください。",
1755 "Use cut & paste of auto picker editor (_) to keep old prefs."));
1761 tmp_fff = my_fopen(tmp_file, "r");
1762 pref_fff = my_fopen(pref_file, "w");
1764 while (!my_fgets(tmp_fff, buf, sizeof(buf)))
1765 fprintf(pref_fff, "%s\n", buf);
1767 my_fclose(pref_fff);
1777 * Automatically register an auto-destroy preference line
1779 bool autopick_autoregister(player_type *player_ptr, object_type *o_ptr)
1782 char pref_file[1024];
1784 autopick_type an_entry, *entry = &an_entry;
1785 int match_autopick = is_autopick(player_ptr, o_ptr);
1786 if (match_autopick != -1)
1789 byte act = autopick_list[match_autopick].action;
1790 if (act & DO_AUTOPICK) what = _("自動で拾う", "auto-pickup");
1791 else if (act & DO_AUTODESTROY) what = _("自動破壊する", "auto-destroy");
1792 else if (act & DONT_AUTOPICK) what = _("放置する", "leave on floor");
1793 else what = _("確認して拾う", "query auto-pickup");
1795 msg_format(_("そのアイテムは既に%sように設定されています。", "The object is already registered to %s."), what);
1799 if ((object_is_known(o_ptr) && object_is_artifact(o_ptr)) ||
1800 ((o_ptr->ident & IDENT_SENSE) &&
1801 (o_ptr->feeling == FEEL_TERRIBLE || o_ptr->feeling == FEEL_SPECIAL)))
1803 GAME_TEXT o_name[MAX_NLEN];
1804 object_desc(player_ptr, o_name, o_ptr, 0);
1805 msg_format(_("%sは破壊不能だ。", "You cannot auto-destroy %s."), o_name);
1809 if (!player_ptr->autopick_autoregister)
1811 if (!clear_auto_register(player_ptr)) return FALSE;
1814 path_build(pref_file, sizeof(pref_file), ANGBAND_DIR_USER, pickpref_filename(player_ptr, PT_WITH_PNAME));
1815 pref_fff = my_fopen(pref_file, "r");
1819 path_build(pref_file, sizeof(pref_file), ANGBAND_DIR_USER, pickpref_filename(player_ptr, PT_DEFAULT));
1820 pref_fff = my_fopen(pref_file, "r");
1827 if (my_fgets(pref_fff, buf, sizeof(buf)))
1829 player_ptr->autopick_autoregister = FALSE;
1833 if (streq(buf, autoregister_header))
1835 player_ptr->autopick_autoregister = TRUE;
1845 * File could not be opened for reading. Assume header not
1848 player_ptr->autopick_autoregister = FALSE;
1851 pref_fff = my_fopen(pref_file, "a");
1854 msg_format(_("%s を開くことができませんでした。", "Failed to open %s."), pref_file);
1859 if (!player_ptr->autopick_autoregister)
1861 fprintf(pref_fff, "%s\n", autoregister_header);
1863 fprintf(pref_fff, "%s\n", _("# *警告!!* 以降の行は自動登録されたものです。",
1864 "# *Warning!* The lines below will be deleted later."));
1865 fprintf(pref_fff, "%s\n", _("# 後で自動的に削除されますので、必要な行は上の方へ移動しておいてください。",
1866 "# Keep it by cut & paste if you need these lines for future characters."));
1867 player_ptr->autopick_autoregister = TRUE;
1870 autopick_entry_from_object(player_ptr, entry, o_ptr);
1871 entry->action = DO_AUTODESTROY;
1872 add_autopick_list(entry);
1874 concptr tmp = autopick_line_from_entry(entry);
1875 fprintf(pref_fff, "%s\n", tmp);
1883 * Describe which kind of object is Auto-picked/destroyed
1885 static void describe_autopick(char *buff, autopick_type *entry)
1887 concptr str = entry->name;
1888 byte act = entry->action;
1889 concptr insc = entry->insc;
1895 concptr before_str[100], body_str;
1899 if (IS_FLG(FLG_COLLECTING))
1900 before_str[before_n++] = "収集中で既に持っているスロットにまとめられる";
1902 if (IS_FLG(FLG_UNAWARE))
1903 before_str[before_n++] = "未鑑定でその効果も判明していない";
1905 if (IS_FLG(FLG_UNIDENTIFIED))
1906 before_str[before_n++] = "未鑑定の";
1908 if (IS_FLG(FLG_IDENTIFIED))
1909 before_str[before_n++] = "鑑定済みの";
1911 if (IS_FLG(FLG_STAR_IDENTIFIED))
1912 before_str[before_n++] = "完全に鑑定済みの";
1914 if (IS_FLG(FLG_BOOSTED))
1916 before_str[before_n++] = "ダメージダイスが通常より大きい";
1920 if (IS_FLG(FLG_MORE_DICE))
1922 static char more_than_desc_str[] = "___";
1923 before_str[before_n++] = "ダメージダイスの最大値が";
1926 sprintf(more_than_desc_str, "%d", entry->dice);
1927 before_str[before_n++] = more_than_desc_str;
1928 before_str[before_n++] = "以上の";
1931 if (IS_FLG(FLG_MORE_BONUS))
1933 static char more_bonus_desc_str[] = "___";
1934 before_str[before_n++] = "修正値が(+";
1936 sprintf(more_bonus_desc_str, "%d", entry->bonus);
1937 before_str[before_n++] = more_bonus_desc_str;
1938 before_str[before_n++] = ")以上の";
1941 if (IS_FLG(FLG_WORTHLESS))
1942 before_str[before_n++] = "店で無価値と判定される";
1944 if (IS_FLG(FLG_ARTIFACT))
1946 before_str[before_n++] = "アーティファクトの";
1950 if (IS_FLG(FLG_EGO))
1952 before_str[before_n++] = "エゴアイテムの";
1956 if (IS_FLG(FLG_GOOD))
1958 before_str[before_n++] = "上質の";
1962 if (IS_FLG(FLG_NAMELESS))
1964 before_str[before_n++] = "エゴでもアーティファクトでもない";
1968 if (IS_FLG(FLG_AVERAGE))
1970 before_str[before_n++] = "並の";
1974 if (IS_FLG(FLG_RARE))
1976 before_str[before_n++] = "ドラゴン装備やカオス・ブレード等を含む珍しい";
1980 if (IS_FLG(FLG_COMMON))
1982 before_str[before_n++] = "ありふれた(ドラゴン装備やカオス・ブレード等の珍しい物ではない)";
1986 if (IS_FLG(FLG_WANTED))
1988 before_str[before_n++] = "ハンター事務所で賞金首とされている";
1992 if (IS_FLG(FLG_HUMAN))
1994 before_str[before_n++] = "悪魔魔法で使うための人間やヒューマノイドの";
1998 if (IS_FLG(FLG_UNIQUE))
2000 before_str[before_n++] = "ユニークモンスターの";
2004 if (IS_FLG(FLG_UNREADABLE))
2006 before_str[before_n++] = "あなたが読めない領域の";
2010 if (IS_FLG(FLG_REALM1))
2012 before_str[before_n++] = "第一領域の";
2016 if (IS_FLG(FLG_REALM2))
2018 before_str[before_n++] = "第二領域の";
2022 if (IS_FLG(FLG_FIRST))
2024 before_str[before_n++] = "全4冊の内の1冊目の";
2028 if (IS_FLG(FLG_SECOND))
2030 before_str[before_n++] = "全4冊の内の2冊目の";
2034 if (IS_FLG(FLG_THIRD))
2036 before_str[before_n++] = "全4冊の内の3冊目の";
2040 if (IS_FLG(FLG_FOURTH))
2042 before_str[before_n++] = "全4冊の内の4冊目の";
2046 if (IS_FLG(FLG_ITEMS))
2047 ; /* Nothing to do */
2048 else if (IS_FLG(FLG_WEAPONS))
2050 else if (IS_FLG(FLG_FAVORITE_WEAPONS))
2052 else if (IS_FLG(FLG_ARMORS))
2054 else if (IS_FLG(FLG_MISSILES))
2055 body_str = "弾や矢やクロスボウの矢";
2056 else if (IS_FLG(FLG_DEVICES))
2057 body_str = "巻物や魔法棒や杖やロッド";
2058 else if (IS_FLG(FLG_LIGHTS))
2059 body_str = "光源用のアイテム";
2060 else if (IS_FLG(FLG_JUNKS))
2061 body_str = "折れた棒等のガラクタ";
2062 else if (IS_FLG(FLG_CORPSES))
2064 else if (IS_FLG(FLG_SPELLBOOKS))
2066 else if (IS_FLG(FLG_HAFTED))
2068 else if (IS_FLG(FLG_SHIELDS))
2070 else if (IS_FLG(FLG_BOWS))
2071 body_str = "スリングや弓やクロスボウ";
2072 else if (IS_FLG(FLG_RINGS))
2074 else if (IS_FLG(FLG_AMULETS))
2075 body_str = "アミュレット";
2076 else if (IS_FLG(FLG_SUITS))
2078 else if (IS_FLG(FLG_CLOAKS))
2080 else if (IS_FLG(FLG_HELMS))
2081 body_str = "ヘルメットや冠";
2082 else if (IS_FLG(FLG_GLOVES))
2084 else if (IS_FLG(FLG_BOOTS))
2089 strcat(buff, "全ての");
2090 else for (i = 0; i < before_n && before_str[i]; i++)
2091 strcat(buff, before_str[i]);
2093 strcat(buff, body_str);
2103 strcat(buff, "で、名前が「");
2104 strncat(buff, str, 80);
2106 strcat(buff, "」で始まるもの");
2108 strcat(buff, "」を含むもの");
2113 strncat(buff, format("に「%s」", insc), 80);
2115 if (my_strstr(insc, "%%all"))
2116 strcat(buff, "(%%allは全能力を表す英字の記号で置換)");
2117 else if (my_strstr(insc, "%all"))
2118 strcat(buff, "(%allは全能力を表す記号で置換)");
2119 else if (my_strstr(insc, "%%"))
2120 strcat(buff, "(%%は追加能力を表す英字の記号で置換)");
2121 else if (my_strstr(insc, "%"))
2122 strcat(buff, "(%は追加能力を表す記号で置換)");
2124 strcat(buff, "と刻んで");
2129 if (act & DONT_AUTOPICK)
2130 strcat(buff, "放置する。");
2131 else if (act & DO_AUTODESTROY)
2132 strcat(buff, "破壊する。");
2133 else if (act & DO_QUERY_AUTOPICK)
2134 strcat(buff, "確認の後に拾う。");
2136 strcat(buff, "拾う。");
2138 if (act & DO_DISPLAY)
2140 if (act & DONT_AUTOPICK)
2141 strcat(buff, "全体マップ('M')で'N'を押したときに表示する。");
2142 else if (act & DO_AUTODESTROY)
2143 strcat(buff, "全体マップ('M')で'K'を押したときに表示する。");
2145 strcat(buff, "全体マップ('M')で'M'を押したときに表示する。");
2148 strcat(buff, "全体マップには表示しない。");
2152 concptr before_str[20], after_str[20], which_str[20], whose_str[20], body_str;
2153 int before_n = 0, after_n = 0, which_n = 0, whose_n = 0;
2155 if (IS_FLG(FLG_COLLECTING))
2156 which_str[which_n++] = "can be absorbed into an existing inventory list slot";
2158 if (IS_FLG(FLG_UNAWARE))
2160 before_str[before_n++] = "unidentified";
2161 whose_str[whose_n++] = "basic abilities are not known";
2164 if (IS_FLG(FLG_UNIDENTIFIED))
2165 before_str[before_n++] = "unidentified";
2167 if (IS_FLG(FLG_IDENTIFIED))
2168 before_str[before_n++] = "identified";
2170 if (IS_FLG(FLG_STAR_IDENTIFIED))
2171 before_str[before_n++] = "fully identified";
2173 if (IS_FLG(FLG_RARE))
2175 before_str[before_n++] = "very rare";
2176 body_str = "equipments";
2177 after_str[after_n++] = "such as Dragon armor, Blades of Chaos, etc.";
2180 if (IS_FLG(FLG_COMMON))
2182 before_str[before_n++] = "relatively common";
2183 body_str = "equipments";
2184 after_str[after_n++] = "compared to very rare Dragon armor, Blades of Chaos, etc.";
2187 if (IS_FLG(FLG_WORTHLESS))
2189 before_str[before_n++] = "worthless";
2190 which_str[which_n++] = "can not be sold at stores";
2193 if (IS_FLG(FLG_ARTIFACT))
2195 before_str[before_n++] = "artifact";
2198 if (IS_FLG(FLG_EGO))
2200 before_str[before_n++] = "ego";
2203 if (IS_FLG(FLG_GOOD))
2205 body_str = "equipment";
2206 which_str[which_n++] = "have good quality";
2209 if (IS_FLG(FLG_NAMELESS))
2211 body_str = "equipment";
2212 which_str[which_n++] = "is neither ego-item nor artifact";
2215 if (IS_FLG(FLG_AVERAGE))
2217 body_str = "equipment";
2218 which_str[which_n++] = "have average quality";
2221 if (IS_FLG(FLG_BOOSTED))
2223 body_str = "weapons";
2224 whose_str[whose_n++] = "damage dice is bigger than normal";
2227 if (IS_FLG(FLG_MORE_DICE))
2229 static char more_than_desc_str[] =
2230 "maximum damage from dice is bigger than __";
2231 body_str = "weapons";
2233 sprintf(more_than_desc_str + sizeof(more_than_desc_str) - 3,
2235 whose_str[whose_n++] = more_than_desc_str;
2238 if (IS_FLG(FLG_MORE_BONUS))
2240 static char more_bonus_desc_str[] =
2241 "magical bonus is bigger than (+__)";
2243 sprintf(more_bonus_desc_str + sizeof(more_bonus_desc_str) - 4,
2244 "%d)", entry->bonus);
2245 whose_str[whose_n++] = more_bonus_desc_str;
2248 if (IS_FLG(FLG_WANTED))
2250 body_str = "corpse or skeletons";
2251 which_str[which_n++] = "is wanted at the Hunter's Office";
2254 if (IS_FLG(FLG_HUMAN))
2256 before_str[before_n++] = "humanoid";
2257 body_str = "corpse or skeletons";
2258 which_str[which_n++] = "can be used for Daemon magic";
2261 if (IS_FLG(FLG_UNIQUE))
2263 before_str[before_n++] = "unique monster's";
2264 body_str = "corpse or skeletons";
2267 if (IS_FLG(FLG_UNREADABLE))
2269 body_str = "spellbooks";
2270 after_str[after_n++] = "of different realms from yours";
2273 if (IS_FLG(FLG_REALM1))
2275 body_str = "spellbooks";
2276 after_str[after_n++] = "of your first realm";
2279 if (IS_FLG(FLG_REALM2))
2281 body_str = "spellbooks";
2282 after_str[after_n++] = "of your second realm";
2285 if (IS_FLG(FLG_FIRST))
2287 before_str[before_n++] = "first one of four";
2288 body_str = "spellbooks";
2291 if (IS_FLG(FLG_SECOND))
2293 before_str[before_n++] = "second one of four";
2294 body_str = "spellbooks";
2297 if (IS_FLG(FLG_THIRD))
2299 before_str[before_n++] = "third one of four";
2300 body_str = "spellbooks";
2303 if (IS_FLG(FLG_FOURTH))
2305 before_str[before_n++] = "fourth one of four";
2306 body_str = "spellbooks";
2309 if (IS_FLG(FLG_ITEMS))
2310 ; /* Nothing to do */
2311 else if (IS_FLG(FLG_WEAPONS))
2312 body_str = "weapons";
2313 else if (IS_FLG(FLG_FAVORITE_WEAPONS))
2314 body_str = "favorite weapons";
2315 else if (IS_FLG(FLG_ARMORS))
2316 body_str = "armors";
2317 else if (IS_FLG(FLG_MISSILES))
2318 body_str = "shots, arrows or crossbow bolts";
2319 else if (IS_FLG(FLG_DEVICES))
2320 body_str = "scrolls, wands, staffs or rods";
2321 else if (IS_FLG(FLG_LIGHTS))
2322 body_str = "light sources";
2323 else if (IS_FLG(FLG_JUNKS))
2324 body_str = "junk such as broken sticks";
2325 else if (IS_FLG(FLG_CORPSES))
2326 body_str = "corpses or skeletons";
2327 else if (IS_FLG(FLG_SPELLBOOKS))
2328 body_str = "spellbooks";
2329 else if (IS_FLG(FLG_HAFTED))
2330 body_str = "hafted weapons";
2331 else if (IS_FLG(FLG_SHIELDS))
2332 body_str = "shields";
2333 else if (IS_FLG(FLG_BOWS))
2334 body_str = "slings, bows or crossbows";
2335 else if (IS_FLG(FLG_RINGS))
2337 else if (IS_FLG(FLG_AMULETS))
2338 body_str = "amulets";
2339 else if (IS_FLG(FLG_SUITS))
2340 body_str = "body armors";
2341 else if (IS_FLG(FLG_CLOAKS))
2342 body_str = "cloaks";
2343 else if (IS_FLG(FLG_HELMS))
2344 body_str = "helms or crowns";
2345 else if (IS_FLG(FLG_GLOVES))
2346 body_str = "gloves";
2347 else if (IS_FLG(FLG_BOOTS))
2356 whose_str[whose_n++] = "name begins with \"";
2359 which_str[which_n++] = "have \"";
2363 if (act & DONT_AUTOPICK)
2364 strcpy(buff, "Leave on floor ");
2365 else if (act & DO_AUTODESTROY)
2366 strcpy(buff, "Destroy ");
2367 else if (act & DO_QUERY_AUTOPICK)
2368 strcpy(buff, "Ask to pick up ");
2370 strcpy(buff, "Pickup ");
2374 strncat(buff, format("and inscribe \"%s\"", insc), 80);
2376 if (my_strstr(insc, "%all"))
2377 strcat(buff, ", replacing %all with code string representing all abilities,");
2378 else if (my_strstr(insc, "%"))
2379 strcat(buff, ", replacing % with code string representing extra random abilities,");
2381 strcat(buff, " on ");
2385 strcat(buff, "all ");
2386 else for (i = 0; i < before_n && before_str[i]; i++)
2388 strcat(buff, before_str[i]);
2392 strcat(buff, body_str);
2394 for (i = 0; i < after_n && after_str[i]; i++)
2397 strcat(buff, after_str[i]);
2400 for (i = 0; i < whose_n && whose_str[i]; i++)
2403 strcat(buff, " whose ");
2405 strcat(buff, ", and ");
2407 strcat(buff, whose_str[i]);
2416 if (whose_n && which_n)
2417 strcat(buff, ", and ");
2419 for (i = 0; i < which_n && which_str[i]; i++)
2422 strcat(buff, " which ");
2424 strcat(buff, ", and ");
2426 strcat(buff, which_str[i]);
2431 strncat(buff, str, 80);
2432 strcat(buff, "\" as part of its name");
2436 if (act & DO_DISPLAY)
2438 if (act & DONT_AUTOPICK)
2439 strcat(buff, " Display these items when you press the N key in the full 'M'ap.");
2440 else if (act & DO_AUTODESTROY)
2441 strcat(buff, " Display these items when you press the K key in the full 'M'ap.");
2443 strcat(buff, " Display these items when you press the M key in the full 'M'ap.");
2446 strcat(buff, " Not displayed in the full map.");
2452 * Read whole lines of a file to memory
2454 static concptr *read_text_lines(concptr filename)
2456 concptr *lines_list = NULL;
2462 path_build(buf, sizeof(buf), ANGBAND_DIR_USER, filename);
2463 fff = my_fopen(buf, "r");
2464 if (!fff) return NULL;
2466 C_MAKE(lines_list, MAX_LINES, concptr);
2467 while (my_fgets(fff, buf, sizeof(buf)) == 0)
2469 lines_list[lines++] = string_make(buf);
2470 if (lines >= MAX_LINES - 1) break;
2474 lines_list[0] = string_make("");
2482 * Copy the default autopick file to the user directory
2484 static void prepare_default_pickpref(player_type *player_ptr)
2486 const concptr messages[] = {
2487 _("あなたは「自動拾いエディタ」を初めて起動しました。", "You have activated the Auto-Picker Editor for the first time."),
2488 _("自動拾いのユーザー設定ファイルがまだ書かれていないので、", "Since user pref file for autopick is not yet created,"),
2489 _("基本的な自動拾い設定ファイルをlib/pref/picktype.prfからコピーします。", "the default setting is loaded from lib/pref/pickpref.prf ."),
2493 concptr filename = pickpref_filename(player_ptr, PT_DEFAULT);
2494 for (int i = 0; messages[i]; i++)
2496 msg_print(messages[i]);
2501 path_build(buf, sizeof(buf), ANGBAND_DIR_USER, filename);
2503 user_fp = my_fopen(buf, "w");
2504 if (!user_fp) return;
2506 fprintf(user_fp, "#***\n");
2507 for (int i = 0; messages[i]; i++)
2509 fprintf(user_fp, "#*** %s\n", messages[i]);
2512 fprintf(user_fp, "#***\n\n\n");
2513 path_build(buf, sizeof(buf), ANGBAND_DIR_PREF, filename);
2515 pref_fp = my_fopen(buf, "r");
2523 while (!my_fgets(pref_fp, buf, sizeof(buf)))
2525 fprintf(user_fp, "%s\n", buf);
2533 * Read an autopick prefence file to memory
2534 * Prepare default if no user file is found
2536 static concptr *read_pickpref_text_lines(player_type *player_ptr, int *filename_mode_p)
2538 /* Try a filename with player name */
2539 *filename_mode_p = PT_WITH_PNAME;
2541 strcpy(buf, pickpref_filename(player_ptr, *filename_mode_p));
2542 concptr *lines_list;
2543 lines_list = read_text_lines(buf);
2547 *filename_mode_p = PT_DEFAULT;
2548 strcpy(buf, pickpref_filename(player_ptr, *filename_mode_p));
2549 lines_list = read_text_lines(buf);
2554 prepare_default_pickpref(player_ptr);
2555 lines_list = read_text_lines(buf);
2560 C_MAKE(lines_list, MAX_LINES, concptr);
2561 lines_list[0] = string_make("");
2569 * Write whole lines of memory to a file.
2571 static bool write_text_lines(concptr filename, concptr *lines_list)
2574 path_build(buf, sizeof(buf), ANGBAND_DIR_USER, filename);
2576 fff = my_fopen(buf, "w");
2577 if (!fff) return FALSE;
2579 for (int lines = 0; lines_list[lines]; lines++)
2581 my_fputs(fff, lines_list[lines], 1024);
2590 * Free memory of lines_list.
2592 static void free_text_lines(concptr *lines_list)
2594 for (int lines = 0; lines_list[lines]; lines++)
2596 string_free(lines_list[lines]);
2599 /* free list of pointers */
2600 C_KILL(lines_list, MAX_LINES, concptr);
2605 * Delete or insert string
2607 static void toggle_keyword(text_body_type *tb, BIT_FLAGS flg)
2614 by1 = MIN(tb->my, tb->cy);
2615 by2 = MAX(tb->my, tb->cy);
2617 else /* if (!tb->mark) */
2622 for (int y = by1; y <= by2; y++)
2624 autopick_type an_entry, *entry = &an_entry;
2625 if (!autopick_new_entry(entry, tb->lines_list[y], !fixed)) continue;
2627 string_free(tb->lines_list[y]);
2630 if (!IS_FLG(flg)) add = TRUE;
2636 if (FLG_NOUN_BEGIN <= flg && flg <= FLG_NOUN_END)
2639 for (i = FLG_NOUN_BEGIN; i <= FLG_NOUN_END; i++)
2642 else if (FLG_UNAWARE <= flg && flg <= FLG_STAR_IDENTIFIED)
2645 for (i = FLG_UNAWARE; i <= FLG_STAR_IDENTIFIED; i++)
2648 else if (FLG_ARTIFACT <= flg && flg <= FLG_AVERAGE)
2651 for (i = FLG_ARTIFACT; i <= FLG_AVERAGE; i++)
2654 else if (FLG_RARE <= flg && flg <= FLG_COMMON)
2657 for (i = FLG_RARE; i <= FLG_COMMON; i++)
2661 if (add) ADD_FLG(flg);
2664 tb->lines_list[y] = autopick_line_from_entry_kill(entry);
2665 tb->dirty_flags |= DIRTY_ALL;
2672 * Change command letter
2674 static void toggle_command_letter(text_body_type *tb, byte flg)
2676 autopick_type an_entry, *entry = &an_entry;
2682 by1 = MIN(tb->my, tb->cy);
2683 by2 = MAX(tb->my, tb->cy);
2685 else /* if (!tb->mark) */
2690 for (y = by1; y <= by2; y++)
2694 if (!autopick_new_entry(entry, tb->lines_list[y], FALSE)) continue;
2696 string_free(tb->lines_list[y]);
2700 if (!(entry->action & flg)) add = TRUE;
2706 if (entry->action & DONT_AUTOPICK) wid--;
2707 else if (entry->action & DO_AUTODESTROY) wid--;
2708 else if (entry->action & DO_QUERY_AUTOPICK) wid--;
2709 if (!(entry->action & DO_DISPLAY)) wid--;
2711 if (flg != DO_DISPLAY)
2713 entry->action &= ~(DO_AUTOPICK | DONT_AUTOPICK | DO_AUTODESTROY | DO_QUERY_AUTOPICK);
2714 if (add) entry->action |= flg;
2715 else entry->action |= DO_AUTOPICK;
2719 entry->action &= ~(DO_DISPLAY);
2720 if (add) entry->action |= flg;
2725 if (entry->action & DONT_AUTOPICK) wid++;
2726 else if (entry->action & DO_AUTODESTROY) wid++;
2727 else if (entry->action & DO_QUERY_AUTOPICK) wid++;
2728 if (!(entry->action & DO_DISPLAY)) wid++;
2730 if (wid > 0) tb->cx++;
2731 if (wid < 0 && tb->cx > 0) tb->cx--;
2734 tb->lines_list[y] = autopick_line_from_entry_kill(entry);
2735 tb->dirty_flags |= DIRTY_ALL;
2742 * Delete or insert string
2744 static void add_keyword(text_body_type *tb, BIT_FLAGS flg)
2749 by1 = MIN(tb->my, tb->cy);
2750 by2 = MAX(tb->my, tb->cy);
2757 for (int y = by1; y <= by2; y++)
2759 autopick_type an_entry, *entry = &an_entry;
2760 if (!autopick_new_entry(entry, tb->lines_list[y], FALSE)) continue;
2764 autopick_free_entry(entry);
2768 string_free(tb->lines_list[y]);
2769 if (FLG_NOUN_BEGIN <= flg && flg <= FLG_NOUN_END)
2772 for (i = FLG_NOUN_BEGIN; i <= FLG_NOUN_END; i++)
2777 tb->lines_list[y] = autopick_line_from_entry_kill(entry);
2778 tb->dirty_flags |= DIRTY_ALL;
2785 * Check if this line is expression or not.
2786 * And update it if it is.
2788 static void check_expression_line(text_body_type *tb, int y)
2790 concptr s = tb->lines_list[y];
2792 if ((s[0] == '?' && s[1] == ':') ||
2793 (tb->states[y] & LSTAT_BYPASS))
2795 tb->dirty_flags |= DIRTY_EXPRESSION;
2801 * Add an empty line at the last of the file
2803 static bool add_empty_line(text_body_type *tb)
2806 for (num_lines = 0; tb->lines_list[num_lines]; num_lines++);
2808 if (num_lines >= MAX_LINES - 2) return FALSE;
2809 if (!tb->lines_list[num_lines - 1][0]) return FALSE;
2811 tb->lines_list[num_lines] = string_make("");
2812 tb->dirty_flags |= DIRTY_EXPRESSION;
2819 * Insert return code and split the line
2821 static bool insert_return_code(text_body_type *tb)
2823 char buf[MAX_LINELEN];
2824 int i, j, num_lines;
2826 for (num_lines = 0; tb->lines_list[num_lines]; num_lines++);
2828 if (num_lines >= MAX_LINES - 2) return FALSE;
2831 for (; tb->cy < num_lines; num_lines--)
2833 tb->lines_list[num_lines + 1] = tb->lines_list[num_lines];
2834 tb->states[num_lines + 1] = tb->states[num_lines];
2837 for (i = j = 0; tb->lines_list[tb->cy][i] && i < tb->cx; i++)
2840 if (iskanji(tb->lines_list[tb->cy][i]))
2841 buf[j++] = tb->lines_list[tb->cy][i++];
2843 buf[j++] = tb->lines_list[tb->cy][i];
2847 tb->lines_list[tb->cy + 1] = string_make(&tb->lines_list[tb->cy][i]);
2848 string_free(tb->lines_list[tb->cy]);
2849 tb->lines_list[tb->cy] = string_make(buf);
2850 tb->dirty_flags |= DIRTY_EXPRESSION;
2857 * Choose an item and get auto-picker entry from it.
2859 static bool entry_from_choosed_object(player_type *player_ptr, autopick_type *entry)
2861 concptr q = _("どのアイテムを登録しますか? ", "Enter which item? ");
2862 concptr s = _("アイテムを持っていない。", "You have nothing to enter.");
2864 o_ptr = choose_object(player_ptr, NULL, q, s, USE_INVEN | USE_FLOOR | USE_EQUIP, 0);
2865 if (!o_ptr) return FALSE;
2867 autopick_entry_from_object(player_ptr, entry, o_ptr);
2873 * Choose an item for search
2875 static bool get_object_for_search(player_type *player_ptr, object_type **o_handle, concptr *search_strp)
2877 concptr q = _("どのアイテムを検索しますか? ", "Enter which item? ");
2878 concptr s = _("アイテムを持っていない。", "You have nothing to enter.");
2880 o_ptr = choose_object(player_ptr, NULL, q, s, USE_INVEN | USE_FLOOR | USE_EQUIP, 0);
2881 if (!o_ptr) return FALSE;
2884 string_free(*search_strp);
2885 char buf[MAX_NLEN + 20];
2886 object_desc(player_ptr, buf, *o_handle, (OD_NO_FLAVOR | OD_OMIT_PREFIX | OD_NO_PLURAL));
2887 *search_strp = string_make(format("<%s>", buf));
2893 * Prepare for search by destroyed object
2895 static bool get_destroyed_object_for_search(player_type *player_ptr, object_type **o_handle, concptr *search_strp)
2897 if (!autopick_last_destroyed_object.k_idx) return FALSE;
2899 *o_handle = &autopick_last_destroyed_object;
2900 string_free(*search_strp);
2901 char buf[MAX_NLEN + 20];
2902 object_desc(player_ptr, buf, *o_handle, (OD_NO_FLAVOR | OD_OMIT_PREFIX | OD_NO_PLURAL));
2903 *search_strp = string_make(format("<%s>", buf));
2909 * Choose an item or string for search
2911 static byte get_string_for_search(player_type *player_ptr, object_type **o_handle, concptr *search_strp)
2915 * TERM_YELLOW : Overwrite mode
2916 * TERM_WHITE : Insert mode
2918 byte color = TERM_YELLOW;
2919 char buf[MAX_NLEN + 20];
2921 char prompt[] = _("検索(^I:持ち物 ^L:破壊された物): ", "Search key(^I:inven ^L:destroyed): ");
2922 int col = sizeof(prompt) - 1;
2923 if (*search_strp) strcpy(buf, *search_strp);
2926 if (*o_handle) color = TERM_L_GREEN;
2935 Term_erase(col, 0, 255);
2936 Term_putstr(col, 0, -1, color, buf);
2937 Term_gotoxy(col + pos, 0);
2939 skey = inkey_special(TRUE);
2947 if (pos == 0) break;
2951 int next_pos = i + 1;
2954 if (iskanji(buf[i])) next_pos++;
2956 if (next_pos >= pos) break;
2968 if ('\0' == buf[pos]) break;
2971 if (iskanji(buf[pos])) pos += 2;
2988 if (*o_handle) return (back ? -1 : 1);
2989 string_free(*search_strp);
2990 *search_strp = string_make(buf);
2992 return (back ? -1 : 1);
2995 return get_object_for_search(player_ptr, o_handle, search_strp);
2998 if (get_destroyed_object_for_search(player_ptr, o_handle, search_strp))
3006 if (pos == 0) break;
3010 int next_pos = i + 1;
3012 if (iskanji(buf[i])) next_pos++;
3014 if (next_pos >= pos) break;
3028 if (buf[pos] == '\0') break;
3032 if (iskanji(buf[pos])) src++;
3035 while ('\0' != (buf[dst++] = buf[src++]));
3044 if (skey & SKEY_MASK) break;
3047 if (color != TERM_WHITE)
3049 if (color == TERM_L_GREEN)
3052 string_free(*search_strp);
3053 *search_strp = NULL;
3060 strcpy(tmp, buf + pos);
3082 if (pos < len && (isprint(c) || iskana(c)))
3084 if (pos < len && isprint(c))
3096 my_strcat(buf, tmp, len + 1);
3102 if (*o_handle == NULL || color == TERM_L_GREEN) continue;
3106 string_free(*search_strp);
3107 *search_strp = NULL;
3113 * Search next line matches for o_ptr
3115 static void search_for_object(player_type *player_ptr, text_body_type *tb, object_type *o_ptr, bool forward)
3117 autopick_type an_entry, *entry = &an_entry;
3118 GAME_TEXT o_name[MAX_NLEN];
3119 int bypassed_cy = -1;
3121 object_desc(player_ptr, o_name, o_ptr, (OD_NO_FLAVOR | OD_OMIT_PREFIX | OD_NO_PLURAL));
3122 str_tolower(o_name);
3129 if (!tb->lines_list[++i]) break;
3136 if (!autopick_new_entry(entry, tb->lines_list[i], FALSE)) continue;
3138 match = is_autopick_aux(player_ptr, o_ptr, entry, o_name);
3139 autopick_free_entry(entry);
3140 if (!match) continue;
3142 if (tb->states[i] & LSTAT_BYPASS)
3144 if (bypassed_cy == -1) bypassed_cy = i;
3150 if (bypassed_cy != -1)
3152 tb->dirty_flags |= DIRTY_SKIP_INACTIVE;
3158 if (bypassed_cy == -1)
3160 tb->dirty_flags |= DIRTY_NOT_FOUND;
3165 tb->cy = bypassed_cy;
3166 tb->dirty_flags |= DIRTY_INACTIVE;
3171 * Search next line matches to the string
3173 static void search_for_string(text_body_type *tb, concptr search_str, bool forward)
3175 int bypassed_cy = -1;
3176 int bypassed_cx = 0;
3184 if (!tb->lines_list[++i]) break;
3191 pos = my_strstr(tb->lines_list[i], search_str);
3194 if ((tb->states[i] & LSTAT_BYPASS) &&
3195 !(tb->states[i] & LSTAT_EXPRESSION))
3197 if (bypassed_cy == -1)
3200 bypassed_cx = (int)(pos - tb->lines_list[i]);
3206 tb->cx = (int)(pos - tb->lines_list[i]);
3209 if (bypassed_cy != -1)
3211 tb->dirty_flags |= DIRTY_SKIP_INACTIVE;
3217 if (bypassed_cy == -1)
3219 tb->dirty_flags |= DIRTY_NOT_FOUND;
3223 tb->cx = bypassed_cx;
3224 tb->cy = bypassed_cy;
3225 tb->dirty_flags |= DIRTY_INACTIVE;
3230 * Find a command by 'key'.
3232 static int get_com_id(char key)
3234 for (int i = 0; menu_data[i].name; i++)
3236 if (menu_data[i].key == key)
3238 return menu_data[i].com_id;
3247 * Display the menu, and get a command
3249 static int do_command_menu(int level, int start)
3252 int col0 = 5 + level * 7;
3253 int row0 = 1 + level * 3;
3254 int menu_id_list[26];
3256 char linestr[MAX_LINELEN];
3259 for (int i = start; menu_data[i].level >= level; i++)
3263 /* Ignore lower level sub menus */
3264 if (menu_data[i].level > level) continue;
3266 len = strlen(menu_data[i].name);
3267 if (len > max_len) max_len = len;
3269 menu_id_list[menu_key] = i;
3273 while (menu_key < 26)
3275 menu_id_list[menu_key] = -1;
3279 int max_menu_wid = max_len + 3 + 3;
3281 /* Prepare box line */
3283 strcat(linestr, "+");
3284 for (int i = 0; i < max_menu_wid + 2; i++)
3286 strcat(linestr, "-");
3289 strcat(linestr, "+");
3299 int row1 = row0 + 1;
3300 Term_putstr(col0, row0, -1, TERM_WHITE, linestr);
3303 for (int i = start; menu_data[i].level >= level; i++)
3305 char com_key_str[3];
3307 if (menu_data[i].level > level) continue;
3309 if (menu_data[i].com_id == -1)
3311 strcpy(com_key_str, _("▼", ">"));
3313 else if (menu_data[i].key != -1)
3315 com_key_str[0] = '^';
3316 com_key_str[1] = menu_data[i].key + '@';
3317 com_key_str[2] = '\0';
3321 com_key_str[0] = '\0';
3324 str = format("| %c) %-*s %2s | ", menu_key + 'a', max_len, menu_data[i].name, com_key_str);
3326 Term_putstr(col0, row1++, -1, TERM_WHITE, str);
3331 Term_putstr(col0, row1, -1, TERM_WHITE, linestr);
3335 prt(format(_("(a-%c) コマンド:", "(a-%c) Command:"), menu_key + 'a' - 1), 0, 0);
3338 if (key == ESCAPE) return 0;
3340 bool is_alphabet = key >= 'a' && key <= 'z';
3343 com_id = get_com_id(key);
3352 menu_id = menu_id_list[key - 'a'];
3354 if (menu_id < 0) continue;
3356 com_id = menu_data[menu_id].com_id;
3360 com_id = do_command_menu(level + 1, menu_id + 1);
3362 if (com_id) return com_id;
3373 static chain_str_type *new_chain_str(concptr str)
3375 chain_str_type *chain;
3376 size_t len = strlen(str);
3377 chain = (chain_str_type *)ralloc(sizeof(chain_str_type) + len * sizeof(char));
3378 strcpy(chain->s, str);
3384 static void kill_yank_chain(text_body_type *tb)
3386 chain_str_type *chain = tb->yank;
3388 tb->yank_eol = TRUE;
3392 chain_str_type *next = chain->next;
3393 size_t len = strlen(chain->s);
3395 rnfree(chain, sizeof(chain_str_type) + len * sizeof(char));
3402 static void add_str_to_yank(text_body_type *tb, concptr str)
3404 tb->yank_eol = FALSE;
3405 if (NULL == tb->yank)
3407 tb->yank = new_chain_str(str);
3411 chain_str_type *chain;
3418 chain->next = new_chain_str(str);
3423 chain = chain->next;
3429 * Do work for the copy editor-command
3431 static void copy_text_to_yank(text_body_type *tb)
3433 int len = strlen(tb->lines_list[tb->cy]);
3434 if (tb->cx > len) tb->cx = len;
3443 kill_yank_chain(tb);
3444 if (tb->my != tb->cy)
3446 int by1 = MIN(tb->my, tb->cy);
3447 int by2 = MAX(tb->my, tb->cy);
3449 for (int y = by1; y <= by2; y++)
3451 add_str_to_yank(tb, tb->lines_list[y]);
3454 add_str_to_yank(tb, "");
3456 tb->dirty_flags |= DIRTY_ALL;
3460 char buf[MAX_LINELEN];
3461 int bx1 = MIN(tb->mx, tb->cx);
3462 int bx2 = MAX(tb->mx, tb->cx);
3463 if (bx2 > len) bx2 = len;
3465 if (bx1 == 0 && bx2 == len)
3467 add_str_to_yank(tb, tb->lines_list[tb->cy]);
3468 add_str_to_yank(tb, "");
3472 int end = bx2 - bx1;
3473 for (int i = 0; i < bx2 - bx1; i++)
3475 buf[i] = tb->lines_list[tb->cy][bx1 + i];
3479 add_str_to_yank(tb, buf);
3483 tb->dirty_flags |= DIRTY_ALL;
3490 static void draw_text_editor(player_type *player_ptr, text_body_type *tb)
3493 int by1 = 0, by2 = 0;
3495 Term_get_size(&tb->wid, &tb->hgt);
3498 * Top line (-1), description line (-3), separator (-1)
3501 tb->hgt -= 2 + DESCRIPT_HGT;
3504 /* Don't let cursor at second byte of kanji */
3505 for (i = 0; tb->lines_list[tb->cy][i]; i++)
3506 if (iskanji(tb->lines_list[tb->cy][i]))
3512 * Move to a correct position in the
3515 if (i & 1) tb->cx--;
3521 if (tb->cy < tb->upper || tb->upper + tb->hgt <= tb->cy)
3522 tb->upper = tb->cy - (tb->hgt) / 2;
3525 if ((tb->cx < tb->left + 10 && tb->left > 0) || tb->left + tb->wid - 5 <= tb->cx)
3526 tb->left = tb->cx - (tb->wid) * 2 / 3;
3530 if (tb->old_wid != tb->wid || tb->old_hgt != tb->hgt)
3531 tb->dirty_flags |= DIRTY_SCREEN;
3532 else if (tb->old_upper != tb->upper || tb->old_left != tb->left)
3533 tb->dirty_flags |= DIRTY_ALL;
3535 if (tb->dirty_flags & DIRTY_SCREEN)
3537 tb->dirty_flags |= (DIRTY_ALL | DIRTY_MODE);
3541 if (tb->dirty_flags & DIRTY_MODE)
3543 char buf[MAX_LINELEN];
3544 int sepa_length = tb->wid;
3545 for (i = 0; i < sepa_length; i++)
3548 Term_putstr(0, tb->hgt + 1, sepa_length, TERM_WHITE, buf);
3551 if (tb->dirty_flags & DIRTY_EXPRESSION)
3554 for (int y = 0; tb->lines_list[y]; y++)
3558 concptr s = tb->lines_list[y];
3562 tb->states[y] = state;
3564 if (*s++ != '?') continue;
3565 if (*s++ != ':') continue;
3567 if (streq(s, "$AUTOREGISTER"))
3568 state |= LSTAT_AUTOREGISTER;
3571 ss = (char *)string_make(s);
3574 v = process_pref_file_expr(player_ptr, &ss, &f);
3576 if (streq(v, "0")) state |= LSTAT_BYPASS;
3577 else state &= ~LSTAT_BYPASS;
3579 C_KILL(s_keep, s_len + 1, char);
3581 tb->states[y] = state | LSTAT_EXPRESSION;
3584 tb->dirty_flags |= DIRTY_ALL;
3589 tb->dirty_flags |= DIRTY_ALL;
3591 by1 = MIN(tb->my, tb->cy);
3592 by2 = MAX(tb->my, tb->cy);
3595 for (i = 0; i < tb->hgt; i++)
3601 int y = tb->upper + i;
3603 if (!(tb->dirty_flags & DIRTY_ALL) && (tb->dirty_line != y))
3606 msg = tb->lines_list[y];
3609 for (j = 0; *msg; msg++, j++)
3611 if (j == tb->left) break;
3626 Term_erase(0, i + 1, tb->wid);
3627 if (tb->states[y] & LSTAT_AUTOREGISTER)
3633 if (tb->states[y] & LSTAT_BYPASS) color = TERM_SLATE;
3634 else color = TERM_WHITE;
3637 if (!tb->mark || (y < by1 || by2 < y))
3639 Term_putstr(leftcol, i + 1, tb->wid - 1, color, msg);
3641 else if (by1 != by2)
3643 Term_putstr(leftcol, i + 1, tb->wid - 1, TERM_YELLOW, msg);
3647 int x0 = leftcol + tb->left;
3648 int len = strlen(tb->lines_list[tb->cy]);
3649 int bx1 = MIN(tb->mx, tb->cx);
3650 int bx2 = MAX(tb->mx, tb->cx);
3652 if (bx2 > len) bx2 = len;
3654 Term_gotoxy(leftcol, i + 1);
3655 if (x0 < bx1) Term_addstr(bx1 - x0, color, msg);
3656 if (x0 < bx2) Term_addstr(bx2 - bx1, TERM_YELLOW, msg + (bx1 - x0));
3657 Term_addstr(-1, color, msg + (bx2 - x0));
3661 for (; i < tb->hgt; i++)
3663 Term_erase(0, i + 1, tb->wid);
3666 bool is_dirty_diary = (tb->dirty_flags & (DIRTY_ALL | DIRTY_NOT_FOUND | DIRTY_NO_SEARCH)) != 0;
3667 bool is_updated = tb->old_cy != tb->cy || is_dirty_diary || tb->dirty_line == tb->cy;
3668 if (is_updated) return;
3670 autopick_type an_entry, *entry = &an_entry;
3671 concptr str1 = NULL, str2 = NULL;
3672 for (i = 0; i < DESCRIPT_HGT; i++)
3674 Term_erase(0, tb->hgt + 2 + i, tb->wid);
3677 if (tb->dirty_flags & DIRTY_NOT_FOUND)
3679 str1 = format(_("パターンが見つかりません: %s", "Pattern not found: %s"), tb->search_str);
3681 else if (tb->dirty_flags & DIRTY_SKIP_INACTIVE)
3683 str1 = format(_("無効状態の行をスキップしました。(%sを検索中)",
3684 "Some inactive lines are skipped. (Searching %s)"), tb->search_str);
3686 else if (tb->dirty_flags & DIRTY_INACTIVE)
3688 str1 = format(_("無効状態の行だけが見付かりました。(%sを検索中)",
3689 "Found only an inactive line. (Searching %s)"), tb->search_str);
3691 else if (tb->dirty_flags & DIRTY_NO_SEARCH)
3693 str1 = _("検索するパターンがありません(^S で検索)。", "No pattern to search. (Press ^S to search.)");
3695 else if (tb->lines_list[tb->cy][0] == '#')
3697 str1 = _("この行はコメントです。", "This line is a comment.");
3699 else if (tb->lines_list[tb->cy][0] && tb->lines_list[tb->cy][1] == ':')
3701 switch (tb->lines_list[tb->cy][0])
3704 str1 = _("この行は条件分岐式です。", "This line is a Conditional Expression.");
3707 str1 = _("この行はマクロの実行内容を定義します。", "This line defines a Macro action.");
3710 str1 = _("この行はマクロのトリガー・キーを定義します。", "This line defines a Macro trigger key.");
3713 str1 = _("この行はキー配置を定義します。", "This line defines a Keymap.");
3717 switch (tb->lines_list[tb->cy][0])
3720 if (tb->states[tb->cy] & LSTAT_BYPASS)
3722 str2 = _("現在の式の値は「偽(=0)」です。", "The expression is 'False'(=0) currently.");
3726 str2 = _("現在の式の値は「真(=1)」です。", "The expression is 'True'(=1) currently.");
3731 if (tb->states[tb->cy] & LSTAT_AUTOREGISTER)
3733 str2 = _("この行は後で削除されます。", "This line will be delete later.");
3736 else if (tb->states[tb->cy] & LSTAT_BYPASS)
3738 str2 = _("この行は現在は無効な状態です。", "This line is bypassed currently.");
3743 else if (autopick_new_entry(entry, tb->lines_list[tb->cy], FALSE))
3745 char buf[MAX_LINELEN];
3746 char temp[MAX_LINELEN];
3749 describe_autopick(buf, entry);
3751 if (tb->states[tb->cy] & LSTAT_AUTOREGISTER)
3753 strcat(buf, _("この行は後で削除されます。", " This line will be delete later."));
3756 if (tb->states[tb->cy] & LSTAT_BYPASS)
3758 strcat(buf, _("この行は現在は無効な状態です。", " This line is bypassed currently."));
3761 roff_to_buf(buf, 81, temp, sizeof(temp));
3763 for (i = 0; i < 3; i++)
3769 prt(t, tb->hgt + 1 + 1 + i, 0);
3773 autopick_free_entry(entry);
3776 if (str1) prt(str1, tb->hgt + 1 + 1, 0);
3777 if (str2) prt(str2, tb->hgt + 1 + 2, 0);
3782 * Kill segment of a line
3784 static void kill_line_segment(text_body_type *tb, int y, int x0, int x1, bool whole)
3786 concptr s = tb->lines_list[y];
3787 if (whole && x0 == 0 && s[x1] == '\0' && tb->lines_list[y + 1])
3789 string_free(tb->lines_list[y]);
3792 for (i = y; tb->lines_list[i + 1]; i++)
3793 tb->lines_list[i] = tb->lines_list[i + 1];
3794 tb->lines_list[i] = NULL;
3796 tb->dirty_flags |= DIRTY_EXPRESSION;
3801 if (x0 == x1) return;
3803 char buf[MAX_LINELEN];
3805 for (int x = 0; x < x0; x++)
3808 for (int x = x1; s[x]; x++)
3812 string_free(tb->lines_list[y]);
3813 tb->lines_list[y] = string_make(buf);
3814 check_expression_line(tb, y);
3820 * Get a trigger key and insert ASCII string for the trigger
3822 static bool insert_macro_line(text_body_type *tb)
3841 ascii_to_text(tmp, buf);
3842 if (!tmp[0]) return FALSE;
3845 insert_return_code(tb);
3846 string_free(tb->lines_list[tb->cy]);
3847 tb->lines_list[tb->cy] = string_make(format("P:%s", tmp));
3849 i = macro_find_exact(buf);
3856 ascii_to_text(tmp, macro__act[i]);
3859 insert_return_code(tb);
3860 string_free(tb->lines_list[tb->cy]);
3861 tb->lines_list[tb->cy] = string_make(format("A:%s", tmp));
3868 * Get a command key and insert ASCII string for the key
3870 static bool insert_keymap_line(text_body_type *tb)
3873 if (rogue_like_commands)
3875 mode = KEYMAP_MODE_ROGUE;
3879 mode = KEYMAP_MODE_ORIG;
3889 ascii_to_text(tmp, buf);
3890 if (!tmp[0]) return FALSE;
3893 insert_return_code(tb);
3894 string_free(tb->lines_list[tb->cy]);
3895 tb->lines_list[tb->cy] = string_make(format("C:%d:%s", mode, tmp));
3897 concptr act = keymap_act[mode][(byte)(buf[0])];
3900 ascii_to_text(tmp, act);
3903 insert_return_code(tb);
3904 string_free(tb->lines_list[tb->cy]);
3905 tb->lines_list[tb->cy] = string_make(format("A:%s", tmp));
3912 * Execute a single editor command
3914 static bool do_editor_command(player_type *player_ptr, text_body_type *tb, int com_id)
3921 if (!get_check(_("全ての変更を破棄してから終了します。よろしいですか? ",
3922 "Discard all changes and quit. Are you sure? "))) break;
3925 return QUIT_WITHOUT_SAVE;
3928 return QUIT_AND_SAVE;
3931 if (!get_check(_("全ての変更を破棄して元の状態に戻します。よろしいですか? ",
3932 "Discard all changes and revert to original file. Are you sure? "))) break;
3934 free_text_lines(tb->lines_list);
3935 tb->lines_list = read_pickpref_text_lines(player_ptr, &tb->filename_mode);
3936 tb->dirty_flags |= DIRTY_ALL | DIRTY_MODE | DIRTY_EXPRESSION;
3937 tb->cx = tb->cy = 0;
3940 tb->changed = FALSE;
3944 (void)show_file(player_ptr, TRUE, _("jeditor.txt", "editor.txt"), NULL, 0, 0);
3945 tb->dirty_flags |= DIRTY_SCREEN;
3953 tb->dirty_flags |= DIRTY_ALL;
3956 insert_return_code(tb);
3960 tb->dirty_flags |= DIRTY_ALL;
3972 len = strlen(tb->lines_list[tb->cy]);
3973 if (len < tb->cx) tb->cx = len;
3975 for (i = 0; tb->lines_list[tb->cy][i]; i++)
3977 if (iskanji(tb->lines_list[tb->cy][i]))
3989 else if (tb->cy > 0)
3992 tb->cx = strlen(tb->lines_list[tb->cy]);
3998 if (!tb->lines_list[tb->cy + 1])
4000 if (!add_empty_line(tb)) break;
4007 if (tb->cy > 0) tb->cy--;
4013 if (iskanji(tb->lines_list[tb->cy][tb->cx])) tb->cx++;
4016 int len = strlen(tb->lines_list[tb->cy]);
4020 if (!tb->lines_list[tb->cy + 1])
4022 if (!add_empty_line(tb)) break;
4036 tb->cx = strlen(tb->lines_list[tb->cy]);
4040 while (0 < tb->cy && tb->upper <= tb->cy)
4042 while (0 < tb->upper && tb->cy + 1 < tb->upper + tb->hgt)
4047 while (tb->cy < tb->upper + tb->hgt)
4049 if (!tb->lines_list[tb->cy + 1])
4051 if (!add_empty_line(tb)) break;
4067 if (!tb->lines_list[tb->cy + 1])
4069 if (!add_empty_line(tb)) break;
4080 copy_text_to_yank(tb);
4081 if (tb->my == tb->cy)
4083 int bx1 = MIN(tb->mx, tb->cx);
4084 int bx2 = MAX(tb->mx, tb->cx);
4085 int len = strlen(tb->lines_list[tb->cy]);
4086 if (bx2 > len) bx2 = len;
4088 kill_line_segment(tb, tb->cy, bx1, bx2, TRUE);
4093 int by1 = MIN(tb->my, tb->cy);
4094 int by2 = MAX(tb->my, tb->cy);
4096 for (int y = by2; y >= by1; y--)
4098 int len = strlen(tb->lines_list[y]);
4100 kill_line_segment(tb, y, 0, len, TRUE);
4108 tb->dirty_flags |= DIRTY_ALL;
4113 copy_text_to_yank(tb);
4116 * Move cursor position to the end of the selection
4118 * Pressing ^C ^V correctly duplicates the selection.
4120 if (tb->my != tb->cy)
4122 tb->cy = MAX(tb->cy, tb->my);
4123 if (!tb->lines_list[tb->cy + 1])
4125 if (!add_empty_line(tb)) break;
4132 tb->cx = MAX(tb->cx, tb->mx);
4133 if (!tb->lines_list[tb->cy][tb->cx])
4135 if (!tb->lines_list[tb->cy + 1])
4137 if (!add_empty_line(tb)) break;
4148 chain_str_type *chain = tb->yank;
4149 int len = strlen(tb->lines_list[tb->cy]);
4151 if (tb->cx > len) tb->cx = len;
4156 tb->dirty_flags |= DIRTY_ALL;
4161 concptr yank_str = chain->s;
4162 char buf[MAX_LINELEN];
4164 char rest[MAX_LINELEN], *rest_ptr = rest;
4165 for (i = 0; i < tb->cx; i++)
4166 buf[i] = tb->lines_list[tb->cy][i];
4168 strcpy(rest, &(tb->lines_list[tb->cy][i]));
4169 while (*yank_str && i < MAX_LINELEN - 1)
4171 buf[i++] = *yank_str++;
4175 chain = chain->next;
4176 if (chain || tb->yank_eol)
4178 insert_return_code(tb);
4179 string_free(tb->lines_list[tb->cy]);
4180 tb->lines_list[tb->cy] = string_make(buf);
4187 tb->cx = strlen(buf);
4188 while (*rest_ptr && i < MAX_LINELEN - 1)
4190 buf[i++] = *rest_ptr++;
4194 string_free(tb->lines_list[tb->cy]);
4195 tb->lines_list[tb->cy] = string_make(buf);
4199 tb->dirty_flags |= DIRTY_ALL;
4200 tb->dirty_flags |= DIRTY_EXPRESSION;
4209 tb->dirty_flags |= DIRTY_ALL;
4213 tb->mark = MARK_MARK;
4214 if (com_id == tb->old_com_id)
4222 tb->dirty_flags |= DIRTY_ALL;
4226 int len = strlen(tb->lines_list[tb->cy]);
4230 if (tb->cx > len) tb->mx = len;
4235 int len = strlen(tb->lines_list[tb->cy]);
4236 if (tb->cx > len) tb->cx = len;
4241 tb->dirty_flags |= DIRTY_ALL;
4244 if (tb->old_com_id != com_id)
4246 kill_yank_chain(tb);
4252 add_str_to_yank(tb, &(tb->lines_list[tb->cy][tb->cx]));
4253 kill_line_segment(tb, tb->cy, tb->cx, len, FALSE);
4254 tb->dirty_line = tb->cy;
4258 if (tb->yank_eol) add_str_to_yank(tb, "");
4260 tb->yank_eol = TRUE;
4261 do_editor_command(player_ptr, tb, EC_DELETE_CHAR);
4264 case EC_DELETE_CHAR:
4269 tb->dirty_flags |= DIRTY_ALL;
4273 if (iskanji(tb->lines_list[tb->cy][tb->cx])) tb->cx++;
4276 int len = strlen(tb->lines_list[tb->cy]);
4279 do_editor_command(player_ptr, tb, EC_BACKSPACE);
4283 if (tb->lines_list[tb->cy + 1])
4294 do_editor_command(player_ptr, tb, EC_BACKSPACE);
4300 char buf[MAX_LINELEN];
4304 tb->dirty_flags |= DIRTY_ALL;
4307 len = strlen(tb->lines_list[tb->cy]);
4308 if (len < tb->cx) tb->cx = len;
4312 if (tb->cy == 0) break;
4313 tb->cx = strlen(tb->lines_list[tb->cy - 1]);
4314 strcpy(buf, tb->lines_list[tb->cy - 1]);
4315 strcat(buf, tb->lines_list[tb->cy]);
4316 string_free(tb->lines_list[tb->cy - 1]);
4317 string_free(tb->lines_list[tb->cy]);
4318 tb->lines_list[tb->cy - 1] = string_make(buf);
4320 for (i = tb->cy; tb->lines_list[i + 1]; i++)
4321 tb->lines_list[i] = tb->lines_list[i + 1];
4323 tb->lines_list[i] = NULL;
4325 tb->dirty_flags |= DIRTY_ALL;
4326 tb->dirty_flags |= DIRTY_EXPRESSION;
4331 for (i = j = k = 0; tb->lines_list[tb->cy][i] && i < tb->cx; i++)
4335 if (iskanji(tb->lines_list[tb->cy][i]))
4336 buf[j++] = tb->lines_list[tb->cy][i++];
4338 buf[j++] = tb->lines_list[tb->cy][i];
4347 for (; tb->lines_list[tb->cy][i]; i++)
4349 buf[j++] = tb->lines_list[tb->cy][i];
4353 string_free(tb->lines_list[tb->cy]);
4354 tb->lines_list[tb->cy] = string_make(buf);
4355 tb->dirty_line = tb->cy;
4356 check_expression_line(tb, tb->cy);
4363 tb->dirty_flags |= DIRTY_SCREEN;
4364 search_dir = get_string_for_search(player_ptr, &tb->search_o_ptr, &tb->search_str);
4366 if (!search_dir) break;
4368 if (search_dir == 1) do_editor_command(player_ptr, tb, EC_SEARCH_FORW);
4369 else do_editor_command(player_ptr, tb, EC_SEARCH_BACK);
4372 case EC_SEARCH_FORW:
4373 if (tb->search_o_ptr)
4375 search_for_object(player_ptr, tb, tb->search_o_ptr, TRUE);
4379 if (tb->search_str && tb->search_str[0])
4381 search_for_string(tb, tb->search_str, TRUE);
4385 tb->dirty_flags |= DIRTY_NO_SEARCH;
4388 case EC_SEARCH_BACK:
4389 if (tb->search_o_ptr)
4391 search_for_object(player_ptr, tb, tb->search_o_ptr, FALSE);
4395 if (tb->search_str && tb->search_str[0])
4397 search_for_string(tb, tb->search_str, FALSE);
4401 tb->dirty_flags |= DIRTY_NO_SEARCH;
4405 tb->dirty_flags |= DIRTY_SCREEN;
4407 if (!get_object_for_search(player_ptr, &tb->search_o_ptr, &tb->search_str)) break;
4409 do_editor_command(player_ptr, tb, EC_SEARCH_FORW);
4412 case EC_SEARCH_DESTROYED:
4413 if (!get_destroyed_object_for_search(player_ptr, &tb->search_o_ptr, &tb->search_str))
4415 tb->dirty_flags |= DIRTY_NO_SEARCH;
4419 do_editor_command(player_ptr, tb, EC_SEARCH_FORW);
4422 case EC_INSERT_OBJECT:
4424 autopick_type an_entry, *entry = &an_entry;
4425 if (!entry_from_choosed_object(player_ptr, entry))
4427 tb->dirty_flags |= DIRTY_SCREEN;
4432 insert_return_code(tb);
4433 string_free(tb->lines_list[tb->cy]);
4434 tb->lines_list[tb->cy] = autopick_line_from_entry_kill(entry);
4435 tb->dirty_flags |= DIRTY_SCREEN;
4438 case EC_INSERT_DESTROYED:
4439 if (!tb->last_destroyed) break;
4442 insert_return_code(tb);
4443 string_free(tb->lines_list[tb->cy]);
4444 tb->lines_list[tb->cy] = string_make(tb->last_destroyed);
4445 tb->dirty_flags |= DIRTY_ALL;
4449 case EC_INSERT_BLOCK:
4451 char expression[80];
4452 sprintf(expression, "?:[AND [EQU $RACE %s] [EQU $CLASS %s] [GEQ $LEVEL %02d]]",
4454 rp_ptr->E_title, cp_ptr->E_title,
4456 rp_ptr->title, cp_ptr->title,
4460 insert_return_code(tb);
4461 string_free(tb->lines_list[tb->cy]);
4462 tb->lines_list[tb->cy] = string_make(expression);
4464 insert_return_code(tb);
4465 string_free(tb->lines_list[tb->cy]);
4466 tb->lines_list[tb->cy] = string_make("?:1");
4467 tb->dirty_flags |= DIRTY_ALL;
4472 case EC_INSERT_MACRO:
4473 draw_text_editor(player_ptr, tb);
4474 Term_erase(0, tb->cy - tb->upper + 1, tb->wid);
4475 Term_putstr(0, tb->cy - tb->upper + 1, tb->wid - 1, TERM_YELLOW, _("P:<トリガーキー>: ", "P:<Trigger key>: "));
4476 if (!insert_macro_line(tb)) break;
4479 tb->dirty_flags |= DIRTY_ALL;
4483 case EC_INSERT_KEYMAP:
4484 draw_text_editor(player_ptr, tb);
4485 Term_erase(0, tb->cy - tb->upper + 1, tb->wid);
4486 Term_putstr(0, tb->cy - tb->upper + 1, tb->wid - 1, TERM_YELLOW,
4487 format(_("C:%d:<コマンドキー>: ", "C:%d:<Keypress>: "), (rogue_like_commands ? KEYMAP_MODE_ROGUE : KEYMAP_MODE_ORIG)));
4489 if (!insert_keymap_line(tb)) break;
4492 tb->dirty_flags |= DIRTY_ALL;
4496 case EC_CL_AUTOPICK: toggle_command_letter(tb, DO_AUTOPICK); break;
4497 case EC_CL_DESTROY: toggle_command_letter(tb, DO_AUTODESTROY); break;
4498 case EC_CL_LEAVE: toggle_command_letter(tb, DONT_AUTOPICK); break;
4499 case EC_CL_QUERY: toggle_command_letter(tb, DO_QUERY_AUTOPICK); break;
4500 case EC_CL_NO_DISP: toggle_command_letter(tb, DO_DISPLAY); break;
4502 case EC_IK_UNAWARE: toggle_keyword(tb, FLG_UNAWARE); break;
4503 case EC_IK_UNIDENTIFIED: toggle_keyword(tb, FLG_UNIDENTIFIED); break;
4504 case EC_IK_IDENTIFIED: toggle_keyword(tb, FLG_IDENTIFIED); break;
4505 case EC_IK_STAR_IDENTIFIED: toggle_keyword(tb, FLG_STAR_IDENTIFIED); break;
4506 case EC_KK_WEAPONS: toggle_keyword(tb, FLG_WEAPONS); break;
4507 case EC_KK_FAVORITE_WEAPONS: toggle_keyword(tb, FLG_FAVORITE_WEAPONS); break;
4508 case EC_KK_ARMORS: toggle_keyword(tb, FLG_ARMORS); break;
4509 case EC_KK_MISSILES: toggle_keyword(tb, FLG_MISSILES); break;
4510 case EC_KK_DEVICES: toggle_keyword(tb, FLG_DEVICES); break;
4511 case EC_KK_LIGHTS: toggle_keyword(tb, FLG_LIGHTS); break;
4512 case EC_KK_JUNKS: toggle_keyword(tb, FLG_JUNKS); break;
4513 case EC_KK_CORPSES: toggle_keyword(tb, FLG_CORPSES); break;
4514 case EC_KK_SPELLBOOKS: toggle_keyword(tb, FLG_SPELLBOOKS); break;
4515 case EC_KK_SHIELDS: toggle_keyword(tb, FLG_SHIELDS); break;
4516 case EC_KK_BOWS: toggle_keyword(tb, FLG_BOWS); break;
4517 case EC_KK_RINGS: toggle_keyword(tb, FLG_RINGS); break;
4518 case EC_KK_AMULETS: toggle_keyword(tb, FLG_AMULETS); break;
4519 case EC_KK_SUITS: toggle_keyword(tb, FLG_SUITS); break;
4520 case EC_KK_CLOAKS: toggle_keyword(tb, FLG_CLOAKS); break;
4521 case EC_KK_HELMS: toggle_keyword(tb, FLG_HELMS); break;
4522 case EC_KK_GLOVES: toggle_keyword(tb, FLG_GLOVES); break;
4523 case EC_KK_BOOTS: toggle_keyword(tb, FLG_BOOTS); break;
4524 case EC_OK_COLLECTING: toggle_keyword(tb, FLG_COLLECTING); break;
4525 case EC_OK_BOOSTED: toggle_keyword(tb, FLG_BOOSTED); break;
4526 case EC_OK_MORE_DICE: toggle_keyword(tb, FLG_MORE_DICE); break;
4527 case EC_OK_MORE_BONUS: toggle_keyword(tb, FLG_MORE_BONUS); break;
4528 case EC_OK_WORTHLESS: toggle_keyword(tb, FLG_WORTHLESS); break;
4529 case EC_OK_ARTIFACT: toggle_keyword(tb, FLG_ARTIFACT); break;
4530 case EC_OK_EGO: toggle_keyword(tb, FLG_EGO); break;
4531 case EC_OK_GOOD: toggle_keyword(tb, FLG_GOOD); break;
4532 case EC_OK_NAMELESS: toggle_keyword(tb, FLG_NAMELESS); break;
4533 case EC_OK_AVERAGE: toggle_keyword(tb, FLG_AVERAGE); break;
4534 case EC_OK_RARE: toggle_keyword(tb, FLG_RARE); break;
4535 case EC_OK_COMMON: toggle_keyword(tb, FLG_COMMON); break;
4536 case EC_OK_WANTED: toggle_keyword(tb, FLG_WANTED); break;
4537 case EC_OK_UNIQUE: toggle_keyword(tb, FLG_UNIQUE); break;
4538 case EC_OK_HUMAN: toggle_keyword(tb, FLG_HUMAN); break;
4539 case EC_OK_UNREADABLE:
4540 toggle_keyword(tb, FLG_UNREADABLE);
4541 add_keyword(tb, FLG_SPELLBOOKS);
4544 toggle_keyword(tb, FLG_REALM1);
4545 add_keyword(tb, FLG_SPELLBOOKS);
4548 toggle_keyword(tb, FLG_REALM2);
4549 add_keyword(tb, FLG_SPELLBOOKS);
4552 toggle_keyword(tb, FLG_FIRST);
4553 add_keyword(tb, FLG_SPELLBOOKS);
4556 toggle_keyword(tb, FLG_SECOND);
4557 add_keyword(tb, FLG_SPELLBOOKS);
4560 toggle_keyword(tb, FLG_THIRD);
4561 add_keyword(tb, FLG_SPELLBOOKS);
4564 toggle_keyword(tb, FLG_FOURTH);
4565 add_keyword(tb, FLG_SPELLBOOKS);
4569 tb->old_com_id = com_id;
4575 * Insert single letter at cursor position.
4577 static void insert_single_letter(text_body_type *tb, int key)
4580 char buf[MAX_LINELEN];
4582 for (i = j = 0; tb->lines_list[tb->cy][i] && i < tb->cx; i++)
4584 buf[j++] = tb->lines_list[tb->cy][i];
4594 if (j + 2 < MAX_LINELEN)
4596 buf[j++] = (char)key;
4597 buf[j++] = (char)next;
4606 if (j + 1 < MAX_LINELEN)
4607 buf[j++] = (char)key;
4611 for (; tb->lines_list[tb->cy][i] && j + 1 < MAX_LINELEN; i++)
4612 buf[j++] = tb->lines_list[tb->cy][i];
4615 string_free(tb->lines_list[tb->cy]);
4616 tb->lines_list[tb->cy] = string_make(buf);
4617 len = strlen(tb->lines_list[tb->cy]);
4618 if (len < tb->cx) tb->cx = len;
4620 tb->dirty_line = tb->cy;
4621 check_expression_line(tb, tb->cy);
4627 * Check special key code and get a movement command id
4629 static int analyze_move_key(text_body_type *tb, int skey)
4632 if (!(skey & SKEY_MASK)) return 0;
4634 switch (skey & ~SKEY_MOD_MASK)
4636 case SKEY_DOWN: com_id = EC_DOWN; break;
4637 case SKEY_LEFT: com_id = EC_LEFT; break;
4638 case SKEY_RIGHT: com_id = EC_RIGHT; break;
4639 case SKEY_UP: com_id = EC_UP; break;
4640 case SKEY_PGUP: com_id = EC_PGUP; break;
4641 case SKEY_PGDOWN: com_id = EC_PGDOWN; break;
4642 case SKEY_TOP: com_id = EC_TOP; break;
4643 case SKEY_BOTTOM: com_id = EC_BOTTOM; break;
4648 if (!(skey & SKEY_MOD_SHIFT))
4651 * Un-shifted cursor keys cancells
4652 * selection created by shift+cursor.
4654 if (tb->mark & MARK_BY_SHIFT)
4657 tb->dirty_flags |= DIRTY_ALL;
4663 if (tb->mark) return com_id;
4665 int len = strlen(tb->lines_list[tb->cy]);
4666 tb->mark = MARK_MARK | MARK_BY_SHIFT;
4669 if (tb->cx > len) tb->mx = len;
4671 if (com_id == EC_UP || com_id == EC_DOWN)
4673 tb->dirty_flags |= DIRTY_ALL;
4677 tb->dirty_line = tb->cy;
4684 * In-game editor of Object Auto-picker/Destoryer
4685 * @param player_ptr プレーヤーへの参照ポインタ
4687 void do_cmd_edit_autopick(player_type *player_ptr)
4689 static int cx_save = 0;
4690 static int cy_save = 0;
4691 text_body_type text_body, *tb = &text_body;
4692 autopick_type an_entry, *entry = &an_entry;
4693 char buf[MAX_LINELEN];
4696 static s32b old_autosave_turn = 0L;
4699 tb->changed = FALSE;
4702 tb->upper = tb->left = 0;
4704 tb->mx = tb->my = 0;
4705 tb->old_cy = tb->old_upper = tb->old_left = -1;
4706 tb->old_wid = tb->old_hgt = -1;
4710 tb->search_o_ptr = NULL;
4711 tb->search_str = NULL;
4712 tb->last_destroyed = NULL;
4713 tb->dirty_flags = DIRTY_ALL | DIRTY_MODE | DIRTY_EXPRESSION;
4714 tb->dirty_line = -1;
4715 tb->filename_mode = PT_DEFAULT;
4717 if (current_world_ptr->game_turn < old_autosave_turn)
4719 while (old_autosave_turn > current_world_ptr->game_turn) old_autosave_turn -= TURNS_PER_TICK * TOWN_DAWN;
4722 if (current_world_ptr->game_turn > old_autosave_turn + 100L)
4724 do_cmd_save_game(player_ptr, TRUE);
4725 old_autosave_turn = current_world_ptr->game_turn;
4730 if (autopick_last_destroyed_object.k_idx)
4732 autopick_entry_from_object(player_ptr, entry, &autopick_last_destroyed_object);
4733 tb->last_destroyed = autopick_line_from_entry_kill(entry);
4736 tb->lines_list = read_pickpref_text_lines(player_ptr, &tb->filename_mode);
4737 for (i = 0; i < tb->cy; i++)
4739 if (!tb->lines_list[i])
4741 tb->cy = tb->cx = 0;
4750 draw_text_editor(player_ptr, tb);
4751 prt(_("(^Q:終了 ^W:セーブして終了, ESC:メニュー, その他:入力)",
4752 "(^Q:Quit, ^W:Save&Quit, ESC:Menu, Other:Input text)"), 0, 0);
4755 prt(format("(%d,%d)", tb->cx, tb->cy), 0, 60);
4759 prt(format("(%d,%d)-(%d,%d)", tb->mx, tb->my, tb->cx, tb->cy), 0, 60);
4762 Term_gotoxy(tb->cx - tb->left, tb->cy - tb->upper + 1);
4763 tb->dirty_flags = 0;
4764 tb->dirty_line = -1;
4765 tb->old_cy = tb->cy;
4766 tb->old_upper = tb->upper;
4767 tb->old_left = tb->left;
4768 tb->old_wid = tb->wid;
4769 tb->old_hgt = tb->hgt;
4771 key = inkey_special(TRUE);
4773 if (key & SKEY_MASK)
4775 com_id = analyze_move_key(tb, key);
4777 else if (key == ESCAPE)
4779 com_id = do_command_menu(0, 0);
4780 tb->dirty_flags |= DIRTY_SCREEN;
4782 else if (!iscntrl((unsigned char)key))
4787 tb->dirty_flags |= DIRTY_ALL;
4790 insert_single_letter(tb, key);
4795 com_id = get_com_id((char)key);
4798 if (com_id) quit = do_editor_command(player_ptr, tb, com_id);
4802 strcpy(buf, pickpref_filename(player_ptr, tb->filename_mode));
4804 if (quit == QUIT_AND_SAVE)
4805 write_text_lines(buf, tb->lines_list);
4807 free_text_lines(tb->lines_list);
4808 string_free(tb->search_str);
4809 string_free(tb->last_destroyed);
4810 kill_yank_chain(tb);
4812 process_autopick_file(player_ptr, buf);
4813 current_world_ptr->start_time = (u32b)time(NULL);