OSDN Git Service

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