OSDN Git Service

fix #36207
[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     char *s;
497
498     Strcpy(buf, let_to_name(oclass, FALSE, FALSE));
499     for (s = buf; *s; ++s)
500         *s = lowc(*s);
501     return buf;
502 }
503
504 /* the '`' command - show discovered object types for one class */
505 int
506 doclassdisco()
507 {
508     static NEARDATA const char
509         prompt[] = "View discoveries for which sort of objects?",
510         havent_discovered_any[] = "haven't discovered any %s yet.",
511         unique_items[] = "unique items",
512         artifact_items[] = "artifacts";
513     char *s, c, oclass, menulet, allclasses[MAXOCLASSES],
514         discosyms[2 + MAXOCLASSES + 1], buf[BUFSZ];
515     int i, ct, dis, xtras;
516     boolean traditional;
517     winid tmpwin;
518     anything any;
519     menu_item *pick_list = 0;
520
521     discosyms[0] = '\0';
522     traditional = (flags.menu_style == MENU_TRADITIONAL
523                    || flags.menu_style == MENU_COMBINATION);
524     tmpwin = !traditional ? create_nhwindow(NHW_MENU) : WIN_ERR;
525     any = zeroany;
526     menulet = 'a';
527
528     /* check whether we've discovered any unique objects */
529     for (i = 0; i < SIZE(uniq_objs); i++)
530         if (objects[uniq_objs[i]].oc_name_known) {
531             Strcat(discosyms, "u");
532             if (!traditional) {
533                 any.a_int = 'u';
534                 add_menu(tmpwin, NO_GLYPH, &any, menulet++, 0, ATR_NONE,
535                          unique_items, MENU_UNSELECTED);
536             }
537             break;
538         }
539
540     /* check whether we've discovered any artifacts */
541     if (disp_artifact_discoveries(WIN_ERR) > 0) {
542         Strcat(discosyms, "a");
543         if (!traditional) {
544             any.a_int = 'a';
545             add_menu(tmpwin, NO_GLYPH, &any, menulet++, 0, ATR_NONE,
546                      artifact_items, MENU_UNSELECTED);
547         }
548     }
549
550     /* collect classes with discoveries, in packorder ordering; several
551        classes are omitted from packorder and one is of interest here */
552     Strcpy(allclasses, flags.inv_order);
553     if (!index(allclasses, VENOM_CLASS))
554         Sprintf(eos(allclasses), "%c", VENOM_CLASS);
555     /* construct discosyms[] */
556     for (s = allclasses; *s; ++s) {
557         oclass = *s;
558         c = def_oc_syms[(int) oclass].sym;
559         for (i = bases[(int) oclass];
560              i < NUM_OBJECTS && objects[i].oc_class == oclass; ++i)
561             if ((dis = disco[i]) != 0 && interesting_to_discover(dis)) {
562                 if (!index(discosyms, c)) {
563                     Sprintf(eos(discosyms), "%c", c);
564                     if (!traditional) {
565                         any.a_int = c;
566                         add_menu(tmpwin, NO_GLYPH, &any, menulet++, c,
567                                  ATR_NONE, oclass_to_name(oclass, buf),
568                                  MENU_UNSELECTED);
569                     }
570                 }
571             }
572     }
573
574     /* there might not be anything for us to do... */
575     if (!discosyms[0]) {
576         You(havent_discovered_any, "items");
577         if (tmpwin != WIN_ERR)
578             destroy_nhwindow(tmpwin);
579         return 0;
580     }
581
582     /* have player choose a class */
583     c = '\0'; /* class not chosen yet */
584     if (traditional) {
585         /* we'll prompt even if there's only one viable class; we add all
586            nonviable classes as unseen acceptable choices so player can ask
587            for discoveries of any class whether it has discoveries or not */
588         for (s = allclasses, xtras = 0; *s; ++s) {
589             c = def_oc_syms[(int) *s].sym;
590             if (!index(discosyms, c)) {
591                 if (!xtras++)
592                     Sprintf(eos(discosyms), "%c", '\033');
593                 Sprintf(eos(discosyms), "%c", c);
594             }
595         }
596         /* get the class (via its symbol character) */
597         c = yn_function(prompt, discosyms, '\0');
598         savech(c);
599         if (!c)
600             clear_nhwindow(WIN_MESSAGE);
601     } else {
602         /* menustyle:full or menustyle:partial */
603         if (!discosyms[1] && flags.menu_style == MENU_PARTIAL) {
604             /* only one class; menustyle:partial normally jumps past class
605                filtering straight to final menu so skip class filter here */
606             c = discosyms[0];
607         } else {
608             /* more than one choice, or menustyle:full which normally has
609                an intermediate class selection menu before the final menu */
610             end_menu(tmpwin, prompt);
611             i = select_menu(tmpwin, PICK_ONE, &pick_list);
612             if (i > 0) {
613                 c = pick_list[0].item.a_int;
614                 free((genericptr_t) pick_list);
615             } /* else c stays 0 */
616         }
617         destroy_nhwindow(tmpwin);
618     }
619     if (!c)
620         return 0; /* player declined to make a selection */
621
622     /*
623      * show discoveries for object class c
624      */
625     tmpwin = create_nhwindow(NHW_MENU);
626     ct = 0;
627     switch (c) {
628     case 'u':
629         putstr(tmpwin, iflags.menu_headings,
630                upstart(strcpy(buf, unique_items)));
631         for (i = 0; i < SIZE(uniq_objs); i++)
632             if (objects[uniq_objs[i]].oc_name_known) {
633                 Sprintf(buf, "  %s", OBJ_NAME(objects[uniq_objs[i]]));
634                 putstr(tmpwin, 0, buf);
635                 ++ct;
636             }
637         if (!ct)
638             You(havent_discovered_any, unique_items);
639         break;
640     case 'a':
641         /* disp_artifact_discoveries() includes a header */
642         ct = disp_artifact_discoveries(tmpwin);
643         if (!ct)
644             You(havent_discovered_any, artifact_items);
645         break;
646     default:
647         oclass = def_char_to_objclass(c);
648         Sprintf(buf, "Discovered %s", let_to_name(oclass, FALSE, FALSE));
649         putstr(tmpwin, iflags.menu_headings, buf);
650         for (i = bases[(int) oclass];
651              i < NUM_OBJECTS && objects[i].oc_class == oclass; ++i) {
652             if ((dis = disco[i]) != 0 && interesting_to_discover(dis)) {
653                 Sprintf(buf, "%s %s",
654                         objects[dis].oc_pre_discovered ? "*" : " ",
655                         obj_typename(dis));
656                 putstr(tmpwin, 0, buf);
657                 ++ct;
658             }
659         }
660         if (!ct)
661             You(havent_discovered_any, oclass_to_name(oclass, buf));
662         break;
663     }
664     if (ct)
665         display_nhwindow(tmpwin, TRUE);
666     destroy_nhwindow(tmpwin);
667     return 0;
668 }
669
670 /* put up nameable subset of discoveries list as a menu */
671 void
672 rename_disco()
673 {
674     register int i, dis;
675     int ct = 0, mn = 0, sl;
676     char *s, oclass, prev_class;
677     winid tmpwin;
678     anything any;
679     menu_item *selected = 0;
680
681     any = zeroany;
682     tmpwin = create_nhwindow(NHW_MENU);
683     start_menu(tmpwin);
684
685     /*
686      * Skip the "unique objects" section (each will appear within its
687      * regular class if it is nameable) and the artifacts section.
688      * We assume that classes omitted from packorder aren't nameable
689      * so we skip venom too.
690      */
691
692     /* for each class, show discoveries in that class */
693     for (s = flags.inv_order; *s; s++) {
694         oclass = *s;
695         prev_class = oclass + 1; /* forced different from oclass */
696         for (i = bases[(int) oclass];
697              i < NUM_OBJECTS && objects[i].oc_class == oclass; i++) {
698             dis = disco[i];
699             if (!dis || !interesting_to_discover(dis))
700                 continue;
701             ct++;
702             if (!objtyp_is_callable(dis))
703                 continue;
704             mn++;
705
706             if (oclass != prev_class) {
707                 any.a_int = 0;
708                 add_menu(tmpwin, NO_GLYPH, &any, ' ', iflags.menu_headings,
709                          ATR_NONE, let_to_name(oclass, FALSE, FALSE),
710                          MENU_UNSELECTED);
711                 prev_class = oclass;
712             }
713             any.a_int = dis;
714             add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
715                      obj_typename(dis), MENU_UNSELECTED);
716         }
717     }
718     if (ct == 0) {
719         You("haven't discovered anything yet...");
720     } else if (mn == 0) {
721         pline("None of your discoveries can be assigned names...");
722     } else {
723         end_menu(tmpwin, "Pick an object type to name");
724         dis = STRANGE_OBJECT;
725         sl = select_menu(tmpwin, PICK_ONE, &selected);
726         if (sl > 0) {
727             dis = selected[0].item.a_int;
728             free((genericptr_t) selected);
729         }
730         if (dis != STRANGE_OBJECT) {
731             struct obj odummy;
732
733             odummy = zeroobj;
734             odummy.otyp = dis;
735             odummy.oclass = objects[dis].oc_class;
736             odummy.quan = 1L;
737             odummy.known = !objects[dis].oc_uses_known;
738             odummy.dknown = 1;
739             docall(&odummy);
740         }
741     }
742     destroy_nhwindow(tmpwin);
743     return;
744 }
745
746 /*o_init.c*/