OSDN Git Service

rearrange main dungeon
[nethackexpress/trunk.git] / src / o_init.c
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. */
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
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] =
37                         glyph2tile[objects[i].oc_descr_idx + GLYPH_OBJ_OFF];
38
39         for (i = 0; i < NUM_OBJECTS; i++)
40                 glyph2tile[i + GLYPH_OBJ_OFF] = tmp_tilemap[i];
41 }
42 #endif  /* USE_TILES */
43
44 STATIC_OVL void
45 setgemprobs(dlev)
46 d_level *dlev;
47 {
48         int j, first, lev;
49
50         if (dlev)
51             lev = (ledger_no(dlev) > maxledgerno())
52                                 ? maxledgerno() : ledger_no(dlev);
53         else
54             lev = 0;
55         first = bases[GEM_CLASS];
56
57         for(j = 0; j < 9-lev/3; j++)
58                 objects[first+j].oc_prob = 0;
59         first += j;
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",
63                         first, j, LAST_GEM);
64                 wait_synch();
65             }
66         for (j = first; j <= LAST_GEM; j++)
67                 objects[j].oc_prob = (171+j-first)/(LAST_GEM+1-first);
68 }
69
70 /* shuffle descriptions on objects o_low to o_high */
71 STATIC_OVL void
72 shuffle(o_low, o_high, domaterial)
73         int o_low, o_high;
74         boolean domaterial;
75 {
76         int i, j, num_to_shuffle;
77         short sw;
78         int color;
79
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;
83
84         for (j=o_low; j <= o_high; j++) {
85                 if (objects[j].oc_name_known) continue;
86                 do
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;
98
99                 /* shuffle material */
100                 if (domaterial) {
101                         sw = objects[j].oc_material;
102                         objects[j].oc_material = objects[i].oc_material;
103                         objects[i].oc_material = sw;
104                 }
105         }
106 }
107
108 void
109 init_objects()
110 {
111 register int i, first, last, sum;
112 register char oclass;
113 #ifdef TEXTCOLOR
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
117 #else
118 # define COPY_OBJ_DESCR(o_dst,o_src) o_dst.oc_descr_idx = o_src.oc_descr_idx
119 #endif
120
121         /* bug fix to prevent "initialization error" abort on Intel Xenix.
122          * reported by mikew@semike
123          */
124         for (i = 0; i < MAXOCLASSES; i++)
125                 bases[i] = 0;
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 */
131         first = 0;
132         while( first < NUM_OBJECTS ) {
133                 oclass = objects[first].oc_class;
134                 last = first+1;
135                 while (last < NUM_OBJECTS && objects[last].oc_class == oclass) last++;
136                 bases[(int)oclass] = first;
137
138                 if (oclass == GEM_CLASS) {
139                         setgemprobs((d_level *)0);
140
141                         if (rn2(2)) { /* change turquoise from green to blue? */
142                             COPY_OBJ_DESCR(objects[TURQUOISE],objects[SAPPHIRE]);
143                         }
144                         if (rn2(2)) { /* change aquamarine from green to blue? */
145                             COPY_OBJ_DESCR(objects[AQUAMARINE],objects[SAPPHIRE]);
146                         }
147                         switch (rn2(4)) { /* change fluorite from violet? */
148                             case 0:  break;
149                             case 1:     /* blue */
150                                 COPY_OBJ_DESCR(objects[FLUORITE],objects[SAPPHIRE]);
151                                 break;
152                             case 2:     /* white */
153                                 COPY_OBJ_DESCR(objects[FLUORITE],objects[DIAMOND]);
154                                 break;
155                             case 3:     /* green */
156                                 COPY_OBJ_DESCR(objects[FLUORITE],objects[EMERALD]);
157                                 break;
158                         }
159                 }
160         check:
161                 sum = 0;
162                 for(i = first; i < last; i++) sum += objects[i].oc_prob;
163                 if(sum == 0) {
164                         for(i = first; i < last; i++)
165                             objects[i].oc_prob = (1000+i-first)/(last-first);
166                         goto check;
167                 }
168                 if(sum != 1000)
169                         error("init-prob error for class %d (%d%%)", oclass, sum);
170                 first = last;
171         }
172         /* shuffle descriptions */
173         shuffle_all();
174 #ifdef USE_TILES
175         shuffle_tiles();
176 #endif
177 }
178
179 STATIC_OVL void
180 shuffle_all()
181 {
182         int first, last, oclass;
183
184         for (oclass = 1; oclass < MAXOCLASSES; oclass++) {
185                 first = bases[oclass];
186                 last = first+1;
187                 while (last < NUM_OBJECTS && objects[last].oc_class == oclass)
188                         last++;
189
190                 if (OBJ_DESCR(objects[first]) != (char *)0 &&
191                                 oclass != TOOL_CLASS &&
192                                 oclass != WEAPON_CLASS &&
193                                 oclass != ARMOR_CLASS &&
194                                 oclass != GEM_CLASS) {
195                         int j = last-1;
196
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)
203                                 j--;
204                         }
205
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.
210                          */
211                         shuffle(first, j, TRUE);
212                 }
213         }
214
215         /* shuffle the helmets */
216         shuffle(HELMET, HELM_OF_TELEPATHY, FALSE);
217
218         /* shuffle the gloves */
219         shuffle(LEATHER_GLOVES, GAUNTLETS_OF_DEXTERITY, FALSE);
220
221         /* shuffle the cloaks */
222         shuffle(CLOAK_OF_PROTECTION, CLOAK_OF_DISPLACEMENT, FALSE);
223
224         /* shuffle the boots [if they change, update find_skates() below] */
225         shuffle(SPEED_BOOTS, LEVITATION_BOOTS, FALSE);
226 }
227
228 /* find the object index for snow boots; used [once] by slippery ice code */
229 int
230 find_skates()
231 {
232     register int i;
233     register const char *s;
234
235     for (i = SPEED_BOOTS; i <= LEVITATION_BOOTS; i++)
236         if ((s = OBJ_DESCR(objects[i])) != 0 && !strcmp(s, "snow boots"))
237             return i;
238
239     impossible("snow boots not found?");
240     return -1;  /* not 0, or caller would try again each move */
241 }
242
243 void
244 oinit()                 /* level dependent initialization */
245 {
246         setgemprobs(&u.uz);
247 }
248
249 void
250 savenames(fd, mode)
251 int fd, mode;
252 {
253         register int i;
254         unsigned int len;
255
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);
261         }
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);
271                 }
272                 if (release_data(mode)) {
273                     free((genericptr_t)objects[i].oc_uname);
274                     objects[i].oc_uname = 0;
275                 }
276             }
277 }
278
279 void
280 restnames(fd)
281 register int fd;
282 {
283         register int i;
284         unsigned int len;
285
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);
294             }
295 #ifdef USE_TILES
296         shuffle_tiles();
297 #endif
298 }
299
300 void
301 discover_object(oindx, mark_as_known, credit_hero)
302 register int oindx;
303 boolean mark_as_known;
304 boolean credit_hero;
305 {
306     if (!objects[oindx].oc_name_known) {
307         register int dindx, acls = objects[oindx].oc_class;
308
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...
312          */
313         for (dindx = bases[acls]; disco[dindx] != 0; dindx++)
314             if (disco[dindx] == oindx) break;
315         disco[dindx] = oindx;
316
317         if (mark_as_known) {
318             objects[oindx].oc_name_known = 1;
319             if (credit_hero) exercise(A_WIS, TRUE);
320         }
321         if (moves > 1L) update_inventory();
322     }
323 }
324
325 /* if a class name has been cleared, we may need to purge it from disco[] */
326 void
327 undiscover_object(oindx)
328 register int oindx;
329 {
330     if (!objects[oindx].oc_name_known) {
331         register int dindx, acls = objects[oindx].oc_class;
332         register boolean found = FALSE;
333
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++)
338             if (found)
339                 disco[dindx-1] = disco[dindx];
340             else if (disco[dindx] == oindx)
341                 found = TRUE;
342
343         /* clear last slot */
344         if (found) disco[dindx-1] = 0;
345         else impossible("named object not in disco");
346         update_inventory();
347     }
348 }
349
350 STATIC_OVL boolean
351 interesting_to_discover(i)
352 register int i;
353 {
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)));
357 }
358
359 /* items that should stand out once they're known */
360 static short uniq_objs[] = {
361         AMULET_OF_YENDOR,
362         SPE_BOOK_OF_THE_DEAD,
363         CANDELABRUM_OF_INVOCATION,
364         BELL_OF_OPENING,
365 };
366
367 int
368 dodiscovered()                          /* free after Robert Viduya */
369 {
370     register int i, dis;
371     int ct = 0;
372     char *s, oclass, prev_class, classes[MAXOCLASSES];
373     winid tmpwin;
374         char buf[BUFSZ];
375
376     tmpwin = create_nhwindow(NHW_MENU);
377     putstr(tmpwin, 0, "Discoveries");
378     putstr(tmpwin, 0, "");
379
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) {
384             if (!dis++)
385                 putstr(tmpwin, iflags.menu_headings, "Unique Items");
386                 Sprintf(buf, "  %s", OBJ_NAME(objects[uniq_objs[i]]));
387             putstr(tmpwin, 0, buf);
388             ++ct;
389         }
390     /* display any known artifacts as another pseudo-class */
391     ct += disp_artifact_discoveries(tmpwin);
392
393     /* several classes are omitted from packorder; one is of interest here */
394     Strcpy(classes, flags.inv_order);
395     if (!index(classes, VENOM_CLASS)) {
396         s = eos(classes);
397         *s++ = VENOM_CLASS;
398         *s = '\0';
399     }
400
401     for (s = classes; *s; s++) {
402         oclass = *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)) {
407                 ct++;
408                 if (oclass != prev_class) {
409                     putstr(tmpwin, iflags.menu_headings, let_to_name(oclass, FALSE));
410                     prev_class = oclass;
411                 }
412                 Sprintf(buf, "%s %s",(objects[dis].oc_pre_discovered ? "*" : " "),
413                                 obj_typename(dis));
414                 putstr(tmpwin, 0, buf);
415             }
416         }
417     }
418     if (ct == 0) {
419         You("haven't discovered anything yet...");
420     } else
421         display_nhwindow(tmpwin, TRUE);
422     destroy_nhwindow(tmpwin);
423
424     return 0;
425 }
426
427 /*o_init.c*/