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. */
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. */
11 #include "lev.h" /* save & restore info */
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 *));
19 static NEARDATA short disco[NUM_OBJECTS] = DUMMY;
22 STATIC_DCL void NDECL(shuffle_tiles);
23 extern short glyph2tile[]; /* from tile.c */
25 /* Shuffle tile assignments to match descriptions, so a red potion isn't
26 * displayed with a blue tile and so on.
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
38 short tmp_tilemap[NUM_OBJECTS];
40 for (i = 0; i < NUM_OBJECTS; i++)
41 tmp_tilemap[i] = glyph2tile[objects[i].oc_descr_idx + GLYPH_OBJ_OFF];
43 for (i = 0; i < NUM_OBJECTS; i++)
44 glyph2tile[i + GLYPH_OBJ_OFF] = tmp_tilemap[i];
46 #endif /* USE_TILES */
55 lev = (ledger_no(dlev) > maxledgerno()) ? maxledgerno()
59 first = bases[GEM_CLASS];
61 for (j = 0; j < 9 - lev / 3; j++)
62 objects[first + j].oc_prob = 0;
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,
70 for (j = first; j <= LAST_GEM; j++)
71 objects[j].oc_prob = (171 + j - first) / (LAST_GEM + 1 - first);
74 /* shuffle descriptions on objects o_low to o_high */
76 shuffle(o_low, o_high, domaterial)
80 int i, j, num_to_shuffle;
84 for (num_to_shuffle = 0, j = o_low; j <= o_high; j++)
85 if (!objects[j].oc_name_known)
87 if (num_to_shuffle < 2)
90 for (j = o_low; j <= o_high; j++) {
91 if (objects[j].oc_name_known)
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;
106 /* shuffle material */
108 sw = objects[j].oc_material;
109 objects[j].oc_material = objects[i].oc_material;
110 objects[i].oc_material = sw;
118 register int i, first, last, sum;
119 register char oclass;
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
124 #define COPY_OBJ_DESCR(o_dst, o_src) o_dst.oc_descr_idx = o_src.oc_descr_idx
127 /* bug fix to prevent "initialization error" abort on Intel Xenix.
128 * reported by mikew@semike
130 for (i = 0; i < MAXOCLASSES; i++)
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 */
138 while (first < NUM_OBJECTS) {
139 oclass = objects[first].oc_class;
141 while (last < NUM_OBJECTS && objects[last].oc_class == oclass)
143 bases[(int) oclass] = first;
145 if (oclass == GEM_CLASS) {
146 setgemprobs((d_level *) 0);
148 if (rn2(2)) { /* change turquoise from green to blue? */
149 COPY_OBJ_DESCR(objects[TURQUOISE], objects[SAPPHIRE]);
151 if (rn2(2)) { /* change aquamarine from green to blue? */
152 COPY_OBJ_DESCR(objects[AQUAMARINE], objects[SAPPHIRE]);
154 switch (rn2(4)) { /* change fluorite from violet? */
158 COPY_OBJ_DESCR(objects[FLUORITE], objects[SAPPHIRE]);
161 COPY_OBJ_DESCR(objects[FLUORITE], objects[DIAMOND]);
164 COPY_OBJ_DESCR(objects[FLUORITE], objects[EMERALD]);
170 for (i = first; i < last; i++)
171 sum += objects[i].oc_prob;
173 for (i = first; i < last; i++)
174 objects[i].oc_prob = (1000 + i - first) / (last - first);
178 error("init-prob error for class %d (%d%%)", oclass, sum);
181 /* shuffle descriptions */
186 objects[WAN_NOTHING].oc_dir = rn2(2) ? NODIR : IMMEDIATE;
189 /* retrieve the range of objects that otyp shares descriptions with */
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 */
195 int i, ocls = objects[otyp].oc_class;
197 /* default is just the object itself */
198 *lo_p = *hi_p = otyp;
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;
212 /* potion of water has the only fixed description */
213 *lo_p = bases[POTION_CLASS];
214 *hi_p = POT_WATER - 1;
219 /* exclude non-magic types and also unique ones */
221 for (i = *lo_p; objects[i].oc_class == ocls; i++)
222 if (objects[i].oc_unique || !objects[i].oc_magic)
231 for (i = *lo_p; objects[i].oc_class == ocls; i++)
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;
244 /* randomize object descriptions */
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,
253 /* sub-class type ranges (one item from each group) */
254 static short shuffle_types[] = {
255 HELMET, LEATHER_GLOVES, CLOAK_OF_PROTECTION, SPEED_BOOTS,
257 int first, last, idx;
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);
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);
272 /* find the object index for snow boots; used [once] by slippery ice code */
277 register const char *s;
279 for (i = SPEED_BOOTS; i <= LEVITATION_BOOTS; i++)
281 if ((s = OBJ_DESCR(objects[i])) != 0 && !strcmp(s, "snow boots"))
283 if ((s = OBJ_DESCR(objects[i])) != 0 && !strcmp(s, "
\90á
\8cC"))
286 impossible("snow boots not found?");
287 return -1; /* not 0, or caller would try again each move */
290 /* level dependent initialization */
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);
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);
320 if (release_data(mode)) {
321 free((genericptr_t) objects[i].oc_uname);
322 objects[i].oc_uname = 0;
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);
349 discover_object(oindx, mark_as_known, credit_hero)
351 boolean mark_as_known;
354 if (!objects[oindx].oc_name_known) {
355 register int dindx, acls = objects[oindx].oc_class;
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...
361 for (dindx = bases[acls]; disco[dindx] != 0; dindx++)
362 if (disco[dindx] == oindx)
364 disco[dindx] = oindx;
367 objects[oindx].oc_name_known = 1;
369 exercise(A_WIS, TRUE);
376 /* if a class name has been cleared, we may need to purge it from disco[] */
378 undiscover_object(oindx)
381 if (!objects[oindx].oc_name_known) {
382 register int dindx, acls = objects[oindx].oc_class;
383 register boolean found = FALSE;
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;
390 disco[dindx - 1] = disco[dindx];
391 else if (disco[dindx] == oindx)
394 /* clear last slot */
396 disco[dindx - 1] = 0;
398 impossible("named object not in disco");
404 interesting_to_discover(i)
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));
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,
419 /* the '\' command - show discovered object types */
421 dodiscovered() /* free after Robert Viduya */
425 char *s, oclass, prev_class, classes[MAXOCLASSES], buf[BUFSZ];
428 tmpwin = create_nhwindow(NHW_MENU);
430 putstr(tmpwin, 0, "Discoveries");
432 putstr(tmpwin, 0, "
\94
\8c©
\95¨
\88ê
\97\97");
433 putstr(tmpwin, 0, "");
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) {
441 putstr(tmpwin, iflags.menu_headings, "Unique items");
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);
448 /* display any known artifacts as another pseudo-class */
449 ct += disp_artifact_discoveries(tmpwin);
451 /* several classes are omitted from packorder; one is of interest here */
452 Strcpy(classes, flags.inv_order);
453 if (!index(classes, VENOM_CLASS)) {
459 for (s = classes; *s; 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)) {
466 if (oclass != prev_class) {
467 putstr(tmpwin, iflags.menu_headings,
468 let_to_name(oclass, FALSE, FALSE));
471 Sprintf(buf, "%s %s",
472 (objects[dis].oc_pre_discovered ? "*" : " "),
474 putstr(tmpwin, 0, buf);
480 You("haven't discovered anything yet...");
482 You("
\82Ü
\82¾
\89½
\82à
\94
\8c©
\82µ
\82Ä
\82¢
\82È
\82¢
\81D
\81D
\81D");
484 display_nhwindow(tmpwin, TRUE);
485 destroy_nhwindow(tmpwin);
490 /* lower case let_to_name() output, which differs from def_oc_syms[].name */
492 oclass_to_name(oclass, buf)
496 #if 0 /*JP*//*
\8eg
\82í
\82È
\82¢*/
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)
508 /* the '`' command - show discovered object types for one class */
512 static NEARDATA const char
514 prompt[] = "View discoveries for which sort of objects?",
516 prompt[] = "
\82Ç
\82Ì
\8eí
\97Þ
\82Ì
\94
\8c©
\95¨
\82ð
\8c©
\82Ü
\82·
\82©
\81H",
518 havent_discovered_any[] = "haven't discovered any %s yet.",
520 havent_discovered_any[] = "
\82Ü
\82¾
\89½
\82à%s
\82ð
\94
\8c©
\82µ
\82Ä
\82¢
\82È
\82¢
\81D",
522 unique_items[] = "unique items",
524 unique_items[] = "
\93Á
\8eê
\83A
\83C
\83e
\83\80",
526 artifact_items[] = "artifacts";
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;
535 menu_item *pick_list = 0;
538 traditional = (flags.menu_style == MENU_TRADITIONAL
539 || flags.menu_style == MENU_COMBINATION);
540 tmpwin = !traditional ? create_nhwindow(NHW_MENU) : WIN_ERR;
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");
550 add_menu(tmpwin, NO_GLYPH, &any, menulet++, 0, ATR_NONE,
551 unique_items, MENU_UNSELECTED);
556 /* check whether we've discovered any artifacts */
557 if (disp_artifact_discoveries(WIN_ERR) > 0) {
558 Strcat(discosyms, "a");
561 add_menu(tmpwin, NO_GLYPH, &any, menulet++, 0, ATR_NONE,
562 artifact_items, MENU_UNSELECTED);
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) {
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);
582 add_menu(tmpwin, NO_GLYPH, &any, menulet++, c,
583 ATR_NONE, oclass_to_name(oclass, buf),
590 /* there might not be anything for us to do... */
593 You(havent_discovered_any, "items");
595 You(havent_discovered_any, "
\83A
\83C
\83e
\83\80");
596 if (tmpwin != WIN_ERR)
597 destroy_nhwindow(tmpwin);
601 /* have player choose a class */
602 c = '\0'; /* class not chosen yet */
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)) {
611 Sprintf(eos(discosyms), "%c", '\033');
612 Sprintf(eos(discosyms), "%c", c);
615 /* get the class (via its symbol character) */
616 c = yn_function(prompt, discosyms, '\0');
619 clear_nhwindow(WIN_MESSAGE);
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 */
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);
632 c = pick_list[0].item.a_int;
633 free((genericptr_t) pick_list);
634 } /* else c stays 0 */
636 destroy_nhwindow(tmpwin);
639 return 0; /* player declined to make a selection */
642 * show discoveries for object class c
644 tmpwin = create_nhwindow(NHW_MENU);
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);
657 You(havent_discovered_any, unique_items);
660 /* disp_artifact_discoveries() includes a header */
661 ct = disp_artifact_discoveries(tmpwin);
663 You(havent_discovered_any, artifact_items);
666 oclass = def_char_to_objclass(c);
668 Sprintf(buf, "Discovered %s", let_to_name(oclass, FALSE, FALSE));
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 ? "*" : " ",
678 putstr(tmpwin, 0, buf);
683 You(havent_discovered_any, oclass_to_name(oclass, buf));
687 display_nhwindow(tmpwin, TRUE);
688 destroy_nhwindow(tmpwin);
692 /* put up nameable subset of discoveries list as a menu */
697 int ct = 0, mn = 0, sl;
698 char *s, oclass, prev_class;
701 menu_item *selected = 0;
704 tmpwin = create_nhwindow(NHW_MENU);
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.
714 /* for each class, show discoveries in that class */
715 for (s = flags.inv_order; *s; 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++) {
721 if (!dis || !interesting_to_discover(dis))
724 if (!objtyp_is_callable(dis))
728 if (oclass != prev_class) {
730 add_menu(tmpwin, NO_GLYPH, &any, ' ', iflags.menu_headings,
731 ATR_NONE, let_to_name(oclass, FALSE, FALSE),
736 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
737 obj_typename(dis), MENU_UNSELECTED);
742 You("haven't discovered anything yet...");
744 You("
\82Ü
\82¾
\89½
\82à
\94
\8c©
\82µ
\82Ä
\82¢
\82È
\82¢
\81D
\81D
\81D");
745 } else if (mn == 0) {
747 pline("None of your discoveries can be assigned names...");
749 pline("
\96¼
\91O
\82Ì
\95t
\82¯
\82ç
\82ê
\82é
\94
\8c©
\95¨
\82Í
\82È
\82¢
\81D
\81D
\81D");
752 end_menu(tmpwin, "Pick an object type to name");
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);
758 dis = selected[0].item.a_int;
759 free((genericptr_t) selected);
761 if (dis != STRANGE_OBJECT) {
766 odummy.oclass = objects[dis].oc_class;
768 odummy.known = !objects[dis].oc_uses_known;
773 destroy_nhwindow(tmpwin);