OSDN Git Service

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