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