OSDN Git Service

[Refactor] #38852 いくつかの do_cmd_*() をリファクタリング。 / Refactor some do_cmd_*().
[hengband/hengband.git] / src / autopick.c
1 /*!
2  * @file autopick.c
3  * @brief 自動拾い機能の実装 / Object Auto-picker/Destroyer
4  * @date 2014/01/02
5  * @author
6  * Copyright (c) 2002  Mogami\n
7  *\n
8  * This software may be copied and distributed for educational, research, and\n
9  * not for profit purposes provided that this copyright and statement are\n
10  * included in all such copies.\n
11  * 2014 Deskull rearranged comment for Doxygen.\n
12  */
13
14 #include "angband.h"
15 #include "store.h"
16
17 #define MAX_LINELEN 1024
18
19 /*
20  * Macros for Keywords
21  */
22 #define FLG_ALL                         0
23 #define FLG_UNAWARE                     1
24 #define FLG_UNIDENTIFIED        2
25 #define FLG_IDENTIFIED          3
26 #define FLG_STAR_IDENTIFIED     4
27 #define FLG_COLLECTING          5
28 #define FLG_ARTIFACT            6
29 #define FLG_EGO              7 
30 #define FLG_GOOD             10
31 #define FLG_NAMELESS     11
32 #define FLG_AVERAGE          12
33 #define FLG_WORTHLESS    13
34 #define FLG_RARE             14
35 #define FLG_COMMON           15
36 #define FLG_BOOSTED          16
37 #define FLG_MORE_DICE    17
38 #define FLG_MORE_BONUS   18
39 #define FLG_WANTED           19
40 #define FLG_UNIQUE           20
41 #define FLG_HUMAN            21
42 #define FLG_UNREADABLE   22
43 #define FLG_REALM1           23
44 #define FLG_REALM2           24
45 #define FLG_FIRST            25
46 #define FLG_SECOND           26
47 #define FLG_THIRD            27
48 #define FLG_FOURTH           28
49
50 #define FLG_ITEMS            30
51 #define FLG_WEAPONS          31
52 #define FLG_FAVORITE_WEAPONS 32
53 #define FLG_ARMORS           33
54 #define FLG_MISSILES         34
55 #define FLG_DEVICES          35
56 #define FLG_LIGHTS           36
57 #define FLG_JUNKS            37
58 #define FLG_CORPSES          38
59 #define FLG_SPELLBOOKS       39
60 #define FLG_HAFTED           40
61 #define FLG_SHIELDS          41
62 #define FLG_BOWS             42
63 #define FLG_RINGS            43
64 #define FLG_AMULETS          44
65 #define FLG_SUITS            45
66 #define FLG_CLOAKS           46
67 #define FLG_HELMS            47
68 #define FLG_GLOVES           48
69 #define FLG_BOOTS            49
70
71 #define FLG_NOUN_BEGIN      FLG_ITEMS
72 #define FLG_NOUN_END        FLG_BOOTS
73
74 #ifdef JP
75
76 static GAME_TEXT KEY_ALL[] = "すべての";
77 static GAME_TEXT KEY_UNAWARE[] = "未判明の";
78 static GAME_TEXT KEY_UNIDENTIFIED[] = "未鑑定の";
79 static GAME_TEXT KEY_IDENTIFIED[] = "鑑定済みの";
80 static GAME_TEXT KEY_STAR_IDENTIFIED[] = "*鑑定*済みの";
81 static GAME_TEXT KEY_COLLECTING[] = "収集中の";
82 static GAME_TEXT KEY_ARTIFACT[] = "アーティファクト";
83 static GAME_TEXT KEY_EGO[] = "エゴ";
84 static GAME_TEXT KEY_GOOD[] = "上質の";
85 static GAME_TEXT KEY_NAMELESS[] = "無銘の";
86 static GAME_TEXT KEY_AVERAGE[] = "並の";
87 static GAME_TEXT KEY_WORTHLESS[] = "無価値の";
88 static GAME_TEXT KEY_RARE[] = "レアな";
89 static GAME_TEXT KEY_COMMON[] = "ありふれた";
90 static GAME_TEXT KEY_BOOSTED[] = "ダイス目の違う";
91 static GAME_TEXT KEY_MORE_THAN[] =  "ダイス目";
92 static GAME_TEXT KEY_DICE[] =  "以上の";
93 static GAME_TEXT KEY_MORE_BONUS[] =  "修正値";
94 static GAME_TEXT KEY_MORE_BONUS2[] =  "以上の";
95 static GAME_TEXT KEY_WANTED[] = "賞金首の";
96 static GAME_TEXT KEY_UNIQUE[] = "ユニーク・モンスターの";
97 static GAME_TEXT KEY_HUMAN[] = "人間の";
98 static GAME_TEXT KEY_UNREADABLE[] = "読めない";
99 static GAME_TEXT KEY_REALM1[] = "第一領域の";
100 static GAME_TEXT KEY_REALM2[] = "第二領域の";
101 static GAME_TEXT KEY_FIRST[] = "1冊目の";
102 static GAME_TEXT KEY_SECOND[] = "2冊目の";
103 static GAME_TEXT KEY_THIRD[] = "3冊目の";
104 static GAME_TEXT KEY_FOURTH[] = "4冊目の";
105 static GAME_TEXT KEY_ITEMS[] = "アイテム";
106 static GAME_TEXT KEY_WEAPONS[] = "武器";
107 static GAME_TEXT KEY_FAVORITE_WEAPONS[] = "得意武器";
108 static GAME_TEXT KEY_ARMORS[] = "防具";
109 static GAME_TEXT KEY_MISSILES[] = "矢";
110 static GAME_TEXT KEY_DEVICES[] = "魔法アイテム";
111 static GAME_TEXT KEY_LIGHTS[] = "光源";
112 static GAME_TEXT KEY_JUNKS[] = "がらくた";
113 static GAME_TEXT KEY_CORPSES[] = "死体や骨";
114 static GAME_TEXT KEY_SPELLBOOKS[] = "魔法書";
115 static GAME_TEXT KEY_HAFTED[] = "鈍器";
116 static GAME_TEXT KEY_SHIELDS[] = "盾";
117 static GAME_TEXT KEY_BOWS[] = "弓";
118 static GAME_TEXT KEY_RINGS[] = "指輪";
119 static GAME_TEXT KEY_AMULETS[] = "アミュレット";
120 static GAME_TEXT KEY_SUITS[] = "鎧";
121 static GAME_TEXT KEY_CLOAKS[] = "クローク";
122 static GAME_TEXT KEY_HELMS[] = "兜";
123 static GAME_TEXT KEY_GLOVES[] = "籠手";
124 static GAME_TEXT KEY_BOOTS[] = "靴";
125
126 #else 
127
128 static GAME_TEXT KEY_ALL[] = "all";
129 static GAME_TEXT KEY_UNAWARE[] = "unaware";
130 static GAME_TEXT KEY_UNIDENTIFIED[] = "unidentified";
131 static GAME_TEXT KEY_IDENTIFIED[] = "identified";
132 static GAME_TEXT KEY_STAR_IDENTIFIED[] = "*identified*";
133 static GAME_TEXT KEY_COLLECTING[] = "collecting";
134 static GAME_TEXT KEY_ARTIFACT[] = "artifact";
135 static GAME_TEXT KEY_EGO[] = "ego";
136 static GAME_TEXT KEY_GOOD[] = "good";
137 static GAME_TEXT KEY_nameLESS[] = "nameless";
138 static GAME_TEXT KEY_AVERAGE[] = "average";
139 static GAME_TEXT KEY_WORTHLESS[] = "worthless";
140 static GAME_TEXT KEY_RARE[] = "rare";
141 static GAME_TEXT KEY_COMMON[] = "common";
142 static GAME_TEXT KEY_BOOSTED[] = "dice boosted";
143 static GAME_TEXT KEY_MORE_THAN[] =  "more than";
144 static GAME_TEXT KEY_DICE[] =  " dice";
145 static GAME_TEXT KEY_MORE_BONUS[] =  "more bonus than";
146 static GAME_TEXT KEY_MORE_BONUS2[] =  "";
147 static GAME_TEXT KEY_WANTED[] = "wanted";
148 static GAME_TEXT KEY_UNIQUE[] = "unique monster's";
149 static GAME_TEXT KEY_HUMAN[] = "human";
150 static GAME_TEXT KEY_UNREADABLE[] = "unreadable";
151 static GAME_TEXT KEY_REALM1[] = "first realm's";
152 static GAME_TEXT KEY_REALM2[] = "second realm's";
153 static GAME_TEXT KEY_FIRST[] = "first";
154 static GAME_TEXT KEY_SECOND[] = "second";
155 static GAME_TEXT KEY_THIRD[] = "third";
156 static GAME_TEXT KEY_FOURTH[] = "fourth";
157 static GAME_TEXT KEY_ITEMS[] = "items";
158 static GAME_TEXT KEY_WEAPONS[] = "weapons";
159 static GAME_TEXT KEY_FAVORITE_WEAPONS[] = "favorite weapons";
160 static GAME_TEXT KEY_ARMORS[] = "armors";
161 static GAME_TEXT KEY_MISSILES[] = "missiles";
162 static GAME_TEXT KEY_DEVICES[] = "magical devices";
163 static GAME_TEXT KEY_LIGHTS[] = "lights";
164 static GAME_TEXT KEY_JUNKS[] = "junks";
165 static GAME_TEXT KEY_CORPSES[] = "corpses or skeletons";
166 static GAME_TEXT KEY_SPELLBOOKS[] = "spellbooks";
167 static GAME_TEXT KEY_HAFTED[] = "hafted weapons";
168 static GAME_TEXT KEY_SHIELDS[] = "shields";
169 static GAME_TEXT KEY_BOWS[] = "bows";
170 static GAME_TEXT KEY_RINGS[] = "rings";
171 static GAME_TEXT KEY_AMULETS[] = "amulets";
172 static GAME_TEXT KEY_SUITS[] = "suits";
173 static GAME_TEXT KEY_CLOAKS[] = "cloaks";
174 static GAME_TEXT KEY_HELMS[] = "helms";
175 static GAME_TEXT KEY_GLOVES[] = "gloves";
176 static GAME_TEXT KEY_BOOTS[] = "boots";
177
178 #endif /* JP */
179
180 #define MATCH_KEY(KEY) (!strncmp(ptr, KEY, sizeof(KEY)-1)\
181      ? (ptr += sizeof(KEY)-1, (' '==*ptr) ? ptr++ : 0, TRUE) : FALSE)
182 #define MATCH_KEY2(KEY) (!strncmp(ptr, KEY, sizeof(KEY)-1)\
183      ? (prev_ptr = ptr, ptr += sizeof(KEY)-1, (' '==*ptr) ? ptr++ : 0, TRUE) : FALSE)
184
185 #ifdef JP
186 #define ADD_KEY(KEY) strcat(ptr, KEY)
187 #else
188 #define ADD_KEY(KEY) (strcat(ptr, KEY), strcat(ptr, " "))
189 #endif
190 #define ADD_KEY2(KEY) strcat(ptr, KEY)
191
192 #define ADD_FLG(FLG) (entry->flag[FLG / 32] |= (1L << (FLG % 32)))
193 #define REM_FLG(FLG) (entry->flag[FLG / 32] &= ~(1L << (FLG % 32)))
194 #define ADD_FLG_NOUN(FLG) (ADD_FLG(FLG), prev_flg = FLG)
195 #define IS_FLG(FLG) (entry->flag[FLG / 32] & (1L << (FLG % 32)))
196
197 #ifdef JP
198         static char kanji_colon[] = ":";
199 #endif
200
201
202 /*
203  * A function to create new entry
204  */
205 static bool autopick_new_entry(autopick_type *entry, cptr str, bool allow_default)
206 {
207         cptr insc;
208         int i;
209         byte act = 0;
210         char buf[MAX_LINELEN];
211         cptr prev_ptr, ptr, old_ptr;
212         int prev_flg;
213
214         if (str[0] && str[1] == ':') switch (str[0])
215         {
216         case '?': case '%':
217         case 'A': case 'P': case 'C':
218                 return FALSE;
219         }
220
221         entry->flag[0] = entry->flag[1] = 0L;
222         entry->dice = 0;
223         entry->bonus = 0;
224
225         act = DO_AUTOPICK | DO_DISPLAY;
226         while (TRUE)
227         {
228                 if ((act & DO_AUTOPICK) && *str == '!')
229                 {
230                         act &= ~DO_AUTOPICK;
231                         act |= DO_AUTODESTROY;
232                         str++;
233                 }
234                 else if ((act & DO_AUTOPICK) && *str == '~')
235                 {
236                         act &= ~DO_AUTOPICK;
237                         act |= DONT_AUTOPICK;
238                         str++;
239                 }
240                 else if ((act & DO_AUTOPICK) && *str == ';')
241                 {
242                         act &= ~DO_AUTOPICK;
243                         act |= DO_QUERY_AUTOPICK;
244                         str++;
245                 }
246                 else if ((act & DO_DISPLAY) && *str == '(')
247                 {
248                         act &= ~DO_DISPLAY;
249                         str++;
250                 }
251                 else
252                         break;
253         }
254
255         /* don't mind upper or lower case */
256         insc = NULL;
257         for (i = 0; *str; i++)
258         {
259                 char c = *str++;
260 #ifdef JP
261                 if (iskanji(c))
262                 {
263                         buf[i++] = c;
264                         buf[i] = *str++;
265                         continue;
266                 }
267 #endif
268                 /* Auto-inscription? */
269                 if (c == '#')
270                 {
271                         buf[i] = '\0';
272                         insc = str;
273                         break;
274                 }
275
276                 if (isupper(c)) c = (char)tolower(c);
277
278                 buf[i] = c;
279         }
280         buf[i] = '\0';
281
282         /* Skip empty line unless allow_default */
283         if (!allow_default && *buf == 0) return FALSE;
284
285         /* Skip comment line */
286         if (*buf == 0 && insc) return FALSE;
287
288         ptr = prev_ptr = buf;
289         old_ptr = NULL;
290
291         while (old_ptr != ptr)
292         {
293                 /* Save current location */
294                 old_ptr = ptr;
295
296                 if (MATCH_KEY(KEY_ALL)) ADD_FLG(FLG_ALL);
297                 if (MATCH_KEY(KEY_COLLECTING)) ADD_FLG(FLG_COLLECTING);
298                 if (MATCH_KEY(KEY_UNAWARE)) ADD_FLG(FLG_UNAWARE);
299                 if (MATCH_KEY(KEY_UNIDENTIFIED)) ADD_FLG(FLG_UNIDENTIFIED);
300                 if (MATCH_KEY(KEY_IDENTIFIED)) ADD_FLG(FLG_IDENTIFIED);
301                 if (MATCH_KEY(KEY_STAR_IDENTIFIED)) ADD_FLG(FLG_STAR_IDENTIFIED);
302                 if (MATCH_KEY(KEY_BOOSTED)) ADD_FLG(FLG_BOOSTED);
303
304                 /*** Weapons whose dd*ds is more than nn ***/
305                 if (MATCH_KEY2(KEY_MORE_THAN))
306                 {
307                         int k = 0;
308                         entry->dice = 0;
309
310                         /* Drop leading spaces */
311                         while (' ' == *ptr) ptr++;
312
313                         /* Read number */
314                         while ('0' <= *ptr && *ptr <= '9')
315                         {
316                                 entry->dice = 10 * entry->dice + (*ptr - '0');
317                                 ptr++;
318                                 k++;
319                         }
320
321                         if (k > 0 && k <= 2)
322                         {
323                                 (void)MATCH_KEY(KEY_DICE);
324                                 ADD_FLG(FLG_MORE_DICE);
325                         }
326                         else
327                                 ptr = prev_ptr;
328                 }
329
330                 /*** Items whose magical bonus is more than n ***/
331                 if (MATCH_KEY2(KEY_MORE_BONUS))
332                 {
333                         int k = 0;
334                         entry->bonus = 0;
335
336                         /* Drop leading spaces */
337                         while (' ' == *ptr) ptr++;
338
339                         /* Read number */
340                         while ('0' <= *ptr && *ptr <= '9')
341                         {
342                                 entry->bonus = 10 * entry->bonus + (*ptr - '0');
343                                 ptr++;
344                                 k++;
345                         }
346
347                         if (k > 0 && k <= 2)
348                         {
349 #ifdef JP
350                                 (void)MATCH_KEY(KEY_MORE_BONUS2);
351 #else
352                                 if (' ' == *ptr) ptr++;
353 #endif
354                                 ADD_FLG(FLG_MORE_BONUS);
355                         }
356                         else
357                                 ptr = prev_ptr;
358                 }
359
360                 if (MATCH_KEY(KEY_WORTHLESS)) ADD_FLG(FLG_WORTHLESS);
361                 if (MATCH_KEY(KEY_EGO)) ADD_FLG(FLG_EGO);
362                 if (MATCH_KEY(KEY_GOOD)) ADD_FLG(FLG_GOOD);
363                 if (MATCH_KEY(KEY_NAMELESS)) ADD_FLG(FLG_NAMELESS);
364                 if (MATCH_KEY(KEY_AVERAGE)) ADD_FLG(FLG_AVERAGE);
365                 if (MATCH_KEY(KEY_RARE)) ADD_FLG(FLG_RARE);
366                 if (MATCH_KEY(KEY_COMMON)) ADD_FLG(FLG_COMMON);
367                 if (MATCH_KEY(KEY_WANTED)) ADD_FLG(FLG_WANTED);
368                 if (MATCH_KEY(KEY_UNIQUE)) ADD_FLG(FLG_UNIQUE);
369                 if (MATCH_KEY(KEY_HUMAN)) ADD_FLG(FLG_HUMAN);
370                 if (MATCH_KEY(KEY_UNREADABLE)) ADD_FLG(FLG_UNREADABLE);
371                 if (MATCH_KEY(KEY_REALM1)) ADD_FLG(FLG_REALM1);
372                 if (MATCH_KEY(KEY_REALM2)) ADD_FLG(FLG_REALM2);
373                 if (MATCH_KEY(KEY_FIRST)) ADD_FLG(FLG_FIRST);
374                 if (MATCH_KEY(KEY_SECOND)) ADD_FLG(FLG_SECOND);
375                 if (MATCH_KEY(KEY_THIRD)) ADD_FLG(FLG_THIRD);
376                 if (MATCH_KEY(KEY_FOURTH)) ADD_FLG(FLG_FOURTH);
377         }
378
379         /* Not yet found any noun */
380         prev_flg = -1;
381
382         if (MATCH_KEY2(KEY_ARTIFACT)) ADD_FLG_NOUN(FLG_ARTIFACT);
383
384         if (MATCH_KEY2(KEY_ITEMS)) ADD_FLG_NOUN(FLG_ITEMS);
385         else if (MATCH_KEY2(KEY_WEAPONS)) ADD_FLG_NOUN(FLG_WEAPONS);
386         else if (MATCH_KEY2(KEY_FAVORITE_WEAPONS)) ADD_FLG_NOUN(FLG_FAVORITE_WEAPONS);
387         else if (MATCH_KEY2(KEY_ARMORS)) ADD_FLG_NOUN(FLG_ARMORS);
388         else if (MATCH_KEY2(KEY_MISSILES)) ADD_FLG_NOUN(FLG_MISSILES);
389         else if (MATCH_KEY2(KEY_DEVICES)) ADD_FLG_NOUN(FLG_DEVICES);
390         else if (MATCH_KEY2(KEY_LIGHTS)) ADD_FLG_NOUN(FLG_LIGHTS);
391         else if (MATCH_KEY2(KEY_JUNKS)) ADD_FLG_NOUN(FLG_JUNKS);
392         else if (MATCH_KEY2(KEY_CORPSES)) ADD_FLG_NOUN(FLG_CORPSES);
393         else if (MATCH_KEY2(KEY_SPELLBOOKS)) ADD_FLG_NOUN(FLG_SPELLBOOKS);
394         else if (MATCH_KEY2(KEY_HAFTED)) ADD_FLG_NOUN(FLG_HAFTED);
395         else if (MATCH_KEY2(KEY_SHIELDS)) ADD_FLG_NOUN(FLG_SHIELDS);
396         else if (MATCH_KEY2(KEY_BOWS)) ADD_FLG_NOUN(FLG_BOWS);
397         else if (MATCH_KEY2(KEY_RINGS)) ADD_FLG_NOUN(FLG_RINGS);
398         else if (MATCH_KEY2(KEY_AMULETS)) ADD_FLG_NOUN(FLG_AMULETS);
399         else if (MATCH_KEY2(KEY_SUITS)) ADD_FLG_NOUN(FLG_SUITS);
400         else if (MATCH_KEY2(KEY_CLOAKS)) ADD_FLG_NOUN(FLG_CLOAKS);
401         else if (MATCH_KEY2(KEY_HELMS)) ADD_FLG_NOUN(FLG_HELMS);
402         else if (MATCH_KEY2(KEY_GLOVES)) ADD_FLG_NOUN(FLG_GLOVES);
403         else if (MATCH_KEY2(KEY_BOOTS)) ADD_FLG_NOUN(FLG_BOOTS);
404
405         /* Last 'keyword' must be at the correct location */
406         if (*ptr == ':')
407                 ptr++;
408 #ifdef JP
409         else if (ptr[0] == kanji_colon[0] && ptr[1] == kanji_colon[1])
410                 ptr += 2;
411 #endif
412         else if (*ptr == '\0')
413         {
414                 /* There was no noun */
415                 if (prev_flg == -1)
416
417                 /* Add extra word "items" */
418                 ADD_FLG_NOUN(FLG_ITEMS);
419         }
420         else
421         {
422                 /* Noun type? */
423                 if (prev_flg != -1)
424                 {
425                         /* A noun type keyword didn't end correctly */
426                         entry->flag[prev_flg/32] &= ~(1L<< (prev_flg%32));
427                         ptr = prev_ptr;
428                 }
429         }
430
431         /* Save this auto-picker entry line */
432         entry->name = string_make(ptr);
433         entry->action = act;
434         entry->insc = string_make(insc);
435
436         return TRUE;
437 }
438
439
440 /*
441  * Get auto-picker entry from o_ptr.
442  */
443 static void autopick_entry_from_object(autopick_type *entry, object_type *o_ptr)
444 {
445         /* Assume that object name is to be added */
446         bool name = TRUE;
447
448 #ifdef JP
449         /* エゴ銘が邪魔かもしれないので、デフォルトで「^」は付けない */
450         bool bol_mark = FALSE;
451 #else
452         /* We can always use the ^ mark in English */
453         bool bol_mark = TRUE;
454 #endif
455
456         GAME_TEXT name_str[MAX_NLEN];
457
458         /* Initialize name string */
459         name_str[0] = '\0';
460
461         entry->insc = string_make(quark_str(o_ptr->inscription));
462         entry->action = DO_AUTOPICK | DO_DISPLAY;
463         entry->flag[0] = entry->flag[1] = 0L;
464         entry->dice = 0;
465
466         /* Unaware */
467         if (!object_is_aware(o_ptr))
468         {
469                 ADD_FLG(FLG_UNAWARE);
470                 bol_mark = TRUE;
471         }
472
473         /* Not really identified */
474         else if (!object_is_known(o_ptr))
475         {
476                 if (!(o_ptr->ident & IDENT_SENSE))
477                 {
478                         ADD_FLG(FLG_UNIDENTIFIED);
479                         bol_mark = TRUE;
480                 }
481                 else
482                 {
483                         /* Pseudo-identified */
484                         switch (o_ptr->feeling)
485                         {
486                         case FEEL_AVERAGE:
487                         case FEEL_GOOD:
488                                 ADD_FLG(FLG_NAMELESS);
489                                 bol_mark = TRUE;
490                                 break;
491
492                         case FEEL_BROKEN:
493                         case FEEL_CURSED:
494                                 ADD_FLG(FLG_NAMELESS);
495                                 ADD_FLG(FLG_WORTHLESS);
496                                 bol_mark = TRUE;
497                                 break;
498
499                         case FEEL_TERRIBLE:
500                         case FEEL_WORTHLESS:
501                                 ADD_FLG(FLG_WORTHLESS);
502                                 break;
503
504                         case FEEL_EXCELLENT:
505                                 ADD_FLG(FLG_EGO);
506                                 break;
507
508                         case FEEL_UNCURSED:
509                                 /* XXX No appropriate flag */
510                                 /* ADD_FLG(); */
511                                 break;
512
513                         default:
514                                 /* Never reach here */
515                                 break;
516                         }
517                 }
518         }
519
520         /* Identified */
521         else
522         {
523                 /* Ego objects */
524                 if (object_is_ego(o_ptr))
525                 {
526                         if (object_is_weapon_armour_ammo(o_ptr))
527                         {
528                                 /*
529                                  * Base name of ego weapons and armors
530                                  * are almost meaningless.
531                                  * Register the ego type only.
532                                  */
533                                 ego_item_type *e_ptr = &e_info[o_ptr->name2];
534 #ifdef JP
535                                 /* エゴ銘には「^」マークが使える */
536                                 sprintf(name_str, "^%s", e_name + e_ptr->name);
537 #else
538                                 /* We ommit the basename and cannot use the ^ mark */
539                                 strcpy(name_str, e_name + e_ptr->name);
540 #endif
541
542                                 /* Don't use the object description */
543                                 name = FALSE;
544
545                                 /* Restrict to 'common' equipments */
546                                 if (!object_is_rare(o_ptr)) ADD_FLG(FLG_COMMON);
547                         }
548
549                         ADD_FLG(FLG_EGO);
550                 }
551
552                 /* Artifact */
553                 else if (object_is_artifact(o_ptr))
554                         ADD_FLG(FLG_ARTIFACT);
555
556                 /* Non-ego, non-artifact */
557                 else
558                 {
559                         /* Wearable nameless object */
560                         if (object_is_equipment(o_ptr))
561                                 ADD_FLG(FLG_NAMELESS);
562
563                         bol_mark = TRUE;
564                 }
565
566         }
567
568         /* Melee weapon with boosted dice */
569         if (object_is_melee_weapon(o_ptr))
570         {
571                 object_kind *k_ptr = &k_info[o_ptr->k_idx];
572
573                 if ((o_ptr->dd != k_ptr->dd) || (o_ptr->ds != k_ptr->ds))
574                         ADD_FLG(FLG_BOOSTED);
575         }
576
577         /* Wanted monster's corpse */
578         if (object_is_shoukinkubi(o_ptr))
579         {
580                 REM_FLG(FLG_WORTHLESS);
581                 ADD_FLG(FLG_WANTED);
582         }
583
584         if ((o_ptr->tval == TV_CORPSE || o_ptr->tval == TV_STATUE)
585             && (r_info[o_ptr->pval].flags1 & RF1_UNIQUE))
586         {
587                 ADD_FLG(FLG_UNIQUE);
588         }
589
590         if (o_ptr->tval == TV_CORPSE && my_strchr("pht", r_info[o_ptr->pval].d_char))
591         {
592                 ADD_FLG(FLG_HUMAN);
593         }
594
595         if (o_ptr->tval >= TV_LIFE_BOOK &&
596             !check_book_realm(o_ptr->tval, o_ptr->sval))
597         {
598                 ADD_FLG(FLG_UNREADABLE);
599                 if (o_ptr->tval != TV_ARCANE_BOOK) name = FALSE;
600         }
601
602         if (REALM1_BOOK == o_ptr->tval &&
603             p_ptr->pclass != CLASS_SORCERER &&
604             p_ptr->pclass != CLASS_RED_MAGE)
605         {
606                 ADD_FLG(FLG_REALM1);
607                 name = FALSE;
608         }
609
610         if (REALM2_BOOK == o_ptr->tval &&
611             p_ptr->pclass != CLASS_SORCERER &&
612             p_ptr->pclass != CLASS_RED_MAGE)
613         {
614                 ADD_FLG(FLG_REALM2);
615                 name = FALSE;
616         }
617
618         if (o_ptr->tval >= TV_LIFE_BOOK && 0 == o_ptr->sval)
619                 ADD_FLG(FLG_FIRST);
620         if (o_ptr->tval >= TV_LIFE_BOOK && 1 == o_ptr->sval)
621                 ADD_FLG(FLG_SECOND);
622         if (o_ptr->tval >= TV_LIFE_BOOK && 2 == o_ptr->sval)
623                 ADD_FLG(FLG_THIRD);
624         if (o_ptr->tval >= TV_LIFE_BOOK && 3 == o_ptr->sval)
625                 ADD_FLG(FLG_FOURTH);
626
627         if (object_is_ammo(o_ptr))
628                 ADD_FLG(FLG_MISSILES);
629         else if (o_ptr->tval == TV_SCROLL || o_ptr->tval == TV_STAFF
630                  || o_ptr->tval == TV_WAND || o_ptr->tval == TV_ROD)
631                 ADD_FLG(FLG_DEVICES);
632         else if (o_ptr->tval == TV_LITE)
633                 ADD_FLG(FLG_LIGHTS);
634         else if (o_ptr->tval == TV_SKELETON || o_ptr->tval == TV_BOTTLE
635                  || o_ptr->tval == TV_JUNK || o_ptr->tval == TV_STATUE)
636                 ADD_FLG(FLG_JUNKS);
637         else if (o_ptr->tval == TV_CORPSE)
638                 ADD_FLG(FLG_CORPSES);
639         else if (o_ptr->tval >= TV_LIFE_BOOK)
640                 ADD_FLG(FLG_SPELLBOOKS);
641         else if (o_ptr->tval == TV_POLEARM || o_ptr->tval == TV_SWORD
642                  || o_ptr->tval == TV_DIGGING || o_ptr->tval == TV_HAFTED)
643                 ADD_FLG(FLG_WEAPONS);
644         else if (o_ptr->tval == TV_SHIELD)
645                 ADD_FLG(FLG_SHIELDS);
646         else if (o_ptr->tval == TV_BOW)
647                 ADD_FLG(FLG_BOWS);
648         else if (o_ptr->tval == TV_RING)
649                 ADD_FLG(FLG_RINGS);
650         else if (o_ptr->tval == TV_AMULET)
651                 ADD_FLG(FLG_AMULETS);
652         else if (o_ptr->tval == TV_DRAG_ARMOR || o_ptr->tval == TV_HARD_ARMOR ||
653                  o_ptr->tval == TV_SOFT_ARMOR)
654                 ADD_FLG(FLG_SUITS);
655         else if (o_ptr->tval == TV_CLOAK)
656                 ADD_FLG(FLG_CLOAKS);
657         else if (o_ptr->tval == TV_HELM)
658                 ADD_FLG(FLG_HELMS);
659         else if (o_ptr->tval == TV_GLOVES)
660                 ADD_FLG(FLG_GLOVES);
661         else if (o_ptr->tval == TV_BOOTS)
662                 ADD_FLG(FLG_BOOTS);
663
664         /* Prepare the object description */
665         if (name)
666         {
667                 GAME_TEXT o_name[MAX_NLEN];
668
669                 object_desc(o_name, o_ptr, (OD_NO_FLAVOR | OD_OMIT_PREFIX | OD_NO_PLURAL | OD_NAME_ONLY));
670
671                 /*
672                  * If necessary, add a '^' which indicates the
673                  * beginning of line.
674                  */
675                 sprintf(name_str, "%s%s", bol_mark ? "^" : "", o_name);
676         }
677
678         /* Register the name in lowercase */
679         str_tolower(name_str);
680         entry->name = string_make(name_str);
681
682         return;
683 }
684
685
686 /*
687  * A function to delete entry
688  */
689 static void autopick_free_entry(autopick_type *entry)
690 {
691         string_free(entry->name);
692         string_free(entry->insc);
693         entry->name = NULL;
694         entry->insc = NULL;
695 }
696
697
698 #define MAX_AUTOPICK_DEFAULT 200
699
700 /*
701  * Initialize the autopick
702  */
703 static void init_autopick(void)
704 {
705         static const char easy_autopick_inscription[] = "(:=g";
706         autopick_type entry;
707         int i;
708
709         if (!autopick_list)
710         {
711                 max_max_autopick = MAX_AUTOPICK_DEFAULT;
712                 C_MAKE(autopick_list, max_max_autopick, autopick_type);
713                 max_autopick = 0;
714         }
715
716         /* Clear old entries */
717         for( i = 0; i < max_autopick; i++)
718                 autopick_free_entry(&autopick_list[i]);
719
720         max_autopick = 0;
721
722         /* There is always one entry "=g" */
723         autopick_new_entry(&entry, easy_autopick_inscription, TRUE);
724         autopick_list[max_autopick++] = entry;
725 }
726
727
728 #define PT_DEFAULT 0
729 #define PT_WITH_PNAME 1
730
731 /*
732  *  Get file name for autopick preference
733  */
734 static cptr pickpref_filename(int filename_mode)
735 {
736         static const char namebase[] = _("picktype", "pickpref");
737
738         switch (filename_mode)
739         {
740         case PT_DEFAULT:
741                 return format("%s.prf", namebase);
742
743         case PT_WITH_PNAME:
744                 return format("%s-%s.prf", namebase, player_base);
745
746         default:
747                 return NULL;
748         }
749 }
750
751
752 /*
753  * Load an autopick preference file
754  */
755 void autopick_load_pref(bool disp_mes)
756 {
757         GAME_TEXT buf[80];
758         errr err;
759
760         /* Free old entries */
761         init_autopick();
762
763         /* Try a filename with player name */
764         my_strcpy(buf, pickpref_filename(PT_WITH_PNAME), sizeof(buf));
765
766         /* Load the file */
767         err = process_autopick_file(buf);
768
769         if (err == 0 && disp_mes)
770         {
771                 /* Success */
772                 msg_format(_("%sを読み込みました。", "Loaded '%s'."), buf);
773         }
774
775         /* No file found */
776         if (0 > err)
777         {
778                 /* Use default name */
779                 my_strcpy(buf, pickpref_filename(PT_DEFAULT), sizeof(buf));
780
781                 /* Load the file */
782                 err = process_autopick_file(buf);
783
784                 if (err == 0 && disp_mes)
785                 {
786                         /* Success */
787                         msg_format(_("%sを読み込みました。", "Loaded '%s'."), buf);
788                 }
789         }
790
791         if (err && disp_mes)
792         {
793                 /* Failed */
794                 msg_print(_("自動拾い設定ファイルの読み込みに失敗しました。", "Failed to reload autopick preference."));
795         }
796 }
797
798
799 /*
800  * Add one line to autopick_list[]
801  */
802 static void add_autopick_list(autopick_type *entry)
803 {
804         /* There is no enough space to add one line */
805         if (max_autopick >= max_max_autopick)
806         {
807                 int old_max_max_autopick = max_max_autopick;
808                 autopick_type *old_autopick_list = autopick_list;
809
810                 /* Increase size of list */
811                 max_max_autopick += MAX_AUTOPICK_DEFAULT;
812
813                 /* Allocate */
814                 C_MAKE(autopick_list, max_max_autopick, autopick_type);
815
816                 /* Copy from old list to new list */
817                 (void)C_COPY(autopick_list, old_autopick_list, old_max_max_autopick, autopick_type);
818
819                 /* Kill old list */
820                 C_KILL(old_autopick_list, old_max_max_autopick, autopick_type);
821         }
822
823         /* Add one line */
824         autopick_list[max_autopick] = *entry;
825
826         max_autopick++;
827 }
828
829
830 /*
831  *  Process line for auto picker/destroyer.
832  */
833 errr process_autopick_file_command(char *buf)
834 {
835         autopick_type an_entry, *entry = &an_entry;
836         int i;
837
838         /* Nuke illegal char */
839         for(i = 0; buf[i]; i++)
840         {
841 #ifdef JP
842                 if (iskanji(buf[i]))
843                 {
844                         i++;
845                         continue;
846                 }
847 #endif
848                 if (iswspace(buf[i]) && buf[i] != ' ')
849                         break;
850         }
851         buf[i] = 0;
852         
853         if (!autopick_new_entry(entry, buf, FALSE)) return 0;
854
855         /* Already has the same entry? */ 
856         for(i = 0; i < max_autopick; i++)
857                 if(!strcmp(entry->name, autopick_list[i].name)
858                    && entry->flag[0] == autopick_list[i].flag[0]
859                    && entry->flag[1] == autopick_list[i].flag[1]
860                    && entry->dice == autopick_list[i].dice
861                    && entry->bonus == autopick_list[i].bonus)
862                 {
863                         autopick_free_entry(entry);
864                         return 0;
865                 }
866
867         add_autopick_list(entry);
868         return 0;
869 }
870
871
872 /*
873  * Reconstruct preference line from entry
874  */
875 cptr autopick_line_from_entry(autopick_type *entry)
876 {
877         char buf[MAX_LINELEN];
878         char *ptr;
879         bool sepa_flag = TRUE;
880
881         *buf = '\0';
882         if (!(entry->action & DO_DISPLAY)) strcat(buf, "(");
883         if (entry->action & DO_QUERY_AUTOPICK) strcat(buf, ";");
884         if (entry->action & DO_AUTODESTROY) strcat(buf, "!");
885         if (entry->action & DONT_AUTOPICK) strcat(buf, "~");
886
887         ptr = buf;
888
889         if (IS_FLG(FLG_ALL)) ADD_KEY(KEY_ALL);
890         if (IS_FLG(FLG_COLLECTING)) ADD_KEY(KEY_COLLECTING);
891         if (IS_FLG(FLG_UNAWARE)) ADD_KEY(KEY_UNAWARE);
892         if (IS_FLG(FLG_UNIDENTIFIED)) ADD_KEY(KEY_UNIDENTIFIED);
893         if (IS_FLG(FLG_IDENTIFIED)) ADD_KEY(KEY_IDENTIFIED);
894         if (IS_FLG(FLG_STAR_IDENTIFIED)) ADD_KEY(KEY_STAR_IDENTIFIED);
895         if (IS_FLG(FLG_BOOSTED)) ADD_KEY(KEY_BOOSTED);
896
897         if (IS_FLG(FLG_MORE_DICE))
898         {
899                 ADD_KEY(KEY_MORE_THAN);
900                 strcat(ptr, format("%d", entry->dice));
901                 ADD_KEY(KEY_DICE);
902         }
903
904         if (IS_FLG(FLG_MORE_BONUS))
905         {
906                 ADD_KEY(KEY_MORE_BONUS);
907                 strcat(ptr, format("%d", entry->bonus));
908                 ADD_KEY(KEY_MORE_BONUS2);
909         }
910
911         if (IS_FLG(FLG_UNREADABLE)) ADD_KEY(KEY_UNREADABLE);
912         if (IS_FLG(FLG_REALM1)) ADD_KEY(KEY_REALM1);
913         if (IS_FLG(FLG_REALM2)) ADD_KEY(KEY_REALM2);
914         if (IS_FLG(FLG_FIRST)) ADD_KEY(KEY_FIRST);
915         if (IS_FLG(FLG_SECOND)) ADD_KEY(KEY_SECOND);
916         if (IS_FLG(FLG_THIRD)) ADD_KEY(KEY_THIRD);
917         if (IS_FLG(FLG_FOURTH)) ADD_KEY(KEY_FOURTH);
918         if (IS_FLG(FLG_WANTED)) ADD_KEY(KEY_WANTED);
919         if (IS_FLG(FLG_UNIQUE)) ADD_KEY(KEY_UNIQUE);
920         if (IS_FLG(FLG_HUMAN)) ADD_KEY(KEY_HUMAN);
921         if (IS_FLG(FLG_WORTHLESS)) ADD_KEY(KEY_WORTHLESS);
922         if (IS_FLG(FLG_GOOD)) ADD_KEY(KEY_GOOD);
923         if (IS_FLG(FLG_NAMELESS)) ADD_KEY(KEY_NAMELESS);
924         if (IS_FLG(FLG_AVERAGE)) ADD_KEY(KEY_AVERAGE);
925         if (IS_FLG(FLG_RARE)) ADD_KEY(KEY_RARE);
926         if (IS_FLG(FLG_COMMON)) ADD_KEY(KEY_COMMON);
927         if (IS_FLG(FLG_EGO)) ADD_KEY(KEY_EGO);
928
929         if (IS_FLG(FLG_ARTIFACT)) ADD_KEY(KEY_ARTIFACT);
930
931         if (IS_FLG(FLG_ITEMS)) ADD_KEY2(KEY_ITEMS);
932         else if (IS_FLG(FLG_WEAPONS)) ADD_KEY2(KEY_WEAPONS);
933         else if (IS_FLG(FLG_FAVORITE_WEAPONS)) ADD_KEY2(KEY_FAVORITE_WEAPONS);
934         else if (IS_FLG(FLG_ARMORS)) ADD_KEY2(KEY_ARMORS);
935         else if (IS_FLG(FLG_MISSILES)) ADD_KEY2(KEY_MISSILES);
936         else if (IS_FLG(FLG_DEVICES)) ADD_KEY2(KEY_DEVICES);
937         else if (IS_FLG(FLG_LIGHTS)) ADD_KEY2(KEY_LIGHTS);
938         else if (IS_FLG(FLG_JUNKS)) ADD_KEY2(KEY_JUNKS);
939         else if (IS_FLG(FLG_CORPSES)) ADD_KEY2(KEY_CORPSES);
940         else if (IS_FLG(FLG_SPELLBOOKS)) ADD_KEY2(KEY_SPELLBOOKS);
941         else if (IS_FLG(FLG_HAFTED)) ADD_KEY2(KEY_HAFTED);
942         else if (IS_FLG(FLG_SHIELDS)) ADD_KEY2(KEY_SHIELDS);
943         else if (IS_FLG(FLG_BOWS)) ADD_KEY2(KEY_BOWS);
944         else if (IS_FLG(FLG_RINGS)) ADD_KEY2(KEY_RINGS);
945         else if (IS_FLG(FLG_AMULETS)) ADD_KEY2(KEY_AMULETS);
946         else if (IS_FLG(FLG_SUITS)) ADD_KEY2(KEY_SUITS);
947         else if (IS_FLG(FLG_CLOAKS)) ADD_KEY2(KEY_CLOAKS);
948         else if (IS_FLG(FLG_HELMS)) ADD_KEY2(KEY_HELMS);
949         else if (IS_FLG(FLG_GLOVES)) ADD_KEY2(KEY_GLOVES);
950         else if (IS_FLG(FLG_BOOTS)) ADD_KEY2(KEY_BOOTS);
951
952         /* You don't need sepalator after adjective */
953         /* 'artifact' is not true adjective */
954         else if (!IS_FLG(FLG_ARTIFACT))
955                 sepa_flag = FALSE;
956
957         if (entry->name && entry->name[0])
958         {
959                 int i, j = 0;
960
961                 if (sepa_flag) strcat(buf, ":");
962
963                 i = strlen(buf);
964                 while (entry->name[j] && i < MAX_LINELEN - 2 - 1)
965                 {
966 #ifdef JP
967                         if (iskanji(entry->name[j]))
968                                 buf[i++] = entry->name[j++];
969 #endif
970                         buf[i++] = entry->name[j++];
971                 }
972                 buf[i] = '\0';
973         }
974
975         if (entry->insc)
976         {
977                 int i, j = 0;
978                 strcat(buf, "#");
979                 i = strlen(buf);
980
981                 while (entry->insc[j] && i < MAX_LINELEN - 2)
982                 {
983 #ifdef JP
984                         if (iskanji(entry->insc[j]))
985                                 buf[i++] = entry->insc[j++];
986 #endif
987                         buf[i++] = entry->insc[j++];
988                 }
989                 buf[i] = '\0';
990         }
991
992         return string_make(buf);
993 }
994
995
996 /*
997  * Reconstruct preference line from entry and kill entry
998  */
999 static cptr autopick_line_from_entry_kill(autopick_type *entry)
1000 {
1001         cptr ptr = autopick_line_from_entry(entry);
1002
1003         /* Free memory for original entry */
1004         autopick_free_entry(entry);
1005
1006         return ptr;
1007 }
1008
1009
1010 /*
1011  * A function for Auto-picker/destroyer
1012  * Examine whether the object matches to the entry
1013  */
1014 static bool is_autopick_aux(object_type *o_ptr, autopick_type *entry, cptr o_name)
1015 {
1016         int j;
1017         cptr ptr = entry->name;
1018
1019         /*** Unaware items ***/
1020         if (IS_FLG(FLG_UNAWARE) && object_is_aware(o_ptr))
1021                 return FALSE;
1022
1023         /*** Unidentified ***/
1024         if (IS_FLG(FLG_UNIDENTIFIED)
1025             && (object_is_known(o_ptr) || (o_ptr->ident & IDENT_SENSE)))
1026                 return FALSE;
1027
1028         /*** Identified ***/
1029         if (IS_FLG(FLG_IDENTIFIED) && !object_is_known(o_ptr))
1030                 return FALSE;
1031
1032         /*** *Identified* ***/
1033         if (IS_FLG(FLG_STAR_IDENTIFIED) &&
1034             (!object_is_known(o_ptr) || !(o_ptr->ident & IDENT_MENTAL)))
1035                 return FALSE;
1036
1037         /*** Dice boosted (weapon of slaying) ***/
1038         if (IS_FLG(FLG_BOOSTED))
1039         {
1040                 object_kind *k_ptr = &k_info[o_ptr->k_idx];
1041
1042                 /* Require melee weapon */
1043                 if (!object_is_melee_weapon(o_ptr))
1044                         return FALSE;
1045
1046                 /* Require boosted dice */
1047                 if ((o_ptr->dd == k_ptr->dd) && (o_ptr->ds == k_ptr->ds))
1048                         return FALSE;
1049                 
1050                 /* In Vault Quest, Dice must be hide.*/
1051                 if(!object_is_known(o_ptr) && object_is_quest_target(o_ptr))
1052                 {
1053                         return FALSE;
1054                 }
1055         }
1056
1057         /*** Weapons which dd*ds is more than nn ***/
1058         if (IS_FLG(FLG_MORE_DICE))
1059         {
1060                 if (o_ptr->dd * o_ptr->ds < entry->dice)
1061                         return FALSE;
1062         }
1063                                 
1064         /*** Weapons whic dd*ds is more than nn ***/
1065         if (IS_FLG(FLG_MORE_BONUS))
1066         {
1067                 if (!object_is_known(o_ptr)) return FALSE;
1068
1069                 if (o_ptr->pval)
1070                 {
1071                         if (o_ptr->pval < entry->bonus) return FALSE;
1072                 }
1073                 else
1074                 {
1075                         if (o_ptr->to_h < entry->bonus &&
1076                             o_ptr->to_d < entry->bonus &&
1077                             o_ptr->to_a < entry->bonus &&
1078                             o_ptr->pval < entry->bonus)
1079                                 return FALSE;
1080                 }
1081         }
1082                                 
1083         /*** Worthless items ***/
1084         if (IS_FLG(FLG_WORTHLESS) && object_value(o_ptr) > 0)
1085                 return FALSE;
1086
1087         /*** Artifact object ***/
1088         if (IS_FLG(FLG_ARTIFACT))
1089         {
1090                 if (!object_is_known(o_ptr) || !object_is_artifact(o_ptr))
1091                         return FALSE;
1092         }
1093
1094         /*** Ego object ***/
1095         if (IS_FLG(FLG_EGO))
1096         {
1097                 /* Need to be an ego item */
1098                 if (!object_is_ego(o_ptr)) return FALSE;
1099
1100                 /* Need to be known to be an ego */
1101                 if (!object_is_known(o_ptr) &&
1102                     !((o_ptr->ident & IDENT_SENSE) && o_ptr->feeling == FEEL_EXCELLENT))
1103                         return FALSE;
1104         }
1105
1106         /*** Good ***/
1107         if (IS_FLG(FLG_GOOD))
1108         {
1109                 if (!object_is_equipment(o_ptr)) return FALSE;
1110
1111                 /* Identified */
1112                 if (object_is_known(o_ptr))
1113                 {
1114                         /* Artifacts and Ego objects are not okay */
1115                         if (!object_is_nameless(o_ptr))
1116                                 return FALSE;
1117
1118                         /* Average are not okay */
1119                         if (o_ptr->to_a <= 0 && (o_ptr->to_h + o_ptr->to_d) <= 0)
1120                                 return FALSE;
1121                 }
1122
1123                 /* Pseudo-identified */
1124                 else if (o_ptr->ident & IDENT_SENSE)
1125                 {
1126                         switch (o_ptr->feeling)
1127                         {
1128                         case FEEL_GOOD:
1129                                 /* It's good */
1130                                 break;
1131
1132                         default:
1133                                 /* It's not good */
1134                                 return FALSE;
1135                         }
1136                 }
1137
1138                 /* Unidentified */
1139                 else
1140                 {
1141                         /* Not known to be good */
1142                         return FALSE;
1143                 }
1144         }
1145
1146         /*** Nameless ***/
1147         if (IS_FLG(FLG_NAMELESS))
1148         {
1149                 if (!object_is_equipment(o_ptr)) return FALSE;
1150
1151                 /* Identified */
1152                 if (object_is_known(o_ptr))
1153                 {
1154                         /* Artifacts and Ego objects are not okay */
1155                         if (!object_is_nameless(o_ptr))
1156                                 return FALSE;
1157                 }
1158
1159                 /* Pseudo-identified */
1160                 else if (o_ptr->ident & IDENT_SENSE)
1161                 {
1162                         switch (o_ptr->feeling)
1163                         {
1164                         case FEEL_AVERAGE:
1165                         case FEEL_GOOD:
1166                         case FEEL_BROKEN:
1167                         case FEEL_CURSED:
1168                                 /* It's nameless */
1169                                 break;
1170
1171                         default:
1172                                 /* It's not nameless */
1173                                 return FALSE;
1174                         }
1175                 }
1176
1177                 /* Unidentified */
1178                 else
1179                 {
1180                         /* Not known to be nameless */
1181                         return FALSE;
1182                 }
1183         }
1184
1185         /*** Average ***/
1186         if (IS_FLG(FLG_AVERAGE))
1187         {
1188                 if (!object_is_equipment(o_ptr)) return FALSE;
1189
1190                 /* Identified */
1191                 if (object_is_known(o_ptr))
1192                 {
1193                         /* Artifacts and Ego objects are not okay */
1194                         if (!object_is_nameless(o_ptr))
1195                                 return FALSE;
1196
1197                         /* Cursed or broken objects are not okay */
1198                         if (object_is_cursed(o_ptr) || object_is_broken(o_ptr))
1199                                 return FALSE;
1200
1201                         /* Good are not okay */
1202                         if (o_ptr->to_a > 0 || (o_ptr->to_h + o_ptr->to_d) > 0)
1203                                 return FALSE;
1204                 }
1205
1206                 /* Pseudo-identified */
1207                 else if (o_ptr->ident & IDENT_SENSE)
1208                 {
1209                         switch (o_ptr->feeling)
1210                         {
1211                         case FEEL_AVERAGE:
1212                                 /* It's average */
1213                                 break;
1214
1215                         default:
1216                                 /* It's not average */
1217                                 return FALSE;
1218                         }
1219                 }
1220
1221                 /* Unidentified */
1222                 else
1223                 {
1224                         /* Not known to be average */
1225                         return FALSE;
1226                 }
1227         }
1228
1229         /*** Rere equipments ***/
1230         if (IS_FLG(FLG_RARE) && !object_is_rare(o_ptr))
1231                 return FALSE;
1232
1233         /*** Common equipments ***/
1234         if (IS_FLG(FLG_COMMON) && object_is_rare(o_ptr))
1235                 return FALSE;
1236
1237         /*** Wanted monster's corpse/skeletons ***/
1238         if (IS_FLG(FLG_WANTED) && !object_is_shoukinkubi(o_ptr))
1239                 return FALSE;
1240
1241         /*** Unique monster's corpse/skeletons/statues ***/
1242         if (IS_FLG(FLG_UNIQUE) &&
1243             ((o_ptr->tval != TV_CORPSE && o_ptr->tval != TV_STATUE) ||
1244              !(r_info[o_ptr->pval].flags1 & RF1_UNIQUE)))
1245                 return FALSE;
1246
1247         /*** Human corpse/skeletons (for Daemon magic) ***/
1248         if (IS_FLG(FLG_HUMAN) &&
1249             (o_ptr->tval != TV_CORPSE ||
1250              !my_strchr("pht", r_info[o_ptr->pval].d_char)))
1251                 return FALSE;
1252
1253         /*** Unreadable spellbooks ***/
1254         if (IS_FLG(FLG_UNREADABLE) &&
1255             (o_ptr->tval < TV_LIFE_BOOK ||
1256              check_book_realm(o_ptr->tval, o_ptr->sval)))
1257                 return FALSE;
1258
1259         /*** First realm spellbooks ***/
1260         if (IS_FLG(FLG_REALM1) && 
1261             (REALM1_BOOK != o_ptr->tval ||
1262              p_ptr->pclass == CLASS_SORCERER ||
1263              p_ptr->pclass == CLASS_RED_MAGE))
1264                 return FALSE;
1265
1266         /*** Second realm spellbooks ***/
1267         if (IS_FLG(FLG_REALM2) &&
1268             (REALM2_BOOK != o_ptr->tval ||
1269              p_ptr->pclass == CLASS_SORCERER ||
1270              p_ptr->pclass == CLASS_RED_MAGE))
1271                 return FALSE;
1272
1273         /*** First rank spellbooks ***/
1274         if (IS_FLG(FLG_FIRST) &&
1275             (o_ptr->tval < TV_LIFE_BOOK || 0 != o_ptr->sval))
1276                 return FALSE;
1277
1278         /*** Second rank spellbooks ***/
1279         if (IS_FLG(FLG_SECOND) &&
1280             (o_ptr->tval < TV_LIFE_BOOK || 1 != o_ptr->sval))
1281                 return FALSE;
1282
1283         /*** Third rank spellbooks ***/
1284         if (IS_FLG(FLG_THIRD) && 
1285             (o_ptr->tval < TV_LIFE_BOOK || 2 != o_ptr->sval))
1286                 return FALSE;
1287
1288         /*** Fourth rank spellbooks ***/
1289         if (IS_FLG(FLG_FOURTH) &&
1290             (o_ptr->tval < TV_LIFE_BOOK || 3 != o_ptr->sval))
1291                 return FALSE;
1292
1293         /*** Items ***/
1294         if (IS_FLG(FLG_WEAPONS))
1295         {
1296                 if (!object_is_weapon(o_ptr))
1297                         return FALSE;
1298         }
1299         else if (IS_FLG(FLG_FAVORITE_WEAPONS))
1300         {
1301                 if (!object_is_favorite(o_ptr))
1302                         return FALSE;
1303         }
1304         else if (IS_FLG(FLG_ARMORS))
1305         {
1306                 if (!object_is_armour(o_ptr))
1307                         return FALSE;
1308         }
1309         else if (IS_FLG(FLG_MISSILES))
1310         {
1311                 if (!object_is_ammo(o_ptr)) return FALSE;
1312         }
1313         else if (IS_FLG(FLG_DEVICES))
1314         {
1315                 switch(o_ptr->tval)
1316                 {
1317                 case TV_SCROLL: case TV_STAFF: case TV_WAND: case TV_ROD:
1318                         break;
1319                 default: return FALSE;
1320                 }
1321         }
1322         else if (IS_FLG(FLG_LIGHTS))
1323         {
1324                 if (!(o_ptr->tval == TV_LITE))
1325                         return FALSE;
1326         }
1327         else if (IS_FLG(FLG_JUNKS))
1328         {
1329                 switch(o_ptr->tval)
1330                 {
1331                 case TV_SKELETON: case TV_BOTTLE:
1332                 case TV_JUNK: case TV_STATUE:
1333                         break;
1334                 default: return FALSE;
1335                 }
1336         }
1337         else if (IS_FLG(FLG_CORPSES))
1338         {
1339                 if (o_ptr->tval != TV_CORPSE && o_ptr->tval != TV_SKELETON)
1340                         return FALSE;
1341         }
1342         else if (IS_FLG(FLG_SPELLBOOKS))
1343         {
1344                 if (!(o_ptr->tval >= TV_LIFE_BOOK))
1345                         return FALSE;
1346         }
1347         else if (IS_FLG(FLG_HAFTED))
1348         {
1349                 if (!(o_ptr->tval == TV_HAFTED))
1350                         return FALSE;
1351         }
1352         else if (IS_FLG(FLG_SHIELDS))
1353         {
1354                 if (!(o_ptr->tval == TV_SHIELD))
1355                         return FALSE;
1356         }
1357         else if (IS_FLG(FLG_BOWS))
1358         {
1359                 if (!(o_ptr->tval == TV_BOW))
1360                         return FALSE;
1361         }
1362         else if (IS_FLG(FLG_RINGS))
1363         {
1364                 if (!(o_ptr->tval == TV_RING))
1365                         return FALSE;
1366         }
1367         else if (IS_FLG(FLG_AMULETS))
1368         {
1369                 if (!(o_ptr->tval == TV_AMULET))
1370                         return FALSE;
1371         }
1372         else if (IS_FLG(FLG_SUITS))
1373         {
1374                 if (!(o_ptr->tval == TV_DRAG_ARMOR ||
1375                       o_ptr->tval == TV_HARD_ARMOR ||
1376                       o_ptr->tval == TV_SOFT_ARMOR))
1377                         return FALSE;
1378         }
1379         else if (IS_FLG(FLG_CLOAKS))
1380         {
1381                 if (!(o_ptr->tval == TV_CLOAK))
1382                         return FALSE;
1383         }
1384         else if (IS_FLG(FLG_HELMS))
1385         {
1386                 if (!(o_ptr->tval == TV_CROWN || o_ptr->tval == TV_HELM))
1387                         return FALSE;
1388         }
1389         else if (IS_FLG(FLG_GLOVES))
1390         {
1391                 if (!(o_ptr->tval == TV_GLOVES))
1392                         return FALSE;
1393         }
1394         else if (IS_FLG(FLG_BOOTS))
1395         {
1396                 if (!(o_ptr->tval == TV_BOOTS))
1397                         return FALSE;
1398         }
1399
1400         /* Keyword don't match */
1401         if (*ptr == '^')
1402         {
1403                 ptr++;
1404                 if (strncmp(o_name, ptr, strlen(ptr))) return FALSE;
1405         }
1406         else
1407         {
1408                 if (!my_strstr(o_name, ptr)) return FALSE;
1409         }
1410
1411         /* TRUE when it need not to be 'collecting' */
1412         if (!IS_FLG(FLG_COLLECTING)) return TRUE;
1413
1414         /* Check if there is a same item */
1415         for (j = 0; j < INVEN_PACK; j++)
1416         {
1417                 /*
1418                  * 'Collecting' means the item must be absorbed 
1419                  * into an inventory slot.
1420                  * But an item can not be absorbed into itself!
1421                  */
1422                 if ((&inventory[j] != o_ptr) &&
1423                     object_similar(&inventory[j], o_ptr))
1424                         return TRUE;
1425         }
1426
1427         /* Not collecting */
1428         return FALSE;
1429 }
1430
1431
1432 /*
1433  * A function for Auto-picker/destroyer
1434  * Examine whether the object matches to the list of keywords or not.
1435  */
1436 int is_autopick(object_type *o_ptr)
1437 {
1438         int i;
1439         GAME_TEXT o_name[MAX_NLEN];
1440
1441         if (o_ptr->tval == TV_GOLD) return -1;
1442
1443         /* Prepare object name string first */
1444         object_desc(o_name, o_ptr, (OD_NO_FLAVOR | OD_OMIT_PREFIX | OD_NO_PLURAL));
1445
1446         /* Convert the string to lower case */
1447         str_tolower(o_name);
1448
1449         /* Look for a matching entry in the list */     
1450         for (i=0; i < max_autopick; i++)
1451         {
1452                 autopick_type *entry = &autopick_list[i];
1453
1454                 if (is_autopick_aux(o_ptr, entry, o_name)) return i;
1455         }
1456
1457         /* No matching entry */
1458         return -1;
1459 }
1460
1461
1462 /*
1463  *  Auto inscription
1464  */
1465 static void auto_inscribe_item(object_type *o_ptr, int idx)
1466 {
1467         /* Are there auto-inscription? */
1468         if (idx < 0 || !autopick_list[idx].insc) return;
1469
1470         if (!o_ptr->inscription)
1471                 o_ptr->inscription = quark_add(autopick_list[idx].insc);
1472
1473         /* Redraw inscription */
1474         p_ptr->window |= (PW_EQUIP | PW_INVEN);
1475
1476         /* {.} and {$} effect p_ptr->warning and TRC_TELEPORT_SELF */
1477         p_ptr->update |= (PU_BONUS);
1478 }
1479
1480
1481 /*
1482  * Automatically destroy items in this grid.
1483  */
1484 static bool is_opt_confirm_destroy(object_type *o_ptr)
1485 {
1486         if (!destroy_items) return FALSE;
1487
1488         /* Known to be worthless? */
1489         if (leave_worth)
1490                 if (object_value(o_ptr) > 0) return FALSE;
1491
1492         if (leave_equip)
1493                 if (object_is_weapon_armour_ammo(o_ptr)) return FALSE;
1494
1495         if (leave_chest)
1496                 if ((o_ptr->tval == TV_CHEST) && o_ptr->pval) return FALSE;
1497
1498         if (leave_wanted)
1499         {
1500                 if (object_is_shoukinkubi(o_ptr)) return FALSE;
1501         }
1502
1503         if (leave_corpse)
1504                 if (o_ptr->tval == TV_CORPSE) return FALSE;
1505
1506         if (leave_junk)
1507                 if ((o_ptr->tval == TV_SKELETON) || (o_ptr->tval == TV_BOTTLE) || (o_ptr->tval == TV_JUNK) || (o_ptr->tval == TV_STATUE)) return FALSE;
1508
1509         if (leave_special)
1510         {
1511                 if (p_ptr->prace == RACE_DEMON)
1512                 {
1513                         if (o_ptr->tval == TV_CORPSE &&
1514                             o_ptr->sval == SV_CORPSE &&
1515                             my_strchr("pht", r_info[o_ptr->pval].d_char))
1516                                 return FALSE;
1517                 }
1518
1519                 if (p_ptr->pclass == CLASS_ARCHER)
1520                 {
1521                         if (o_ptr->tval == TV_SKELETON ||
1522                             (o_ptr->tval == TV_CORPSE && o_ptr->sval == SV_SKELETON))
1523                                 return FALSE;
1524                 }
1525                 else if (p_ptr->pclass == CLASS_NINJA)
1526                 {
1527                         if (o_ptr->tval == TV_LITE &&
1528                             o_ptr->name2 == EGO_LITE_DARKNESS && object_is_known(o_ptr))
1529                                 return FALSE;
1530                 }
1531                 else if (p_ptr->pclass == CLASS_BEASTMASTER ||
1532                          p_ptr->pclass == CLASS_CAVALRY)
1533                 {
1534                         if (o_ptr->tval == TV_WAND &&
1535                             o_ptr->sval == SV_WAND_HEAL_MONSTER && object_is_aware(o_ptr))
1536                                 return FALSE;
1537                 }
1538         }
1539
1540         if (o_ptr->tval == TV_GOLD) return FALSE;
1541
1542         return TRUE;
1543 }
1544
1545
1546 /*
1547  * Automatically destroy an item if it is to be destroyed
1548  *
1549  * When always_pickup is 'yes', we disable auto-destroyer function of
1550  * auto-picker/destroyer, and do only easy-auto-destroyer.
1551  */
1552 static object_type autopick_last_destroyed_object;
1553
1554 static void auto_destroy_item(object_type *o_ptr, int autopick_idx)
1555 {
1556         bool destroy = FALSE;
1557
1558         /* Easy-Auto-Destroyer (3rd priority) */
1559         if (is_opt_confirm_destroy(o_ptr)) destroy = TRUE;
1560
1561         /* Protected by auto-picker (2nd priotity) */
1562         if (autopick_idx >= 0 &&
1563             !(autopick_list[autopick_idx].action & DO_AUTODESTROY))
1564                 destroy = FALSE;
1565
1566         /* Auto-destroyer works only when !always_pickup */
1567         if (!always_pickup)
1568         {
1569                 /* Auto-picker/destroyer (1st priority) */
1570                 if (autopick_idx >= 0 &&
1571                     (autopick_list[autopick_idx].action & DO_AUTODESTROY))
1572                         destroy = TRUE;
1573         }
1574
1575         /* Not to be destroyed */
1576         if (!destroy) return;
1577
1578         /* Now decided to destroy */
1579
1580         disturb(FALSE, FALSE);
1581
1582         /* Artifact? */
1583         if (!can_player_destroy_object(o_ptr))
1584         {
1585                 GAME_TEXT o_name[MAX_NLEN];
1586
1587                 /* Describe the object (with {terrible/special}) */
1588                 object_desc(o_name, o_ptr, 0);
1589
1590                 msg_format(_("%sは破壊不能だ。", "You cannot auto-destroy %s."), o_name);
1591
1592                 return;
1593         }
1594
1595         /* Record name of destroyed item */
1596         (void)COPY(&autopick_last_destroyed_object, o_ptr, object_type);
1597
1598         /* Destroy Later */
1599         o_ptr->marked |= OM_AUTODESTROY;
1600         p_ptr->update |= PU_AUTODESTROY;
1601
1602         return;
1603 }
1604
1605
1606 /*
1607  *  Auto-destroy marked item
1608  */
1609 static void autopick_delayed_alter_aux(INVENTORY_IDX item)
1610 {
1611         object_type *o_ptr;
1612
1613         /* Get the item (in the pack) */
1614         if (item >= 0) o_ptr = &inventory[item];
1615
1616         /* Get the item (on the floor) */
1617         else o_ptr = &o_list[0 - item];
1618
1619         if (o_ptr->k_idx && (o_ptr->marked & OM_AUTODESTROY))
1620         {
1621                 GAME_TEXT o_name[MAX_NLEN];
1622
1623                 /* Describe the object (with {terrible/special}) */
1624                 object_desc(o_name, o_ptr, 0);
1625
1626                 /* Eliminate the item (from the pack) */
1627                 if (item >= 0)
1628                 {
1629                         inven_item_increase(item, -(o_ptr->number));
1630                         inven_item_optimize(item);
1631                 }
1632
1633                 /* Eliminate the item (from the floor) */
1634                 else
1635                 {
1636                         delete_object_idx(0 - item);
1637                 }
1638
1639                 msg_format(_("%sを自動破壊します。", "Auto-destroying %s."), o_name);
1640         }
1641 }
1642
1643
1644 /*
1645  *  Auto-destroy marked items in inventry and on floor
1646  */
1647 void autopick_delayed_alter(void)
1648 {
1649         INVENTORY_IDX item;
1650
1651         /* 
1652          * Scan inventry in reverse order to prevent
1653          * skipping after inven_item_optimize()
1654          */
1655         for (item = INVEN_TOTAL - 1; item >= 0 ; item--)
1656                 autopick_delayed_alter_aux(item);
1657
1658         /* Scan the pile of objects */
1659         item = cave[p_ptr->y][p_ptr->x].o_idx;
1660         while (item)
1661         {
1662                 OBJECT_IDX next = o_list[item].next_o_idx;
1663                 autopick_delayed_alter_aux(-item);
1664                 item = next;
1665         }
1666 }
1667
1668
1669 /*
1670  * Auto-inscription and/or destroy
1671  *
1672  * Auto-destroyer works only on inventory or on floor stack only when
1673  * requested.
1674  */
1675 void autopick_alter_item(INVENTORY_IDX item, bool destroy)
1676 {
1677         object_type *o_ptr;
1678         int idx;
1679
1680         /* Get the item (in the pack) */
1681         if (item >= 0) o_ptr = &inventory[item];
1682
1683         /* Get the item (on the floor) */
1684         else o_ptr = &o_list[0 - item];
1685
1686         /* Get the index in the auto-pick/destroy list */
1687         idx = is_autopick(o_ptr);
1688
1689         /* Do auto-inscription */
1690         auto_inscribe_item(o_ptr, idx);
1691
1692         /* Do auto-destroy if needed */
1693         if (destroy && item <= INVEN_PACK)
1694                 auto_destroy_item(o_ptr, idx);
1695 }
1696
1697
1698 /*
1699  * Automatically pickup/destroy items in this grid.
1700  */
1701 void autopick_pickup_items(cave_type *c_ptr)
1702 {
1703         OBJECT_IDX this_o_idx, next_o_idx = 0;
1704         
1705         /* Scan the pile of objects */
1706         for (this_o_idx = c_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx)
1707         {
1708                 int idx;
1709                         object_type *o_ptr = &o_list[this_o_idx];
1710                 
1711                 /* Acquire next object */
1712                 next_o_idx = o_ptr->next_o_idx;
1713
1714                 idx = is_autopick(o_ptr);
1715
1716                 /* Item index for floor -1,-2,-3,...  */
1717                 auto_inscribe_item(o_ptr, idx);
1718
1719                 if (idx >= 0 &&
1720                         (autopick_list[idx].action & (DO_AUTOPICK | DO_QUERY_AUTOPICK)))
1721                 {
1722                         disturb(FALSE, FALSE);
1723
1724                         if (!inven_carry_okay(o_ptr))
1725                         {
1726                                 GAME_TEXT o_name[MAX_NLEN];
1727
1728                                 object_desc(o_name, o_ptr, 0);
1729
1730                                 msg_format(_("ザックには%sを入れる隙間がない。", "You have no room for %s."), o_name);
1731                                 /* Hack - remember that the item has given a message here. */
1732                                 o_ptr->marked |= OM_NOMSG;
1733
1734                                 continue;
1735                         }
1736                         else if (autopick_list[idx].action & DO_QUERY_AUTOPICK)
1737                         {
1738                                 char out_val[MAX_NLEN+20];
1739                                 GAME_TEXT o_name[MAX_NLEN];
1740
1741                                 if (o_ptr->marked & OM_NO_QUERY)
1742                                 {
1743                                         /* Already answered as 'No' */
1744                                         continue;
1745                                 }
1746
1747                                 object_desc(o_name, o_ptr, 0);
1748
1749                                 sprintf(out_val, _("%sを拾いますか? ", "Pick up %s? "), o_name);
1750
1751                                 if (!get_check(out_val))
1752                                 {
1753                                         /* Hack - remember that the item has given a message here. */
1754                                         o_ptr->marked |= (OM_NOMSG | OM_NO_QUERY);
1755                                         continue;
1756                                 }
1757
1758                         }
1759                         py_pickup_aux(this_o_idx);
1760                 }
1761                 
1762                 /*
1763                  * Do auto-destroy;
1764                  * When always_pickup is 'yes', we disable
1765                  * auto-destroyer from autopick function, and do only
1766                  * easy-auto-destroyer.
1767                  */
1768                 else
1769                 {
1770                         auto_destroy_item(o_ptr, idx);
1771                 }
1772         } /* for () */
1773 }
1774
1775
1776 static const char autoregister_header[] = "?:$AUTOREGISTER";
1777
1778 /*
1779  *  Clear auto registered lines in the picktype.prf .
1780  */
1781 static bool clear_auto_register(void)
1782 {
1783         char tmp_file[1024];
1784         char pref_file[1024];
1785         char buf[1024];
1786         FILE *pref_fff;
1787         FILE *tmp_fff;
1788         int num = 0;
1789         bool autoregister = FALSE;
1790         bool okay = TRUE;
1791
1792         path_build(pref_file, sizeof(pref_file), ANGBAND_DIR_USER, pickpref_filename(PT_WITH_PNAME));
1793         pref_fff = my_fopen(pref_file, "r");
1794
1795         if (!pref_fff)
1796         {
1797                 path_build(pref_file, sizeof(pref_file), ANGBAND_DIR_USER, pickpref_filename(PT_DEFAULT));
1798                 pref_fff = my_fopen(pref_file, "r");
1799         }
1800
1801         if (!pref_fff)
1802         {
1803                 /* No file yet */
1804                 return TRUE;
1805         }
1806
1807         /* Open a new (temporary) file */
1808         tmp_fff = my_fopen_temp(tmp_file, sizeof(tmp_file));
1809
1810         if (!tmp_fff)
1811         {
1812                 /* Close the preference file */
1813                 fclose(pref_fff);
1814                 msg_format(_("一時ファイル %s を作成できませんでした。", "Failed to create temporary file %s."), tmp_file);
1815                 msg_print(NULL);
1816                 return FALSE;
1817         }
1818
1819         
1820         /* Loop for every line */
1821         while (TRUE)
1822         {
1823                 /* Read a line */
1824                 if (my_fgets(pref_fff, buf, sizeof(buf))) break;
1825
1826                 if (autoregister)
1827                 {
1828                         /* Delete auto-registered line */
1829
1830                         /* Count auto-destroy preference lines */
1831                         if (buf[0] != '#' && buf[0] != '?') num++;
1832                 }
1833
1834                 /* We are looking for auto-registered line */
1835                 else
1836                 {
1837                         if (streq(buf, autoregister_header))
1838                         {
1839                                 /* Delete all further lines */
1840                                 autoregister = TRUE;
1841                         }
1842                         else
1843                         {
1844                                 /* Copy orginally lines */
1845                                 fprintf(tmp_fff, "%s\n", buf);
1846                         }
1847                 }
1848         }
1849
1850         /* Close files */
1851         my_fclose(pref_fff);
1852         my_fclose(tmp_fff);
1853
1854         if (num)
1855         {
1856                 msg_format(_("以前のキャラクター用の自動設定(%d行)が残っています。",
1857                                          "Auto registered lines (%d lines) for previous character are remaining."), num);
1858                 strcpy(buf, _("古い設定行は削除します。よろしいですか?", "These lines will be deleted.  Are you sure? "));
1859
1860                 /* You can cancel it */
1861                 if (!get_check(buf))
1862                 {
1863                         okay = FALSE;
1864                         autoregister = FALSE;
1865
1866                         msg_print(_("エディタのカット&ペースト等を使って必要な行を避難してください。",
1867                                                 "Use cut & paste of auto picker editor (_) to keep old prefs."));
1868                 }
1869         }
1870
1871
1872         /* If there are some changes, overwrite the original file with new one */
1873         if (autoregister)
1874         {
1875                 /* Copy contents of temporary file */
1876
1877                 tmp_fff = my_fopen(tmp_file, "r");
1878                 pref_fff = my_fopen(pref_file, "w");
1879
1880                 while (!my_fgets(tmp_fff, buf, sizeof(buf)))
1881                         fprintf(pref_fff, "%s\n", buf);
1882
1883                 my_fclose(pref_fff);
1884                 my_fclose(tmp_fff);
1885         }
1886
1887         /* Kill the temporary file */
1888         fd_kill(tmp_file);
1889
1890         return okay;
1891 }
1892
1893
1894 /*
1895  *  Automatically register an auto-destroy preference line
1896  */
1897 bool autopick_autoregister(object_type *o_ptr)
1898 {
1899         char buf[1024];
1900         char pref_file[1024];
1901         FILE *pref_fff;
1902         autopick_type an_entry, *entry = &an_entry;
1903
1904         int match_autopick = is_autopick(o_ptr);
1905
1906         /* Already registered */
1907         if (match_autopick != -1)
1908         {
1909                 cptr what;
1910                 byte act = autopick_list[match_autopick].action;
1911
1912                 if (act & DO_AUTOPICK) what = _("自動で拾う", "auto-pickup");
1913                 else if (act & DO_AUTODESTROY) what = _("自動破壊する", "auto-destroy");
1914                 else if (act & DONT_AUTOPICK) what = _("放置する", "leave on floor");
1915                 else /* if (act & DO_QUERY_AUTOPICK) */ what = _("確認して拾う", "query auto-pickup");
1916
1917                 msg_format(_("そのアイテムは既に%sように設定されています。", "The object is already registered to %s."), what);
1918                 return FALSE;
1919         }
1920
1921         /* Known to be an artifact? */
1922         if ((object_is_known(o_ptr) && object_is_artifact(o_ptr)) ||
1923             ((o_ptr->ident & IDENT_SENSE) &&
1924              (o_ptr->feeling == FEEL_TERRIBLE || o_ptr->feeling == FEEL_SPECIAL)))
1925         {
1926                 GAME_TEXT o_name[MAX_NLEN];
1927
1928                 /* Describe the object (with {terrible/special}) */
1929                 object_desc(o_name, o_ptr, 0);
1930
1931                 msg_format(_("%sは破壊不能だ。", "You cannot auto-destroy %s."), o_name);
1932
1933                 return FALSE;
1934         }
1935
1936
1937         if (!p_ptr->autopick_autoregister)
1938         {
1939                 /* Clear old auto registered lines */
1940                 if (!clear_auto_register()) return FALSE;
1941         }
1942
1943         /* Try a filename with player name */
1944         path_build(pref_file, sizeof(pref_file), ANGBAND_DIR_USER, pickpref_filename(PT_WITH_PNAME));
1945         pref_fff = my_fopen(pref_file, "r");
1946
1947         if (!pref_fff)
1948         {
1949                 /* Use default name */
1950                 path_build(pref_file, sizeof(pref_file), ANGBAND_DIR_USER, pickpref_filename(PT_DEFAULT));
1951                 pref_fff = my_fopen(pref_file, "r");
1952         }
1953
1954         /* Check the header */
1955         while (TRUE)
1956         {
1957                 /* Read a line */
1958                 if (my_fgets(pref_fff, buf, sizeof(buf)))
1959                 {
1960                         /* No header found */
1961                         p_ptr->autopick_autoregister = FALSE;
1962
1963                         break;
1964                 }
1965
1966                 if (streq(buf, autoregister_header))
1967                 {
1968                         /* Found the header */
1969                         p_ptr->autopick_autoregister = TRUE;
1970
1971                         break;
1972                 }
1973         }
1974
1975         /* Close read only FILE* */
1976         fclose(pref_fff);
1977
1978         /* Open for append */
1979         pref_fff = my_fopen(pref_file, "a");
1980
1981         /* Failure */
1982         if (!pref_fff) {
1983                 msg_format(_("%s を開くことができませんでした。", "Failed to open %s."), pref_file);
1984                 msg_print(NULL);
1985
1986                 /* Failed */
1987                 return FALSE;
1988         }
1989
1990         if (!p_ptr->autopick_autoregister)
1991         {
1992                 /* Add the header */
1993                 fprintf(pref_fff, "%s\n", autoregister_header);
1994
1995                 fprintf(pref_fff, "%s\n", _("# *警告!!* 以降の行は自動登録されたものです。",
1996                                                             "# *Waring!* The lines below will be deleated later."));
1997                 fprintf(pref_fff, "%s\n", _("# 後で自動的に削除されますので、必要な行は上の方へ移動しておいてください。", 
1998                                                             "# Keep it by cut & paste if you need these lines for future characters."));
1999
2000                 /* Now auto register is in-use */
2001                 p_ptr->autopick_autoregister = TRUE;
2002         }
2003
2004         /* Get a preference entry */
2005         autopick_entry_from_object(entry, o_ptr);
2006
2007         /* Set to auto-destroy (with no-display) */
2008         entry->action = DO_AUTODESTROY;
2009
2010         /* Load the new line as preference */
2011         add_autopick_list(entry);
2012
2013         /* Add a line to the file */
2014         /* Don't kill "entry" */
2015         fprintf(pref_fff, "%s\n", autopick_line_from_entry(entry));
2016         fclose(pref_fff);
2017
2018         return TRUE;
2019 }
2020
2021
2022 /********  Auto-picker/destroyer editor  **********/
2023
2024 #define MAX_YANK MAX_LINELEN
2025 #define MAX_LINES 3000
2026
2027 #define MARK_MARK     0x01
2028 #define MARK_BY_SHIFT 0x02
2029
2030 #define LSTAT_BYPASS        0x01
2031 #define LSTAT_EXPRESSION    0x02
2032 #define LSTAT_AUTOREGISTER  0x04
2033
2034 #define QUIT_WITHOUT_SAVE 1
2035 #define QUIT_AND_SAVE     2
2036
2037 /* 
2038  * Struct for yank buffer
2039  */
2040 typedef struct chain_str {
2041         struct chain_str *next;
2042         char s[1];
2043 } chain_str_type;
2044
2045
2046 /*
2047  * Data struct for text editor
2048  */
2049 typedef struct {
2050         int wid, hgt;
2051         int cx, cy;
2052         int upper, left;
2053         int old_wid, old_hgt;
2054         int old_cy;
2055         int old_upper, old_left;
2056         int mx, my;
2057         byte mark;
2058
2059         object_type *search_o_ptr;
2060         cptr search_str;
2061         cptr last_destroyed;
2062
2063         chain_str_type *yank;
2064         bool yank_eol;
2065
2066         cptr *lines_list;
2067         byte states[MAX_LINES];
2068
2069         u16b dirty_flags;
2070         int dirty_line;
2071         int filename_mode;
2072         int old_com_id;
2073
2074         bool changed;
2075 } text_body_type;
2076
2077
2078 /*
2079  * Dirty flag for text editor
2080  */
2081 #define DIRTY_ALL           0x0001
2082 #define DIRTY_MODE          0x0004
2083 #define DIRTY_SCREEN        0x0008
2084 #define DIRTY_NOT_FOUND     0x0010
2085 #define DIRTY_NO_SEARCH     0x0020
2086 #define DIRTY_EXPRESSION    0x0040
2087 #define DIRTY_SKIP_INACTIVE 0x0080
2088 #define DIRTY_INACTIVE      0x0100
2089
2090 /*
2091  * Describe which kind of object is Auto-picked/destroyed
2092  */
2093 static void describe_autopick(char *buff, autopick_type *entry)
2094 {
2095         cptr str = entry->name;
2096         byte act = entry->action;
2097         cptr insc = entry->insc;
2098         int i;
2099
2100         bool top = FALSE;
2101
2102 #ifdef JP
2103         cptr before_str[100], body_str;
2104         int before_n = 0;
2105
2106         body_str = "アイテム";
2107
2108         /*** Collecting items ***/
2109         /*** Which can be absorbed into a slot as a bundle ***/
2110         if (IS_FLG(FLG_COLLECTING))
2111                 before_str[before_n++] = "収集中で既に持っているスロットにまとめられる";
2112         
2113         /*** Unaware items ***/
2114         if (IS_FLG(FLG_UNAWARE))
2115                 before_str[before_n++] = "未鑑定でその効果も判明していない";
2116
2117         /*** Unidentified ***/
2118         if (IS_FLG(FLG_UNIDENTIFIED))
2119                 before_str[before_n++] = "未鑑定の";
2120
2121         /*** Identified ***/
2122         if (IS_FLG(FLG_IDENTIFIED))
2123                 before_str[before_n++] = "鑑定済みの";
2124
2125         /*** *Identified* ***/
2126         if (IS_FLG(FLG_STAR_IDENTIFIED))
2127                 before_str[before_n++] = "完全に鑑定済みの";
2128
2129         /*** Dice boosted (weapon of slaying) ***/
2130         if (IS_FLG(FLG_BOOSTED))
2131         {
2132                 before_str[before_n++] = "ダメージダイスが通常より大きい";
2133                 body_str = "武器";
2134         }
2135
2136         /*** Weapons whose dd*ds is more than nn ***/
2137         if (IS_FLG(FLG_MORE_DICE))
2138         {
2139                 static char more_than_desc_str[] = "___";
2140                 before_str[before_n++] = "ダメージダイスの最大値が";
2141                 body_str = "武器";
2142                         
2143                 sprintf(more_than_desc_str,"%d", entry->dice);
2144                 before_str[before_n++] = more_than_desc_str;
2145                 before_str[before_n++] = "以上の";
2146         }
2147
2148         /*** Items whose magical bonus is more than nn ***/
2149         if (IS_FLG(FLG_MORE_BONUS))
2150         {
2151                 static char more_bonus_desc_str[] = "___";
2152                 before_str[before_n++] = "修正値が(+";
2153                         
2154                 sprintf(more_bonus_desc_str,"%d", entry->bonus);
2155                 before_str[before_n++] = more_bonus_desc_str;
2156                 before_str[before_n++] = ")以上の";
2157         }
2158
2159         /*** Worthless items ***/
2160         if (IS_FLG(FLG_WORTHLESS))
2161                 before_str[before_n++] = "店で無価値と判定される";
2162
2163         /*** Artifact ***/
2164         if (IS_FLG(FLG_ARTIFACT))
2165         {
2166                 before_str[before_n++] = "アーティファクトの";
2167                 body_str = "装備";
2168         }
2169
2170         /*** Ego ***/
2171         if (IS_FLG(FLG_EGO))
2172         {
2173                 before_str[before_n++] = "エゴアイテムの";
2174                 body_str = "装備";
2175         }
2176
2177         /*** Good ***/
2178         if (IS_FLG(FLG_GOOD))
2179         {
2180                 before_str[before_n++] = "上質の";
2181                 body_str = "装備";
2182         }
2183
2184         /*** Nameless ***/
2185         if (IS_FLG(FLG_NAMELESS))
2186         {
2187                 before_str[before_n++] = "エゴでもアーティファクトでもない";
2188                 body_str = "装備";
2189         }
2190
2191         /*** Average ***/
2192         if (IS_FLG(FLG_AVERAGE))
2193         {
2194                 before_str[before_n++] = "並の";
2195                 body_str = "装備";
2196         }
2197
2198         /*** Rare equipments ***/
2199         if (IS_FLG(FLG_RARE))
2200         {
2201                 before_str[before_n++] = "ドラゴン装備やカオス・ブレード等を含む珍しい";
2202                 body_str = "装備";
2203         }
2204
2205         /*** Common equipments ***/
2206         if (IS_FLG(FLG_COMMON))
2207         {
2208                 before_str[before_n++] = "ありふれた(ドラゴン装備やカオス・ブレード等の珍しい物ではない)";
2209                 body_str = "装備";
2210         }
2211
2212         /*** Wanted monster's corpse/skeletons ***/
2213         if (IS_FLG(FLG_WANTED))
2214         {
2215                 before_str[before_n++] = "ハンター事務所で賞金首とされている";
2216                 body_str = "死体や骨";
2217         }
2218
2219         /*** Human corpse/skeletons (for Daemon magic) ***/
2220         if (IS_FLG(FLG_HUMAN))
2221         {
2222                 before_str[before_n++] = "悪魔魔法で使うための人間やヒューマノイドの";
2223                 body_str = "死体や骨";
2224         }
2225
2226         /*** Unique monster's corpse/skeletons/statues ***/
2227         if (IS_FLG(FLG_UNIQUE))
2228         {
2229                 before_str[before_n++] = "ユニークモンスターの";
2230                 body_str = "死体や骨";
2231         }
2232
2233         /*** Unreadable spellbooks ***/
2234         if (IS_FLG(FLG_UNREADABLE))
2235         {
2236                 before_str[before_n++] = "あなたが読めない領域の";
2237                 body_str = "魔法書";
2238         }
2239
2240         /*** First realm spellbooks ***/
2241         if (IS_FLG(FLG_REALM1))
2242         {
2243                 before_str[before_n++] = "第一領域の";
2244                 body_str = "魔法書";
2245         }
2246
2247         /*** Second realm spellbooks ***/
2248         if (IS_FLG(FLG_REALM2))
2249         {
2250                 before_str[before_n++] = "第二領域の";
2251                 body_str = "魔法書";
2252         }
2253
2254         /*** First rank spellbooks ***/
2255         if (IS_FLG(FLG_FIRST))
2256         {
2257                 before_str[before_n++] = "全4冊の内の1冊目の";
2258                 body_str = "魔法書";
2259         }
2260
2261         /*** Second rank spellbooks ***/
2262         if (IS_FLG(FLG_SECOND))
2263         {
2264                 before_str[before_n++] = "全4冊の内の2冊目の";
2265                 body_str = "魔法書";
2266         }
2267
2268         /*** Third rank spellbooks ***/
2269         if (IS_FLG(FLG_THIRD))
2270         {
2271                 before_str[before_n++] = "全4冊の内の3冊目の";
2272                 body_str = "魔法書";
2273         }
2274
2275         /*** Fourth rank spellbooks ***/
2276         if (IS_FLG(FLG_FOURTH))
2277         {
2278                 before_str[before_n++] = "全4冊の内の4冊目の";
2279                 body_str = "魔法書";
2280         }
2281
2282         /*** Items ***/
2283         if (IS_FLG(FLG_ITEMS))
2284                 ; /* Nothing to do */
2285         else if (IS_FLG(FLG_WEAPONS))
2286                 body_str = "武器";
2287         else if (IS_FLG(FLG_FAVORITE_WEAPONS))
2288                 body_str = "得意武器";
2289         else if (IS_FLG(FLG_ARMORS))
2290                 body_str = "防具";
2291         else if (IS_FLG(FLG_MISSILES))
2292                 body_str = "弾や矢やクロスボウの矢";
2293         else if (IS_FLG(FLG_DEVICES))
2294                 body_str = "巻物や魔法棒や杖やロッド";
2295         else if (IS_FLG(FLG_LIGHTS))
2296                 body_str = "光源用のアイテム";
2297         else if (IS_FLG(FLG_JUNKS))
2298                 body_str = "折れた棒等のガラクタ";
2299         else if (IS_FLG(FLG_CORPSES))
2300                 body_str = "死体や骨";
2301         else if (IS_FLG(FLG_SPELLBOOKS))
2302                 body_str = "魔法書";
2303         else if (IS_FLG(FLG_HAFTED))
2304                 body_str = "鈍器";
2305         else if (IS_FLG(FLG_SHIELDS))
2306                 body_str = "盾";
2307         else if (IS_FLG(FLG_BOWS))
2308                 body_str = "スリングや弓やクロスボウ";
2309         else if (IS_FLG(FLG_RINGS))
2310                 body_str = "指輪";
2311         else if (IS_FLG(FLG_AMULETS))
2312                 body_str = "アミュレット";
2313         else if (IS_FLG(FLG_SUITS))
2314                 body_str = "鎧";
2315         else if (IS_FLG(FLG_CLOAKS))
2316                 body_str = "クローク";
2317         else if (IS_FLG(FLG_HELMS))
2318                 body_str = "ヘルメットや冠";
2319         else if (IS_FLG(FLG_GLOVES))
2320                 body_str = "籠手";
2321         else if (IS_FLG(FLG_BOOTS))
2322                 body_str = "ブーツ";
2323
2324         *buff = '\0';
2325         if (!before_n) 
2326                 strcat(buff, "全ての");
2327         else for (i = 0; i < before_n && before_str[i]; i++)
2328                 strcat(buff, before_str[i]);
2329
2330         strcat(buff, body_str);
2331
2332         if (*str)
2333         {
2334                 if (*str == '^')
2335                 {
2336                         str++;
2337                         top = TRUE;
2338                 }
2339
2340                 strcat(buff, "で、名前が「");
2341                 strncat(buff, str, 80);
2342                 if (top)
2343                         strcat(buff, "」で始まるもの");
2344                 else
2345                         strcat(buff, "」を含むもの");
2346         }
2347
2348         if (insc)
2349         {
2350                 strncat(buff, format("に「%s」", insc), 80);
2351
2352                 if (my_strstr(insc, "%%all"))
2353                         strcat(buff, "(%%allは全能力を表す英字の記号で置換)");
2354                 else if (my_strstr(insc, "%all"))
2355                         strcat(buff, "(%allは全能力を表す記号で置換)");
2356                 else if (my_strstr(insc, "%%"))
2357                         strcat(buff, "(%%は追加能力を表す英字の記号で置換)");
2358                 else if (my_strstr(insc, "%"))
2359                         strcat(buff, "(%は追加能力を表す記号で置換)");
2360
2361                 strcat(buff, "と刻んで");
2362         }
2363         else
2364                 strcat(buff, "を");
2365
2366         if (act & DONT_AUTOPICK)
2367                 strcat(buff, "放置する。");
2368         else if (act & DO_AUTODESTROY)
2369                 strcat(buff, "破壊する。");
2370         else if (act & DO_QUERY_AUTOPICK)
2371                 strcat(buff, "確認の後に拾う。");
2372         else
2373                 strcat(buff, "拾う。");
2374
2375         if (act & DO_DISPLAY)
2376         {
2377                 if (act & DONT_AUTOPICK)
2378                         strcat(buff, "全体マップ('M')で'N'を押したときに表示する。");
2379                 else if (act & DO_AUTODESTROY)
2380                         strcat(buff, "全体マップ('M')で'K'を押したときに表示する。");
2381                 else
2382                         strcat(buff, "全体マップ('M')で'M'を押したときに表示する。");
2383         }
2384         else
2385                 strcat(buff, "全体マップには表示しない。");
2386
2387 #else /* JP */
2388
2389         cptr before_str[20], after_str[20], which_str[20], whose_str[20], body_str;
2390         int before_n = 0, after_n = 0, which_n = 0, whose_n = 0;
2391
2392         body_str = "items";
2393
2394         /*** Collecting items ***/
2395         /*** Which can be absorbed into a slot as a bundle ***/
2396         if (IS_FLG(FLG_COLLECTING))
2397                 which_str[which_n++] = "can be absorbed into an existing inventory slot";
2398         
2399         /*** Unaware items ***/
2400         if (IS_FLG(FLG_UNAWARE))
2401         {
2402                 before_str[before_n++] = "unidentified";
2403                 whose_str[whose_n++] = "basic abilities are not known";
2404         }
2405
2406         /*** Unidentified ***/
2407         if (IS_FLG(FLG_UNIDENTIFIED))
2408                 before_str[before_n++] = "unidentified";
2409
2410         /*** Identified ***/
2411         if (IS_FLG(FLG_IDENTIFIED))
2412                 before_str[before_n++] = "identified";
2413
2414         /*** *Identified* ***/
2415         if (IS_FLG(FLG_STAR_IDENTIFIED))
2416                 before_str[before_n++] = "fully identified";
2417
2418         /*** Rare equipments ***/
2419         if (IS_FLG(FLG_RARE))
2420         {
2421                 before_str[before_n++] = "very rare";
2422                 body_str = "equipments";
2423                 after_str[after_n++] = "such like Dragon armors, Blades of Chaos, etc.";
2424         }
2425
2426         /*** Common equipments ***/
2427         if (IS_FLG(FLG_COMMON))
2428         {
2429                 before_str[before_n++] = "relatively common";
2430                 body_str = "equipments";
2431                 after_str[after_n++] = "compared to very rare Dragon armors, Blades of Chaos, etc.";
2432         }
2433
2434         /*** Worthless items ***/
2435         if (IS_FLG(FLG_WORTHLESS))
2436         {
2437                 before_str[before_n++] = "worthless";
2438                 which_str[which_n++] = "can not be sold at stores";
2439         }
2440
2441         /*** Artifacto ***/
2442         if (IS_FLG(FLG_ARTIFACT))
2443         {
2444                 before_str[before_n++] = "artifact";
2445         }
2446
2447         /*** Ego ***/
2448         if (IS_FLG(FLG_EGO))
2449         {
2450                 before_str[before_n++] = "ego";
2451         }
2452
2453         /*** Good ***/
2454         if (IS_FLG(FLG_GOOD))
2455         {
2456                 body_str = "equipment";
2457                 which_str[which_n++] = "have good quality";
2458         }
2459
2460         /*** Nameless ***/
2461         if (IS_FLG(FLG_NAMELESS))
2462         {
2463                 body_str = "equipment";
2464                 which_str[which_n++] = "is neither ego-item nor artifact";
2465         }
2466
2467         /*** Average ***/
2468         if (IS_FLG(FLG_AVERAGE))
2469         {
2470                 body_str = "equipment";
2471                 which_str[which_n++] = "have average quality";
2472         }
2473
2474         /*** Dice boosted (weapon of slaying) ***/
2475         if (IS_FLG(FLG_BOOSTED))
2476         {
2477                 body_str = "weapons";
2478                 whose_str[whose_n++] = "damage dice is bigger than normal";
2479         }
2480
2481         /*** Weapons whose dd*ds is more than nn ***/
2482         if (IS_FLG(FLG_MORE_DICE))
2483         {
2484                 static char more_than_desc_str[] =
2485                         "maximum damage from dice is bigger than __";
2486                 body_str = "weapons";
2487                         
2488                 sprintf(more_than_desc_str + sizeof(more_than_desc_str) - 3,
2489                         "%d", entry->dice);
2490                 whose_str[whose_n++] = more_than_desc_str;
2491         }
2492
2493         /*** Items whose magical bonus is more than nn ***/
2494         if (IS_FLG(FLG_MORE_BONUS))
2495         {
2496                 static char more_bonus_desc_str[] =
2497                         "magical bonus is bigger than (+__)";
2498                         
2499                 sprintf(more_bonus_desc_str + sizeof(more_bonus_desc_str) - 4,
2500                         "%d)", entry->bonus);
2501                 whose_str[whose_n++] = more_bonus_desc_str;
2502         }
2503
2504         /*** Wanted monster's corpse/skeletons ***/
2505         if (IS_FLG(FLG_WANTED))
2506         {
2507                 body_str = "corpse or skeletons";
2508                 which_str[which_n++] = "is wanted at the Hunter's Office";
2509         }
2510
2511         /*** Human corpse/skeletons (for Daemon magic) ***/
2512         if (IS_FLG(FLG_HUMAN))
2513         {
2514                 before_str[before_n++] = "humanoid";
2515                 body_str = "corpse or skeletons";
2516                 which_str[which_n++] = "can be used for Daemon magic";
2517         }
2518
2519         /*** Unique monster's corpse/skeletons/statues ***/
2520         if (IS_FLG(FLG_UNIQUE))
2521         {
2522                 before_str[before_n++] = "unique monster's";
2523                 body_str = "corpse or skeletons";
2524         }
2525
2526         /*** Unreadable spellbooks ***/
2527         if (IS_FLG(FLG_UNREADABLE))
2528         {
2529                 body_str = "spellbooks";
2530                 after_str[after_n++] = "of different realms from yours";
2531         }
2532
2533         /*** First realm spellbooks ***/
2534         if (IS_FLG(FLG_REALM1))
2535         {
2536                 body_str = "spellbooks";
2537                 after_str[after_n++] = "of your first realm";
2538         }
2539
2540         /*** Second realm spellbooks ***/
2541         if (IS_FLG(FLG_REALM2))
2542         {
2543                 body_str = "spellbooks";
2544                 after_str[after_n++] = "of your second realm";
2545         }
2546
2547         /*** First rank spellbooks ***/
2548         if (IS_FLG(FLG_FIRST))
2549         {
2550                 before_str[before_n++] = "first one of four";
2551                 body_str = "spellbooks";
2552         }
2553
2554         /*** Second rank spellbooks ***/
2555         if (IS_FLG(FLG_SECOND))
2556         {
2557                 before_str[before_n++] = "second one of four";
2558                 body_str = "spellbooks";
2559         }
2560
2561         /*** Third rank spellbooks ***/
2562         if (IS_FLG(FLG_THIRD))
2563         {
2564                 before_str[before_n++] = "third one of four";
2565                 body_str = "spellbooks";
2566         }
2567
2568         /*** Fourth rank spellbooks ***/
2569         if (IS_FLG(FLG_FOURTH))
2570         {
2571                 before_str[before_n++] = "fourth one of four";
2572                 body_str = "spellbooks";
2573         }
2574
2575         /*** Items ***/
2576         if (IS_FLG(FLG_ITEMS))
2577                 ; /* Nothing to do */
2578         else if (IS_FLG(FLG_WEAPONS))
2579                 body_str = "weapons";
2580         else if (IS_FLG(FLG_FAVORITE_WEAPONS))
2581                 body_str = "favorite weapons";
2582         else if (IS_FLG(FLG_ARMORS))
2583                 body_str = "armors";
2584         else if (IS_FLG(FLG_MISSILES))
2585                 body_str = "shots, arrows or crossbow bolts";
2586         else if (IS_FLG(FLG_DEVICES))
2587                 body_str = "scrolls, wands, staves or rods";
2588         else if (IS_FLG(FLG_LIGHTS))
2589                 body_str = "light sources";
2590         else if (IS_FLG(FLG_JUNKS))
2591                 body_str = "junk such as broken sticks";
2592         else if (IS_FLG(FLG_CORPSES))
2593                 body_str = "corpses or skeletons";
2594         else if (IS_FLG(FLG_SPELLBOOKS))
2595                 body_str = "spellbooks";
2596         else if (IS_FLG(FLG_HAFTED))
2597                 body_str = "hafted weapons";
2598         else if (IS_FLG(FLG_SHIELDS))
2599                 body_str = "shields";
2600         else if (IS_FLG(FLG_BOWS))
2601                 body_str = "slings, bows or crossbows";
2602         else if (IS_FLG(FLG_RINGS))
2603                 body_str = "rings";
2604         else if (IS_FLG(FLG_AMULETS))
2605                 body_str = "amulets";
2606         else if (IS_FLG(FLG_SUITS))
2607                 body_str = "body armors";
2608         else if (IS_FLG(FLG_CLOAKS))
2609                 body_str = "cloaks";
2610         else if (IS_FLG(FLG_HELMS))
2611                 body_str = "helms or crowns";
2612         else if (IS_FLG(FLG_GLOVES))
2613                 body_str = "gloves";
2614         else if (IS_FLG(FLG_BOOTS))
2615                 body_str = "boots";
2616
2617         /* Prepare a string for item name */
2618         if (*str)
2619         {
2620                 if (*str == '^')
2621                 {
2622                         str++;
2623                         top = TRUE;
2624                         whose_str[whose_n++] = "name is beginning with \"";
2625                 }
2626                 else
2627                         which_str[which_n++] = "have \"";
2628         }
2629
2630
2631         /* Describe action flag */
2632         if (act & DONT_AUTOPICK)
2633                 strcpy(buff, "Leave on floor ");
2634         else if (act & DO_AUTODESTROY)
2635                 strcpy(buff, "Destroy ");
2636         else if (act & DO_QUERY_AUTOPICK)
2637                 strcpy(buff, "Ask to pick up ");
2638         else
2639                 strcpy(buff, "Pickup ");
2640
2641         /* Auto-insctiption */
2642         if (insc)
2643         {
2644                 strncat(buff, format("and inscribe \"%s\"", insc), 80);
2645
2646                 if (my_strstr(insc, "%all"))
2647                         strcat(buff, ", replacing %all with code string representing all abilities,");
2648                 else if (my_strstr(insc, "%"))
2649                         strcat(buff, ", replacing % with code string representing extra random abilities,");
2650
2651                 strcat(buff, " on ");
2652         }
2653
2654         /* Adjective */
2655         if (!before_n) 
2656                 strcat(buff, "all ");
2657         else for (i = 0; i < before_n && before_str[i]; i++)
2658         {
2659                 strcat(buff, before_str[i]);
2660                 strcat(buff, " ");
2661         }
2662
2663         /* Item class */
2664         strcat(buff, body_str);
2665
2666         /* of ... */
2667         for (i = 0; i < after_n && after_str[i]; i++)
2668         {
2669                 strcat(buff, " ");
2670                 strcat(buff, after_str[i]);
2671         }
2672
2673         /* which ... */
2674         for (i = 0; i < whose_n && whose_str[i]; i++)
2675         {
2676                 if (i == 0)
2677                         strcat(buff, " whose ");
2678                 else
2679                         strcat(buff, ", and ");
2680
2681                 strcat(buff, whose_str[i]);
2682         }
2683
2684         /* Item name ; whose name is beginning with "str" */
2685         if (*str && top)
2686         {
2687                 strcat(buff, str);
2688                 strcat(buff, "\"");
2689         }
2690
2691         /* whose ..., and which .... */
2692         if (whose_n && which_n)
2693                 strcat(buff, ", and ");
2694
2695         /* which ... */
2696         for (i = 0; i < which_n && which_str[i]; i++)
2697         {
2698                 if (i == 0)
2699                         strcat(buff, " which ");
2700                 else
2701                         strcat(buff, ", and ");
2702
2703                 strcat(buff, which_str[i]);
2704         }
2705
2706         /* Item name ; which have "str" as part of its name */
2707         if (*str && !top)
2708         {
2709                 strncat(buff, str, 80);
2710                 strcat(buff, "\" as part of its name");
2711         }
2712         strcat(buff, ".");
2713
2714         /* Describe whether it will be displayed on the full map or not */
2715         if (act & DO_DISPLAY)
2716         {
2717                 if (act & DONT_AUTOPICK)
2718                         strcat(buff, "  Display these items when you press the N key in the full 'M'ap.");
2719                 else if (act & DO_AUTODESTROY)
2720                         strcat(buff, "  Display these items when you press the K key in the full 'M'ap.");
2721                 else
2722                         strcat(buff, "  Display these items when you press the M key in the full 'M'ap.");
2723         }
2724         else
2725                 strcat(buff, " Not displayed in the full map.");
2726 #endif /* JP */
2727
2728 }
2729
2730
2731 /*
2732  * Read whole lines of a file to memory
2733  */
2734 static cptr *read_text_lines(cptr filename)
2735 {
2736         cptr *lines_list = NULL;
2737         FILE *fff;
2738
2739         int lines = 0;
2740         char buf[1024];
2741
2742         path_build(buf, sizeof(buf), ANGBAND_DIR_USER, filename);
2743         
2744         /* Open the file */
2745         fff = my_fopen(buf, "r");
2746
2747         if (fff)
2748         {
2749                 /* Allocate list of pointers */
2750                 C_MAKE(lines_list, MAX_LINES, cptr);
2751
2752                 /* Parse it */
2753                 while (0 == my_fgets(fff, buf, sizeof(buf)))
2754                 {
2755                         lines_list[lines++] = string_make(buf);
2756                         if (lines >= MAX_LINES - 1) break;
2757                 }
2758                 if (lines == 0)
2759                         lines_list[0] = string_make("");
2760
2761                 my_fclose(fff);
2762         }
2763
2764         if (!fff) return NULL;
2765         return lines_list;
2766 }
2767
2768
2769 /*
2770  * Copy the default autopick file to the user directory
2771  */
2772 static void prepare_default_pickpref(void)
2773 {
2774         const cptr messages[] = {
2775                 _("あなたは「自動拾いエディタ」を初めて起動しました。", "You have activated the Auto-Picker Editor for the first time."),
2776                 _("自動拾いのユーザー設定ファイルがまだ書かれていないので、", "Since user pref file for autopick is not yet created,"),
2777                 _("基本的な自動拾い設定ファイルをlib/pref/picktype.prfからコピーします。", "the default setting is loaded from lib/pref/pickpref.prf ."),
2778                 NULL
2779         };
2780
2781         char buf[1024];
2782         FILE *pref_fp;
2783         FILE *user_fp;
2784         int i;
2785         cptr filename = pickpref_filename(PT_DEFAULT);
2786
2787         /* Display messages */
2788         for (i = 0; messages[i]; i++) msg_print(messages[i]);
2789         msg_print(NULL);
2790
2791
2792         /* Open new file */
2793         path_build(buf, sizeof(buf), ANGBAND_DIR_USER, filename);
2794         user_fp = my_fopen(buf, "w");
2795
2796         /* Failed */
2797         if (!user_fp) return;
2798
2799         /* Write header messages for a notification */
2800         fprintf(user_fp, "#***\n");
2801         for (i = 0; messages[i]; i++)
2802         {
2803                 fprintf(user_fp, "#***  %s\n", messages[i]);
2804         }
2805         fprintf(user_fp, "#***\n\n\n");
2806
2807
2808         /* Open the default file */
2809         path_build(buf, sizeof(buf), ANGBAND_DIR_PREF, filename);
2810         pref_fp = my_fopen(buf, "r");
2811
2812         /* Failed */
2813         if (!pref_fp)
2814         {
2815                 my_fclose(user_fp);
2816                 return;
2817         }
2818
2819         /* Copy the contents of default file */
2820         while (!my_fgets(pref_fp, buf, sizeof(buf)))
2821                 fprintf(user_fp, "%s\n", buf);
2822
2823         my_fclose(user_fp);
2824         my_fclose(pref_fp);
2825 }
2826
2827 /*
2828  * Read an autopick prefence file to memory
2829  * Prepare default if no user file is found
2830  */
2831 static cptr *read_pickpref_text_lines(int *filename_mode_p)
2832 {
2833         char buf[1024];
2834         cptr *lines_list;
2835
2836         /* Try a filename with player name */
2837         *filename_mode_p = PT_WITH_PNAME;
2838         strcpy(buf, pickpref_filename(*filename_mode_p));
2839         lines_list = read_text_lines(buf);
2840
2841         if (!lines_list)
2842         {
2843                 /* Use default name */
2844                 *filename_mode_p = PT_DEFAULT;
2845                 strcpy(buf, pickpref_filename(*filename_mode_p));
2846                 lines_list = read_text_lines(buf);
2847         }
2848
2849         if (!lines_list)
2850         {
2851                 /* There is no preference file in the user directory */
2852
2853                 /* Copy the default autopick file to the user directory */
2854                 prepare_default_pickpref();
2855
2856                 /* Use default name again */
2857                 lines_list = read_text_lines(buf);
2858         }
2859
2860         if (!lines_list)
2861         {
2862                 /* Allocate list of pointers */
2863                 C_MAKE(lines_list, MAX_LINES, cptr);
2864                 lines_list[0] = string_make("");
2865         }
2866         return lines_list;
2867 }
2868
2869
2870 /*
2871  * Write whole lines of memory to a file.
2872  */
2873 static bool write_text_lines(cptr filename, cptr *lines_list)
2874 {
2875         FILE *fff;
2876
2877         int lines = 0;
2878         char buf[1024];
2879
2880         /* Build the filename */
2881         path_build(buf, sizeof(buf), ANGBAND_DIR_USER, filename);
2882         
2883         /* Open the file */
2884         fff = my_fopen(buf, "w");
2885         if (fff)
2886         {
2887                 for (lines = 0; lines_list[lines]; lines++)
2888                         my_fputs(fff, lines_list[lines], 1024);
2889
2890                 my_fclose(fff);
2891         }
2892
2893         if (!fff) return FALSE;
2894         return TRUE;
2895 }
2896
2897
2898 /*
2899  * Free memory of lines_list.
2900  */
2901 static void free_text_lines(cptr *lines_list)
2902 {
2903         int lines;
2904
2905         for (lines = 0; lines_list[lines]; lines++)
2906                 string_free(lines_list[lines]);
2907
2908         /* free list of pointers */
2909         C_KILL(lines_list, MAX_LINES, cptr);
2910 }
2911
2912
2913 /*
2914  * Delete or insert string
2915  */
2916 static void toggle_keyword(text_body_type *tb, BIT_FLAGS flg)
2917 {
2918         int by1, by2, y;
2919         bool add = TRUE;
2920         bool fixed = FALSE;
2921
2922         /* Some lines are selected */
2923         if (tb->mark)
2924         {
2925                 by1 = MIN(tb->my, tb->cy);
2926                 by2 = MAX(tb->my, tb->cy);
2927         }
2928
2929         /* No mark -- Select current line */
2930         else /* if (!tb->mark) */
2931         {
2932                 by1 = by2 = tb->cy;
2933         }
2934
2935
2936         /* Set/Reset flag of each line */
2937         for (y = by1; y <= by2; y++)
2938         {
2939                 autopick_type an_entry, *entry = &an_entry;
2940
2941                 if (!autopick_new_entry(entry, tb->lines_list[y], !fixed)) continue;
2942
2943                 string_free(tb->lines_list[y]);
2944
2945                 if (!fixed)
2946                 {
2947                         /* Add? or Remove? */
2948                         if (!IS_FLG(flg)) add = TRUE;
2949                         else add = FALSE;
2950
2951                         /* No more change */
2952                         fixed = TRUE;
2953                 }
2954
2955                 /* You can use only one noun flag */
2956                 if (FLG_NOUN_BEGIN <= flg && flg <= FLG_NOUN_END)
2957                 {
2958                         int i;
2959                         for (i = FLG_NOUN_BEGIN; i <= FLG_NOUN_END; i++)
2960                                 REM_FLG(i);
2961                 }
2962                 
2963                 /* You can use only one identify state flag */
2964                 else if (FLG_UNAWARE <= flg && flg <= FLG_STAR_IDENTIFIED)
2965                 {
2966                         int i;
2967                         for (i = FLG_UNAWARE; i <= FLG_STAR_IDENTIFIED; i++)
2968                                 REM_FLG(i);
2969                 }
2970                 
2971                 /* You can use only one flag in artifact/ego/nameless */
2972                 else if (FLG_ARTIFACT <= flg && flg <= FLG_AVERAGE)
2973                 {
2974                         int i;
2975                         for (i = FLG_ARTIFACT; i <= FLG_AVERAGE; i++)
2976                                 REM_FLG(i);
2977                 }
2978                 
2979                 /* You can use only one flag in rare/common */
2980                 else if (FLG_RARE <= flg && flg <= FLG_COMMON)
2981                 {
2982                         int i;
2983                         for (i = FLG_RARE; i <= FLG_COMMON; i++)
2984                                 REM_FLG(i);
2985                 }
2986                 
2987                 if (add) ADD_FLG(flg);
2988                 else REM_FLG(flg);
2989                 
2990                 tb->lines_list[y] = autopick_line_from_entry_kill(entry);
2991                 
2992                 /* Now dirty */
2993                 tb->dirty_flags |= DIRTY_ALL;
2994
2995                 /* Text is changed */
2996                 tb->changed = TRUE;
2997         }
2998 }
2999
3000
3001 /*
3002  * Change command letter
3003  */
3004 static void toggle_command_letter(text_body_type *tb, byte flg)
3005 {
3006         autopick_type an_entry, *entry = &an_entry;
3007         int by1, by2, y;
3008         bool add = TRUE;
3009         bool fixed = FALSE;
3010
3011         /* Some lines are selected */
3012         if (tb->mark)
3013         {
3014                 by1 = MIN(tb->my, tb->cy);
3015                 by2 = MAX(tb->my, tb->cy);
3016         }
3017
3018         /* No mark -- Select current line */
3019         else /* if (!tb->mark) */
3020         {
3021                 by1 = by2 = tb->cy;
3022         }
3023
3024
3025         /* Set/Reset flag of each line */
3026         for (y = by1; y <= by2; y++)
3027         {
3028                 int wid = 0;
3029
3030                 if (!autopick_new_entry(entry, tb->lines_list[y], FALSE)) continue;
3031
3032                 string_free(tb->lines_list[y]);
3033
3034                 if (!fixed)
3035                 {
3036                         /* Add? or Remove? */
3037                         if (!(entry->action & flg)) add = TRUE;
3038                         else add = FALSE;
3039
3040                         /* No more change */
3041                         fixed = TRUE;
3042                 }
3043
3044                 /* Count number of letter (by negative number) */
3045                 if (entry->action & DONT_AUTOPICK) wid--;
3046                 else if (entry->action & DO_AUTODESTROY) wid--;
3047                 else if (entry->action & DO_QUERY_AUTOPICK) wid--;
3048                 if (!(entry->action & DO_DISPLAY)) wid--;
3049
3050                 /* Set/Reset the flag */
3051                 if (flg != DO_DISPLAY)
3052                 {
3053                         entry->action &= ~(DO_AUTOPICK | DONT_AUTOPICK | DO_AUTODESTROY | DO_QUERY_AUTOPICK);
3054                         if (add) entry->action |= flg;
3055                         else entry->action |= DO_AUTOPICK;
3056                 }
3057                 else
3058                 {
3059                         entry->action &= ~(DO_DISPLAY);
3060                         if (add) entry->action |= flg;
3061                 }
3062
3063                 /* Correct cursor location */
3064                 if (tb->cy == y)
3065                 {
3066                         if (entry->action & DONT_AUTOPICK) wid++;
3067                         else if (entry->action & DO_AUTODESTROY) wid++;
3068                         else if (entry->action & DO_QUERY_AUTOPICK) wid++;
3069                         if (!(entry->action & DO_DISPLAY)) wid++;
3070
3071                         if (wid > 0) tb->cx++;
3072                         if (wid < 0 && tb->cx > 0) tb->cx--;
3073                 }
3074                         
3075                 tb->lines_list[y] = autopick_line_from_entry_kill(entry);
3076                         
3077                 /* Now dirty */
3078                 tb->dirty_flags |= DIRTY_ALL;
3079
3080                 /* Text is changed */
3081                 tb->changed = TRUE;
3082         }
3083 }
3084
3085 /*
3086  * Delete or insert string
3087  */
3088 static void add_keyword(text_body_type *tb, BIT_FLAGS flg)
3089 {
3090         int by1, by2, y;
3091
3092         /* Some lines are selected */
3093         if (tb->mark)
3094         {
3095                 by1 = MIN(tb->my, tb->cy);
3096                 by2 = MAX(tb->my, tb->cy);
3097         }
3098
3099         /* No mark -- Select current line */
3100         else /* if (!tb->mark) */
3101         {
3102                 by1 = by2 = tb->cy;
3103         }
3104
3105
3106         /* Set/Reset flag of each line */
3107         for (y = by1; y <= by2; y++)
3108         {
3109                 autopick_type an_entry, *entry = &an_entry;
3110
3111                 if (!autopick_new_entry(entry, tb->lines_list[y], FALSE)) continue;
3112
3113                 /* There is the flag already */
3114                 if (IS_FLG(flg))
3115                 {
3116                         /* Free memory for the entry */
3117                         autopick_free_entry(entry);
3118                         
3119                         continue;
3120                 }
3121                 
3122                 string_free(tb->lines_list[y]);
3123                 
3124                 /* Remove all noun flag */
3125                 if (FLG_NOUN_BEGIN <= flg && flg <= FLG_NOUN_END)
3126                 {
3127                         int i;
3128                         for (i = FLG_NOUN_BEGIN; i <= FLG_NOUN_END; i++)
3129                                 REM_FLG(i);
3130                 }
3131                 
3132                 ADD_FLG(flg);
3133                 
3134                 tb->lines_list[y] = autopick_line_from_entry_kill(entry);
3135
3136                 /* Now dirty */
3137                 tb->dirty_flags |= DIRTY_ALL;
3138
3139                 /* Text is changed */
3140                 tb->changed = TRUE;
3141         }
3142 }
3143
3144
3145 /*
3146  * Check if this line is expression or not.
3147  * And update it if it is.
3148  */
3149 static void check_expression_line(text_body_type *tb, int y)
3150 {
3151         cptr s = tb->lines_list[y];
3152
3153         if ((s[0] == '?' && s[1] == ':') ||
3154             (tb->states[y] & LSTAT_BYPASS))
3155         {
3156                 /* Expressions need re-evaluation */
3157                 tb->dirty_flags |= DIRTY_EXPRESSION;
3158         }
3159 }
3160
3161
3162 /*
3163  * Add an empty line at the last of the file
3164  */
3165 static bool add_empty_line(text_body_type *tb)
3166 {
3167         int k;
3168
3169         for (k = 0; tb->lines_list[k]; k++)
3170                 /* count number of lines */ ;
3171
3172         /* Too many lines! */
3173         if (k >= MAX_LINES - 2) return FALSE;
3174
3175         /* The last line is already empty */
3176         if (!tb->lines_list[k-1][0]) return FALSE;
3177
3178         /* Create new empty line */
3179         tb->lines_list[k] = string_make("");
3180
3181         /* Expressions need re-evaluation */
3182         tb->dirty_flags |= DIRTY_EXPRESSION;
3183
3184         /* Text is changed */
3185         tb->changed = TRUE;
3186
3187         /* A line is added */
3188         return TRUE;
3189 }
3190
3191
3192 /*
3193  * Insert return code and split the line
3194  */
3195 static bool insert_return_code(text_body_type *tb)
3196 {
3197         char buf[MAX_LINELEN];
3198         int i, j, k;
3199
3200         for (k = 0; tb->lines_list[k]; k++)
3201                 /* count number of lines */ ;
3202
3203         if (k >= MAX_LINES - 2) return FALSE;
3204         k--;
3205
3206         /* Move down lines */
3207         for (; tb->cy < k; k--)
3208         {
3209                 tb->lines_list[k+1] = tb->lines_list[k];
3210                 tb->states[k+1] = tb->states[k];
3211         }
3212
3213         /* Split current line */
3214         for (i = j = 0; tb->lines_list[tb->cy][i] && i < tb->cx; i++)
3215         {
3216 #ifdef JP
3217                 if (iskanji(tb->lines_list[tb->cy][i]))
3218                         buf[j++] = tb->lines_list[tb->cy][i++];
3219 #endif
3220                 buf[j++] = tb->lines_list[tb->cy][i];
3221         }
3222         buf[j] = '\0';
3223         tb->lines_list[tb->cy+1] = string_make(&tb->lines_list[tb->cy][i]);
3224         string_free(tb->lines_list[tb->cy]);
3225         tb->lines_list[tb->cy] = string_make(buf);
3226
3227         /* Expressions need re-evaluation */
3228         tb->dirty_flags |= DIRTY_EXPRESSION;
3229
3230         /* Text is changed */
3231         tb->changed = TRUE;
3232
3233         return TRUE;
3234 }
3235
3236
3237 /*
3238  * Choose an item and get auto-picker entry from it.
3239  */
3240 static bool entry_from_choosed_object(autopick_type *entry)
3241 {
3242         object_type *o_ptr;
3243         cptr q, s;
3244
3245         q = _("どのアイテムを登録しますか? ", "Enter which item? ");
3246         s = _("アイテムを持っていない。", "You have nothing to enter.");
3247         o_ptr = choose_object(NULL, q, s, USE_INVEN | USE_FLOOR | USE_EQUIP);
3248         if (!o_ptr) return FALSE;
3249
3250         autopick_entry_from_object(entry, o_ptr);
3251         return TRUE;
3252 }
3253
3254
3255 /*
3256  * Choose an item for search
3257  */
3258 static byte get_object_for_search(object_type **o_handle, cptr *search_strp)
3259 {
3260         char buf[MAX_NLEN+20];
3261         object_type *o_ptr;
3262         cptr q, s;
3263
3264         q = _("どのアイテムを検索しますか? ", "Enter which item? ");
3265         s = _("アイテムを持っていない。", "You have nothing to enter.");
3266         o_ptr = choose_object(NULL, q, s, USE_INVEN | USE_FLOOR | USE_EQUIP);
3267         if (!o_ptr) return 0;
3268
3269         *o_handle = o_ptr;
3270
3271         string_free(*search_strp);
3272         object_desc(buf, *o_handle, (OD_NO_FLAVOR | OD_OMIT_PREFIX | OD_NO_PLURAL));
3273         *search_strp = string_make(format("<%s>", buf));
3274         return 1;
3275 }
3276
3277
3278 /*
3279  * Prepare for search by destroyed object
3280  */
3281 static byte get_destroyed_object_for_search(object_type **o_handle, cptr *search_strp)
3282 {
3283         char buf[MAX_NLEN+20];
3284
3285         if (!autopick_last_destroyed_object.k_idx) return 0;
3286
3287         *o_handle = &autopick_last_destroyed_object;
3288
3289         string_free(*search_strp);
3290         object_desc(buf, *o_handle, (OD_NO_FLAVOR | OD_OMIT_PREFIX | OD_NO_PLURAL));
3291         *search_strp = string_make(format("<%s>", buf));
3292         return 1;
3293 }
3294
3295
3296 /*
3297  * Choose an item or string for search
3298  */
3299 static byte get_string_for_search(object_type **o_handle, cptr *search_strp)
3300 {
3301         int pos = 0;
3302
3303         /*
3304          * Text color
3305          * TERM_YELLOW : Overwrite mode
3306          * TERM_WHITE : Insert mode
3307          */
3308         byte color = TERM_YELLOW;
3309         char buf[MAX_NLEN+20];
3310         const int len = 80;
3311
3312         char prompt[] = _("検索(^I:持ち物 ^L:破壊された物): ", "Search key(^I:inven ^L:destroyed): ");
3313         int col = sizeof(prompt) - 1;
3314
3315         /* Prepare string buffer for edit */
3316         if (*search_strp) strcpy(buf, *search_strp);
3317         else buf[0] = '\0';
3318
3319         /* Object searching mode */
3320         if (*o_handle)
3321         {
3322                 color = TERM_L_GREEN;
3323         }
3324
3325         /* Display prompt */
3326         prt(prompt, 0, 0);
3327
3328
3329         /* Process input */
3330         while (TRUE)
3331         {
3332                 bool back = FALSE;
3333                 int skey;
3334
3335                 /* Display the string */
3336                 Term_erase(col, 0, 255);
3337                 Term_putstr(col, 0, -1, color, buf);
3338
3339                 /* Place cursor */
3340                 Term_gotoxy(col + pos, 0);
3341
3342                 /* Get a special key code */
3343                 skey = inkey_special(TRUE);
3344
3345                 /* Analyze the key */
3346                 switch (skey)
3347                 {
3348                 case SKEY_LEFT:
3349                 case KTRL('b'):
3350                 {
3351                         int i = 0;
3352
3353                         /* Now on insert mode */
3354                         color = TERM_WHITE;
3355
3356                         /* No move at beginning of line */
3357                         if (0 == pos) break;
3358
3359                         while (TRUE)
3360                         {
3361                                 int next_pos = i + 1;
3362
3363 #ifdef JP
3364                                 if (iskanji(buf[i])) next_pos++;
3365 #endif
3366
3367                                 /* Is there the cursor at next position? */ 
3368                                 if (next_pos >= pos) break;
3369
3370                                 /* Move to next */
3371                                 i = next_pos;
3372                         }
3373
3374                         /* Get previous position */
3375                         pos = i;
3376
3377                         break;
3378                 }
3379
3380                 case SKEY_RIGHT:
3381                 case KTRL('f'):
3382                         /* Now on insert mode */
3383                         color = TERM_WHITE;
3384
3385                         /* No move at end of line */
3386                         if ('\0' == buf[pos]) break;
3387
3388 #ifdef JP
3389                         /* Move right */
3390                         if (iskanji(buf[pos])) pos += 2;
3391                         else pos++;
3392 #else
3393                         pos++;
3394 #endif
3395
3396                         break;
3397
3398                 case ESCAPE:
3399                         return 0;
3400
3401                 case KTRL('r'):
3402                         back = TRUE;
3403                         /* Fall through */
3404
3405                 case '\n':
3406                 case '\r':
3407                 case KTRL('s'):
3408                         if (*o_handle) return (back ? -1 : 1);
3409                         string_free(*search_strp);
3410                         *search_strp = string_make(buf);
3411                         *o_handle = NULL;
3412                         return (back ? -1 : 1);
3413
3414                 case KTRL('i'):
3415                         return get_object_for_search(o_handle, search_strp);
3416
3417                 case KTRL('l'):
3418                         /* Prepare string for destroyed object if there is one. */
3419                         if (get_destroyed_object_for_search(o_handle, search_strp))
3420                                 return 1;
3421                         break;
3422
3423                 case '\010':
3424                 {
3425                         /* Backspace */
3426
3427                         int i = 0;
3428
3429                         /* Now on insert mode */
3430                         color = TERM_WHITE;
3431
3432                         /* No move at beginning of line */
3433                         if (0 == pos) break;
3434
3435                         while (TRUE)
3436                         {
3437                                 int next_pos = i + 1;
3438
3439 #ifdef JP
3440                                 if (iskanji(buf[i])) next_pos++;
3441 #endif
3442
3443                                 /* Is there the cursor at next position? */ 
3444                                 if (next_pos >= pos) break;
3445
3446                                 /* Move to next */
3447                                 i = next_pos;
3448                         }
3449
3450                         /* Get previous position */
3451                         pos = i;
3452
3453                         /* Fall through to 'Delete key' */
3454                 }
3455
3456                 case 0x7F:
3457                 case KTRL('d'):
3458                         /* Delete key */
3459                 {
3460                         int dst, src;
3461
3462                         /* Now on insert mode */
3463                         color = TERM_WHITE;
3464
3465                         /* No move at end of line */
3466                         if ('\0' == buf[pos]) break;
3467
3468                         /* Position of next character */
3469                         src = pos + 1;
3470
3471 #ifdef JP
3472                         /* Next character is one more byte away */
3473                         if (iskanji(buf[pos])) src++;
3474 #endif
3475
3476                         dst = pos;
3477
3478                         /* Move characters at src to dst */
3479                         while ('\0' != (buf[dst++] = buf[src++]))
3480                                 /* loop */;
3481
3482                         break;
3483                 }
3484
3485                 default:
3486                 {
3487                         /* Insert a character */
3488
3489                         char tmp[100];
3490                         char c;
3491
3492                         /* Ignore special keys */
3493                         if (skey & SKEY_MASK) break;
3494
3495                         /* Get a character code */
3496                         c = (char)skey;
3497
3498                         /* Was non insert mode? */
3499                         if (color != TERM_WHITE)
3500                         {
3501                                 /* Was object searching mode */
3502                                 if (color == TERM_L_GREEN)
3503                                 {
3504                                         /* Cancel the mode */
3505                                         *o_handle = NULL;
3506
3507                                         /* Remove indicating string */
3508                                         string_free(*search_strp);
3509                                         *search_strp = NULL;
3510                                 }
3511
3512                                 /* Overwrite default string */
3513                                 buf[0] = '\0';
3514
3515                                 /* Go to insert mode */
3516                                 color = TERM_WHITE;
3517                         }
3518
3519                         /* Save right part of string */
3520                         strcpy(tmp, buf + pos);
3521 #ifdef JP
3522                         if (iskanji(c))
3523                         {
3524                                 char next;
3525
3526                                 /* Bypass macro processing */
3527                                 inkey_base = TRUE;
3528                                 next = inkey();
3529
3530                                 if (pos + 1 < len)
3531                                 {
3532                                         buf[pos++] = c;
3533                                         buf[pos++] = next;
3534                                 }
3535                                 else
3536                                 {
3537                                         bell();
3538                                 }
3539                         }
3540                         else
3541 #endif
3542                         {
3543 #ifdef JP
3544                                 if (pos < len && (isprint(c) || iskana(c)))
3545 #else
3546                                 if (pos < len && isprint(c))
3547 #endif
3548                                 {
3549                                         buf[pos++] = c;
3550                                 }
3551                                 else
3552                                 {
3553                                         bell();
3554                                 }
3555                         }
3556
3557                         /* Terminate */
3558                         buf[pos] = '\0';
3559
3560                         /* Write back the left part of string */
3561                         my_strcat(buf, tmp, len + 1);
3562
3563                         break;
3564                 } /* default: */
3565
3566                 }
3567
3568                 /* Object searching mode was cancelled? */
3569                 if (*o_handle && color != TERM_L_GREEN)
3570                 {
3571                         /* Cancel the mode */
3572                         *o_handle = NULL;
3573
3574                         /* Remove indicating string */
3575                         buf[0] = '\0';
3576                         string_free(*search_strp);
3577                         *search_strp = NULL;
3578
3579                 }
3580
3581
3582         } /* while (TRUE) */
3583 }
3584
3585
3586 /*
3587  * Search next line matches for o_ptr
3588  */
3589 static void search_for_object(text_body_type *tb, object_type *o_ptr, bool forward)
3590 {
3591         autopick_type an_entry, *entry = &an_entry;
3592         GAME_TEXT o_name[MAX_NLEN];
3593         int bypassed_cy = -1;
3594
3595         /* Start searching from current cursor position */
3596         int i = tb->cy;
3597
3598         /* Prepare object name string first */
3599         object_desc(o_name, o_ptr, (OD_NO_FLAVOR | OD_OMIT_PREFIX | OD_NO_PLURAL));
3600
3601         /* Convert the string to lower case */
3602         str_tolower(o_name);
3603
3604         while (TRUE)
3605         {
3606                 bool match;
3607
3608                 /* End of list? */
3609                 if (forward)
3610                 {
3611                         if (!tb->lines_list[++i]) break;
3612                 }
3613                 else
3614                 {
3615                         if (--i < 0) break;
3616                 }
3617
3618                 /* Is this line is a correct entry? */
3619                 if (!autopick_new_entry(entry, tb->lines_list[i], FALSE)) continue;
3620
3621                 /* Does this line match to the object? */
3622                 match = is_autopick_aux(o_ptr, entry, o_name);
3623                 autopick_free_entry(entry);
3624                 if (!match)     continue;
3625
3626                 /* Found a line but it's inactive */
3627                 if (tb->states[i] & LSTAT_BYPASS)
3628                 {
3629                         /* If it is first found, remember it */
3630                         if (bypassed_cy == -1) bypassed_cy = i;
3631                 }
3632
3633                 /* Found an active line! */
3634                 else
3635                 {
3636                         /* Move to this line */
3637                         tb->cx = 0;
3638                         tb->cy = i;
3639
3640                         if (bypassed_cy != -1)
3641                         {
3642                                 /* Mark as some lines are skipped */
3643                                 tb->dirty_flags |= DIRTY_SKIP_INACTIVE;
3644                         }
3645
3646                         /* Found it! */
3647                         return;
3648                 }
3649         }
3650
3651         if (bypassed_cy != -1)
3652         {
3653                 /* Move to the remembered line */
3654                 tb->cx = 0;
3655                 tb->cy = bypassed_cy;
3656
3657                 /* Mark as this line is inactive */
3658                 tb->dirty_flags |= DIRTY_INACTIVE;
3659         }
3660
3661         else
3662         {
3663                 /* Mark as NOT FOUND */
3664                 tb->dirty_flags |= DIRTY_NOT_FOUND;
3665         }
3666
3667         return;
3668 }
3669
3670
3671 /*
3672  * Search next line matches to the string
3673  */
3674 static void search_for_string(text_body_type *tb, cptr search_str, bool forward)
3675 {
3676         int bypassed_cy = -1;
3677         int bypassed_cx = 0;
3678
3679         /* Start searching from current cursor position */
3680         int i = tb->cy;
3681
3682         while (TRUE)
3683         {
3684                 cptr pos;
3685
3686                 /* End of list? */
3687                 if (forward)
3688                 {
3689                         if (!tb->lines_list[++i]) break;
3690                 }
3691                 else
3692                 {
3693                         if (--i < 0) break;
3694                 }
3695
3696                 /* Look for the string pattern */
3697                 pos = my_strstr(tb->lines_list[i], search_str);
3698
3699                 /* Not found! */
3700                 if (!pos) continue;
3701
3702                 /* Found a line but it's inactive */
3703                 if ((tb->states[i] & LSTAT_BYPASS) &&
3704                     !(tb->states[i] & LSTAT_EXPRESSION))
3705                 {
3706                         /* If it is first found, remember it */
3707                         if (bypassed_cy == -1)
3708                         {
3709                                 bypassed_cy = i;
3710                                 bypassed_cx = (int)(pos - tb->lines_list[i]);
3711                         }
3712                 }
3713
3714                 /* Found an active line! */
3715                 else
3716                 {
3717                         /* Move to this location */
3718                         tb->cx = (int)(pos - tb->lines_list[i]);
3719                         tb->cy = i;
3720
3721                         if (bypassed_cy != -1)
3722                         {
3723                                 /* Mark as some lines are skipped */
3724                                 tb->dirty_flags |= DIRTY_SKIP_INACTIVE;
3725                         }
3726
3727                         /* Found it! */
3728                         return;
3729                 }
3730         }
3731
3732         if (bypassed_cy != -1)
3733         {
3734                 /* Move to the remembered line */
3735                 tb->cx = bypassed_cx;
3736                 tb->cy = bypassed_cy;
3737
3738                 /* Mark as this line is inactive */
3739                 tb->dirty_flags |= DIRTY_INACTIVE;
3740         }
3741
3742         else
3743         {
3744                 /* Mark as NOT FOUND */
3745                 tb->dirty_flags |= DIRTY_NOT_FOUND;
3746         }
3747
3748         return;
3749 }
3750
3751
3752
3753
3754 /*
3755  * Editor command id's
3756  */
3757 #define EC_QUIT            1
3758 #define EC_SAVEQUIT        2
3759 #define EC_REVERT              3
3760 #define EC_HELP            4
3761 #define EC_RETURN              5
3762 #define EC_LEFT                6 
3763 #define EC_DOWN                7 
3764 #define EC_UP                  8 
3765 #define EC_RIGHT               9 
3766 #define EC_BOL                 10
3767 #define EC_EOL                 11
3768 #define EC_PGUP                12
3769 #define EC_PGDOWN              13
3770 #define EC_TOP                 14
3771 #define EC_BOTTOM              15
3772 #define EC_CUT                 16
3773 #define EC_COPY                17
3774 #define EC_PASTE               18
3775 #define EC_BLOCK               19
3776 #define EC_KILL_LINE           20
3777 #define EC_DELETE_CHAR         21
3778 #define EC_BACKSPACE           22
3779 #define EC_SEARCH_STR          23
3780 #define EC_SEARCH_FORW         24
3781 #define EC_SEARCH_BACK         25
3782 #define EC_SEARCH_OBJ          26
3783 #define EC_SEARCH_DESTROYED    27
3784 #define EC_INSERT_OBJECT       28
3785 #define EC_INSERT_DESTROYED    29
3786 #define EC_INSERT_BLOCK        30
3787 #define EC_INSERT_MACRO        31
3788 #define EC_INSERT_KEYMAP       32
3789 #define EC_CL_AUTOPICK         33
3790 #define EC_CL_DESTROY          34
3791 #define EC_CL_LEAVE            35
3792 #define EC_CL_QUERY            36
3793 #define EC_CL_NO_DISP          37
3794 #define EC_OK_COLLECTING       38
3795 #define EC_IK_UNAWARE          39
3796 #define EC_IK_UNIDENTIFIED     40
3797 #define EC_IK_IDENTIFIED       41
3798 #define EC_IK_STAR_IDENTIFIED  42
3799 #define EC_OK_BOOSTED          43
3800 #define EC_OK_MORE_DICE        44
3801 #define EC_OK_MORE_BONUS       45
3802 #define EC_OK_WORTHLESS        46
3803 #define EC_OK_ARTIFACT         47
3804 #define EC_OK_EGO              48
3805 #define EC_OK_GOOD             49
3806 #define EC_OK_NAMELESS         50
3807 #define EC_OK_AVERAGE          51
3808 #define EC_OK_RARE             52       
3809 #define EC_OK_COMMON           53
3810 #define EC_OK_WANTED           54
3811 #define EC_OK_UNIQUE           55
3812 #define EC_OK_HUMAN            56
3813 #define EC_OK_UNREADABLE       57
3814 #define EC_OK_REALM1           58
3815 #define EC_OK_REALM2           59
3816 #define EC_OK_FIRST            60
3817 #define EC_OK_SECOND           61
3818 #define EC_OK_THIRD            62
3819 #define EC_OK_FOURTH           63
3820 #define EC_KK_WEAPONS          64
3821 #define EC_KK_FAVORITE_WEAPONS 65
3822 #define EC_KK_ARMORS           66
3823 #define EC_KK_MISSILES         67
3824 #define EC_KK_DEVICES          68
3825 #define EC_KK_LIGHTS           69
3826 #define EC_KK_JUNKS            70
3827 #define EC_KK_CORPSES          71
3828 #define EC_KK_SPELLBOOKS       72
3829 #define EC_KK_SHIELDS          73
3830 #define EC_KK_BOWS             74
3831 #define EC_KK_RINGS            75
3832 #define EC_KK_AMULETS          76
3833 #define EC_KK_SUITS            77
3834 #define EC_KK_CLOAKS           78
3835 #define EC_KK_HELMS            79
3836 #define EC_KK_GLOVES           80
3837 #define EC_KK_BOOTS            81
3838
3839
3840 /* Manu names */
3841 #ifdef JP
3842
3843 static GAME_TEXT MN_QUIT[] = "セーブ無しで終了";
3844 static GAME_TEXT MN_SAVEQUIT[] = "セーブして終了";
3845 static GAME_TEXT MN_REVERT[] = "全ての変更を破棄";
3846 static GAME_TEXT MN_HELP[] = "ヘルプ";
3847
3848 static GAME_TEXT MN_MOVE[] = "カーソル移動";
3849 static GAME_TEXT MN_LEFT[] =   "左          (←矢印キー)";
3850 static GAME_TEXT MN_DOWN[] =   "下          (↓矢印キー)";
3851 static GAME_TEXT MN_UP[] =     "上          (↑矢印キー)";
3852 static GAME_TEXT MN_RIGHT[] =  "右          (→矢印キー)";
3853 static GAME_TEXT MN_BOL[] =    "行の先頭";
3854 static GAME_TEXT MN_EOL[] =    "行の終端";
3855 static GAME_TEXT MN_PGUP[] =   "上のページ  (PageUpキー)";
3856 static GAME_TEXT MN_PGDOWN[] = "下のページ  (PageDownキー)";
3857 static GAME_TEXT MN_TOP[] =    "1行目へ移動 (Homeキー)";
3858 static GAME_TEXT MN_BOTTOM[] = "最下行へ移動(Endキー)";
3859
3860 static GAME_TEXT MN_EDIT[] = "編集";
3861 static GAME_TEXT MN_CUT[] = "カット";
3862 static GAME_TEXT MN_COPY[] = "コピー";
3863 static GAME_TEXT MN_PASTE[] = "ペースト";
3864 static GAME_TEXT MN_BLOCK[] = "選択範囲の指定";
3865 static GAME_TEXT MN_KILL_LINE[] = "行の残りを削除";
3866 static GAME_TEXT MN_DELETE_CHAR[] = "1文字削除";
3867 static GAME_TEXT MN_BACKSPACE[] = "バックスペース";
3868 static GAME_TEXT MN_RETURN[] = "改行";
3869
3870 static GAME_TEXT MN_SEARCH[] = "検索";
3871 static GAME_TEXT MN_SEARCH_STR[] = "文字列で検索";
3872 static GAME_TEXT MN_SEARCH_FORW[] = "前方へ再検索";
3873 static GAME_TEXT MN_SEARCH_BACK[] = "後方へ再検索";
3874 static GAME_TEXT MN_SEARCH_OBJ[] = "アイテムを選択して検索";
3875 static GAME_TEXT MN_SEARCH_DESTROYED[] = "自動破壊されたアイテムで検索";
3876
3877 static GAME_TEXT MN_INSERT[] = "色々挿入";
3878 static GAME_TEXT MN_INSERT_OBJECT[] = "選択したアイテムの名前を挿入";
3879 static GAME_TEXT MN_INSERT_DESTROYED[] = "自動破壊されたアイテムの名前を挿入";
3880 static GAME_TEXT MN_INSERT_BLOCK[] = "条件分岐ブロックの例を挿入";
3881 static GAME_TEXT MN_INSERT_MACRO[] = "マクロ定義を挿入";
3882 static GAME_TEXT MN_INSERT_KEYMAP[] = "キーマップ定義を挿入";
3883
3884 static GAME_TEXT MN_COMMAND_LETTER[] = "拾い/破壊/放置の選択";
3885 static GAME_TEXT MN_CL_AUTOPICK[] = "「 」 (自動拾い)";
3886 static GAME_TEXT MN_CL_DESTROY[] = "「!」 (自動破壊)";
3887 static GAME_TEXT MN_CL_LEAVE[] = "「~」 (放置)";
3888 static GAME_TEXT MN_CL_QUERY[] = "「;」 (確認して拾う)";
3889 static GAME_TEXT MN_CL_NO_DISP[] = "「(」 (マップコマンドで表示しない)";
3890
3891 static GAME_TEXT MN_ADJECTIVE_GEN[] = "形容詞(一般)の選択";
3892 static GAME_TEXT MN_RARE[] = "レアな (装備)";
3893 static GAME_TEXT MN_COMMON[] = "ありふれた (装備)";
3894
3895 static GAME_TEXT MN_ADJECTIVE_SPECIAL[] = "形容詞(特殊)の選択";
3896 static GAME_TEXT MN_BOOSTED[] = "ダイス目の違う (武器)";
3897 static GAME_TEXT MN_MORE_DICE[] = "ダイス目 # 以上の (武器)";
3898 static GAME_TEXT MN_MORE_BONUS[] = "修正値 # 以上の (指輪等)";
3899 static GAME_TEXT MN_WANTED[] = "賞金首の (死体)";
3900 static GAME_TEXT MN_UNIQUE[] = "ユニーク・モンスターの (死体)";
3901 static GAME_TEXT MN_HUMAN[] = "人間の (死体)";
3902 static GAME_TEXT MN_UNREADABLE[] = "読めない (魔法書)";
3903 static GAME_TEXT MN_REALM1[] = "第一領域の (魔法書)";
3904 static GAME_TEXT MN_REALM2[] = "第二領域の (魔法書)";
3905 static GAME_TEXT MN_FIRST[] = "1冊目の (魔法書)";
3906 static GAME_TEXT MN_SECOND[] = "2冊目の (魔法書)";
3907 static GAME_TEXT MN_THIRD[] = "3冊目の (魔法書)";
3908 static GAME_TEXT MN_FOURTH[] = "4冊目の (魔法書)";
3909
3910 static GAME_TEXT MN_NOUN[] = "名詞の選択";
3911
3912 #else
3913
3914 static GAME_TEXT MN_QUIT[] = "Quit without save";
3915 static GAME_TEXT MN_SAVEQUIT[] = "Save & Quit";
3916 static GAME_TEXT MN_REVERT[] = "Revert all changes";
3917 static GAME_TEXT MN_HELP[] = "Help";
3918
3919 static GAME_TEXT MN_MOVE[] =   "Move cursor";
3920 static GAME_TEXT MN_LEFT[] =   "Left     (Left Arrow key)";
3921 static GAME_TEXT MN_DOWN[] =   "Down     (Down Arrow key)";
3922 static GAME_TEXT MN_UP[] =     "Up       (Up Arrow key)";
3923 static GAME_TEXT MN_RIGHT[] =  "Right    (Right Arrow key)";
3924 static GAME_TEXT MN_BOL[] =    "Beggining of line";
3925 static GAME_TEXT MN_EOL[] =    "End of line";
3926 static GAME_TEXT MN_PGUP[] =   "Page up  (PageUp key)";
3927 static GAME_TEXT MN_PGDOWN[] = "Page down(PageDown key)";
3928 static GAME_TEXT MN_TOP[] =    "Top      (Home key)";
3929 static GAME_TEXT MN_BOTTOM[] = "Bottom   (End key)";
3930
3931 static GAME_TEXT MN_EDIT[] = "Edit";
3932 static GAME_TEXT MN_CUT[] = "Cut";
3933 static GAME_TEXT MN_COPY[] = "Copy";
3934 static GAME_TEXT MN_PASTE[] = "Paste";
3935 static GAME_TEXT MN_BLOCK[] = "Select block";
3936 static GAME_TEXT MN_KILL_LINE[] = "Kill rest of line";
3937 static GAME_TEXT MN_DELETE_CHAR[] = "Delete character";
3938 static GAME_TEXT MN_BACKSPACE[] = "Backspace";
3939 static GAME_TEXT MN_RETURN[] = "Return";
3940
3941 static GAME_TEXT MN_SEARCH[] = "Search";
3942 static GAME_TEXT MN_SEARCH_STR[] = "Search by string";
3943 static GAME_TEXT MN_SEARCH_FORW[] = "Search forward";
3944 static GAME_TEXT MN_SEARCH_BACK[] = "Search backward";
3945 static GAME_TEXT MN_SEARCH_OBJ[] = "Search by inventory object";
3946 static GAME_TEXT MN_SEARCH_DESTROYED[] = "Search by destroyed object";
3947
3948 static GAME_TEXT MN_INSERT[] = "Insert...";
3949 static GAME_TEXT MN_INSERT_OBJECT[] = "Insert name of choosen object";
3950 static GAME_TEXT MN_INSERT_DESTROYED[] = "Insert name of destroyed object";
3951 static GAME_TEXT MN_INSERT_BLOCK[] = "Insert conditional block";
3952 static GAME_TEXT MN_INSERT_MACRO[] = "Insert a macro definition";
3953 static GAME_TEXT MN_INSERT_KEYMAP[] = "Insert a keymap definition";
3954
3955 static GAME_TEXT MN_COMMAND_LETTER[] = "Command letter";
3956 static GAME_TEXT MN_CL_AUTOPICK[] = "' ' (Auto pick)";
3957 static GAME_TEXT MN_CL_DESTROY[] = "'!' (Auto destroy)";
3958 static GAME_TEXT MN_CL_LEAVE[] = "'~' (Leave it on the floor)";
3959 static GAME_TEXT MN_CL_QUERY[] = "';' (Query to pick up)";
3960 static GAME_TEXT MN_CL_NO_DISP[] = "'(' (No display on the large map)";
3961
3962 static GAME_TEXT MN_ADJECTIVE_GEN[] = "Adjective (general)";
3963 static GAME_TEXT MN_RARE[] = "rare (equipments)";
3964 static GAME_TEXT MN_COMMON[] = "common (equipments)";
3965
3966 static GAME_TEXT MN_ADJECTIVE_SPECIAL[] = "Adjective (special)";
3967 static GAME_TEXT MN_BOOSTED[] = "dice boosted (weapons)";
3968 static GAME_TEXT MN_MORE_DICE[] = "more than # dice (weapons)";
3969 static GAME_TEXT MN_MORE_BONUS[] = "more bonus than # (rings etc.)";
3970 static GAME_TEXT MN_WANTED[] = "wanted (corpse)";
3971 static GAME_TEXT MN_UNIQUE[] = "unique (corpse)";
3972 static GAME_TEXT MN_HUMAN[] = "human (corpse)";
3973 static GAME_TEXT MN_UNREADABLE[] = "unreadable (spellbooks)";
3974 static GAME_TEXT MN_REALM1[] = "realm1 (spellbooks)";
3975 static GAME_TEXT MN_REALM2[] = "realm2 (spellbooks)";
3976 static GAME_TEXT MN_FIRST[] = "first (spellbooks)";
3977 static GAME_TEXT MN_SECOND[] = "second (spellbooks)";
3978 static GAME_TEXT MN_THIRD[] = "third (spellbooks)";
3979 static GAME_TEXT MN_FOURTH[] = "fourth (spellbooks)";
3980
3981 static GAME_TEXT MN_NOUN[] = "Keywords (noun)";
3982
3983 #endif
3984
3985
3986 typedef struct {
3987         cptr name;
3988         int level;
3989         int key;
3990         int com_id;
3991 } command_menu_type;
3992
3993
3994 command_menu_type menu_data[] =
3995 {
3996         {MN_HELP, 0, -1, EC_HELP},
3997         {MN_QUIT, 0, KTRL('q'), EC_QUIT}, 
3998         {MN_SAVEQUIT, 0, KTRL('w'), EC_SAVEQUIT}, 
3999         {MN_REVERT, 0, KTRL('z'), EC_REVERT},
4000
4001         {MN_EDIT, 0, -1, -1},
4002         {MN_CUT, 1, KTRL('x'), EC_CUT},
4003         {MN_COPY, 1, KTRL('c'), EC_COPY},
4004         {MN_PASTE, 1, KTRL('v'), EC_PASTE},
4005         {MN_BLOCK, 1, KTRL('g'), EC_BLOCK},
4006         {MN_KILL_LINE, 1, KTRL('k'), EC_KILL_LINE},
4007         {MN_DELETE_CHAR, 1, KTRL('d'), EC_DELETE_CHAR},
4008         {MN_BACKSPACE, 1, KTRL('h'), EC_BACKSPACE},
4009         {MN_RETURN, 1, KTRL('j'), EC_RETURN},
4010         {MN_RETURN, 1, KTRL('m'), EC_RETURN},
4011
4012         {MN_SEARCH, 0, -1, -1},
4013         {MN_SEARCH_STR, 1, KTRL('s'), EC_SEARCH_STR},
4014         {MN_SEARCH_FORW, 1, -1, EC_SEARCH_FORW},
4015         {MN_SEARCH_BACK, 1, KTRL('r'), EC_SEARCH_BACK},
4016         {MN_SEARCH_OBJ, 1, KTRL('y'), EC_SEARCH_OBJ},
4017         {MN_SEARCH_DESTROYED, 1, -1, EC_SEARCH_DESTROYED},
4018
4019         {MN_MOVE, 0, -1, -1},
4020         {MN_LEFT, 1, KTRL('b'), EC_LEFT},
4021         {MN_DOWN, 1, KTRL('n'), EC_DOWN},
4022         {MN_UP, 1, KTRL('p'), EC_UP},
4023         {MN_RIGHT, 1, KTRL('f'), EC_RIGHT},
4024         {MN_BOL, 1, KTRL('a'), EC_BOL},
4025         {MN_EOL, 1, KTRL('e'), EC_EOL},
4026         {MN_PGUP, 1, KTRL('o'), EC_PGUP},
4027         {MN_PGDOWN, 1, KTRL('l'), EC_PGDOWN},
4028         {MN_TOP, 1, KTRL('t'), EC_TOP},
4029         {MN_BOTTOM, 1, KTRL('u'), EC_BOTTOM},
4030
4031         {MN_INSERT, 0, -1, -1},
4032         {MN_INSERT_OBJECT, 1, KTRL('i'), EC_INSERT_OBJECT},
4033         {MN_INSERT_DESTROYED, 1, -1, EC_INSERT_DESTROYED},
4034         {MN_INSERT_BLOCK, 1, -1, EC_INSERT_BLOCK},
4035         {MN_INSERT_MACRO, 1, -1, EC_INSERT_MACRO},
4036         {MN_INSERT_KEYMAP, 1, -1, EC_INSERT_KEYMAP},
4037
4038         {MN_ADJECTIVE_GEN, 0, -1, -1},
4039         {KEY_UNAWARE, 1, -1, EC_IK_UNAWARE},
4040         {KEY_UNIDENTIFIED, 1, -1, EC_IK_UNIDENTIFIED},
4041         {KEY_IDENTIFIED, 1, -1, EC_IK_IDENTIFIED},
4042         {KEY_STAR_IDENTIFIED, 1, -1, EC_IK_STAR_IDENTIFIED},
4043         {KEY_COLLECTING, 1, -1, EC_OK_COLLECTING},
4044         {KEY_ARTIFACT, 1, -1, EC_OK_ARTIFACT},
4045         {KEY_EGO, 1, -1, EC_OK_EGO},
4046         {KEY_GOOD, 1, -1, EC_OK_GOOD},
4047         {KEY_NAMELESS, 1, -1, EC_OK_NAMELESS},
4048         {KEY_AVERAGE, 1, -1, EC_OK_AVERAGE},
4049         {KEY_WORTHLESS, 1, -1, EC_OK_WORTHLESS},
4050         {MN_RARE, 1, -1, EC_OK_RARE},
4051         {MN_COMMON, 1, -1, EC_OK_COMMON},
4052
4053         {MN_ADJECTIVE_SPECIAL, 0, -1, -1},
4054         {MN_BOOSTED, 1, -1, EC_OK_BOOSTED},
4055         {MN_MORE_DICE, 1, -1, EC_OK_MORE_DICE},
4056         {MN_MORE_BONUS, 1, -1, EC_OK_MORE_BONUS},
4057         {MN_WANTED, 1, -1, EC_OK_WANTED},
4058         {MN_UNIQUE, 1, -1, EC_OK_UNIQUE},
4059         {MN_HUMAN, 1, -1, EC_OK_HUMAN},
4060         {MN_UNREADABLE, 1, -1, EC_OK_UNREADABLE},
4061         {MN_REALM1, 1, -1, EC_OK_REALM1},
4062         {MN_REALM2, 1, -1, EC_OK_REALM2},
4063         {MN_FIRST, 1, -1, EC_OK_FIRST},
4064         {MN_SECOND, 1, -1, EC_OK_SECOND},
4065         {MN_THIRD, 1, -1, EC_OK_THIRD},
4066         {MN_FOURTH, 1, -1, EC_OK_FOURTH},
4067
4068         {MN_NOUN, 0, -1, -1},
4069         {KEY_WEAPONS, 1, -1, EC_KK_WEAPONS},
4070         {KEY_FAVORITE_WEAPONS, 1, -1, EC_KK_FAVORITE_WEAPONS},
4071         {KEY_ARMORS, 1, -1, EC_KK_ARMORS},
4072         {KEY_MISSILES, 1, -1, EC_KK_MISSILES},
4073         {KEY_DEVICES, 1, -1, EC_KK_DEVICES},
4074         {KEY_LIGHTS, 1, -1, EC_KK_LIGHTS},
4075         {KEY_JUNKS, 1, -1, EC_KK_JUNKS},
4076         {KEY_CORPSES, 1, -1, EC_KK_CORPSES},
4077         {KEY_SPELLBOOKS, 1, -1, EC_KK_SPELLBOOKS},
4078         {KEY_SHIELDS, 1, -1, EC_KK_SHIELDS},
4079         {KEY_BOWS, 1, -1, EC_KK_BOWS},
4080         {KEY_RINGS, 1, -1, EC_KK_RINGS},
4081         {KEY_AMULETS, 1, -1, EC_KK_AMULETS},
4082         {KEY_SUITS, 1, -1, EC_KK_SUITS},
4083         {KEY_CLOAKS, 1, -1, EC_KK_CLOAKS},
4084         {KEY_HELMS, 1, -1, EC_KK_HELMS},
4085         {KEY_GLOVES, 1, -1, EC_KK_GLOVES},
4086         {KEY_BOOTS, 1, -1, EC_KK_BOOTS},
4087
4088         {MN_COMMAND_LETTER, 0, -1, -1},
4089         {MN_CL_AUTOPICK, 1, -1, EC_CL_AUTOPICK},
4090         {MN_CL_DESTROY, 1, -1, EC_CL_DESTROY},
4091         {MN_CL_LEAVE, 1, -1, EC_CL_LEAVE},
4092         {MN_CL_QUERY, 1, -1, EC_CL_QUERY},
4093         {MN_CL_NO_DISP, 1, -1, EC_CL_NO_DISP},
4094
4095         {MN_DELETE_CHAR, -1, 0x7F, EC_DELETE_CHAR},
4096
4097         {NULL, -1, -1, 0}
4098 };
4099
4100
4101 /*
4102  * Find a command by 'key'.
4103  */
4104 static int get_com_id(char key)
4105 {
4106         int i;
4107
4108         for (i = 0; menu_data[i].name; i++)
4109         {
4110                 if (menu_data[i].key == key)
4111                 {
4112                         return menu_data[i].com_id;
4113                 }
4114         }
4115
4116         return 0;
4117 }
4118
4119
4120 /*
4121  * Display the menu, and get a command 
4122  */
4123 static int do_command_menu(int level, int start)
4124 {
4125         int i;
4126         int max_len = 0;
4127         int max_menu_wid;
4128         int col0 = 5 + level*7;
4129         int row0 = 1 + level*3;
4130         byte menu_key = 0;
4131         int menu_id_list[26];
4132         bool redraw = TRUE;
4133         char linestr[MAX_LINELEN];
4134
4135         /* Get max length */
4136         menu_key = 0;
4137         for (i = start; menu_data[i].level >= level; i++)
4138         {
4139                 int len;
4140
4141                 /* Ignore lower level sub menus */
4142                 if (menu_data[i].level > level) continue;
4143
4144                 len = strlen(menu_data[i].name);
4145                 if (len > max_len) max_len = len;
4146
4147                 menu_id_list[menu_key] = i;
4148                 menu_key++;
4149         }
4150
4151         while (menu_key < 26)
4152         {
4153                 menu_id_list[menu_key] = -1;
4154                 menu_key++;
4155         }
4156
4157         /* Extra space for displaying menu key and command key */
4158         max_menu_wid = max_len + 3 + 3;
4159
4160         /* Prepare box line */
4161         linestr[0] = '\0';
4162         strcat(linestr, "+");
4163         for (i = 0; i < max_menu_wid + 2; i++)
4164         {
4165                 strcat(linestr, "-");
4166         }
4167         strcat(linestr, "+");
4168
4169         while (TRUE)
4170         {
4171                 int com_id;
4172                 char key;
4173                 int menu_id;
4174
4175                 if (redraw)
4176                 {
4177                         int row1 = row0 + 1;
4178
4179                         /* Draw top line */
4180                         Term_putstr(col0, row0, -1, TERM_WHITE, linestr);
4181
4182                         /* Draw menu items */
4183                         menu_key = 0;
4184                         for (i = start; menu_data[i].level >= level; i++)
4185                         {
4186                                 char com_key_str[3];
4187                                 cptr str;
4188
4189                                 /* Ignore lower level sub menus */
4190                                 if (menu_data[i].level > level) continue;
4191
4192                                 if (menu_data[i].com_id == -1)
4193                                 {
4194                                         strcpy(com_key_str, _("▼", ">"));
4195                                 }
4196                                 else if (menu_data[i].key != -1)
4197                                 {
4198                                         com_key_str[0] = '^';
4199                                         com_key_str[1] = menu_data[i].key + '@';
4200                                         com_key_str[2] = '\0';
4201                                 }
4202                                 else
4203                                 {
4204                                         com_key_str[0] = '\0';
4205                                 }
4206
4207                                 str = format("| %c) %-*s %2s | ", menu_key + 'a', max_len, menu_data[i].name, com_key_str);
4208
4209                                 Term_putstr(col0, row1++, -1, TERM_WHITE, str);
4210
4211                                 menu_key++;
4212                         }
4213
4214                         /* Draw bottom line */
4215                         Term_putstr(col0, row1, -1, TERM_WHITE, linestr);
4216
4217                         /* The menu was shown */
4218                         redraw = FALSE;
4219                 }
4220                 prt(format(_("(a-%c) コマンド:", "(a-%c) Command:"), menu_key + 'a' - 1), 0, 0);
4221                 key = inkey();
4222
4223                 if (key == ESCAPE) return 0;
4224
4225                 if ('a' <= key && key <= 'z')
4226                 {
4227                         menu_id = menu_id_list[key - 'a'];
4228
4229                         if (menu_id >= 0)
4230                         {
4231                                 com_id = menu_data[menu_id].com_id;
4232
4233                                 if (com_id == -1)
4234                                 {
4235                                         com_id = do_command_menu(level + 1, menu_id + 1);
4236
4237                                         if (com_id) return com_id;
4238                                         else redraw = TRUE;
4239                                 }
4240                                 else if (com_id)
4241                                 {
4242                                         return com_id;
4243                                 }
4244                         }
4245                 }
4246
4247                 else
4248                 {
4249                         com_id = get_com_id(key);
4250                         if (com_id) return com_id;
4251                         else continue;
4252                 }
4253         }
4254 }
4255
4256
4257 static chain_str_type *new_chain_str(cptr str)
4258 {
4259         chain_str_type *chain;
4260
4261         size_t len = strlen(str);
4262
4263         chain = (chain_str_type *)ralloc(sizeof(chain_str_type) + len * sizeof(char));
4264
4265         strcpy(chain->s, str);
4266         chain->next = NULL;
4267
4268         return chain;
4269 }
4270
4271
4272 static void kill_yank_chain(text_body_type *tb)
4273 {
4274         chain_str_type *chain = tb->yank;
4275         tb->yank = NULL;
4276         tb->yank_eol = TRUE;
4277
4278         while (chain)
4279         {
4280                 chain_str_type *next = chain->next;
4281                 size_t len = strlen(chain->s);
4282
4283                 rnfree(chain, sizeof(chain_str_type) + len * sizeof(char));
4284
4285                 chain = next;
4286         }
4287 }
4288
4289
4290 static void add_str_to_yank(text_body_type *tb, cptr str)
4291 {
4292         chain_str_type *chain;
4293
4294         tb->yank_eol = FALSE;
4295
4296         if (NULL == tb->yank)
4297         {
4298                 tb->yank = new_chain_str(str);
4299                 return;
4300         }
4301
4302         chain = tb->yank;
4303
4304         while (TRUE)
4305         {
4306                 if (!chain->next)
4307                 {
4308                         chain->next = new_chain_str(str);
4309                         return;
4310                 }
4311
4312                 /* Go to next */
4313                 chain = chain->next;
4314         }
4315 }
4316
4317
4318 /*
4319  * Do work for the copy editor-command
4320  */
4321 static void copy_text_to_yank(text_body_type *tb)
4322 {
4323         int len = strlen(tb->lines_list[tb->cy]);
4324
4325         /* Correct cursor location */
4326         if (tb->cx > len) tb->cx = len;
4327
4328         /* Use single line? */
4329         if (!tb->mark)
4330         {
4331                 /* Select a single line */
4332                 tb->cx = 0;
4333                 tb->my = tb->cy;
4334                 tb->mx = len;
4335         }
4336
4337         /* Kill old yank buffer */
4338         kill_yank_chain(tb);
4339
4340
4341         /* Single line case */
4342         if (tb->my == tb->cy)
4343         {
4344                 int i;
4345                 char buf[MAX_LINELEN];
4346                 int bx1 = MIN(tb->mx, tb->cx);
4347                 int bx2 = MAX(tb->mx, tb->cx);
4348
4349                 /* Correct fake cursor position */
4350                 if (bx2 > len) bx2 = len;
4351
4352                 /* Whole part of this line is selected */
4353                 if (bx1 == 0 && bx2 == len)
4354                 {
4355                         /* Copy this line */
4356                         add_str_to_yank(tb, tb->lines_list[tb->cy]);
4357
4358                         /* Add end of line to the buffer */
4359                         add_str_to_yank(tb, "");
4360                 }
4361
4362                 /* Segment of this line is selected */
4363                 else
4364                 {
4365                         for (i = 0; i < bx2 - bx1; i++)
4366                         {
4367                                 buf[i] = tb->lines_list[tb->cy][bx1 + i];
4368                         }
4369                         buf[i] = '\0';
4370
4371                         /* Copy this segment of line */
4372                         add_str_to_yank(tb, buf);
4373                 }
4374         }
4375
4376         /* Multiple lines case */
4377         else /* if (tb->my != tb->cy) */
4378         {
4379                 int y;
4380
4381                 int by1 = MIN(tb->my, tb->cy);
4382                 int by2 = MAX(tb->my, tb->cy);
4383
4384                 /* Copy lines */
4385                 for (y = by1; y <= by2; y++)
4386                 {
4387                         /* Copy this line */
4388                         add_str_to_yank(tb, tb->lines_list[y]);
4389                 }
4390
4391                 /* Add final end of line to the buffer */
4392                 add_str_to_yank(tb, "");
4393         }
4394
4395         /* Disable selection */
4396         tb->mark = 0;
4397
4398         /* Now dirty */
4399         tb->dirty_flags |= DIRTY_ALL;
4400 }
4401
4402
4403 #define DESCRIPT_HGT 3
4404
4405 /*
4406  * Draw text
4407  */
4408 static void draw_text_editor(text_body_type *tb)
4409 {
4410         int i;
4411         int by1 = 0, by2 = 0;
4412
4413         Term_get_size(&tb->wid, &tb->hgt);
4414
4415         /*
4416          * Top line (-1), description line (-3), separator (-1)
4417          *  == -5
4418          */
4419         tb->hgt -= 2 + DESCRIPT_HGT;
4420
4421 #ifdef JP
4422         /* Don't let cursor at second byte of kanji */
4423         for (i = 0; tb->lines_list[tb->cy][i]; i++)
4424                 if (iskanji(tb->lines_list[tb->cy][i]))
4425                 {
4426                         i++;
4427                         if (i == tb->cx)
4428                         {
4429                                 /*
4430                                  * Move to a correct position in the
4431                                  * left or right
4432                                  */
4433                                 if (i & 1) tb->cx--;
4434                                 else tb->cx++;
4435                                 break;
4436                         }
4437                 }
4438 #endif
4439
4440         /* Scroll if necessary */
4441         if (tb->cy < tb->upper || tb->upper + tb->hgt <= tb->cy)
4442                 tb->upper = tb->cy - (tb->hgt)/2;
4443         if (tb->upper < 0)
4444                 tb->upper = 0;
4445         if ((tb->cx < tb->left + 10 && tb->left > 0) || tb->left + tb->wid - 5 <= tb->cx)
4446                 tb->left = tb->cx - (tb->wid)*2/3;
4447         if (tb->left < 0)
4448                 tb->left = 0;
4449
4450         /* Redraw whole window after resize */
4451         if (tb->old_wid != tb->wid || tb->old_hgt != tb->hgt)
4452                 tb->dirty_flags |= DIRTY_SCREEN;
4453
4454         /* Redraw all text after scroll */
4455         else if (tb->old_upper != tb->upper || tb->old_left != tb->left)
4456                 tb->dirty_flags |= DIRTY_ALL;
4457
4458
4459         if (tb->dirty_flags & DIRTY_SCREEN)
4460         {
4461                 tb->dirty_flags |= (DIRTY_ALL | DIRTY_MODE);
4462                 Term_clear();
4463         }
4464
4465         /* Redraw mode line */
4466         if (tb->dirty_flags & DIRTY_MODE)
4467         {
4468                 char buf[MAX_LINELEN];
4469
4470                 int sepa_length = tb->wid;
4471
4472                 /* Separator */
4473                 for (i = 0; i < sepa_length; i++)
4474                         buf[i] = '-';
4475                 buf[i] = '\0';
4476
4477                 Term_putstr(0, tb->hgt + 1, sepa_length, TERM_WHITE, buf);
4478         }
4479
4480         if (tb->dirty_flags & DIRTY_EXPRESSION)
4481         {
4482                 int y;
4483                 byte state = 0;
4484
4485                 for (y = 0; tb->lines_list[y]; y++)
4486                 {
4487                         char f;
4488                         cptr v;
4489                         cptr s = tb->lines_list[y];
4490                         char *ss, *s_keep;
4491                         int s_len;
4492
4493                         /* Update this line's state */
4494                         tb->states[y] = state;
4495
4496                         if (*s++ != '?') continue;
4497                         if (*s++ != ':') continue;
4498
4499                         /* Lines below this line are auto-registered */
4500                         if (streq(s, "$AUTOREGISTER"))
4501                                 state |= LSTAT_AUTOREGISTER;
4502
4503                         s_len = strlen(s);
4504                         ss = (char *)string_make(s);
4505                         s_keep = ss;
4506
4507                         /* Parse the expr */
4508                         v = process_pref_file_expr(&ss, &f);
4509
4510                         /* Set flag */
4511                         if (streq(v, "0")) state |= LSTAT_BYPASS;
4512                         else state &= ~LSTAT_BYPASS;
4513
4514                         /* Cannot use string_free() because the string was "destroyed" */
4515                         C_KILL(s_keep, s_len + 1, char);
4516
4517                         /* Re-update this line's state */
4518                         tb->states[y] = state | LSTAT_EXPRESSION;
4519                 }
4520
4521                 tb->dirty_flags |= DIRTY_ALL;
4522         }
4523
4524         if (tb->mark)
4525         {
4526                 tb->dirty_flags |= DIRTY_ALL;
4527
4528                 by1 = MIN(tb->my, tb->cy);
4529                 by2 = MAX(tb->my, tb->cy);
4530         }
4531
4532         /* Dump up to tb->hgt lines of messages */
4533         for (i = 0; i < tb->hgt; i++)
4534         {
4535                 int j;
4536                 int leftcol = 0;
4537                 cptr msg;
4538                 byte color;
4539                 int y = tb->upper+i;
4540
4541                 /* clean or dirty? */
4542                 if (!(tb->dirty_flags & DIRTY_ALL) && (tb->dirty_line != y))
4543                         continue;
4544
4545                 msg = tb->lines_list[y];
4546                 if (!msg) break;
4547
4548                 /* Apply horizontal scroll */
4549                 for (j = 0; *msg; msg++, j++)
4550                 {
4551                         if (j == tb->left) break;
4552 #ifdef JP
4553                         if (j > tb->left)
4554                         {
4555                                 leftcol = 1;
4556                                 break;
4557                         }
4558                         if (iskanji(*msg))
4559                         {
4560                                 msg++;
4561                                 j++;
4562                         }
4563 #endif
4564                 }
4565
4566                 /* Erase line */
4567                 Term_erase(0, i + 1, tb->wid);
4568
4569                 if (tb->states[y] & LSTAT_AUTOREGISTER)
4570                 {
4571                         /* Warning color -- These lines will be deleted later */
4572                         color = TERM_L_RED;
4573                 }
4574                 else
4575                 {
4576                         /* Bypassed line will be displayed by darker color */
4577                         if (tb->states[y] & LSTAT_BYPASS) color = TERM_SLATE;
4578                         else color = TERM_WHITE;
4579                 }
4580
4581                 /* No mark or Out of mark */
4582                 if (!tb->mark || (y < by1 || by2 < y))
4583                 {
4584                         /* Dump the messages, bottom to top */
4585                         Term_putstr(leftcol, i + 1, tb->wid - 1, color, msg);
4586                 }
4587
4588                 /* Multiple lines selected */
4589                 else if (by1 != by2)
4590                 {
4591                         /* Dump the messages, bottom to top */
4592                         Term_putstr(leftcol, i + 1, tb->wid - 1, TERM_YELLOW, msg);
4593                 }
4594
4595                 /* Single line selected */
4596                 else
4597                 {
4598                         int x0 = leftcol + tb->left;
4599                         int len = strlen(tb->lines_list[tb->cy]);
4600                         int bx1 = MIN(tb->mx, tb->cx);
4601                         int bx2 = MAX(tb->mx, tb->cx);
4602
4603                         /* Correct cursor location */
4604                         if (bx2 > len) bx2 = len;
4605
4606                         Term_gotoxy(leftcol, i + 1);
4607                         if (x0 < bx1) Term_addstr(bx1 - x0, color, msg);
4608                         if (x0 < bx2) Term_addstr(bx2 - bx1, TERM_YELLOW, msg + (bx1 - x0));
4609                         Term_addstr(-1, color, msg + (bx2 - x0));
4610                 }
4611         }
4612
4613         for (; i < tb->hgt; i++)
4614         {
4615                 /* Erase line */
4616                 Term_erase(0, i + 1, tb->wid);
4617         }
4618
4619         /* Display information when updated */
4620         if (tb->old_cy != tb->cy || (tb->dirty_flags & (DIRTY_ALL | DIRTY_NOT_FOUND | DIRTY_NO_SEARCH)) || tb->dirty_line == tb->cy)
4621         {
4622                 autopick_type an_entry, *entry = &an_entry;
4623                 cptr str1 = NULL, str2 = NULL;
4624
4625
4626                 /* Clear information line */
4627                 for (i = 0; i < DESCRIPT_HGT; i++)
4628                 {
4629                         /* Erase line */
4630                         Term_erase(0, tb->hgt + 2 + i, tb->wid);
4631                 }
4632
4633                 /* Display information */
4634                 if (tb->dirty_flags & DIRTY_NOT_FOUND)
4635                 {
4636                         str1 = format(_("パターンが見つかりません: %s", "Pattern not found: %s"), tb->search_str);
4637                 }
4638                 else if (tb->dirty_flags & DIRTY_SKIP_INACTIVE)
4639                 {
4640                         str1 = format(_("無効状態の行をスキップしました。(%sを検索中)", 
4641                                                         "Some inactive lines are skipped. (Searching %s)"), tb->search_str);
4642                 }
4643                 else if (tb->dirty_flags & DIRTY_INACTIVE)
4644                 {
4645                         str1 = format(_("無効状態の行だけが見付かりました。(%sを検索中)",
4646                                                         "Found only an inactive line. (Searching %s)"), tb->search_str);
4647                 }
4648                 else if (tb->dirty_flags & DIRTY_NO_SEARCH)
4649                 {
4650                         str1 = _("検索するパターンがありません(^S で検索)。", "No pattern to search. (Press ^S to search.)");
4651                 }
4652                 else if (tb->lines_list[tb->cy][0] == '#')
4653                 {
4654                         str1 = _("この行はコメントです。", "This line is a comment.");
4655                 }
4656                 else if (tb->lines_list[tb->cy][0] && tb->lines_list[tb->cy][1] == ':')
4657                 {
4658                         switch(tb->lines_list[tb->cy][0])
4659                         {
4660                         case '?':
4661                                 str1 = _("この行は条件分岐式です。", "This line is a Conditional Expression.");
4662                                 break;
4663                         case 'A':
4664                                 str1 = _("この行はマクロの実行内容を定義します。", "This line defines a Macro action.");
4665                                 break;
4666                         case 'P':
4667                                 str1 = _("この行はマクロのトリガー・キーを定義します。", "This line defines a Macro trigger key.");
4668                                 break;
4669                         case 'C':
4670                                 str1 = _("この行はキー配置を定義します。", "This line defines a Keymap.");
4671                                 break;
4672                         }
4673
4674                         switch(tb->lines_list[tb->cy][0])
4675                         {
4676                         case '?':
4677                                 if (tb->states[tb->cy] & LSTAT_BYPASS)
4678                                 {
4679                                         str2 = _("現在の式の値は「偽(=0)」です。", "The expression is 'False'(=0) currently.");
4680                                 }
4681                                 else
4682                                 {
4683                                         str2 = _("現在の式の値は「真(=1)」です。", "The expression is 'True'(=1) currently.");
4684                                 }
4685                                 break;
4686
4687                         default:
4688                                 if (tb->states[tb->cy] & LSTAT_AUTOREGISTER)
4689                                 {
4690                                         str2 = _("この行は後で削除されます。", "This line will be delete later.");
4691                                 }
4692
4693                                 else if (tb->states[tb->cy] & LSTAT_BYPASS)
4694                                 {
4695                                         str2 = _("この行は現在は無効な状態です。", "This line is bypassed currently.");
4696                                 }
4697                                 break;
4698                         }
4699                 }
4700
4701                 /* Get description of an autopicker preference line */
4702                 else if (autopick_new_entry(entry, tb->lines_list[tb->cy], FALSE))
4703                 {
4704                         char buf[MAX_LINELEN];
4705                         char temp[MAX_LINELEN];
4706                         cptr t;
4707
4708                         describe_autopick(buf, entry);
4709
4710                         if (tb->states[tb->cy] & LSTAT_AUTOREGISTER)
4711                         {
4712                                 strcat(buf, _("この行は後で削除されます。", "  This line will be delete later."));
4713                         }
4714
4715                         if (tb->states[tb->cy] & LSTAT_BYPASS)
4716                         {
4717                                 strcat(buf, _("この行は現在は無効な状態です。", "  This line is bypassed currently."));
4718                         }
4719
4720                         roff_to_buf(buf, 81, temp, sizeof(temp));
4721                         t = temp;
4722                         for (i = 0; i < 3; i++)
4723                         {
4724                                 if(t[0] == 0)
4725                                         break; 
4726                                 else
4727                                 {
4728                                         prt(t, tb->hgt +1 + 1 + i, 0);
4729                                         t += strlen(t) + 1;
4730                                 }
4731                         }
4732                         autopick_free_entry(entry);
4733                 }
4734
4735                 /* Draw the first line */
4736                 if (str1) prt(str1, tb->hgt +1 + 1, 0);
4737
4738                 /* Draw the second line */
4739                 if (str2) prt(str2, tb->hgt +1 + 2, 0);
4740         }
4741 }
4742
4743
4744 /*
4745  * Kill segment of a line
4746  */
4747 static void kill_line_segment(text_body_type *tb, int y, int x0, int x1, bool whole)
4748 {
4749         char buf[MAX_LINELEN];
4750         cptr s = tb->lines_list[y];
4751         char *d = buf;
4752         int x;
4753
4754         /* Kill whole line? */
4755         if (whole && x0 == 0 && s[x1] == '\0' && tb->lines_list[y+1])
4756         {
4757                 int i;
4758
4759                 string_free(tb->lines_list[y]);
4760
4761                 /* Shift lines up */
4762                 for (i = y; tb->lines_list[i+1]; i++)
4763                         tb->lines_list[i] = tb->lines_list[i+1];
4764                 tb->lines_list[i] = NULL;
4765
4766                 /* Expressions need re-evaluation */
4767                 tb->dirty_flags |= DIRTY_EXPRESSION;
4768
4769                 return;
4770         }
4771
4772         /* No segment? */
4773         if (x0 == x1) return;
4774
4775         /* Before the segment */
4776         for (x = 0; x < x0; x++)
4777                 *(d++) = s[x];
4778
4779         /* After the segment */
4780         for (x = x1; s[x]; x++)
4781                 *(d++) = s[x];
4782
4783         *d = '\0';
4784
4785         /* Replace */
4786         string_free(tb->lines_list[y]);
4787         tb->lines_list[y] = string_make(buf);
4788
4789         /* Expressions may need re-evaluation */
4790         check_expression_line(tb, y);
4791
4792         /* Text is changed */
4793         tb->changed = TRUE;
4794 }
4795
4796
4797 /*
4798  * Get a trigger key and insert ASCII string for the trigger
4799  */
4800 static bool insert_macro_line(text_body_type *tb)
4801 {
4802         char tmp[1024];
4803         char buf[1024];
4804         int i, n = 0;
4805
4806         /* Flush */
4807         flush();
4808
4809         /* Do not process macros */
4810         inkey_base = TRUE;
4811
4812         /* First key */
4813         i = inkey();
4814
4815         /* Read the pattern */
4816         while (i)
4817         {
4818                 /* Save the key */
4819                 buf[n++] = (char)i;
4820
4821                 /* Do not process macros */
4822                 inkey_base = TRUE;
4823
4824                 /* Do not wait for keys */
4825                 inkey_scan = TRUE;
4826
4827                 /* Attempt to read a key */
4828                 i = inkey();
4829         }
4830
4831         /* Terminate */
4832         buf[n] = '\0';
4833
4834         flush();
4835
4836         /* Convert the trigger */
4837         ascii_to_text(tmp, buf);
4838
4839         /* Null */
4840         if(!tmp[0]) return FALSE;
4841
4842         tb->cx = 0;
4843
4844         /* Insert preference string */
4845         insert_return_code(tb);
4846         string_free(tb->lines_list[tb->cy]);
4847         tb->lines_list[tb->cy] = string_make(format("P:%s", tmp));
4848
4849         /* Acquire action */
4850         i = macro_find_exact(buf);
4851
4852         if (i == -1)
4853         {
4854                 /* Nothing defined */
4855                 tmp[0] = '\0';
4856         }
4857         else
4858         {
4859                 /* Analyze the current action */
4860                 ascii_to_text(tmp, macro__act[i]);
4861         }
4862
4863         /* Insert blank action preference line */
4864         insert_return_code(tb);
4865         string_free(tb->lines_list[tb->cy]);
4866         tb->lines_list[tb->cy] = string_make(format("A:%s", tmp));
4867
4868         return TRUE;
4869 }
4870
4871
4872 /*
4873  * Get a command key and insert ASCII string for the key
4874  */
4875 static bool insert_keymap_line(text_body_type *tb)
4876 {
4877         char tmp[1024];
4878         char buf[2];
4879         BIT_FLAGS mode;
4880         cptr act;
4881
4882         /* Roguelike */
4883         if (rogue_like_commands)
4884         {
4885                 mode = KEYMAP_MODE_ROGUE;
4886         }
4887
4888         /* Original */
4889         else
4890         {
4891                 mode = KEYMAP_MODE_ORIG;
4892         }
4893
4894         flush();
4895
4896         /* Get a key */
4897         buf[0] = inkey();
4898         buf[1] = '\0';
4899
4900         flush();
4901
4902         /* Convert the trigger */
4903         ascii_to_text(tmp, buf);
4904
4905         /* Null */
4906         if(!tmp[0]) return FALSE;
4907
4908         tb->cx = 0;
4909
4910         /* Insert preference string */
4911         insert_return_code(tb);
4912         string_free(tb->lines_list[tb->cy]);
4913         tb->lines_list[tb->cy] = string_make(format("C:%d:%s", mode, tmp));
4914
4915         /* Look up the keymap */
4916         act = keymap_act[mode][(byte)(buf[0])];
4917
4918         if (act)
4919         {
4920                 /* Analyze the current action */
4921                 ascii_to_text(tmp, act);
4922         }
4923         else
4924         {
4925                 /* No keymap defined -- Use trigger key itself as a default */
4926
4927                 /* Nothing to do (use tmp) */
4928         }
4929
4930         /* Insert blank action preference line */
4931         insert_return_code(tb);
4932         string_free(tb->lines_list[tb->cy]);
4933         tb->lines_list[tb->cy] = string_make(format("A:%s", tmp));
4934
4935         return TRUE;
4936 }
4937
4938
4939 /*
4940  * Execute a single editor command
4941  */
4942 static bool do_editor_command(text_body_type *tb, int com_id)
4943 {
4944         switch(com_id)
4945         {
4946         case EC_QUIT:
4947                 if (tb->changed)
4948                 {
4949                         if (!get_check(_("全ての変更を破棄してから終了します。よろしいですか? ",
4950                                                          "Discard all changes and quit. Are you sure? "))) break;
4951                 }
4952                 return QUIT_WITHOUT_SAVE;
4953
4954         case EC_SAVEQUIT:
4955                 return QUIT_AND_SAVE;
4956
4957         case EC_REVERT:
4958                 /* Revert to original */
4959                 if (!get_check(_("全ての変更を破棄して元の状態に戻します。よろしいですか? ",
4960                                                  "Discard all changes and revert to original file. Are you sure? "))) break;
4961
4962                 free_text_lines(tb->lines_list);
4963                 tb->lines_list = read_pickpref_text_lines(&tb->filename_mode);
4964                 tb->dirty_flags |= DIRTY_ALL | DIRTY_MODE | DIRTY_EXPRESSION;
4965                 tb->cx = tb->cy = 0;
4966                 tb->mark = 0;
4967
4968                 /* Text is not changed */
4969                 tb->changed = FALSE;
4970                 break;
4971
4972         case EC_HELP:
4973                 /* Peruse the main help file */
4974                 (void)show_file(TRUE, _("jeditor.txt", "editor.txt"), NULL, 0, 0);
4975                 /* Redraw all */
4976                 tb->dirty_flags |= DIRTY_SCREEN;
4977
4978                 break;
4979
4980         case EC_RETURN:
4981                 /* Split a line or insert end of line */
4982
4983                 /* Ignore selection */
4984                 if (tb->mark)
4985                 {
4986                         tb->mark = 0;
4987
4988                         /* Now dirty */
4989                         tb->dirty_flags |= DIRTY_ALL;
4990                 }
4991
4992                 insert_return_code(tb);
4993                 tb->cy++;
4994                 tb->cx = 0;
4995
4996                 /* Now dirty */
4997                 tb->dirty_flags |= DIRTY_ALL;
4998                 break;
4999
5000         case EC_LEFT:
5001                 /* Back */
5002                 if (0 < tb->cx)
5003                 {
5004                         int len;
5005 #ifdef JP
5006                         int i;
5007 #endif
5008
5009                         tb->cx--;
5010                         len = strlen(tb->lines_list[tb->cy]);
5011                         if (len < tb->cx) tb->cx = len;
5012
5013 #ifdef JP
5014                         /* Don't let cursor at second byte of kanji */
5015                         for (i = 0; tb->lines_list[tb->cy][i]; i++)
5016                         {
5017                                 if (iskanji(tb->lines_list[tb->cy][i]))
5018                                 {
5019                                         i++;
5020                                         if (i == tb->cx)
5021                                         {
5022                                                 /* Move to the left */
5023                                                 tb->cx--;
5024                                                 break;
5025                                         }
5026                                 }
5027                         }
5028 #endif
5029                 }
5030                 else if (tb->cy > 0)
5031                 {
5032                         tb->cy--;
5033                         tb->cx = strlen(tb->lines_list[tb->cy]);
5034                 }
5035                 break;
5036
5037         case EC_DOWN:
5038                 /* Next line */
5039
5040                 /* Is this the last line? */
5041                 if (!tb->lines_list[tb->cy + 1])
5042                 {
5043                         /* Add one more empty line if possible */
5044                         if (!add_empty_line(tb)) break;
5045                 }
5046
5047                 /* Go down */
5048                 tb->cy++;
5049
5050                 break;
5051
5052         case EC_UP:
5053                 /* Previous line */
5054                 if (tb->cy > 0) tb->cy--;
5055                 break;
5056
5057         case EC_RIGHT:
5058         {
5059                 /* Forward */
5060
5061                 int len;
5062 #ifdef JP
5063                 if (iskanji(tb->lines_list[tb->cy][tb->cx])) tb->cx++;
5064 #endif
5065                 tb->cx++;
5066                 len = strlen(tb->lines_list[tb->cy]);
5067                 if (len < tb->cx)
5068                 {
5069                         /* Correct the cursor position */
5070                         tb->cx = len;
5071
5072                         /* Is this the last line? */
5073                         if (!tb->lines_list[tb->cy + 1])
5074                         {
5075                                 /* Add one more empty line if possible */
5076                                 if (!add_empty_line(tb)) break;
5077                         }
5078
5079                         /* Move to the beginning of next line */
5080                         tb->cy++;
5081                         tb->cx = 0;
5082                 }
5083                 break;
5084         }
5085
5086         case EC_BOL:
5087                 /* Beginning of line */
5088                 tb->cx = 0;
5089                 break;
5090
5091         case EC_EOL:
5092                 /* End of line */
5093                 tb->cx = strlen(tb->lines_list[tb->cy]);
5094                 break;
5095
5096         case EC_PGUP:
5097                 while (0 < tb->cy && tb->upper <= tb->cy)
5098                         tb->cy--;
5099                 while (0 < tb->upper && tb->cy + 1 < tb->upper + tb->hgt)
5100                         tb->upper--;
5101                 break;
5102
5103         case EC_PGDOWN:
5104                 /* Page down */
5105                 while (tb->cy < tb->upper + tb->hgt)
5106                 {
5107                         /* Is this the last line? */
5108                         if (!tb->lines_list[tb->cy + 1])
5109                         {
5110                                 /* Add one more empty line if possible */
5111                                 if (!add_empty_line(tb)) break;
5112                         }
5113
5114                         tb->cy++;
5115                 }
5116
5117                 tb->upper = tb->cy;
5118                 break;
5119
5120         case EC_TOP:
5121                 tb->cy = 0;
5122                 break;
5123
5124         case EC_BOTTOM:
5125                 while (TRUE)
5126                 {
5127                         /* Is this the last line? */
5128                         if (!tb->lines_list[tb->cy + 1])
5129                         {
5130                                 /* Add one more empty line if possible */
5131                                 if (!add_empty_line(tb)) break;
5132                         }
5133
5134                         tb->cy++;
5135                 }
5136
5137                 /* Always at the biginning of the last line */
5138                 tb->cx = 0;
5139
5140                 break;
5141
5142         case EC_CUT:
5143         {       
5144                 /* Copy the text first */
5145                 copy_text_to_yank(tb);
5146
5147                 /* Single line case */
5148                 if (tb->my == tb->cy)
5149                 {
5150                         int bx1 = MIN(tb->mx, tb->cx);
5151                         int bx2 = MAX(tb->mx, tb->cx);
5152                         int len = strlen(tb->lines_list[tb->cy]);
5153
5154                         /* Correct fake cursor position */
5155                         if (bx2 > len) bx2 = len;
5156
5157                         kill_line_segment(tb, tb->cy, bx1, bx2, TRUE);
5158
5159                         /* New cursor position */
5160                         tb->cx = bx1;
5161                 }
5162
5163                 /* Multiple lines case */
5164                 else /* if (tb->my != tb->cy) */
5165                 {
5166                         int y;
5167
5168                         int by1 = MIN(tb->my, tb->cy);
5169                         int by2 = MAX(tb->my, tb->cy);
5170
5171                         /* Kill lines in reverse order */
5172                         for (y = by2; y >= by1; y--)
5173                         {
5174                                 int len = strlen(tb->lines_list[y]);
5175                                 
5176                                 kill_line_segment(tb, y, 0, len, TRUE);
5177                         }
5178
5179                         /* New cursor position */
5180                         tb->cy = by1;
5181                         tb->cx = 0;
5182                 }
5183
5184
5185                 /* Disable selection */
5186                 tb->mark = 0;
5187
5188                 /* Now dirty */
5189                 tb->dirty_flags |= DIRTY_ALL;
5190
5191                 /* Text is changed */
5192                 tb->changed = TRUE;
5193
5194                 break;
5195         }
5196
5197         case EC_COPY:
5198                 copy_text_to_yank(tb);
5199
5200                 /*
5201                  * Move cursor position to the end of the selection
5202                  *
5203                  * Pressing ^C ^V correctly duplicates the selection.
5204                  */
5205                 if (tb->my == tb->cy)
5206                 {
5207                         tb->cx = MAX(tb->cx, tb->mx);
5208
5209                         /*
5210                          * When whole line is selected, the end of
5211                          * line code is also copyed.
5212                          */
5213                         if (!tb->lines_list[tb->cy][tb->cx])
5214                         {
5215                                 /* Is this the last line? */
5216                                 if (!tb->lines_list[tb->cy + 1])
5217                                 {
5218                                         /* Add one more empty line if possible */
5219                                         if (!add_empty_line(tb)) break;
5220                                 }
5221
5222                                 /* Go to the beginning of next line */
5223                                 tb->cy++;
5224                                 tb->cx = 0;
5225                         }
5226                 }
5227                 else
5228                 {
5229                         tb->cy = MAX(tb->cy, tb->my);
5230
5231                         /* Is this the last line? */
5232                         if (!tb->lines_list[tb->cy + 1])
5233                         {
5234                                 /* Add one more empty line if possible */
5235                                 if (!add_empty_line(tb)) break;
5236                         }
5237
5238                         /* Go down */
5239                         tb->cy++;
5240                 }
5241
5242                 break;
5243
5244         case EC_PASTE:
5245         {
5246                 /* Paste killed text */
5247
5248                 chain_str_type *chain = tb->yank;
5249                 int len = strlen(tb->lines_list[tb->cy]);
5250
5251                 /* Nothing to do? */
5252                 if (!chain) break;
5253
5254                 /* Correct cursor location */
5255                 if (tb->cx > len) tb->cx = len;
5256
5257                 /* Ignore selection */
5258                 if (tb->mark)
5259                 {
5260                         tb->mark = 0;
5261
5262                         /* Now dirty */
5263                         tb->dirty_flags |= DIRTY_ALL;
5264                 }
5265
5266                 /* Paste text */
5267                 while (chain)
5268                 {
5269                         cptr yank_str = chain->s;
5270
5271                         char buf[MAX_LINELEN];
5272                         int i;
5273                         char rest[MAX_LINELEN], *rest_ptr = rest;
5274
5275                         /* Save preceding string */
5276                         for(i = 0; i < tb->cx; i++)
5277                                 buf[i] = tb->lines_list[tb->cy][i];
5278
5279                         strcpy(rest, &(tb->lines_list[tb->cy][i]));
5280
5281                         /* Paste yank buffer */
5282                         while (*yank_str && i < MAX_LINELEN-1)
5283                         {
5284                                 buf[i++] = *yank_str++;
5285                         }
5286
5287                         /* Terminate */
5288                         buf[i] = '\0';
5289
5290                         chain = chain->next;
5291
5292                         if (chain || tb->yank_eol)
5293                         {
5294                                 /* There is an end of line between chain nodes */
5295
5296                                 insert_return_code(tb);
5297
5298                                 /* Replace this line with new one */
5299                                 string_free(tb->lines_list[tb->cy]);
5300                                 tb->lines_list[tb->cy] = string_make(buf);
5301
5302                                 /* Move to next line */
5303                                 tb->cx = 0;
5304                                 tb->cy++;
5305
5306                                 continue;
5307                         }
5308
5309                         /* Final line doesn't have end of line */
5310
5311                         tb->cx = strlen(buf);
5312
5313                         /* Rest of original line */
5314                         while (*rest_ptr && i < MAX_LINELEN-1)
5315                         {
5316                                 buf[i++] = *rest_ptr++;
5317                         }
5318
5319                         /* Terminate */
5320                         buf[i] = '\0';
5321
5322                         /* Replace this line with new one */
5323                         string_free(tb->lines_list[tb->cy]);
5324                         tb->lines_list[tb->cy] = string_make(buf);
5325
5326                         /* Finish */
5327                         break;
5328                 }
5329
5330                 /* Now dirty */
5331                 tb->dirty_flags |= DIRTY_ALL;
5332
5333                 /* Expressions need re-evaluation */
5334                 tb->dirty_flags |= DIRTY_EXPRESSION;
5335
5336                 /* Text is changed */
5337                 tb->changed = TRUE;
5338
5339                 break;
5340         }
5341
5342         case EC_BLOCK:
5343                 if (tb->mark)
5344                 {
5345                         /* Disable the selection */
5346                         tb->mark = 0;
5347
5348                         /* Redraw text */
5349                         tb->dirty_flags |= DIRTY_ALL;
5350                 }
5351                 else
5352                 {
5353                         tb->mark = MARK_MARK;
5354
5355                         /* Repeating this command swaps cursor position */
5356                         if (com_id == tb->old_com_id)
5357                         {
5358                                 int tmp;
5359
5360                                 tmp = tb->cy;
5361                                 tb->cy = tb->my;
5362                                 tb->my = tmp;
5363                                 tmp = tb->cx;
5364                                 tb->cx = tb->mx;
5365                                 tb->mx = tmp;
5366
5367                                 /* Redraw text */
5368                                 tb->dirty_flags |= DIRTY_ALL;
5369                         }
5370                         else
5371                         {
5372                                 int len = strlen(tb->lines_list[tb->cy]);
5373
5374                                 /* Mark the point 1 */
5375                                 tb->my = tb->cy;
5376                                 tb->mx = tb->cx;
5377
5378                                 /* Correct cursor location */
5379                                 if (tb->cx > len) tb->mx = len;
5380                         }
5381                 }
5382                 break;
5383
5384         case EC_KILL_LINE:
5385         {
5386                 /* Kill rest of line */
5387
5388                 int len = strlen(tb->lines_list[tb->cy]);
5389
5390                 /* Correct cursor location */
5391                 if (tb->cx > len) tb->cx = len;
5392
5393                 /* Ignore selection */
5394                 if (tb->mark)
5395                 {
5396                         tb->mark = 0;
5397
5398                         /* Now dirty */
5399                         tb->dirty_flags |= DIRTY_ALL;
5400                 }
5401
5402                 /* Append only if this command is repeated. */
5403                 if (tb->old_com_id != com_id)
5404                 {
5405                         kill_yank_chain(tb);
5406                         tb->yank = NULL;
5407                 }
5408
5409                 /* Really deleted some text */
5410                 if (tb->cx < len)
5411                 {
5412                         /* Add deleted string to yank buffer */
5413                         add_str_to_yank(tb, &(tb->lines_list[tb->cy][tb->cx]));
5414
5415                         kill_line_segment(tb, tb->cy, tb->cx, len, FALSE);
5416
5417                         /* Now dirty */
5418                         tb->dirty_line = tb->cy;
5419
5420                         /* Leave end of line character */
5421                         break;
5422                 }
5423
5424                 /* Cut the end of line character only */
5425                 if (tb->yank_eol) add_str_to_yank(tb, "");
5426
5427                 /* Cut end of line */
5428                 tb->yank_eol = TRUE;
5429
5430                 do_editor_command(tb, EC_DELETE_CHAR);
5431                 break;
5432         }
5433
5434         case EC_DELETE_CHAR:
5435         {
5436                 /* DELETE == go forward + BACK SPACE */
5437
5438                 int len;
5439
5440                 /* Ignore selection */
5441                 if (tb->mark)
5442                 {
5443                         tb->mark = 0;
5444
5445                         /* Now dirty */
5446                         tb->dirty_flags |= DIRTY_ALL;
5447                 }
5448
5449 #ifdef JP
5450                 if (iskanji(tb->lines_list[tb->cy][tb->cx])) tb->cx++;
5451 #endif
5452                 tb->cx++;
5453
5454                 /* Pass through the end of line to next line */
5455                 len = strlen(tb->lines_list[tb->cy]);
5456                 if (len < tb->cx)
5457                 {
5458                         if (tb->lines_list[tb->cy + 1])
5459                         {
5460                                 tb->cy++;
5461                                 tb->cx = 0;
5462                         }
5463                         else
5464                         {
5465                                 tb->cx = len;
5466                                 break;
5467                         }
5468                 }
5469
5470                 do_editor_command(tb, EC_BACKSPACE);
5471                 break;
5472         }
5473
5474         case EC_BACKSPACE:
5475         {
5476                 /* BACK SPACE */
5477
5478                 int len, i, j, k;
5479                 char buf[MAX_LINELEN];
5480
5481                 /* Ignore selection */
5482                 if (tb->mark)
5483                 {
5484                         tb->mark = 0;
5485
5486                         /* Now dirty */
5487                         tb->dirty_flags |= DIRTY_ALL;
5488                 }
5489
5490                 /* Move to correct collumn */
5491                 len = strlen(tb->lines_list[tb->cy]);
5492                 if (len < tb->cx) tb->cx = len;
5493
5494                 if (tb->cx == 0)
5495                 {
5496                         /* delete a return code and union two lines */
5497                         if (tb->cy == 0) break;
5498                         tb->cx = strlen(tb->lines_list[tb->cy-1]);
5499                         strcpy(buf, tb->lines_list[tb->cy-1]);
5500                         strcat(buf, tb->lines_list[tb->cy]);
5501                         string_free(tb->lines_list[tb->cy-1]);
5502                         string_free(tb->lines_list[tb->cy]);
5503                         tb->lines_list[tb->cy-1] = string_make(buf);
5504
5505                         for (i = tb->cy; tb->lines_list[i+1]; i++)
5506                                 tb->lines_list[i] = tb->lines_list[i+1];
5507
5508                         tb->lines_list[i] = NULL;
5509                         tb->cy--;
5510
5511                         /* Now dirty */
5512                         tb->dirty_flags |= DIRTY_ALL;
5513
5514                         /* Expressions need re-evaluation */
5515                         tb->dirty_flags |= DIRTY_EXPRESSION;
5516
5517                         /* Text is changed */
5518                         tb->changed = TRUE;
5519
5520                         break;
5521                 }
5522
5523                 for (i = j = k = 0; tb->lines_list[tb->cy][i] && i < tb->cx; i++)
5524                 {
5525                         k = j;
5526 #ifdef JP
5527                         if (iskanji(tb->lines_list[tb->cy][i]))
5528                                 buf[j++] = tb->lines_list[tb->cy][i++];
5529 #endif
5530                         buf[j++] = tb->lines_list[tb->cy][i];
5531                 }
5532                 while (j > k)
5533                 {
5534                         tb->cx--;
5535                         j--;
5536                 }
5537                 for (; tb->lines_list[tb->cy][i]; i++)
5538                         buf[j++] = tb->lines_list[tb->cy][i];
5539                 buf[j] = '\0';
5540                 string_free(tb->lines_list[tb->cy]);
5541                 tb->lines_list[tb->cy] = string_make(buf);
5542
5543                 /* Now dirty */
5544                 tb->dirty_line = tb->cy;
5545
5546                 /* Expressions may need re-evaluation */
5547                 check_expression_line(tb, tb->cy);
5548
5549                 /* Text is changed */
5550                 tb->changed = TRUE;
5551
5552                 break;
5553         }
5554
5555         case EC_SEARCH_STR:
5556         {
5557                 byte search_dir;
5558
5559                 /* Become dirty because of item/equip menu */
5560                 tb->dirty_flags |= DIRTY_SCREEN;
5561
5562                 search_dir = get_string_for_search(&tb->search_o_ptr, &tb->search_str);
5563
5564                 if (!search_dir) break;
5565
5566                 if (search_dir == 1) do_editor_command(tb, EC_SEARCH_FORW);
5567                 else do_editor_command(tb, EC_SEARCH_BACK);
5568                 break;
5569         }
5570
5571         case EC_SEARCH_FORW:
5572                 if (tb->search_o_ptr)
5573                 {
5574                         search_for_object(tb, tb->search_o_ptr, TRUE);
5575                 }
5576                 else if (tb->search_str && tb->search_str[0])
5577                 {
5578                         search_for_string(tb, tb->search_str, TRUE);
5579                 }
5580                 else
5581                 {
5582                         tb->dirty_flags |= DIRTY_NO_SEARCH;
5583                 }
5584                 break;
5585
5586         case EC_SEARCH_BACK:
5587                 if (tb->search_o_ptr)
5588                 {
5589                         search_for_object(tb, tb->search_o_ptr, FALSE);
5590                 }
5591                 else if (tb->search_str && tb->search_str[0])
5592                 {
5593                         search_for_string(tb, tb->search_str, FALSE);
5594                 }
5595                 else
5596                 {
5597                         tb->dirty_flags |= DIRTY_NO_SEARCH;
5598                 }
5599                 break;
5600
5601         case EC_SEARCH_OBJ:
5602                 /* Become dirty because of item/equip menu */
5603                 tb->dirty_flags |= DIRTY_SCREEN;
5604
5605                 if (!get_object_for_search(&tb->search_o_ptr, &tb->search_str)) break;
5606
5607                 do_editor_command(tb, EC_SEARCH_FORW);
5608                 break;
5609
5610         case EC_SEARCH_DESTROYED:
5611                 if (!get_destroyed_object_for_search(&tb->search_o_ptr, &tb->search_str))
5612                 {
5613                         /* There is no object to search */
5614                         tb->dirty_flags |= DIRTY_NO_SEARCH;
5615
5616                         break;
5617                 }
5618
5619                 do_editor_command(tb, EC_SEARCH_FORW);
5620                 break;
5621
5622         case EC_INSERT_OBJECT:
5623         {
5624                 /* Insert choosen item name */
5625
5626                 autopick_type an_entry, *entry = &an_entry;
5627
5628                 if (!entry_from_choosed_object(entry))
5629                 {
5630                         /* Now dirty because of item/equip menu */
5631                         tb->dirty_flags |= DIRTY_SCREEN;
5632                         break;
5633                 }
5634
5635                 tb->cx = 0;
5636                 insert_return_code(tb);
5637                 string_free(tb->lines_list[tb->cy]);
5638                 tb->lines_list[tb->cy] = autopick_line_from_entry_kill(entry);
5639
5640                 /* Now dirty because of item/equip menu */
5641                 tb->dirty_flags |= DIRTY_SCREEN;
5642
5643                 break;
5644         }
5645
5646         case EC_INSERT_DESTROYED:
5647                 /* Insert a name of last destroyed item */
5648                 if (tb->last_destroyed)
5649                 {
5650                         tb->cx = 0;
5651                         insert_return_code(tb);
5652                         string_free(tb->lines_list[tb->cy]);
5653                         tb->lines_list[tb->cy] = string_make(tb->last_destroyed);
5654
5655                         /* Now dirty */
5656                         tb->dirty_flags |= DIRTY_ALL;
5657
5658                         /* Text is changed */
5659                         tb->changed = TRUE;
5660                 }
5661                 break;
5662
5663         case EC_INSERT_BLOCK:
5664         {
5665                 /* Insert a conditinal expression line */
5666                 char expression[80];
5667
5668                 /* Conditional Expression for Class and Race */
5669                 sprintf(expression, "?:[AND [EQU $RACE %s] [EQU $CLASS %s] [GEQ $LEVEL %02d]]", 
5670 #ifdef JP
5671                         rp_ptr->E_title, cp_ptr->E_title,
5672 #else
5673                         rp_ptr->title, cp_ptr->title,
5674 #endif
5675                         p_ptr->lev
5676                         );
5677
5678                 tb->cx = 0;
5679                 insert_return_code(tb);
5680                 string_free(tb->lines_list[tb->cy]);
5681                 tb->lines_list[tb->cy] = string_make(expression);
5682                 tb->cy++;
5683                 insert_return_code(tb);
5684                 string_free(tb->lines_list[tb->cy]);
5685                 tb->lines_list[tb->cy] = string_make("?:1");
5686
5687                 /* Now dirty */
5688                 tb->dirty_flags |= DIRTY_ALL;
5689
5690                 /* Text is changed */
5691                 tb->changed = TRUE;
5692
5693                 break;
5694         }
5695
5696         case EC_INSERT_MACRO:
5697                 /* Draw_everythig (delete menu) */
5698                 draw_text_editor(tb);
5699
5700                 /* Erase line */
5701                 Term_erase(0, tb->cy - tb->upper + 1, tb->wid);
5702
5703                 /* Prompt */
5704                 Term_putstr(0, tb->cy - tb->upper + 1, tb->wid - 1, TERM_YELLOW, _("P:<トリガーキー>: ", "P:<Trigger key>: "));
5705                 if (insert_macro_line(tb))
5706                 {
5707                         /* Prepare to input action */
5708                         tb->cx = 2;
5709
5710                         /* Now dirty */
5711                         tb->dirty_flags |= DIRTY_ALL;
5712
5713                         /* Text is changed */
5714                         tb->changed = TRUE;
5715                 }
5716
5717                 break;
5718
5719         case EC_INSERT_KEYMAP:
5720                 /* Draw_everythig (delete menu) */
5721                 draw_text_editor(tb);
5722
5723                 /* Erase line */
5724                 Term_erase(0, tb->cy - tb->upper + 1, tb->wid);
5725
5726                 /* Prompt */
5727                 Term_putstr(0, tb->cy - tb->upper + 1, tb->wid - 1, TERM_YELLOW, 
5728                                         format(_("C:%d:<コマンドキー>: ", "C:%d:<Keypress>: "), (rogue_like_commands ? KEYMAP_MODE_ROGUE : KEYMAP_MODE_ORIG)));
5729
5730                 if (insert_keymap_line(tb))
5731                 {
5732                         /* Prepare to input action */
5733                         tb->cx = 2;
5734
5735                         /* Now dirty */
5736                         tb->dirty_flags |= DIRTY_ALL;
5737
5738                         /* Text is changed */
5739                         tb->changed = TRUE;
5740                 }                               
5741                 break;
5742
5743         case EC_CL_AUTOPICK: toggle_command_letter(tb, DO_AUTOPICK); break;
5744         case EC_CL_DESTROY: toggle_command_letter(tb, DO_AUTODESTROY); break;
5745         case EC_CL_LEAVE: toggle_command_letter(tb, DONT_AUTOPICK); break;
5746         case EC_CL_QUERY: toggle_command_letter(tb, DO_QUERY_AUTOPICK); break;
5747         case EC_CL_NO_DISP: toggle_command_letter(tb, DO_DISPLAY); break;
5748
5749         case EC_IK_UNAWARE: toggle_keyword(tb, FLG_UNAWARE); break;
5750         case EC_IK_UNIDENTIFIED: toggle_keyword(tb, FLG_UNIDENTIFIED); break;
5751         case EC_IK_IDENTIFIED: toggle_keyword(tb, FLG_IDENTIFIED); break;
5752         case EC_IK_STAR_IDENTIFIED: toggle_keyword(tb, FLG_STAR_IDENTIFIED); break;
5753         case EC_KK_WEAPONS: toggle_keyword(tb, FLG_WEAPONS); break;
5754         case EC_KK_FAVORITE_WEAPONS: toggle_keyword(tb, FLG_FAVORITE_WEAPONS); break;
5755         case EC_KK_ARMORS: toggle_keyword(tb, FLG_ARMORS); break;
5756         case EC_KK_MISSILES: toggle_keyword(tb, FLG_MISSILES); break;
5757         case EC_KK_DEVICES: toggle_keyword(tb, FLG_DEVICES); break;
5758         case EC_KK_LIGHTS: toggle_keyword(tb, FLG_LIGHTS); break;
5759         case EC_KK_JUNKS: toggle_keyword(tb, FLG_JUNKS); break;
5760         case EC_KK_CORPSES: toggle_keyword(tb, FLG_CORPSES); break;
5761         case EC_KK_SPELLBOOKS: toggle_keyword(tb, FLG_SPELLBOOKS); break;
5762         case EC_KK_SHIELDS: toggle_keyword(tb, FLG_SHIELDS); break;
5763         case EC_KK_BOWS: toggle_keyword(tb, FLG_BOWS); break;
5764         case EC_KK_RINGS: toggle_keyword(tb, FLG_RINGS); break;
5765         case EC_KK_AMULETS: toggle_keyword(tb, FLG_AMULETS); break;
5766         case EC_KK_SUITS: toggle_keyword(tb, FLG_SUITS); break;
5767         case EC_KK_CLOAKS: toggle_keyword(tb, FLG_CLOAKS); break;
5768         case EC_KK_HELMS: toggle_keyword(tb, FLG_HELMS); break;
5769         case EC_KK_GLOVES: toggle_keyword(tb, FLG_GLOVES); break;
5770         case EC_KK_BOOTS: toggle_keyword(tb, FLG_BOOTS); break;
5771         case EC_OK_COLLECTING: toggle_keyword(tb, FLG_COLLECTING); break;
5772         case EC_OK_BOOSTED: toggle_keyword(tb, FLG_BOOSTED); break;
5773         case EC_OK_MORE_DICE: toggle_keyword(tb, FLG_MORE_DICE); break;
5774         case EC_OK_MORE_BONUS: toggle_keyword(tb, FLG_MORE_BONUS); break;
5775         case EC_OK_WORTHLESS: toggle_keyword(tb, FLG_WORTHLESS); break;
5776         case EC_OK_ARTIFACT: toggle_keyword(tb, FLG_ARTIFACT); break;
5777         case EC_OK_EGO: toggle_keyword(tb, FLG_EGO); break;
5778         case EC_OK_GOOD: toggle_keyword(tb, FLG_GOOD); break;
5779         case EC_OK_NAMELESS: toggle_keyword(tb, FLG_NAMELESS); break;
5780         case EC_OK_AVERAGE: toggle_keyword(tb, FLG_AVERAGE); break;
5781         case EC_OK_RARE: toggle_keyword(tb, FLG_RARE); break;
5782         case EC_OK_COMMON: toggle_keyword(tb, FLG_COMMON); break;
5783         case EC_OK_WANTED: toggle_keyword(tb, FLG_WANTED); break;
5784         case EC_OK_UNIQUE: toggle_keyword(tb, FLG_UNIQUE); break;
5785         case EC_OK_HUMAN: toggle_keyword(tb, FLG_HUMAN); break;
5786         case EC_OK_UNREADABLE:
5787                 toggle_keyword(tb, FLG_UNREADABLE);
5788                 add_keyword(tb, FLG_SPELLBOOKS);
5789                 break;
5790         case EC_OK_REALM1:
5791                 toggle_keyword(tb, FLG_REALM1);
5792                 add_keyword(tb, FLG_SPELLBOOKS);
5793                 break;
5794         case EC_OK_REALM2:
5795                 toggle_keyword(tb, FLG_REALM2);
5796                 add_keyword(tb, FLG_SPELLBOOKS);
5797                 break;
5798         case EC_OK_FIRST:
5799                 toggle_keyword(tb, FLG_FIRST);
5800                 add_keyword(tb, FLG_SPELLBOOKS);
5801                 break;
5802         case EC_OK_SECOND:
5803                 toggle_keyword(tb, FLG_SECOND);
5804                 add_keyword(tb, FLG_SPELLBOOKS);
5805                 break;
5806         case EC_OK_THIRD:
5807                 toggle_keyword(tb, FLG_THIRD);
5808                 add_keyword(tb, FLG_SPELLBOOKS);
5809                 break;
5810         case EC_OK_FOURTH:
5811                 toggle_keyword(tb, FLG_FOURTH);
5812                 add_keyword(tb, FLG_SPELLBOOKS);
5813                 break;
5814         }
5815
5816         /* Save old command */
5817         tb->old_com_id = com_id;
5818
5819         return FALSE;
5820 }
5821
5822
5823 /*
5824  * Insert single letter at cursor position.
5825  */
5826 static void insert_single_letter(text_body_type *tb, int key)
5827 {
5828         int i, j, len;
5829         char buf[MAX_LINELEN];
5830
5831         /* Save preceding string */
5832         for (i = j = 0; tb->lines_list[tb->cy][i] && i < tb->cx; i++)
5833                 buf[j++] = tb->lines_list[tb->cy][i];
5834
5835         /* Add a character */
5836 #ifdef JP
5837         if (iskanji(key))
5838         {
5839                 int next;
5840
5841                 inkey_base = TRUE;
5842                 next = inkey();
5843                 if (j+2 < MAX_LINELEN)
5844                 {
5845                         buf[j++] = (char)key;
5846                         buf[j++] = (char)next;
5847                         tb->cx += 2;
5848                 }
5849                 else
5850                         bell();
5851         }
5852         else
5853 #endif
5854         {
5855                 if (j+1 < MAX_LINELEN)
5856                         buf[j++] = (char)key;
5857                 tb->cx++;
5858         }
5859
5860         /* Add following */
5861         for (; tb->lines_list[tb->cy][i] && j + 1 < MAX_LINELEN; i++)
5862                 buf[j++] = tb->lines_list[tb->cy][i];
5863         buf[j] = '\0';
5864
5865         /* Replace current line with new line */
5866         string_free(tb->lines_list[tb->cy]);
5867         tb->lines_list[tb->cy] = string_make(buf);
5868
5869         /* Move to correct collumn */
5870         len = strlen(tb->lines_list[tb->cy]);
5871         if (len < tb->cx) tb->cx = len;
5872
5873         /* Now dirty */
5874         tb->dirty_line = tb->cy;
5875
5876         /* Expressions may need re-evaluation */
5877         check_expression_line(tb, tb->cy);
5878
5879         /* Text is changed */
5880         tb->changed = TRUE;
5881 }
5882
5883
5884 /*
5885  * Check special key code and get a movement command id
5886  */
5887 static int analyze_move_key(text_body_type *tb, int skey)
5888 {
5889         int com_id;
5890
5891         /* Not a special key */
5892         if (!(skey & SKEY_MASK)) return 0;
5893
5894         /* Convert from a special key code to an editor command */
5895         switch(skey & ~SKEY_MOD_MASK)
5896         {
5897         case SKEY_DOWN:   com_id = EC_DOWN;   break;
5898         case SKEY_LEFT:   com_id = EC_LEFT;   break;
5899         case SKEY_RIGHT:  com_id = EC_RIGHT;  break;
5900         case SKEY_UP:     com_id = EC_UP;     break;
5901         case SKEY_PGUP:   com_id = EC_PGUP;   break;
5902         case SKEY_PGDOWN: com_id = EC_PGDOWN; break;
5903         case SKEY_TOP:    com_id = EC_TOP;    break;
5904         case SKEY_BOTTOM: com_id = EC_BOTTOM; break;
5905
5906         default:
5907                 /* Not a special movement key */
5908                 return 0;
5909         }
5910
5911         /* Without shift modifier */
5912         if (!(skey & SKEY_MOD_SHIFT))
5913         {
5914                 /*
5915                  * Un-shifted cursor keys cancells
5916                  * selection created by shift+cursor.
5917                  */
5918                 if (tb->mark & MARK_BY_SHIFT)
5919                 {
5920                         tb->mark = 0;
5921
5922                         /* Now dirty */
5923                         tb->dirty_flags |= DIRTY_ALL;
5924                 }
5925         }
5926
5927         /* With shift modifier */
5928         else
5929         {
5930                 /* Start selection by shift + cursor keys */
5931                 if (!tb->mark)
5932                 {
5933                         int len = strlen(tb->lines_list[tb->cy]);
5934
5935                         tb->mark = MARK_MARK | MARK_BY_SHIFT;
5936                         tb->my = tb->cy;
5937                         tb->mx = tb->cx;
5938
5939                         /* Correct cursor location */
5940                         if (tb->cx > len) tb->mx = len;
5941                                                 
5942                         /* Need to redraw text */
5943                         if (com_id == EC_UP || com_id == EC_DOWN)
5944                         {
5945                                 /* Redraw all text */
5946                                 tb->dirty_flags |= DIRTY_ALL;
5947                         }
5948                         else
5949                         {
5950                                 tb->dirty_line = tb->cy;
5951                         }
5952                 }
5953         }
5954
5955         return com_id;
5956 }
5957
5958 /*
5959  * In-game editor of Object Auto-picker/Destoryer
5960  */
5961 void do_cmd_edit_autopick(void)
5962 {
5963         static int cx_save = 0;
5964         static int cy_save = 0;
5965
5966         text_body_type text_body, *tb = &text_body;
5967
5968         autopick_type an_entry, *entry = &an_entry;
5969         char buf[MAX_LINELEN];
5970
5971         int i;
5972         int key = -1;
5973
5974         static s32b old_autosave_turn = 0L;
5975         byte quit = 0;
5976
5977         tb->changed = FALSE;
5978         tb->cx = cx_save;
5979         tb->cy = cy_save;
5980         tb->upper = tb->left = 0;
5981         tb->mark = 0;
5982         tb->mx = tb->my = 0;
5983         tb->old_cy = tb->old_upper = tb->old_left = -1;
5984         tb->old_wid = tb->old_hgt = -1;
5985         tb->old_com_id = 0;
5986
5987         tb->yank = NULL;
5988         tb->search_o_ptr = NULL;
5989         tb->search_str = NULL;
5990         tb->last_destroyed = NULL;
5991         tb->dirty_flags = DIRTY_ALL | DIRTY_MODE | DIRTY_EXPRESSION;
5992         tb->dirty_line = -1;
5993         tb->filename_mode = PT_DEFAULT;
5994
5995         if (turn < old_autosave_turn)
5996         {
5997                 while (old_autosave_turn > turn) old_autosave_turn -= TURNS_PER_TICK * TOWN_DAWN;
5998         }
5999
6000         /* Autosave */
6001         if (turn > old_autosave_turn + 100L)
6002         {
6003                 do_cmd_save_game(TRUE);
6004                 old_autosave_turn = turn;
6005         }
6006
6007         /* HACK -- Reset start_time to stop counting playtime while edit */
6008         update_playtime();
6009
6010         /* Free old entries */
6011         init_autopick();
6012
6013         /* Command Description of the 'Last Destroyed Item' */
6014         if (autopick_last_destroyed_object.k_idx)
6015         {
6016                 autopick_entry_from_object(entry, &autopick_last_destroyed_object);
6017                 tb->last_destroyed = autopick_line_from_entry_kill(entry);
6018         }
6019
6020         /* Read or initialize whole text */
6021         tb->lines_list = read_pickpref_text_lines(&tb->filename_mode);
6022
6023         /* Reset cursor position if needed */
6024         for (i = 0; i < tb->cy; i++)
6025         {
6026                 if (!tb->lines_list[i])
6027                 {
6028                         tb->cy = tb->cx = 0;
6029                         break;
6030                 }
6031         }
6032         screen_save();
6033
6034         /* Process requests until done */
6035         while (!quit)
6036         {
6037                 int com_id = 0;
6038
6039                 /* Draw_everythig */
6040                 draw_text_editor(tb);
6041
6042                 /* Display header line */
6043                 prt(_("(^Q:終了 ^W:セーブして終了, ESC:メニュー, その他:入力)", 
6044                       "(^Q:Quit, ^W:Save&Quit, ESC:Menu, Other:Input text)"), 0, 0);
6045                 if (!tb->mark)
6046                 {
6047                         /* Display current position */
6048                         prt (format("(%d,%d)", tb->cx, tb->cy), 0, 60);
6049                 }
6050                 else
6051                 {
6052                         /* Display current position and mark position */
6053                         prt (format("(%d,%d)-(%d,%d)", tb->mx, tb->my, tb->cx, tb->cy), 0, 60);
6054                 }
6055
6056                 /* Place cursor */
6057                 Term_gotoxy(tb->cx - tb->left, tb->cy - tb->upper + 1);
6058
6059                 /* Now clean */
6060                 tb->dirty_flags = 0;
6061                 tb->dirty_line = -1;
6062
6063                 /* Save old key and location */
6064                 tb->old_cy = tb->cy;
6065                 tb->old_upper = tb->upper;
6066                 tb->old_left = tb->left;
6067                 tb->old_wid = tb->wid;
6068                 tb->old_hgt = tb->hgt;
6069
6070                 key = inkey_special(TRUE);
6071
6072                 /* Special keys */
6073                 if (key & SKEY_MASK)
6074                 {
6075                         /* Get a movement command */
6076                         com_id = analyze_move_key(tb, key);
6077                 }
6078
6079                 /* Open the menu */
6080                 else if (key == ESCAPE)
6081                 {
6082                         com_id = do_command_menu(0, 0);
6083
6084                         /* Redraw all text later */
6085                         tb->dirty_flags |= DIRTY_SCREEN;
6086                 }
6087
6088                 /* Insert a character */
6089                 else if (!iscntrl((unsigned char)key))
6090                 {
6091                         /* Ignore selection */
6092                         if (tb->mark)
6093                         {
6094                                 tb->mark = 0;
6095
6096                                 /* Now dirty */
6097                                 tb->dirty_flags |= DIRTY_ALL;
6098                         }
6099
6100                         insert_single_letter(tb, key);
6101
6102                         /* Next loop */
6103                         continue;
6104                 }
6105
6106                 /* Other commands */
6107                 else
6108                 {
6109                         com_id = get_com_id((char)key);
6110                 }
6111
6112                 if (com_id) quit = do_editor_command(tb, com_id);
6113         } /* while (TRUE) */
6114         screen_load();
6115
6116         /* Get the filename of preference */
6117         strcpy(buf, pickpref_filename(tb->filename_mode));
6118
6119         if (quit == QUIT_AND_SAVE)
6120                 write_text_lines(buf, tb->lines_list);
6121
6122         free_text_lines(tb->lines_list);
6123
6124         string_free(tb->search_str);
6125         string_free(tb->last_destroyed);
6126
6127         /* Destroy string chain */
6128         kill_yank_chain(tb);
6129
6130         /* Reload autopick pref */
6131         process_autopick_file(buf);
6132
6133         /* HACK -- reset start_time so that playtime is not increase while edit */
6134         start_time = (u32b)time(NULL);
6135
6136         /* Save cursor location */
6137         cx_save = tb->cx;
6138         cy_save = tb->cy;
6139 }