OSDN Git Service

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