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*/