OSDN Git Service

update year to 2020
[jnethack/source.git] / src / o_init.c
1 /* NetHack 3.6  o_init.c        $NHDT-Date: 1545383615 2018/12/21 09:13:35 $  $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.25 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Robert Patrick Rankin, 2011. */
4 /* NetHack may be freely redistributed.  See license for details. */
5
6 /* JNetHack Copyright */
7 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000  */
8 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2020            */
9 /* JNetHack may be freely redistributed.  See license for details. */
10
11 #include "hack.h"
12 #include "lev.h" /* save & restore info */
13
14 STATIC_DCL void FDECL(setgemprobs, (d_level *));
15 STATIC_DCL void FDECL(shuffle, (int, int, BOOLEAN_P));
16 STATIC_DCL void NDECL(shuffle_all);
17 STATIC_DCL boolean FDECL(interesting_to_discover, (int));
18 STATIC_DCL char *FDECL(oclass_to_name, (CHAR_P, char *));
19
20 static NEARDATA short disco[NUM_OBJECTS] = DUMMY;
21
22 #ifdef USE_TILES
23 STATIC_DCL void NDECL(shuffle_tiles);
24 extern short glyph2tile[]; /* from tile.c */
25
26 /* Shuffle tile assignments to match descriptions, so a red potion isn't
27  * displayed with a blue tile and so on.
28  *
29  * Tile assignments are not saved, and shouldn't be so that a game can
30  * be resumed on an otherwise identical non-tile-using binary, so we have
31  * to reshuffle the assignments from oc_descr_idx information when a game
32  * is restored.  So might as well do that the first time instead of writing
33  * another routine.
34  */
35 STATIC_OVL void
36 shuffle_tiles()
37 {
38     int i;
39     short tmp_tilemap[NUM_OBJECTS];
40
41     for (i = 0; i < NUM_OBJECTS; i++)
42         tmp_tilemap[i] = glyph2tile[objects[i].oc_descr_idx + GLYPH_OBJ_OFF];
43
44     for (i = 0; i < NUM_OBJECTS; i++)
45         glyph2tile[i + GLYPH_OBJ_OFF] = tmp_tilemap[i];
46 }
47 #endif /* USE_TILES */
48
49 STATIC_OVL void
50 setgemprobs(dlev)
51 d_level *dlev;
52 {
53     int j, first, lev;
54
55     if (dlev)
56         lev = (ledger_no(dlev) > maxledgerno()) ? maxledgerno()
57                                                 : ledger_no(dlev);
58     else
59         lev = 0;
60     first = bases[GEM_CLASS];
61
62     for (j = 0; j < 9 - lev / 3; j++)
63         objects[first + j].oc_prob = 0;
64     first += j;
65     if (first > LAST_GEM || objects[first].oc_class != GEM_CLASS
66         || OBJ_NAME(objects[first]) == (char *) 0) {
67         raw_printf("Not enough gems? - first=%d j=%d LAST_GEM=%d", first, j,
68                    LAST_GEM);
69         wait_synch();
70     }
71     for (j = first; j <= LAST_GEM; j++)
72         objects[j].oc_prob = (171 + j - first) / (LAST_GEM + 1 - first);
73 }
74
75 /* shuffle descriptions on objects o_low to o_high */
76 STATIC_OVL void
77 shuffle(o_low, o_high, domaterial)
78 int o_low, o_high;
79 boolean domaterial;
80 {
81     int i, j, num_to_shuffle;
82     short sw;
83     int color;
84
85     for (num_to_shuffle = 0, j = o_low; j <= o_high; j++)
86         if (!objects[j].oc_name_known)
87             num_to_shuffle++;
88     if (num_to_shuffle < 2)
89         return;
90
91     for (j = o_low; j <= o_high; j++) {
92         if (objects[j].oc_name_known)
93             continue;
94         do
95             i = j + rn2(o_high - j + 1);
96         while (objects[i].oc_name_known);
97         sw = objects[j].oc_descr_idx;
98         objects[j].oc_descr_idx = objects[i].oc_descr_idx;
99         objects[i].oc_descr_idx = sw;
100         sw = objects[j].oc_tough;
101         objects[j].oc_tough = objects[i].oc_tough;
102         objects[i].oc_tough = sw;
103         color = objects[j].oc_color;
104         objects[j].oc_color = objects[i].oc_color;
105         objects[i].oc_color = color;
106
107         /* shuffle material */
108         if (domaterial) {
109             sw = objects[j].oc_material;
110             objects[j].oc_material = objects[i].oc_material;
111             objects[i].oc_material = sw;
112         }
113     }
114 }
115
116 void
117 init_objects()
118 {
119     register int i, first, last, sum;
120     register char oclass;
121 #ifdef TEXTCOLOR
122 #define COPY_OBJ_DESCR(o_dst, o_src) \
123     o_dst.oc_descr_idx = o_src.oc_descr_idx, o_dst.oc_color = o_src.oc_color
124 #else
125 #define COPY_OBJ_DESCR(o_dst, o_src) o_dst.oc_descr_idx = o_src.oc_descr_idx
126 #endif
127
128     /* bug fix to prevent "initialization error" abort on Intel Xenix.
129      * reported by mikew@semike
130      */
131     for (i = 0; i < MAXOCLASSES; i++)
132         bases[i] = 0;
133     /* initialize object descriptions */
134     for (i = 0; i < NUM_OBJECTS; i++)
135         objects[i].oc_name_idx = objects[i].oc_descr_idx = i;
136     /* init base; if probs given check that they add up to 1000,
137        otherwise compute probs */
138     first = 0;
139     while (first < NUM_OBJECTS) {
140         oclass = objects[first].oc_class;
141         last = first + 1;
142         while (last < NUM_OBJECTS && objects[last].oc_class == oclass)
143             last++;
144         bases[(int) oclass] = first;
145
146         if (oclass == GEM_CLASS) {
147             setgemprobs((d_level *) 0);
148
149             if (rn2(2)) { /* change turquoise from green to blue? */
150                 COPY_OBJ_DESCR(objects[TURQUOISE], objects[SAPPHIRE]);
151             }
152             if (rn2(2)) { /* change aquamarine from green to blue? */
153                 COPY_OBJ_DESCR(objects[AQUAMARINE], objects[SAPPHIRE]);
154             }
155             switch (rn2(4)) { /* change fluorite from violet? */
156             case 0:
157                 break;
158             case 1: /* blue */
159                 COPY_OBJ_DESCR(objects[FLUORITE], objects[SAPPHIRE]);
160                 break;
161             case 2: /* white */
162                 COPY_OBJ_DESCR(objects[FLUORITE], objects[DIAMOND]);
163                 break;
164             case 3: /* green */
165                 COPY_OBJ_DESCR(objects[FLUORITE], objects[EMERALD]);
166                 break;
167             }
168         }
169     check:
170         sum = 0;
171         for (i = first; i < last; i++)
172             sum += objects[i].oc_prob;
173         if (sum == 0) {
174             for (i = first; i < last; i++)
175                 objects[i].oc_prob = (1000 + i - first) / (last - first);
176             goto check;
177         }
178         if (sum != 1000)
179             error("init-prob error for class %d (%d%%)", oclass, sum);
180         first = last;
181     }
182     /* shuffle descriptions */
183     shuffle_all();
184 #ifdef USE_TILES
185     shuffle_tiles();
186 #endif
187     objects[WAN_NOTHING].oc_dir = rn2(2) ? NODIR : IMMEDIATE;
188 }
189
190 /* retrieve the range of objects that otyp shares descriptions with */
191 void
192 obj_shuffle_range(otyp, lo_p, hi_p)
193 int otyp;         /* input: representative item */
194 int *lo_p, *hi_p; /* output: range that item belongs among */
195 {
196     int i, ocls = objects[otyp].oc_class;
197
198     /* default is just the object itself */
199     *lo_p = *hi_p = otyp;
200
201     switch (ocls) {
202     case ARMOR_CLASS:
203         if (otyp >= HELMET && otyp <= HELM_OF_TELEPATHY)
204             *lo_p = HELMET, *hi_p = HELM_OF_TELEPATHY;
205         else if (otyp >= LEATHER_GLOVES && otyp <= GAUNTLETS_OF_DEXTERITY)
206             *lo_p = LEATHER_GLOVES, *hi_p = GAUNTLETS_OF_DEXTERITY;
207         else if (otyp >= CLOAK_OF_PROTECTION && otyp <= CLOAK_OF_DISPLACEMENT)
208             *lo_p = CLOAK_OF_PROTECTION, *hi_p = CLOAK_OF_DISPLACEMENT;
209         else if (otyp >= SPEED_BOOTS && otyp <= LEVITATION_BOOTS)
210             *lo_p = SPEED_BOOTS, *hi_p = LEVITATION_BOOTS;
211         break;
212     case POTION_CLASS:
213         /* potion of water has the only fixed description */
214         *lo_p = bases[POTION_CLASS];
215         *hi_p = POT_WATER - 1;
216         break;
217     case AMULET_CLASS:
218     case SCROLL_CLASS:
219     case SPBOOK_CLASS:
220         /* exclude non-magic types and also unique ones */
221         *lo_p = bases[ocls];
222         for (i = *lo_p; objects[i].oc_class == ocls; i++)
223             if (objects[i].oc_unique || !objects[i].oc_magic)
224                 break;
225         *hi_p = i - 1;
226         break;
227     case RING_CLASS:
228     case WAND_CLASS:
229     case VENOM_CLASS:
230         /* entire class */
231         *lo_p = bases[ocls];
232         for (i = *lo_p; objects[i].oc_class == ocls; i++)
233             continue;
234         *hi_p = i - 1;
235         break;
236     }
237
238     /* artifact checking might ask about item which isn't part of any range
239        but fell within the classes that do have ranges specified above */
240     if (otyp < *lo_p || otyp > *hi_p)
241         *lo_p = *hi_p = otyp;
242     return;
243 }
244
245 /* randomize object descriptions */
246 STATIC_OVL void
247 shuffle_all()
248 {
249     /* entire classes; obj_shuffle_range() handles their exceptions */
250     static char shuffle_classes[] = {
251         AMULET_CLASS, POTION_CLASS, RING_CLASS,  SCROLL_CLASS,
252         SPBOOK_CLASS, WAND_CLASS,   VENOM_CLASS,
253     };
254     /* sub-class type ranges (one item from each group) */
255     static short shuffle_types[] = {
256         HELMET, LEATHER_GLOVES, CLOAK_OF_PROTECTION, SPEED_BOOTS,
257     };
258     int first, last, idx;
259
260     /* do whole classes (amulets, &c) */
261     for (idx = 0; idx < SIZE(shuffle_classes); idx++) {
262         obj_shuffle_range(bases[(int) shuffle_classes[idx]], &first, &last);
263         shuffle(first, last, TRUE);
264     }
265     /* do type ranges (helms, &c) */
266     for (idx = 0; idx < SIZE(shuffle_types); idx++) {
267         obj_shuffle_range(shuffle_types[idx], &first, &last);
268         shuffle(first, last, FALSE);
269     }
270     return;
271 }
272
273 /* find the object index for snow boots; used [once] by slippery ice code */
274 int
275 find_skates()
276 {
277     register int i;
278     register const char *s;
279
280     for (i = SPEED_BOOTS; i <= LEVITATION_BOOTS; i++)
281 /*JP
282         if ((s = OBJ_DESCR(objects[i])) != 0 && !strcmp(s, "snow boots"))
283 */
284         if ((s = OBJ_DESCR(objects[i])) != 0 && !strcmp(s, "\90á\8cC"))
285             return i;
286
287     impossible("snow boots not found?");
288     return -1; /* not 0, or caller would try again each move */
289 }
290
291 /* level dependent initialization */
292 void
293 oinit()
294 {
295     setgemprobs(&u.uz);
296 }
297
298 void
299 savenames(fd, mode)
300 int fd, mode;
301 {
302     register int i;
303     unsigned int len;
304
305     if (perform_bwrite(mode)) {
306         bwrite(fd, (genericptr_t) bases, sizeof bases);
307         bwrite(fd, (genericptr_t) disco, sizeof disco);
308         bwrite(fd, (genericptr_t) objects,
309                sizeof(struct objclass) * NUM_OBJECTS);
310     }
311     /* as long as we use only one version of Hack we
312        need not save oc_name and oc_descr, but we must save
313        oc_uname for all objects */
314     for (i = 0; i < NUM_OBJECTS; i++)
315         if (objects[i].oc_uname) {
316             if (perform_bwrite(mode)) {
317                 len = strlen(objects[i].oc_uname) + 1;
318                 bwrite(fd, (genericptr_t) &len, sizeof len);
319                 bwrite(fd, (genericptr_t) objects[i].oc_uname, len);
320             }
321             if (release_data(mode)) {
322                 free((genericptr_t) objects[i].oc_uname);
323                 objects[i].oc_uname = 0;
324             }
325         }
326 }
327
328 void
329 restnames(fd)
330 register int fd;
331 {
332     register int i;
333     unsigned int len;
334
335     mread(fd, (genericptr_t) bases, sizeof bases);
336     mread(fd, (genericptr_t) disco, sizeof disco);
337     mread(fd, (genericptr_t) objects, sizeof(struct objclass) * NUM_OBJECTS);
338     for (i = 0; i < NUM_OBJECTS; i++)
339         if (objects[i].oc_uname) {
340             mread(fd, (genericptr_t) &len, sizeof len);
341             objects[i].oc_uname = (char *) alloc(len);
342             mread(fd, (genericptr_t) objects[i].oc_uname, len);
343         }
344 #ifdef USE_TILES
345     shuffle_tiles();
346 #endif
347 }
348
349 void
350 discover_object(oindx, mark_as_known, credit_hero)
351 register int oindx;
352 boolean mark_as_known;
353 boolean credit_hero;
354 {
355     if (!objects[oindx].oc_name_known) {
356         register int dindx, acls = objects[oindx].oc_class;
357
358         /* Loop thru disco[] 'til we find the target (which may have been
359            uname'd) or the next open slot; one or the other will be found
360            before we reach the next class...
361          */
362         for (dindx = bases[acls]; disco[dindx] != 0; dindx++)
363             if (disco[dindx] == oindx)
364                 break;
365         disco[dindx] = oindx;
366
367         if (mark_as_known) {
368             objects[oindx].oc_name_known = 1;
369             if (credit_hero)
370                 exercise(A_WIS, TRUE);
371         }
372         /* moves==1L => initial inventory, gameover => final disclosure */
373         if (moves > 1L && !program_state.gameover) {
374             if (objects[oindx].oc_class == GEM_CLASS)
375                 gem_learned(oindx); /* could affect price of unpaid gems */
376             update_inventory();
377         }
378     }
379 }
380
381 /* if a class name has been cleared, we may need to purge it from disco[] */
382 void
383 undiscover_object(oindx)
384 register int oindx;
385 {
386     if (!objects[oindx].oc_name_known) {
387         register int dindx, acls = objects[oindx].oc_class;
388         register boolean found = FALSE;
389
390         /* find the object; shift those behind it forward one slot */
391         for (dindx = bases[acls]; dindx < NUM_OBJECTS && disco[dindx] != 0
392                                   && objects[dindx].oc_class == acls;
393              dindx++)
394             if (found)
395                 disco[dindx - 1] = disco[dindx];
396             else if (disco[dindx] == oindx)
397                 found = TRUE;
398
399         /* clear last slot */
400         if (found)
401             disco[dindx - 1] = 0;
402         else
403             impossible("named object not in disco");
404
405         if (objects[oindx].oc_class == GEM_CLASS)
406             gem_learned(oindx); /* ok, it's actually been unlearned */
407         update_inventory();
408     }
409 }
410
411 STATIC_OVL boolean
412 interesting_to_discover(i)
413 register int i;
414 {
415     /* Pre-discovered objects are now printed with a '*' */
416     return (boolean) (objects[i].oc_uname != (char *) 0
417                       || (objects[i].oc_name_known
418                           && OBJ_DESCR(objects[i]) != (char *) 0));
419 }
420
421 /* items that should stand out once they're known */
422 static short uniq_objs[] = {
423     AMULET_OF_YENDOR, SPE_BOOK_OF_THE_DEAD, CANDELABRUM_OF_INVOCATION,
424     BELL_OF_OPENING,
425 };
426
427 /* the '\' command - show discovered object types */
428 int
429 dodiscovered() /* free after Robert Viduya */
430 {
431     register int i, dis;
432     int ct = 0;
433     char *s, oclass, prev_class, classes[MAXOCLASSES], buf[BUFSZ];
434     winid tmpwin;
435
436     tmpwin = create_nhwindow(NHW_MENU);
437 /*JP
438     putstr(tmpwin, 0, "Discoveries");
439 */
440     putstr(tmpwin, 0, "\94­\8c©\95¨\88ê\97\97");
441     putstr(tmpwin, 0, "");
442
443     /* gather "unique objects" into a pseudo-class; note that they'll
444        also be displayed individually within their regular class */
445     for (i = dis = 0; i < SIZE(uniq_objs); i++)
446         if (objects[uniq_objs[i]].oc_name_known) {
447             if (!dis++)
448 /*JP
449                 putstr(tmpwin, iflags.menu_headings, "Unique items");
450 */
451                 putstr(tmpwin, iflags.menu_headings, "\93Á\8eê\83A\83C\83e\83\80");
452             Sprintf(buf, "  %s", OBJ_NAME(objects[uniq_objs[i]]));
453             putstr(tmpwin, 0, buf);
454             ++ct;
455         }
456     /* display any known artifacts as another pseudo-class */
457     ct += disp_artifact_discoveries(tmpwin);
458
459     /* several classes are omitted from packorder; one is of interest here */
460     Strcpy(classes, flags.inv_order);
461     if (!index(classes, VENOM_CLASS))
462         (void) strkitten(classes, VENOM_CLASS); /* append char to string */
463
464     for (s = classes; *s; s++) {
465         oclass = *s;
466         prev_class = oclass + 1; /* forced different from oclass */
467         for (i = bases[(int) oclass];
468              i < NUM_OBJECTS && objects[i].oc_class == oclass; i++) {
469             if ((dis = disco[i]) != 0 && interesting_to_discover(dis)) {
470                 ct++;
471                 if (oclass != prev_class) {
472                     putstr(tmpwin, iflags.menu_headings,
473                            let_to_name(oclass, FALSE, FALSE));
474                     prev_class = oclass;
475                 }
476                 Sprintf(buf, "%s %s",
477                         (objects[dis].oc_pre_discovered ? "*" : " "),
478                         obj_typename(dis));
479                 putstr(tmpwin, 0, buf);
480             }
481         }
482     }
483     if (ct == 0) {
484 /*JP
485         You("haven't discovered anything yet...");
486 */
487         You("\82Ü\82¾\89½\82à\94­\8c©\82µ\82Ä\82¢\82È\82¢\81D\81D\81D");
488     } else
489         display_nhwindow(tmpwin, TRUE);
490     destroy_nhwindow(tmpwin);
491
492     return 0;
493 }
494
495 /* lower case let_to_name() output, which differs from def_oc_syms[].name */
496 STATIC_OVL char *
497 oclass_to_name(oclass, buf)
498 char oclass;
499 char *buf;
500 {
501 #if 0 /*JP*//*\8eg\82í\82È\82¢*/
502     char *s;
503 #endif
504
505     Strcpy(buf, let_to_name(oclass, FALSE, FALSE));
506 #if 0 /*JP*//*\8f¬\95\8e\9a\89»\82µ\82È\82¢*/
507     for (s = buf; *s; ++s)
508         *s = lowc(*s);
509 #endif
510     return buf;
511 }
512
513 /* the '`' command - show discovered object types for one class */
514 int
515 doclassdisco()
516 {
517     static NEARDATA const char
518 /*JP
519         prompt[] = "View discoveries for which sort of objects?",
520 */
521         prompt[] = "\82Ç\82Ì\8eí\97Þ\82Ì\94­\8c©\95¨\82ð\8c©\82Ü\82·\82©\81H",
522 /*JP
523         havent_discovered_any[] = "haven't discovered any %s yet.",
524 */
525         havent_discovered_any[] = "\82Ü\82¾\89½\82à%s\82ð\94­\8c©\82µ\82Ä\82¢\82È\82¢\81D",
526 /*JP
527         unique_items[] = "unique items",
528 */
529         unique_items[] = "\93Á\8eê\83A\83C\83e\83\80",
530 /*JP
531         artifact_items[] = "artifacts";
532 */
533         artifact_items[] = "\90¹\8aí";
534     char *s, c, oclass, menulet, allclasses[MAXOCLASSES],
535         discosyms[2 + MAXOCLASSES + 1], buf[BUFSZ];
536     int i, ct, dis, xtras;
537     boolean traditional;
538     winid tmpwin = WIN_ERR;
539     anything any;
540     menu_item *pick_list = 0;
541
542     discosyms[0] = '\0';
543     traditional = (flags.menu_style == MENU_TRADITIONAL
544                    || flags.menu_style == MENU_COMBINATION);
545     if (!traditional) {
546         tmpwin = create_nhwindow(NHW_MENU);
547         start_menu(tmpwin);
548     }
549     any = zeroany;
550     menulet = 'a';
551
552     /* check whether we've discovered any unique objects */
553     for (i = 0; i < SIZE(uniq_objs); i++)
554         if (objects[uniq_objs[i]].oc_name_known) {
555             Strcat(discosyms, "u");
556             if (!traditional) {
557                 any.a_int = 'u';
558                 add_menu(tmpwin, NO_GLYPH, &any, menulet++, 0, ATR_NONE,
559                          unique_items, MENU_UNSELECTED);
560             }
561             break;
562         }
563
564     /* check whether we've discovered any artifacts */
565     if (disp_artifact_discoveries(WIN_ERR) > 0) {
566         Strcat(discosyms, "a");
567         if (!traditional) {
568             any.a_int = 'a';
569             add_menu(tmpwin, NO_GLYPH, &any, menulet++, 0, ATR_NONE,
570                      artifact_items, MENU_UNSELECTED);
571         }
572     }
573
574     /* collect classes with discoveries, in packorder ordering; several
575        classes are omitted from packorder and one is of interest here */
576     Strcpy(allclasses, flags.inv_order);
577     if (!index(allclasses, VENOM_CLASS))
578         (void) strkitten(allclasses, VENOM_CLASS); /* append char to string */
579     /* construct discosyms[] */
580     for (s = allclasses; *s; ++s) {
581         oclass = *s;
582         c = def_oc_syms[(int) oclass].sym;
583         for (i = bases[(int) oclass];
584              i < NUM_OBJECTS && objects[i].oc_class == oclass; ++i)
585             if ((dis = disco[i]) != 0 && interesting_to_discover(dis)) {
586                 if (!index(discosyms, c)) {
587                     Sprintf(eos(discosyms), "%c", c);
588                     if (!traditional) {
589                         any.a_int = c;
590                         add_menu(tmpwin, NO_GLYPH, &any, menulet++, c,
591                                  ATR_NONE, oclass_to_name(oclass, buf),
592                                  MENU_UNSELECTED);
593                     }
594                 }
595             }
596     }
597
598     /* there might not be anything for us to do... */
599     if (!discosyms[0]) {
600 /*JP
601         You(havent_discovered_any, "items");
602 */
603         You(havent_discovered_any, "\83A\83C\83e\83\80");
604         if (tmpwin != WIN_ERR)
605             destroy_nhwindow(tmpwin);
606         return 0;
607     }
608
609     /* have player choose a class */
610     c = '\0'; /* class not chosen yet */
611     if (traditional) {
612         /* we'll prompt even if there's only one viable class; we add all
613            nonviable classes as unseen acceptable choices so player can ask
614            for discoveries of any class whether it has discoveries or not */
615         for (s = allclasses, xtras = 0; *s; ++s) {
616             c = def_oc_syms[(int) *s].sym;
617             if (!index(discosyms, c)) {
618                 if (!xtras++)
619                     (void) strkitten(discosyms, '\033');
620                 (void) strkitten(discosyms, c);
621             }
622         }
623         /* get the class (via its symbol character) */
624         c = yn_function(prompt, discosyms, '\0');
625         savech(c);
626         if (!c)
627             clear_nhwindow(WIN_MESSAGE);
628     } else {
629         /* menustyle:full or menustyle:partial */
630         if (!discosyms[1] && flags.menu_style == MENU_PARTIAL) {
631             /* only one class; menustyle:partial normally jumps past class
632                filtering straight to final menu so skip class filter here */
633             c = discosyms[0];
634         } else {
635             /* more than one choice, or menustyle:full which normally has
636                an intermediate class selection menu before the final menu */
637             end_menu(tmpwin, prompt);
638             i = select_menu(tmpwin, PICK_ONE, &pick_list);
639             if (i > 0) {
640                 c = pick_list[0].item.a_int;
641                 free((genericptr_t) pick_list);
642             } /* else c stays 0 */
643         }
644         destroy_nhwindow(tmpwin);
645     }
646     if (!c)
647         return 0; /* player declined to make a selection */
648
649     /*
650      * show discoveries for object class c
651      */
652     tmpwin = create_nhwindow(NHW_MENU);
653     ct = 0;
654     switch (c) {
655     case 'u':
656         putstr(tmpwin, iflags.menu_headings,
657                upstart(strcpy(buf, unique_items)));
658         for (i = 0; i < SIZE(uniq_objs); i++)
659             if (objects[uniq_objs[i]].oc_name_known) {
660                 Sprintf(buf, "  %s", OBJ_NAME(objects[uniq_objs[i]]));
661                 putstr(tmpwin, 0, buf);
662                 ++ct;
663             }
664         if (!ct)
665             You(havent_discovered_any, unique_items);
666         break;
667     case 'a':
668         /* disp_artifact_discoveries() includes a header */
669         ct = disp_artifact_discoveries(tmpwin);
670         if (!ct)
671             You(havent_discovered_any, artifact_items);
672         break;
673     default:
674         oclass = def_char_to_objclass(c);
675 /*JP
676         Sprintf(buf, "Discovered %s", let_to_name(oclass, FALSE, FALSE));
677 */
678         Sprintf(buf, "\94­\8c©\82µ\82½%s", let_to_name(oclass, FALSE, FALSE));
679         putstr(tmpwin, iflags.menu_headings, buf);
680         for (i = bases[(int) oclass];
681              i < NUM_OBJECTS && objects[i].oc_class == oclass; ++i) {
682             if ((dis = disco[i]) != 0 && interesting_to_discover(dis)) {
683                 Sprintf(buf, "%s %s",
684                         objects[dis].oc_pre_discovered ? "*" : " ",
685                         obj_typename(dis));
686                 putstr(tmpwin, 0, buf);
687                 ++ct;
688             }
689         }
690         if (!ct)
691             You(havent_discovered_any, oclass_to_name(oclass, buf));
692         break;
693     }
694     if (ct)
695         display_nhwindow(tmpwin, TRUE);
696     destroy_nhwindow(tmpwin);
697     return 0;
698 }
699
700 /* put up nameable subset of discoveries list as a menu */
701 void
702 rename_disco()
703 {
704     register int i, dis;
705     int ct = 0, mn = 0, sl;
706     char *s, oclass, prev_class;
707     winid tmpwin;
708     anything any;
709     menu_item *selected = 0;
710
711     any = zeroany;
712     tmpwin = create_nhwindow(NHW_MENU);
713     start_menu(tmpwin);
714
715     /*
716      * Skip the "unique objects" section (each will appear within its
717      * regular class if it is nameable) and the artifacts section.
718      * We assume that classes omitted from packorder aren't nameable
719      * so we skip venom too.
720      */
721
722     /* for each class, show discoveries in that class */
723     for (s = flags.inv_order; *s; s++) {
724         oclass = *s;
725         prev_class = oclass + 1; /* forced different from oclass */
726         for (i = bases[(int) oclass];
727              i < NUM_OBJECTS && objects[i].oc_class == oclass; i++) {
728             dis = disco[i];
729             if (!dis || !interesting_to_discover(dis))
730                 continue;
731             ct++;
732             if (!objtyp_is_callable(dis))
733                 continue;
734             mn++;
735
736             if (oclass != prev_class) {
737                 any.a_int = 0;
738                 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
739                          let_to_name(oclass, FALSE, FALSE),
740                          MENU_UNSELECTED);
741                 prev_class = oclass;
742             }
743             any.a_int = dis;
744             add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
745                      obj_typename(dis), MENU_UNSELECTED);
746         }
747     }
748     if (ct == 0) {
749 /*JP
750         You("haven't discovered anything yet...");
751 */
752         You("\82Ü\82¾\89½\82à\94­\8c©\82µ\82Ä\82¢\82È\82¢\81D\81D\81D");
753     } else if (mn == 0) {
754 /*JP
755         pline("None of your discoveries can be assigned names...");
756 */
757         pline("\96¼\91O\82Ì\95t\82¯\82ç\82ê\82é\94­\8c©\95¨\82Í\82È\82¢\81D\81D\81D");
758     } else {
759 /*JP
760         end_menu(tmpwin, "Pick an object type to name");
761 */
762         end_menu(tmpwin, "\96¼\91O\82ð\95t\82¯\82é\83I\83u\83W\83F\83N\83g\82Ì\8eí\97Þ\82ð\91I\82ñ\82Å\82­\82¾\82³\82¢");
763         dis = STRANGE_OBJECT;
764         sl = select_menu(tmpwin, PICK_ONE, &selected);
765         if (sl > 0) {
766             dis = selected[0].item.a_int;
767             free((genericptr_t) selected);
768         }
769         if (dis != STRANGE_OBJECT) {
770             struct obj odummy;
771
772             odummy = zeroobj;
773             odummy.otyp = dis;
774             odummy.oclass = objects[dis].oc_class;
775             odummy.quan = 1L;
776             odummy.known = !objects[dis].oc_uses_known;
777             odummy.dknown = 1;
778             docall(&odummy);
779         }
780     }
781     destroy_nhwindow(tmpwin);
782     return;
783 }
784
785 /*o_init.c*/