OSDN Git Service

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