1 | /* SCCS Id: @(#)bones.c 3.3 2000/05/28 */
2 | /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985,1993. */
3 | /* NetHack may be freely redistributed. See license for details. */
4 |
5 | #include "hack.h"
6 | #include "lev.h"
7 |
8 | extern char bones[]; /* from files.c */
9 | #ifdef MFLOPPY
10 | extern long bytes_counted;
11 | #endif
12 |
13 | STATIC_DCL boolean FDECL(no_bones_level, (d_level *));
14 | STATIC_DCL void FDECL(goodfruit, (int));
15 | STATIC_DCL void FDECL(resetobjs,(struct obj *,BOOLEAN_P));
16 | STATIC_DCL void FDECL(drop_upon_death, (struct monst *, struct obj *));
17 |
18 | STATIC_OVL boolean
19 | no_bones_level(lev)
20 | d_level *lev;
21 | {
22 | extern d_level save_dlevel; /* in do.c */
23 | s_level *sptr;
24 |
25 | if (ledger_no(&save_dlevel)) assign_level(lev, &save_dlevel);
26 |
27 | return (boolean)(((sptr = Is_special(lev)) != 0 && !sptr->boneid)
28 | || !dungeons[lev->dnum].boneid
29 | /* no bones on the last or multiway branch levels */
30 | /* in any dungeon (level 1 isn't multiway). */
31 | || Is_botlevel(lev) || (Is_branchlev(lev) && lev->dlevel > 1)
32 | /* no bones in the invocation level */
33 | || (In_hell(lev) && lev->dlevel == dunlevs_in_dungeon(lev) - 1)
34 | );
35 | }
36 |
37 | /* Call this function for each fruit object saved in the bones level: it marks
38 | * that particular type of fruit as existing (the marker is that that type's
39 | * ID is positive instead of negative). This way, when we later save the
40 | * chain of fruit types, we know to only save the types that exist.
41 | */
42 | STATIC_OVL void
43 | goodfruit(id)
44 | int id;
45 | {
46 | register struct fruit *f;
47 |
48 | for(f=ffruit; f; f=f->nextf) {
49 | if(f->fid == -id) {
50 | f->fid = id;
51 | return;
52 | }
53 | }
54 | }
55 |
56 | STATIC_OVL void
57 | resetobjs(ochain,restore)
58 | struct obj *ochain;
59 | boolean restore;
60 | {
61 | struct obj *otmp;
62 |
63 | for (otmp = ochain; otmp; otmp = otmp->nobj) {
64 | if (otmp->cobj)
65 | resetobjs(otmp->cobj,restore);
66 |
67 | if (((otmp->otyp != CORPSE || otmp->corpsenm < SPECIAL_PM)
68 | && otmp->otyp != STATUE)
69 | && (!otmp->oartifact ||
70 | (restore && (exist_artifact(otmp->otyp, ONAME(otmp))
71 | || is_quest_artifact(otmp))))) {
72 | otmp->oartifact = 0;
73 | otmp->onamelth = 0;
74 | *ONAME(otmp) = '\0';
75 | } else if (otmp->oartifact && restore)
76 | artifact_exists(otmp,ONAME(otmp),TRUE);
77 | if (!restore) {
78 | /* do not zero out o_ids for ghost levels anymore */
79 |
80 | if(objects[otmp->otyp].oc_uses_known) otmp->known = 0;
81 | otmp->dknown = otmp->bknown = 0;
82 | otmp->rknown = 0;
83 | otmp->invlet = 0;
84 | otmp->no_charge = 0;
85 |
86 | if (otmp->otyp == SLIME_MOLD) goodfruit(otmp->spe);
87 | #ifdef MAIL
88 | else if (otmp->otyp == SCR_MAIL) otmp->spe = 1;
89 | #endif
90 | else if (otmp->otyp == EGG) otmp->spe = 0;
91 | else if (otmp->otyp == TIN) {
92 | /* make tins of unique monster's meat be empty */
93 | if (otmp->corpsenm >= LOW_PM &&
94 | (mons[otmp->corpsenm].geno & G_UNIQ))
95 | otmp->corpsenm = NON_PM;
96 | } else if (otmp->otyp == AMULET_OF_YENDOR) {
97 | /* no longer the real Amulet */
98 | otmp->otyp = FAKE_AMULET_OF_YENDOR;
99 | curse(otmp);
100 | } else if (otmp->otyp == CANDELABRUM_OF_INVOCATION) {
101 | if (otmp->lamplit)
102 | end_burn(otmp, TRUE);
103 | otmp->otyp = WAX_CANDLE;
104 | otmp->age = 50L; /* assume used */
105 | if (otmp->spe > 0)
106 | otmp->quan = (long)otmp->spe;
107 | otmp->spe = 0;
108 | otmp->owt = weight(otmp);
109 | } else if (otmp->otyp == BELL_OF_OPENING) {
110 | otmp->otyp = BELL;
111 | curse(otmp);
112 | } else if (otmp->otyp == SPE_BOOK_OF_THE_DEAD) {
113 | otmp->otyp = SPE_BLANK_PAPER;
114 | curse(otmp);
115 | }
116 | }
117 | }
118 | }
119 |
120 | STATIC_OVL void
121 | drop_upon_death(mtmp, cont)
122 | struct monst *mtmp;
123 | struct obj *cont;
124 | {
125 | struct obj *otmp;
126 |
127 | while ((otmp = invent) != 0) {
128 | obj_extract_self(otmp);
129 |
130 | otmp->owornmask = 0;
131 | /* lamps don't go out when dropped */
132 | if (cont && obj_is_burning(otmp)) /* smother in statue */
133 | end_burn(otmp, otmp->otyp != MAGIC_LAMP);
134 |
135 | if(otmp->otyp == SLIME_MOLD) goodfruit(otmp->spe);
136 |
137 | if(rn2(5)) curse(otmp);
138 | if (mtmp)
139 | (void) add_to_minv(mtmp, otmp);
140 | else if (cont)
141 | add_to_container(cont, otmp);
142 | else
143 | place_object(otmp, u.ux, u.uy);
144 | }
145 | if(u.ugold) {
146 | long ugold = u.ugold;
147 | if (mtmp) mtmp->mgold = ugold;
148 | else if (cont) add_to_container(cont, mkgoldobj(ugold));
149 | else (void)mkgold(ugold, u.ux, u.uy);
150 | u.ugold = ugold; /* undo mkgoldobj()'s removal */
151 | }
152 | }
153 |
154 | /* check whether bones are feasible */
155 | boolean
156 | can_make_bones()
157 | {
158 | register struct trap *ttmp;
159 |
160 | if (ledger_no(&u.uz) <= 0 || ledger_no(&u.uz) > maxledgerno())
161 | return FALSE;
162 | if (no_bones_level(&u.uz))
163 | return FALSE; /* no bones for specific levels */
164 | if (!Is_branchlev(&u.uz)) {
165 | /* no bones on non-branches with portals */
166 | for(ttmp = ftrap; ttmp; ttmp = ttmp->ntrap)
167 | if (ttmp->ttyp == MAGIC_PORTAL) return FALSE;
168 | }
169 |
170 | if(depth(&u.uz) <= 0 || /* bulletproofing for endgame */
171 | (!rn2(1 + (depth(&u.uz)>>2)) /* fewer ghosts on low levels */
172 | #ifdef WIZARD
173 | && !wizard
174 | #endif
175 | )) return FALSE;
176 | /* don't let multiple restarts generate multiple copies of objects
177 | * in bones files */
178 | if (discover) return FALSE;
179 | return TRUE;
180 | }
181 |
182 | /* save bones and possessions of a deceased adventurer */
183 | void
184 | savebones(corpse)
185 | struct obj *corpse;
186 | {
187 | int fd, x, y;
188 | struct trap *ttmp;
189 | struct monst *mtmp;
190 | struct permonst *mptr;
191 | struct fruit *f;
192 | char c, *bonesid;
193 |
194 | /* caller has already checked `can_make_bones()' */
195 |
196 | fd = open_bonesfile(&u.uz, &bonesid);
197 | if (fd >= 0) {
198 | (void) close(fd);
199 | compress_bonesfile();
200 | #ifdef WIZARD
201 | if (wizard) {
202 | if (yn("Bones file already exists. Replace it?") == 'y') {
203 | if (delete_bonesfile(&u.uz)) goto make_bones;
204 | else pline("Cannot unlink old bones.");
205 | }
206 | }
207 | #endif
208 | return;
209 | }
210 |
211 | make_bones:
212 | unleash_all();
213 | /* in case these characters are not in their home bases */
214 | for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
215 | if (DEADMONSTER(mtmp)) continue;
216 | mptr = mtmp->data;
217 | if (mtmp->iswiz || mptr == &mons[PM_MEDUSA] ||
218 | mptr->msound == MS_NEMESIS || mptr->msound == MS_LEADER ||
219 | mptr == &mons[PM_VLAD_THE_IMPALER])
220 | mongone(mtmp);
221 | }
222 | #ifdef STEED
223 | if (u.usteed) {
224 | coord cc;
225 |
226 | /* Move the steed to an adjacent square */
227 | if (enexto(&cc, u.ux, u.uy, u.usteed->data))
228 | rloc_to(u.usteed, cc.x, cc.y);
229 | u.usteed = 0;
230 | }
231 | #endif
232 | dmonsfree(); /* discard dead or gone monsters */
233 |
234 | /* mark all fruits as nonexistent; when we come to them we'll mark
235 | * them as existing (using goodfruit())
236 | */
237 | for(f=ffruit; f; f=f->nextf) f->fid = -f->fid;
238 |
239 | /* check iron balls separately--maybe they're not carrying it */
240 | if (uball) uball->owornmask = uchain->owornmask = 0;
241 |
242 | /* dispose of your possessions, usually cursed */
243 | if (u.ugrave_arise == (NON_PM - 1)) {
244 | struct obj *otmp;
245 |
246 | /* embed your possessions in your statue */
247 | otmp = mk_named_object(STATUE, &mons[u.umonnum],
248 | u.ux, u.uy, plname);
249 |
250 | drop_upon_death((struct monst *)0, otmp);
251 | if (!otmp) return; /* couldn't make statue */
252 | mtmp = (struct monst *)0;
253 | } else if (u.ugrave_arise < LOW_PM) {
254 | /* drop everything */
255 | drop_upon_death((struct monst *)0, (struct obj *)0);
256 | /* trick makemon() into allowing monster creation
257 | * on your location
258 | */
259 | in_mklev = TRUE;
260 | mtmp = makemon(&mons[PM_GHOST], u.ux, u.uy, MM_NONAME);
261 | in_mklev = FALSE;
262 | if (!mtmp) return;
263 | mtmp = christen_monst(mtmp, plname);
264 | if (corpse)
265 | (void) obj_attach_mid(corpse, mtmp->m_id);
266 | } else {
267 | /* give your possessions to the monster you become */
268 | in_mklev = TRUE;
269 | mtmp = makemon(&mons[u.ugrave_arise], u.ux, u.uy, NO_MM_FLAGS);
270 | in_mklev = FALSE;
271 | if (!mtmp) {
272 | drop_upon_death((struct monst *)0, (struct obj *)0);
273 | return;
274 | }
275 | mtmp = christen_monst(mtmp, plname);
276 | newsym(u.ux, u.uy);
277 | Your("body rises from the dead as %s...",
278 | an(mons[u.ugrave_arise].mname));
279 | display_nhwindow(WIN_MESSAGE, FALSE);
280 | drop_upon_death(mtmp, (struct obj *)0);
281 | m_dowear(mtmp, TRUE);
282 | }
283 | if (mtmp) {
284 | mtmp->m_lev = (u.ulevel ? u.ulevel : 1);
285 | mtmp->mhp = mtmp->mhpmax = u.uhpmax;
286 | mtmp->female = flags.female;
287 | mtmp->msleeping = 1;
288 | }
289 | for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
290 | resetobjs(mtmp->minvent,FALSE);
291 | /* do not zero out m_ids for bones levels any more */
292 | mtmp->mlstmv = 0L;
293 | if(mtmp->mtame) mtmp->mtame = mtmp->mpeaceful = 0;
294 | }
295 | for(ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) {
296 | ttmp->madeby_u = 0;
297 | ttmp->tseen = (ttmp->ttyp == HOLE);
298 | }
299 | resetobjs(fobj,FALSE);
300 | resetobjs(level.buriedobjlist, FALSE);
301 |
302 | /* Hero is no longer on the map. */
303 | u.ux = u.uy = 0;
304 |
305 | /* Clear all memory from the level. */
306 | for(x=0; x<COLNO; x++) for(y=0; y<ROWNO; y++) {
307 | levl[x][y].seenv = 0;
308 | levl[x][y].waslit = 0;
309 | levl[x][y].glyph = cmap_to_glyph(S_stone);
310 | }
311 |
312 | fd = create_bonesfile(&u.uz, &bonesid);
313 | if(fd < 0) {
314 | #ifdef WIZARD
315 | if(wizard)
316 | pline("Cannot create bones file - create failed");
317 | #endif
318 | return;
319 | }
320 | c = (char) (strlen(bonesid) + 1);
321 |
322 | #ifdef MFLOPPY /* check whether there is room */
323 | if (iflags.checkspace) {
324 | savelev(fd, ledger_no(&u.uz), COUNT_SAVE);
325 | /* savelev() initializes bytes_counted to 0, so it must come
326 | * first here even though it does not in the real save. the
327 | * resulting extra bflush() at the end of savelev() may increase
328 | * bytes_counted by a couple over what the real usage will be.
329 | *
330 | * note it is safe to call store_version() here only because
331 | * bufon() is null for ZEROCOMP, which MFLOPPY uses -- otherwise
332 | * this code would have to know the size of the version
333 | * information itself.
334 | */
335 | store_version(fd);
336 | bwrite(fd, (genericptr_t) &c, sizeof c);
337 | bwrite(fd, (genericptr_t) bonesid, (unsigned) c); /* DD.nnn */
338 | savefruitchn(fd, COUNT_SAVE);
339 | bflush(fd);
340 | if (bytes_counted > freediskspace(bones)) { /* not enough room */
341 | # ifdef WIZARD
342 | if (wizard)
343 | pline("Insufficient space to create bones file.");
344 | # endif
345 | (void) close(fd);
346 | cancel_bonesfile();
347 | return;
348 | }
349 | co_false(); /* make sure stuff before savelev() gets written */
350 | }
351 | #endif /* MFLOPPY */
352 |
353 | store_version(fd);
354 | bwrite(fd, (genericptr_t) &c, sizeof c);
355 | bwrite(fd, (genericptr_t) bonesid, (unsigned) c); /* DD.nnn */
356 | savefruitchn(fd, WRITE_SAVE | FREE_SAVE);
357 | update_mlstmv(); /* update monsters for eventual restoration */
358 | savelev(fd, ledger_no(&u.uz), WRITE_SAVE | FREE_SAVE);
359 | bclose(fd);
360 | commit_bonesfile(&u.uz);
361 | compress_bonesfile();
362 | }
363 |
364 | int
365 | getbones()
366 | {
367 | register int fd;
368 | register int ok;
369 | char c, *bonesid, oldbonesid[10];
370 |
371 | if(discover) /* save bones files for real games */
372 | return(0);
373 |
374 | /* wizard check added by GAN 02/05/87 */
375 | if(rn2(3) /* only once in three times do we find bones */
376 | #ifdef WIZARD
377 | && !wizard
378 | #endif
379 | ) return(0);
380 | if(no_bones_level(&u.uz)) return(0);
381 | fd = open_bonesfile(&u.uz, &bonesid);
382 | if (fd < 0) return(0);
383 |
384 | if ((ok = uptodate(fd, bones)) == 0) {
385 | #ifdef WIZARD
386 | if (!wizard)
387 | #endif
388 | pline("Discarding unuseable bones; no need to panic...");
389 | } else {
390 | #ifdef WIZARD
391 | if(wizard) {
392 | if(yn("Get bones?") == 'n') {
393 | (void) close(fd);
394 | compress_bonesfile();
395 | return(0);
396 | }
397 | }
398 | #endif
399 | mread(fd, (genericptr_t) &c, sizeof c); /* length incl. '\0' */
400 | mread(fd, (genericptr_t) oldbonesid, (unsigned) c); /* DD.nnn */
401 | if (strcmp(bonesid, oldbonesid)) {
402 | #ifdef WIZARD
403 | if (wizard) {
404 | pline("This is bones level '%s', not '%s'!",
405 | oldbonesid, bonesid);
406 | ok = FALSE; /* won't die of trickery */
407 | }
408 | #endif
409 | trickery();
410 | } else {
411 | register struct monst *mtmp;
412 | int mndx;
413 |
414 | getlev(fd, 0, 0, TRUE);
415 |
416 | /* to correctly reset named artifacts on the level and
417 | to keep tabs on unique monsters like demon lords */
418 | for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
419 | mndx = monsndx(mtmp->data);
420 | if (mvitals[mndx].mvflags & G_EXTINCT) {
421 | mongone(mtmp);
422 | } else {
423 | if (mons[mndx].geno & G_UNIQ)
424 | mvitals[mndx].mvflags |= G_EXTINCT;
425 | resetobjs(mtmp->minvent,TRUE);
426 | }
427 | }
428 | resetobjs(fobj,TRUE);
429 | resetobjs(level.buriedobjlist,TRUE);
430 | }
431 | }
432 | (void) close(fd);
433 |
434 | #ifdef WIZARD
435 | if(wizard) {
436 | if(yn("Unlink bones?") == 'n') {
437 | compress_bonesfile();
438 | return(ok);
439 | }
440 | }
441 | #endif
442 | if (!delete_bonesfile(&u.uz)) {
443 | /* When N games try to simultaneously restore the same
444 | * bones file, N-1 of them will fail to delete it
445 | * (the first N-1 under AmigaDOS, the last N-1 under UNIX).
446 | * So no point in a mysterious message for a normal event
447 | * -- just generate a new level for those N-1 games.
448 | */
449 | /* pline("Cannot unlink bones."); */
450 | return(0);
451 | }
452 | return(ok);
453 | }
454 |
455 | /*bones.c*/