1 /* SCCS Id: @(#)o_init.c 3.4 1999/12/09 */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
6 #include "lev.h" /* save & restore info */
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));
14 static NEARDATA short disco[NUM_OBJECTS] = DUMMY;
17 STATIC_DCL void NDECL(shuffle_tiles);
18 extern short glyph2tile[]; /* from tile.c */
20 /* Shuffle tile assignments to match descriptions, so a red potion isn't
21 * displayed with a blue tile and so on.
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
33 short tmp_tilemap[NUM_OBJECTS];
35 for (i = 0; i < NUM_OBJECTS; i++)
37 glyph2tile[objects[i].oc_descr_idx + GLYPH_OBJ_OFF];
39 for (i = 0; i < NUM_OBJECTS; i++)
40 glyph2tile[i + GLYPH_OBJ_OFF] = tmp_tilemap[i];
42 #endif /* USE_TILES */
51 lev = (ledger_no(dlev) > maxledgerno())
52 ? maxledgerno() : ledger_no(dlev);
55 first = bases[GEM_CLASS];
57 for(j = 0; j < 9-lev/3; j++)
58 objects[first+j].oc_prob = 0;
60 if (first > LAST_GEM || objects[first].oc_class != GEM_CLASS ||
61 OBJ_NAME(objects[first]) == (char *)0) {
62 raw_printf("Not enough gems? - first=%d j=%d LAST_GEM=%d",
66 for (j = first; j <= LAST_GEM; j++)
67 objects[j].oc_prob = (171+j-first)/(LAST_GEM+1-first);
70 /* shuffle descriptions on objects o_low to o_high */
72 shuffle(o_low, o_high, domaterial)
76 int i, j, num_to_shuffle;
80 for (num_to_shuffle = 0, j=o_low; j <= o_high; j++)
81 if (!objects[j].oc_name_known) num_to_shuffle++;
82 if (num_to_shuffle < 2) return;
84 for (j=o_low; j <= o_high; j++) {
85 if (objects[j].oc_name_known) continue;
87 i = j + rn2(o_high-j+1);
88 while (objects[i].oc_name_known);
89 sw = objects[j].oc_descr_idx;
90 objects[j].oc_descr_idx = objects[i].oc_descr_idx;
91 objects[i].oc_descr_idx = sw;
92 sw = objects[j].oc_tough;
93 objects[j].oc_tough = objects[i].oc_tough;
94 objects[i].oc_tough = sw;
95 color = objects[j].oc_color;
96 objects[j].oc_color = objects[i].oc_color;
97 objects[i].oc_color = color;
99 /* shuffle material */
101 sw = objects[j].oc_material;
102 objects[j].oc_material = objects[i].oc_material;
103 objects[i].oc_material = sw;
111 register int i, first, last, sum;
112 register char oclass;
114 # define COPY_OBJ_DESCR(o_dst,o_src) \
115 o_dst.oc_descr_idx = o_src.oc_descr_idx,\
116 o_dst.oc_color = o_src.oc_color
118 # define COPY_OBJ_DESCR(o_dst,o_src) o_dst.oc_descr_idx = o_src.oc_descr_idx
121 /* bug fix to prevent "initialization error" abort on Intel Xenix.
122 * reported by mikew@semike
124 for (i = 0; i < MAXOCLASSES; i++)
126 /* initialize object descriptions */
127 for (i = 0; i < NUM_OBJECTS; i++)
128 objects[i].oc_name_idx = objects[i].oc_descr_idx = i;
129 /* init base; if probs given check that they add up to 1000,
130 otherwise compute probs */
132 while( first < NUM_OBJECTS ) {
133 oclass = objects[first].oc_class;
135 while (last < NUM_OBJECTS && objects[last].oc_class == oclass) last++;
136 bases[(int)oclass] = first;
138 if (oclass == GEM_CLASS) {
139 setgemprobs((d_level *)0);
141 if (rn2(2)) { /* change turquoise from green to blue? */
142 COPY_OBJ_DESCR(objects[TURQUOISE],objects[SAPPHIRE]);
144 if (rn2(2)) { /* change aquamarine from green to blue? */
145 COPY_OBJ_DESCR(objects[AQUAMARINE],objects[SAPPHIRE]);
147 switch (rn2(4)) { /* change fluorite from violet? */
150 COPY_OBJ_DESCR(objects[FLUORITE],objects[SAPPHIRE]);
153 COPY_OBJ_DESCR(objects[FLUORITE],objects[DIAMOND]);
156 COPY_OBJ_DESCR(objects[FLUORITE],objects[EMERALD]);
162 for(i = first; i < last; i++) sum += objects[i].oc_prob;
164 for(i = first; i < last; i++)
165 objects[i].oc_prob = (1000+i-first)/(last-first);
169 error("init-prob error for class %d (%d%%)", oclass, sum);
172 /* shuffle descriptions */
182 int first, last, oclass;
184 for (oclass = 1; oclass < MAXOCLASSES; oclass++) {
185 first = bases[oclass];
187 while (last < NUM_OBJECTS && objects[last].oc_class == oclass)
190 if (OBJ_DESCR(objects[first]) != (char *)0 &&
191 oclass != TOOL_CLASS &&
192 oclass != WEAPON_CLASS &&
193 oclass != ARMOR_CLASS &&
194 oclass != GEM_CLASS) {
197 if (oclass == POTION_CLASS)
198 j -= 1; /* only water has a fixed description */
199 else if (oclass == AMULET_CLASS ||
200 oclass == SCROLL_CLASS ||
201 oclass == SPBOOK_CLASS) {
202 while (!objects[j].oc_magic || objects[j].oc_unique)
206 /* non-magical amulets, scrolls, and spellbooks
207 * (ex. imitation Amulets, blank, scrolls of mail)
208 * and one-of-a-kind magical artifacts at the end of
209 * their class in objects[] have fixed descriptions.
211 shuffle(first, j, TRUE);
215 /* shuffle the helmets */
216 shuffle(HELMET, HELM_OF_TELEPATHY, FALSE);
218 /* shuffle the gloves */
219 shuffle(LEATHER_GLOVES, GAUNTLETS_OF_DEXTERITY, FALSE);
221 /* shuffle the cloaks */
222 shuffle(CLOAK_OF_PROTECTION, CLOAK_OF_DISPLACEMENT, FALSE);
224 /* shuffle the boots [if they change, update find_skates() below] */
225 shuffle(SPEED_BOOTS, LEVITATION_BOOTS, FALSE);
228 /* find the object index for snow boots; used [once] by slippery ice code */
233 register const char *s;
235 for (i = SPEED_BOOTS; i <= LEVITATION_BOOTS; i++)
236 if ((s = OBJ_DESCR(objects[i])) != 0 && !strcmp(s, "snow boots"))
239 impossible("snow boots not found?");
240 return -1; /* not 0, or caller would try again each move */
244 oinit() /* level dependent initialization */
256 if (perform_bwrite(mode)) {
257 bwrite(fd, (genericptr_t)bases, sizeof bases);
258 bwrite(fd, (genericptr_t)disco, sizeof disco);
259 bwrite(fd, (genericptr_t)objects,
260 sizeof(struct objclass) * NUM_OBJECTS);
262 /* as long as we use only one version of Hack we
263 need not save oc_name and oc_descr, but we must save
264 oc_uname for all objects */
265 for (i = 0; i < NUM_OBJECTS; i++)
266 if (objects[i].oc_uname) {
267 if (perform_bwrite(mode)) {
268 len = strlen(objects[i].oc_uname)+1;
269 bwrite(fd, (genericptr_t)&len, sizeof len);
270 bwrite(fd, (genericptr_t)objects[i].oc_uname, len);
272 if (release_data(mode)) {
273 free((genericptr_t)objects[i].oc_uname);
274 objects[i].oc_uname = 0;
286 mread(fd, (genericptr_t) bases, sizeof bases);
287 mread(fd, (genericptr_t) disco, sizeof disco);
288 mread(fd, (genericptr_t) objects, sizeof(struct objclass) * NUM_OBJECTS);
289 for (i = 0; i < NUM_OBJECTS; i++)
290 if (objects[i].oc_uname) {
291 mread(fd, (genericptr_t) &len, sizeof len);
292 objects[i].oc_uname = (char *) alloc(len);
293 mread(fd, (genericptr_t)objects[i].oc_uname, len);
301 discover_object(oindx, mark_as_known, credit_hero)
303 boolean mark_as_known;
306 if (!objects[oindx].oc_name_known) {
307 register int dindx, acls = objects[oindx].oc_class;
309 /* Loop thru disco[] 'til we find the target (which may have been
310 uname'd) or the next open slot; one or the other will be found
311 before we reach the next class...
313 for (dindx = bases[acls]; disco[dindx] != 0; dindx++)
314 if (disco[dindx] == oindx) break;
315 disco[dindx] = oindx;
318 objects[oindx].oc_name_known = 1;
319 if (credit_hero) exercise(A_WIS, TRUE);
321 if (moves > 1L) update_inventory();
325 /* if a class name has been cleared, we may need to purge it from disco[] */
327 undiscover_object(oindx)
330 if (!objects[oindx].oc_name_known) {
331 register int dindx, acls = objects[oindx].oc_class;
332 register boolean found = FALSE;
334 /* find the object; shift those behind it forward one slot */
335 for (dindx = bases[acls];
336 dindx < NUM_OBJECTS && disco[dindx] != 0
337 && objects[dindx].oc_class == acls; dindx++)
339 disco[dindx-1] = disco[dindx];
340 else if (disco[dindx] == oindx)
343 /* clear last slot */
344 if (found) disco[dindx-1] = 0;
345 else impossible("named object not in disco");
351 interesting_to_discover(i)
354 /* Pre-discovered objects are now printed with a '*' */
355 return((boolean)(objects[i].oc_uname != (char *)0 ||
356 (objects[i].oc_name_known && OBJ_DESCR(objects[i]) != (char *)0)));
359 /* items that should stand out once they're known */
360 static short uniq_objs[] = {
362 SPE_BOOK_OF_THE_DEAD,
363 CANDELABRUM_OF_INVOCATION,
368 dodiscovered() /* free after Robert Viduya */
372 char *s, oclass, prev_class, classes[MAXOCLASSES];
376 tmpwin = create_nhwindow(NHW_MENU);
377 putstr(tmpwin, 0, "Discoveries");
378 putstr(tmpwin, 0, "");
380 /* gather "unique objects" into a pseudo-class; note that they'll
381 also be displayed individually within their regular class */
382 for (i = dis = 0; i < SIZE(uniq_objs); i++)
383 if (objects[uniq_objs[i]].oc_name_known) {
385 putstr(tmpwin, iflags.menu_headings, "Unique Items");
386 Sprintf(buf, " %s", OBJ_NAME(objects[uniq_objs[i]]));
387 putstr(tmpwin, 0, buf);
390 /* display any known artifacts as another pseudo-class */
391 ct += disp_artifact_discoveries(tmpwin);
393 /* several classes are omitted from packorder; one is of interest here */
394 Strcpy(classes, flags.inv_order);
395 if (!index(classes, VENOM_CLASS)) {
401 for (s = classes; *s; s++) {
403 prev_class = oclass + 1; /* forced different from oclass */
404 for (i = bases[(int)oclass];
405 i < NUM_OBJECTS && objects[i].oc_class == oclass; i++) {
406 if ((dis = disco[i]) && interesting_to_discover(dis)) {
408 if (oclass != prev_class) {
409 putstr(tmpwin, iflags.menu_headings, let_to_name(oclass, FALSE));
412 Sprintf(buf, "%s %s",(objects[dis].oc_pre_discovered ? "*" : " "),
414 putstr(tmpwin, 0, buf);
419 You("haven't discovered anything yet...");
421 display_nhwindow(tmpwin, TRUE);
422 destroy_nhwindow(tmpwin);