home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 January
/
usenetsourcesnewsgroupsinfomagicjanuary1994.iso
/
sources
/
games
/
volume16
/
nethack31
/
part54
< prev
next >
Wrap
Internet Message Format
|
1993-02-04
|
58KB
Path: uunet!news.tek.com!master!saab!billr
From: billr@saab.CNA.TEK.COM (Bill Randle)
Newsgroups: comp.sources.games
Subject: v16i062: nethack31 - display oriented dungeons & dragons (Ver. 3.1), Part54/108
Message-ID: <4365@master.CNA.TEK.COM>
Date: 1 Feb 93 19:43:32 GMT
Sender: news@master.CNA.TEK.COM
Lines: 2307
Approved: billr@saab.CNA.TEK.COM
Xref: uunet comp.sources.games:1612
Submitted-by: izchak@linc.cis.upenn.edu (Izchak Miller)
Posting-number: Volume 16, Issue 62
Archive-name: nethack31/Part54
Supersedes: nethack3p9: Volume 10, Issue 46-102
Environment: Amiga, Atari, Mac, MS-DOS, OS2, Unix, VMS, X11
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 54 (of 108)."
# Contents: src/mklev.c src/save.c
# Wrapped by billr@saab on Wed Jan 27 16:09:07 1993
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'src/mklev.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/mklev.c'\"
else
echo shar: Extracting \"'src/mklev.c'\" \(33549 characters\)
sed "s/^X//" >'src/mklev.c' <<'END_OF_FILE'
X/* SCCS Id: @(#)mklev.c 3.1 92/10/10 */
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
X/* NetHack may be freely redistributed. See license for details. */
X
X#include "hack.h"
X/* #define DEBUG /* uncomment to enable code debugging */
X
X#ifdef DEBUG
X# ifdef WIZARD
X#define debugpline if (wizard) pline
X# else
X#define debugpline pline
X# endif
X#endif
X
X/* for UNIX, Rand #def'd to (long)lrand48() or (long)random() */
X/* croom->lx etc are schar (width <= int), so % arith ensures that */
X/* conversion of result to int is reasonable */
X
X
Xstatic void FDECL(mkfount,(int,struct mkroom *));
X#ifdef SINKS
Xstatic void FDECL(mksink,(struct mkroom *));
X#endif
Xstatic void FDECL(mkaltar,(struct mkroom *));
Xstatic void NDECL(makevtele);
Xstatic void NDECL(clear_level_structures);
Xstatic void NDECL(makelevel);
Xstatic boolean FDECL(bydoor,(XCHAR_P,XCHAR_P));
Xstatic struct mkroom *FDECL(find_branch_room, (coord *));
Xstatic struct mkroom *FDECL(pos_to_room, (XCHAR_P, XCHAR_P));
Xstatic boolean FDECL(place_niche,(struct mkroom *,int*,int*,int*));
Xstatic void FDECL(makeniche,(int));
Xstatic void NDECL(make_niches);
XSTATIC_PTR int FDECL(do_comp,(const genericptr,const genericptr));
Xstatic void FDECL(dosdoor,(XCHAR_P,XCHAR_P,struct mkroom *,int));
Xstatic void FDECL(join,(int,int,BOOLEAN_P));
Xstatic void FDECL(do_room_or_subroom, (struct mkroom *,int,int,int,int,
X BOOLEAN_P,SCHAR_P,BOOLEAN_P,BOOLEAN_P));
Xstatic void NDECL(makerooms);
Xstatic void FDECL(finddpos,(coord *,XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P));
Xstatic void FDECL(mkinvpos, (XCHAR_P,XCHAR_P,int));
X#ifdef MULDGN
Xstatic void FDECL(mk_knox_portal, (XCHAR_P,XCHAR_P));
X#endif
X
X#define create_vault() create_room(-1, -1, 2, 2, -1, -1, VAULT, TRUE)
X#define init_vault() vault_x = -1
X#define do_vault() (vault_x != -1)
Xstatic xchar vault_x, vault_y;
Xboolean goldseen;
Xstatic boolean made_branch; /* used only during level creation */
X
X/* Args must be (const genericptr) so that qsort will always be happy. */
X
XSTATIC_PTR int
Xdo_comp(vx,vy)
Xconst genericptr vx;
Xconst genericptr vy;
X{
X#ifdef LINT
X/* lint complains about possible pointer alignment problems, but we know
X that vx and vy are always properly aligned. Hence, the following
X bogus definition:
X*/
X return (vx == vy) ? 0 : -1;
X#else
X register const struct mkroom *x, *y;
X
X x = (const struct mkroom *)vx;
X y = (const struct mkroom *)vy;
X if(x->lx < y->lx) return(-1);
X return(x->lx > y->lx);
X#endif /* LINT */
X}
X
Xstatic void
Xfinddpos(cc, xl,yl,xh,yh)
Xcoord *cc;
Xxchar xl,yl,xh,yh;
X{
X register xchar x, y;
X
X x = (xl == xh) ? xl : (xl + rn2(xh-xl+1));
X y = (yl == yh) ? yl : (yl + rn2(yh-yl+1));
X if(okdoor(x, y))
X goto gotit;
X
X for(x = xl; x <= xh; x++) for(y = yl; y <= yh; y++)
X if(okdoor(x, y))
X goto gotit;
X
X for(x = xl; x <= xh; x++) for(y = yl; y <= yh; y++)
X if(IS_DOOR(levl[x][y].typ) || levl[x][y].typ == SDOOR)
X goto gotit;
X /* cannot find something reasonable -- strange */
X x = xl;
X y = yh;
Xgotit:
X cc->x = x;
X cc->y = y;
X return;
X}
X
Xvoid
Xsort_rooms()
X{
X#if defined(SYSV) || defined(DGUX)
X qsort((genericptr_t) rooms, (unsigned)nroom, sizeof(struct mkroom), do_comp);
X#else
X qsort((genericptr_t) rooms, nroom, sizeof(struct mkroom), do_comp);
X#endif
X}
X
Xstatic void
Xdo_room_or_subroom(croom, lowx, lowy, hix, hiy, lit, rtype, special, is_room)
X register struct mkroom *croom;
X int lowx, lowy;
X register int hix, hiy;
X boolean lit;
X schar rtype;
X boolean special;
X boolean is_room;
X{
X register int x, y;
X struct rm *lev;
X
X /* locations might bump level edges in wall-less rooms */
X /* add/subtract 1 to allow for edge locations */
X if(!lowx) lowx++;
X if(!lowy) lowy++;
X if(hix >= COLNO-1) hix = COLNO-2;
X if(hiy >= ROWNO-1) hiy = ROWNO-2;
X
X if(lit) {
X for(x = lowx-1; x <= hix+1; x++) {
X lev = &levl[x][max(lowy-1,0)];
X for(y = lowy-1; y <= hiy+1; y++)
X lev++->lit = 1;
X }
X croom->rlit = 1;
X } else
X croom->rlit = 0;
X
X croom->lx = lowx;
X croom->hx = hix;
X croom->ly = lowy;
X croom->hy = hiy;
X croom->rtype = rtype;
X croom->doorct = 0;
X /* if we're not making a vault, doorindex will still be 0
X * if we are, we'll have problems adding niches to the previous room
X * unless fdoor is at least doorindex
X */
X croom->fdoor = doorindex;
X croom->irregular = FALSE;
X
X croom->nsubrooms = 0;
X croom->sbrooms[0] = (struct mkroom *) 0;
X if (!special) {
X for(x = lowx-1; x <= hix+1; x++)
X for(y = lowy-1; y <= hiy+1; y += (hiy-lowy+2)) {
X levl[x][y].typ = HWALL;
X levl[x][y].horizontal = 1; /* For open/secret doors. */
X }
X for(x = lowx-1; x <= hix+1; x += (hix-lowx+2))
X for(y = lowy; y <= hiy; y++) {
X levl[x][y].typ = VWALL;
X levl[x][y].horizontal = 0; /* For open/secret doors. */
X }
X for(x = lowx; x <= hix; x++) {
X lev = &levl[x][lowy];
X for(y = lowy; y <= hiy; y++)
X lev++->typ = ROOM;
X }
X if (is_room) {
X levl[lowx-1][lowy-1].typ = TLCORNER;
X levl[hix+1][lowy-1].typ = TRCORNER;
X levl[lowx-1][hiy+1].typ = BLCORNER;
X levl[hix+1][hiy+1].typ = BRCORNER;
X } else { /* a subroom */
X wallification(lowx-1, lowy-1, hix+1, hiy+1);
X }
X }
X}
X
X
Xvoid
Xadd_room(lowx, lowy, hix, hiy, lit, rtype, special)
Xregister int lowx, lowy, hix, hiy;
Xboolean lit;
Xschar rtype;
Xboolean special;
X{
X register struct mkroom *croom;
X
X croom = &rooms[nroom];
X do_room_or_subroom(croom, lowx, lowy, hix, hiy, lit,
X rtype, special, (boolean) TRUE);
X croom++;
X croom->hx = -1;
X nroom++;
X}
X
Xvoid
Xadd_subroom(proom, lowx, lowy, hix, hiy, lit, rtype, special)
Xstruct mkroom *proom;
Xregister int lowx, lowy, hix, hiy;
Xboolean lit;
Xschar rtype;
Xboolean special;
X{
X register struct mkroom *croom;
X
X croom = &subrooms[nsubroom];
X do_room_or_subroom(croom, lowx, lowy, hix, hiy, lit,
X rtype, special, (boolean) FALSE);
X proom->sbrooms[proom->nsubrooms++] = croom;
X croom++;
X croom->hx = -1;
X nsubroom++;
X}
X
Xstatic void
Xmakerooms()
X{
X boolean tried_vault = FALSE;
X
X /* make rooms until satisfied */
X /* rnd_rect() will returns 0 if no more rects are available... */
X while(nroom < MAXNROFROOMS && rnd_rect()) {
X if(nroom >= (MAXNROFROOMS/6) && rn2(2) && !tried_vault) {
X tried_vault = TRUE;
X if (create_vault()) {
X vault_x = rooms[nroom].lx;
X vault_y = rooms[nroom].ly;
X rooms[nroom].hx = -1;
X }
X } else
X if (!create_room(-1, -1, -1, -1, -1, -1, OROOM, -1))
X return;
X }
X return;
X}
X
Xstatic void
Xjoin(a,b,nxcor)
Xregister int a, b;
Xboolean nxcor;
X{
X coord cc,tt, org, dest;
X register int tx, ty, xx, yy;
X register struct mkroom *croom, *troom;
X register int dx, dy;
X
X croom = &rooms[a];
X troom = &rooms[b];
X
X /* find positions cc and tt for doors in croom and troom
X and direction for a corridor between them */
X
X if(troom->hx < 0 || croom->hx < 0 || doorindex >= DOORMAX) return;
X if(troom->lx > croom->hx) {
X dx = 1;
X dy = 0;
X xx = croom->hx+1;
X tx = troom->lx-1;
X finddpos(&cc, xx, croom->ly, xx, croom->hy);
X finddpos(&tt, tx, troom->ly, tx, troom->hy);
X } else if(troom->hy < croom->ly) {
X dy = -1;
X dx = 0;
X yy = croom->ly-1;
X finddpos(&cc, croom->lx, yy, croom->hx, yy);
X ty = troom->hy+1;
X finddpos(&tt, troom->lx, ty, troom->hx, ty);
X } else if(troom->hx < croom->lx) {
X dx = -1;
X dy = 0;
X xx = croom->lx-1;
X tx = troom->hx+1;
X finddpos(&cc, xx, croom->ly, xx, croom->hy);
X finddpos(&tt, tx, troom->ly, tx, troom->hy);
X } else {
X dy = 1;
X dx = 0;
X yy = croom->hy+1;
X ty = troom->ly-1;
X finddpos(&cc, croom->lx, yy, croom->hx, yy);
X finddpos(&tt, troom->lx, ty, troom->hx, ty);
X }
X xx = cc.x;
X yy = cc.y;
X tx = tt.x - dx;
X ty = tt.y - dy;
X if(nxcor && levl[xx+dx][yy+dy].typ)
X return;
X if (okdoor(xx,yy) || !nxcor)
X dodoor(xx,yy,croom);
X
X org.x = xx+dx; org.y = yy+dy;
X dest.x = tx; dest.y = ty;
X
X if (!dig_corridor(org, dest, nxcor, CORR, STONE))
X return;
X
X /* we succeeded in digging the corridor */
X if (okdoor(tt.x, tt.y) || !nxcor)
X dodoor(tt.x, tt.y, troom);
X
X if(smeq[a] < smeq[b])
X smeq[b] = smeq[a];
X else
X smeq[a] = smeq[b];
X}
X
Xvoid
Xmakecorridors()
X{
X int a, b, i;
X boolean any = TRUE;
X
X for(a = 0; a < nroom-1; a++) {
X join(a, a+1, FALSE);
X if(!rn2(50)) break; /* allow some randomness */
X }
X for(a = 0; a < nroom-2; a++)
X if(smeq[a] != smeq[a+2])
X join(a, a+2, FALSE);
X for(a = 0; any && a < nroom; a++) {
X any = FALSE;
X for(b = 0; b < nroom; b++)
X if(smeq[a] != smeq[b]) {
X join(a, b, FALSE);
X any = TRUE;
X }
X }
X if(nroom > 2)
X for(i = rn2(nroom) + 4; i; i--) {
X a = rn2(nroom);
X b = rn2(nroom-2);
X if(b >= a) b += 2;
X join(a, b, TRUE);
X }
X}
X
Xvoid
Xadd_door(x,y,aroom)
Xregister int x, y;
Xregister struct mkroom *aroom;
X{
X register struct mkroom *broom;
X register int tmp;
X
X aroom->doorct++;
X broom = aroom+1;
X if(broom->hx < 0)
X tmp = doorindex;
X else
X for(tmp = doorindex; tmp > broom->fdoor; tmp--)
X doors[tmp] = doors[tmp-1];
X doorindex++;
X doors[tmp].x = x;
X doors[tmp].y = y;
X for( ; broom->hx >= 0; broom++) broom->fdoor++;
X}
X
Xstatic void
Xdosdoor(x,y,aroom,type)
Xregister xchar x, y;
Xregister struct mkroom *aroom;
Xregister int type;
X{
X boolean shdoor = ((*in_rooms(x, y, SHOPBASE))? TRUE : FALSE);
X
X if(!IS_WALL(levl[x][y].typ)) /* avoid SDOORs on already made doors */
X type = DOOR;
X levl[x][y].typ = type;
X if(type == DOOR) {
X if(!rn2(3)) { /* is it a locked door, closed, or a doorway? */
X if(!rn2(5))
X levl[x][y].doormask = D_ISOPEN;
X else if(!rn2(6))
X levl[x][y].doormask = D_LOCKED;
X else
X levl[x][y].doormask = D_CLOSED;
X
X if (levl[x][y].doormask != D_ISOPEN && !shdoor && !rn2(25))
X levl[x][y].doormask |= D_TRAPPED;
X } else
X#ifdef STUPID
X if (shdoor)
X levl[x][y].doormask = D_ISOPEN;
X else
X levl[x][y].doormask = D_NODOOR;
X#else
X levl[x][y].doormask = (shdoor ? D_ISOPEN : D_NODOOR);
X#endif
X if(levl[x][y].doormask & D_TRAPPED) {
X struct monst *mtmp;
X
X if (level_difficulty() >= 9 && !rn2(5) &&
X !((mons[PM_SMALL_MIMIC].geno & (G_GENOD | G_EXTINCT)) &&
X (mons[PM_LARGE_MIMIC].geno & (G_GENOD | G_EXTINCT)) &&
X (mons[PM_GIANT_MIMIC].geno & (G_GENOD | G_EXTINCT)))) {
X /* make a mimic instead */
X levl[x][y].doormask = D_NODOOR;
X mtmp = makemon(mkclass(S_MIMIC,0), x, y);
X if (mtmp)
X set_mimic_sym(mtmp);
X }
X }
X /* newsym(x,y); */
X } else { /* SDOOR */
X if(shdoor || !rn2(5)) levl[x][y].doormask = D_LOCKED;
X else levl[x][y].doormask = D_CLOSED;
X
X if(!shdoor && !rn2(20)) levl[x][y].doormask |= D_TRAPPED;
X }
X
X add_door(x,y,aroom);
X}
X
Xstatic boolean
Xplace_niche(aroom,dy,xx,yy)
Xregister struct mkroom *aroom;
Xint *dy, *xx, *yy;
X{
X coord dd;
X
X if(rn2(2)) {
X *dy = 1;
X finddpos(&dd, aroom->lx, aroom->hy+1, aroom->hx, aroom->hy+1);
X } else {
X *dy = -1;
X finddpos(&dd, aroom->lx, aroom->ly-1, aroom->hx, aroom->ly-1);
X }
X *xx = dd.x;
X *yy = dd.y;
X return(isok(*xx,*yy+*dy) && levl[*xx][(*yy)+(*dy)].typ == STONE);
X}
X
X/* there should be one of these per trap */
Xconst char *trap_engravings[TRAPNUM] = {
X "", "", "", "", "", "", "",
X "", "", "", "", "", "",
X "ad ae?ar um", "?la? ?as ?er?", "ad ae?ar um",
X "", "", "", ""
X#ifdef POLYSELF
X ,""
X#endif
X };
X
Xstatic void
Xmakeniche(trap_type)
Xint trap_type;
X{
X register struct mkroom *aroom;
X register struct rm *rm;
X register int vct = 8;
X int dy, xx, yy;
X register struct trap *ttmp;
X
X if(doorindex < DOORMAX)
X while(vct--) {
X aroom = &rooms[rn2(nroom)];
X if(aroom->rtype != OROOM) continue; /* not an ordinary room */
X if(aroom->doorct == 1 && rn2(5)) continue;
X if(!place_niche(aroom,&dy,&xx,&yy)) continue;
X
X rm = &levl[xx][yy+dy];
X if(trap_type || !rn2(4)) {
X
X rm->typ = SCORR;
X if(trap_type) {
X if(trap_type == TRAPDOOR && !Can_fall_thru(&u.uz))
X trap_type = ROCKTRAP;
X ttmp = maketrap(xx, yy+dy, trap_type);
X ttmp->once = 1;
X if (*trap_engravings[trap_type])
X make_engr_at(xx, yy-dy, trap_engravings[trap_type], 0L, DUST);
X }
X dosdoor(xx, yy, aroom, SDOOR);
X } else {
X rm->typ = CORR;
X if(rn2(7))
X dosdoor(xx, yy, aroom, rn2(5) ? SDOOR : DOOR);
X else {
X (void) mksobj_at(SCR_TELEPORTATION, xx, yy+dy, TRUE);
X if(!rn2(3)) (void) mkobj_at(0, xx, yy+dy, TRUE);
X }
X }
X return;
X }
X}
X
Xstatic void
Xmake_niches()
X{
X register int ct = rnd((nroom>>1) + 1);
X boolean ltptr = TRUE,
X vamp = TRUE;
X
X while(ct--) {
X
X if(depth(&u.uz) > 15 && !rn2(6) && ltptr) {
X ltptr = FALSE;
X makeniche(LEVEL_TELEP);
X } else if(depth(&u.uz) > 5 && depth(&u.uz) < 25
X && !rn2(6) && vamp) {
X vamp = FALSE;
X makeniche(TRAPDOOR);
X } else makeniche(NO_TRAP);
X }
X}
X
Xstatic void
Xmakevtele()
X{
X makeniche(TELEP_TRAP);
X}
X
X/* clear out various globals that keep information on the current level.
X * some of this is only necessary for some types of levels (maze, normal,
X * special) but it's easier to put it all in one place than make sure
X * each type initializes what it needs to separately.
X */
Xstatic void
Xclear_level_structures()
X{
X static struct rm zerorm = { cmap_to_glyph(S_stone),
X 0, 0, 0, 0, 0, 0, 0, 0 };
X register int x,y;
X register struct rm *lev;
X
X for(x=0; x<COLNO; x++) {
X lev = &levl[x][0];
X for(y=0; y<ROWNO; y++) {
X *lev++ = zerorm;
X#ifdef MICROPORT_BUG
X level.objects[x][y] = (struct obj *)0;
X level.monsters[x][y] = (struct monst *)0;
X#endif
X }
X }
X#ifndef MICROPORT_BUG
X (void) memset((genericptr_t)level.objects, 0, sizeof(level.objects));
X (void) memset((genericptr_t)level.monsters, 0, sizeof(level.monsters));
X#endif
X level.flags.nfountains = 0;
X level.flags.nsinks = 0;
X level.flags.has_shop = 0;
X level.flags.has_vault = 0;
X level.flags.has_zoo = 0;
X level.flags.has_court = 0;
X level.flags.has_morgue = 0;
X level.flags.has_beehive = 0;
X#ifdef ARMY
X level.flags.has_barracks = 0;
X#endif
X level.flags.has_temple = 0;
X level.flags.has_swamp = 0;
X level.flags.noteleport = 0;
X level.flags.hardfloor = 0;
X level.flags.nommap = 0;
X level.flags.hero_memory = 1;
X level.flags.shortsighted = 0;
X level.flags.is_maze_lev = 0;
X level.flags.is_cavernous_lev = 0;
X
X nroom = 0;
X rooms[0].hx = -1;
X nsubroom = 0;
X doorindex = 0;
X init_rect();
X init_vault();
X xdnstair = ydnstair = xupstair = yupstair = 0;
X sstairs.sx = sstairs.sy = 0;
X xdnladder = ydnladder = xupladder = yupladder = 0;
X made_branch = FALSE;
X}
X
Xstatic void
Xmakelevel()
X{
X register struct mkroom *croom, *troom;
X register int tryct;
X register int x, y;
X struct monst *tmonst; /* always put a web with a spider */
X
X if(wiz1_level.dlevel == 0) init_dungeons();
X oinit(); /* assign level dependent obj probabilities */
X clear_level_structures();
X
X {
X register s_level *slev = Is_special(&u.uz);
X
X /* check for special levels */
X#ifdef REINCARNATION
X if (slev && !Is_rogue_level(&u.uz))
X#else
X if (slev)
X#endif
X {
X makemaz(slev->proto);
X return;
X } else if (dungeons[u.uz.dnum].proto[0]) {
X makemaz("");
X return;
X#ifdef MULDGN
X } else if (In_mines(&u.uz)) {
X makemaz("minefill");
X return;
X } else if (In_quest(&u.uz)) {
X char fillname[9];
X s_level *loc_lev;
X
X Sprintf(fillname, "%c-locate", pl_character[0]);
X loc_lev = find_level(fillname);
X
X Sprintf(fillname, "%c-fill", pl_character[0]);
X Strcat(fillname,
X (u.uz.dlevel < loc_lev->dlevel.dlevel) ? "a" : "b");
X makemaz(fillname);
X return;
X#endif
X } else if(In_hell(&u.uz) ||
X (rn2(5) && u.uz.dnum == medusa_level.dnum
X && depth(&u.uz) > depth(&medusa_level))) {
X makemaz("");
X return;
X }
X }
X
X /* otherwise, fall through - it's a "regular" level. */
X
X#ifdef REINCARNATION
X if (Is_rogue_level(&u.uz)) {
X makeroguerooms();
X makerogueghost();
X } else
X#endif
X makerooms();
X sort_rooms();
X
X /* construct stairs (up and down in different rooms if possible) */
X croom = &rooms[rn2(nroom)];
X if (!Is_botlevel(&u.uz))
X mkstairs(somex(croom), somey(croom), 0, croom); /* down */
X if (nroom > 1) {
X troom = croom;
X croom = &rooms[rn2(nroom-1)];
X if (croom == troom) croom++;
X }
X
X if (u.uz.dlevel != 1) {
X xchar sx, sy;
X do {
X sx = somex(croom);
X sy = somey(croom);
X } while(occupied(sx, sy));
X mkstairs(sx, sy, 1, croom); /* up */
X }
X
X#ifdef REINCARNATION
X if (Is_rogue_level(&u.uz)) goto skip0;
X#endif
X makecorridors();
X make_niches();
X
X /* make a secret treasure vault, not connected to the rest */
X if(do_vault()) {
X xchar w,h;
X#ifdef DEBUG
X debugpline("trying to make a vault...");
X#endif
X w = 1;
X h = 1;
X if (check_room(&vault_x, &w, &vault_y, &h, TRUE)) {
X fill_vault:
X add_room(vault_x, vault_y, vault_x+w,
X vault_y+h, TRUE, VAULT, FALSE);
X level.flags.has_vault = 1;
X fill_room(&rooms[nroom - 1], FALSE);
X#ifdef MULDGN
X mk_knox_portal(vault_x+w, vault_y+h);
X#endif
X if(!rn2(3)) makevtele();
X } else if(rnd_rect() && create_vault()) {
X vault_x = rooms[nroom].lx;
X vault_y = rooms[nroom].ly;
X if (check_room(&vault_x, &w, &vault_y, &h, TRUE))
X goto fill_vault;
X else
X rooms[nroom].hx = -1;
X }
X }
X
X#ifdef WIZARD
X if(wizard && getenv("SHOPTYPE")) mkroom(SHOPBASE); else
X#endif
X if(depth(&u.uz) > 1 &&
X depth(&u.uz) < depth(&medusa_level) &&
X rn2(depth(&u.uz)) < 3) mkroom(SHOPBASE);
X else if(depth(&u.uz) > 4 && !rn2(6)) mkroom(COURT);
X else if(depth(&u.uz) > 6 && !rn2(7)) mkroom(ZOO);
X else if(depth(&u.uz) > 8 && !rn2(5)) mkroom(TEMPLE);
X else if(depth(&u.uz) > 9 && !rn2(5) &&
X !(mons[PM_KILLER_BEE].geno & (G_GENOD | G_EXTINCT))) mkroom(BEEHIVE);
X else if(depth(&u.uz) > 11 && !rn2(6)) mkroom(MORGUE);
X else
X#ifdef ARMY
X if(depth(&u.uz) > 14 && !rn2(4) &&
X !(mons[PM_SOLDIER].geno & (G_GENOD | G_EXTINCT))) mkroom(BARRACKS);
X else
X#endif
X if(depth(&u.uz) > 18 && !rn2(6)) mkroom(SWAMP);
X
X#ifdef REINCARNATION
Xskip0:
X#endif
X /* Place multi-dungeon branch. */
X place_branch(Is_branchlev(&u.uz), 0, 0);
X
X /* for each room: put things inside */
X for(croom = rooms; croom->hx > 0; croom++) {
X if(croom->rtype != OROOM) continue;
X
X /* put a sleeping monster inside */
X /* Note: monster may be on the stairs. This cannot be
X avoided: maybe the player fell through a trap door
X while a monster was on the stairs. Conclusion:
X we have to check for monsters on the stairs anyway. */
X
X if(u.uhave.amulet || !rn2(3)) {
X x = somex(croom); y = somey(croom);
X tmonst = makemon((struct permonst *) 0, x,y);
X if (tmonst && tmonst->data == &mons[PM_GIANT_SPIDER] &&
X !is_pool(x,y))
X (void) maketrap (x,y,WEB);
X }
X /* put traps and mimics inside */
X goldseen = FALSE;
X x = 8 - (level_difficulty()/6);
X if (x <= 1) x = 2;
X while (!rn2(x))
X mktrap(0,0,croom,(coord*)0);
X if(!goldseen && !rn2(3)) mkgold(0L, somex(croom), somey(croom));
X#ifdef REINCARNATION
X if(Is_rogue_level(&u.uz)) goto skip_nonrogue;
X#endif
X if(!rn2(10)) mkfount(0,croom);
X#ifdef SINKS
X if(!rn2(60)) mksink(croom);
X#endif
X if(!rn2(60)) mkaltar(croom);
X /* put statues inside */
X if(!rn2(20))
X (void) mkcorpstat(STATUE, (struct permonst *)0,
X somex(croom), somey(croom), TRUE);
X
X /* put box/chest inside;
X * 40% chance for at least 1 box, regardless of number
X * of rooms; about 5 - 7.5% for 2 boxes, least likely
X * when few rooms; chance for 3 or more is neglible.
X */
X if(!rn2(nroom * 5 / 2))
X (void) mksobj_at((rn2(3)) ? LARGE_BOX : CHEST,
X somex(croom), somey(croom), TRUE);
X
X /* maybe make some graffiti */
X if(!rn2(27 + 3 * depth(&u.uz))) {
X const char *mesg = random_engraving();
X if (mesg) {
X do {
X x = somex(croom); y = somey(croom);
X } while(levl[x][y].typ != ROOM && !rn2(40));
X if (!(IS_POOL(levl[x][y].typ) ||
X IS_FURNITURE(levl[x][y].typ)))
X make_engr_at(x, y, mesg, 0L, MARK);
X }
X }
X
X#ifdef REINCARNATION
X skip_nonrogue:
X#endif
X if(!rn2(3)) {
X (void) mkobj_at(0, somex(croom), somey(croom), TRUE);
X tryct = 0;
X while(!rn2(5)) {
X if(++tryct > 100) {
X impossible("tryct overflow4");
X break;
X }
X (void) mkobj_at(0, somex(croom), somey(croom), TRUE);
X }
X }
X }
X}
X
Xvoid
Xmklev()
X{
X struct mkroom *croom;
X
X if(getbones()) return;
X in_mklev = TRUE;
X makelevel();
X bound_digging();
X in_mklev = FALSE;
X if(!level.flags.is_maze_lev) {
X for (croom = &rooms[0]; croom != &rooms[nroom]; croom++)
X#ifdef SPECIALIZATION
X topologize(croom, FALSE);
X#else
X topologize(croom);
X#endif
X }
X}
X
Xvoid
X#ifdef SPECIALIZATION
Xtopologize(croom, do_ordinary)
Xregister struct mkroom *croom;
Xboolean do_ordinary;
X#else
Xtopologize(croom)
Xregister struct mkroom *croom;
X#endif
X{
X register int x, y, roomno = (croom - rooms) + ROOMOFFSET;
X register int lowx = croom->lx, lowy = croom->ly;
X register int hix = croom->hx, hiy = croom->hy;
X#ifdef SPECIALIZATION
X register schar rtype = croom->rtype;
X#endif
X register int subindex, nsubrooms = croom->nsubrooms;
X
X /* skip the room if already done; i.e. a shop handled out of order */
X /* also skip if this is non-rectangular (it _must_ be done already) */
X if (levl[lowx][lowy].roomno == roomno || croom->irregular)
X return;
X#ifdef SPECIALIZATION
X# ifdef REINCARNATION
X if (Is_rogue_level(&u.uz))
X do_ordinary = TRUE; /* vision routine helper */
X# endif
X if ((rtype != OROOM) || do_ordinary)
X#endif
X {
X /* do innards first */
X for(x = lowx; x <= hix; x++)
X for(y = lowy; y <= hiy; y++)
X#ifdef SPECIALIZATION
X if (rtype == OROOM)
X levl[x][y].roomno = NO_ROOM;
X else
X#endif
X levl[x][y].roomno = roomno;
X /* top and bottom edges */
X for(x = lowx-1; x <= hix+1; x++)
X for(y = lowy-1; y <= hiy+1; y += (hiy-lowy+2)) {
X levl[x][y].edge = 1;
X if (levl[x][y].roomno)
X levl[x][y].roomno = SHARED;
X else
X levl[x][y].roomno = roomno;
X }
X /* sides */
X for(x = lowx-1; x <= hix+1; x += (hix-lowx+2))
X for(y = lowy; y <= hiy; y++) {
X levl[x][y].edge = 1;
X if (levl[x][y].roomno)
X levl[x][y].roomno = SHARED;
X else
X levl[x][y].roomno = roomno;
X }
X }
X /* subrooms */
X for (subindex = 0; subindex < nsubrooms; subindex++)
X#ifdef SPECIALIZATION
X topologize(croom->sbrooms[subindex], (rtype != OROOM));
X#else
X topologize(croom->sbrooms[subindex]);
X#endif
X}
X
X/* Find an unused room for a branch location. */
Xstatic struct mkroom *
Xfind_branch_room(mp)
X coord *mp;
X{
X struct mkroom *croom = 0;
X
X if (nroom == 0) {
X mazexy(mp); /* already verifies location */
X } else {
X /* not perfect - there may be only one stairway */
X if(nroom > 2) {
X int tryct = 0;
X
X do
X croom = &rooms[rn2(nroom)];
X while((croom == dnstairs_room || croom == upstairs_room ||
X croom->rtype != OROOM) && (++tryct < 100));
X } else
X croom = &rooms[rn2(nroom)];
X
X do {
X if (!somexy(croom, mp))
X impossible("Can't place branch!");
X } while(occupied(mp->x, mp->y) ||
X (levl[mp->x][mp->y].typ != CORR && levl[mp->x][mp->y].typ != ROOM));
X }
X return croom;
X}
X
X/* Find the room for (x,y). Return NULL of not in a room. */
Xstatic struct mkroom *
Xpos_to_room(x, y)
X xchar x, y;
X{
X int i;
X struct mkroom *curr;
X
X for (curr = rooms, i = 0; i < nroom; curr++, i++)
X if (inside_room(curr, x, y)) return curr;;
X return (struct mkroom *) 0;
X}
X
X
X/* If given a branch, randomly place a special stair or portal. */
Xvoid
Xplace_branch(br, x, y)
Xbranch *br; /* branch to place */
Xxchar x, y; /* location */
X{
X coord m;
X d_level *dest;
X boolean make_stairs;
X struct mkroom *br_room;
X
X /*
X * Return immediately if there is no branch to make or we have
X * already made one. This routine can be called twice when
X * a special level is loaded that specifies an SSTAIR location
X * as a favored spot for a branch.
X */
X if (!br || made_branch) return;
X
X if (!x) { /* find random coordinates for branch */
X br_room = find_branch_room(&m);
X x = m.x;
X y = m.y;
X } else {
X br_room = pos_to_room(x, y);
X }
X
X if (on_level(&br->end1, &u.uz)) {
X /* we're on end1 */
X make_stairs = br->type != BR_NO_END1;
X dest = &br->end2;
X } else {
X /* we're on end2 */
X make_stairs = br->type != BR_NO_END2;
X dest = &br->end1;
X }
X
X if (br->type == BR_PORTAL) {
X mkportal(x, y, dest->dnum, dest->dlevel);
X } else if (make_stairs) {
X sstairs.sx = x;
X sstairs.sy = y;
X sstairs.up = (char) on_level(&br->end1, &u.uz) ?
X br->end1_up : !br->end1_up;
X assign_level(&sstairs.tolev, dest);
X sstairs_room = br_room;
X
X levl[x][y].ladder = sstairs.up ? LA_UP : LA_DOWN;
X levl[x][y].typ = STAIRS;
X }
X /*
X * Set made_branch to TRUE even if we didn't make a stairwell (i.e.
X * make_stairs is false) since there is currently only one branch
X * per level, if we failed once, we're going to fail again on the
X * next call.
X */
X made_branch = TRUE;
X}
X
Xstatic boolean
Xbydoor(x, y)
Xregister xchar x, y;
X{
X register boolean tmp1, tmp2;
X
X /* break up large expression to help some compilers */
X tmp1 = (IS_DOOR(levl[x+1][y].typ) || levl[x+1][y].typ == SDOOR ||
X IS_DOOR(levl[x-1][y].typ) || levl[x-1][y].typ == SDOOR);
X tmp2 = (IS_DOOR(levl[x][y+1].typ) || levl[x][y+1].typ == SDOOR ||
X IS_DOOR(levl[x][y-1].typ) || levl[x][y-1].typ == SDOOR);
X return(tmp1 || tmp2);
X}
X
X/* see whether it is allowable to create a door at [x,y] */
Xint
Xokdoor(x,y)
Xregister xchar x, y;
X{
X register boolean near_door = bydoor(x, y);
X
X return((levl[x][y].typ == HWALL || levl[x][y].typ == VWALL) &&
X doorindex < DOORMAX && !near_door);
X}
X
Xvoid
Xdodoor(x,y,aroom)
Xregister int x, y;
Xregister struct mkroom *aroom;
X{
X if(doorindex >= DOORMAX) {
X impossible("DOORMAX exceeded?");
X return;
X }
X
X dosdoor(x,y,aroom,rn2(8) ? DOOR : SDOOR);
X}
X
Xboolean
Xoccupied(x, y)
Xregister xchar x, y;
X{
X return(t_at(x, y) || levl[x][y].typ == STAIRS
X || IS_FOUNTAIN(levl[x][y].typ)
X || IS_THRONE(levl[x][y].typ)
X#ifdef SINKS
X || IS_SINK(levl[x][y].typ)
X#endif
X || levl[x][y].typ == ALTAR
X || is_lava(x,y)
X || is_pool(x,y)
X || invocation_pos(x,y)
X );
X}
X
X/* make a trap somewhere (in croom if mazeflag = 0 && !tm) */
X/* if tm != NULL, make trap at that location */
Xvoid
Xmktrap(num, mazeflag, croom, tm)
Xregister int num, mazeflag;
Xregister struct mkroom *croom;
Xcoord *tm;
X{
X register int kind;
X coord m;
X
X /* no traps in pools */
X if (tm && is_pool(tm->x,tm->y)) return;
X
X if (num > 0 && num < TRAPNUM) {
X kind = num;
X#ifdef REINCARNATION
X } else if (Is_rogue_level(&u.uz)) {
X switch (rn2(7)) {
X default: kind = BEAR_TRAP; break; /* 0 */
X case 1: kind = ARROW_TRAP; break;
X case 2: kind = DART_TRAP; break;
X case 3: kind = TRAPDOOR; break;
X case 4: kind = PIT; break;
X case 5: kind = SLP_GAS_TRAP; break;
X case 6: kind = RUST_TRAP; break;
X }
X#endif
X } else if (Inhell && !rn2(5)) {
X /* bias the frequency of fire traps in Gehennom */
X kind = FIRE_TRAP;
X } else {
X unsigned lvl = level_difficulty();
X
X do {
X kind = rnd(TRAPNUM-1);
X /* reject "too hard" traps */
X switch (kind) {
X case LEVEL_TELEP:
X case LANDMINE:
X if (lvl < 5) kind = NO_TRAP; break;
X case SPIKED_PIT:
X#ifdef POLYSELF
X case POLY_TRAP:
X#endif
X if (lvl < 6) kind = NO_TRAP; break;
X case WEB:
X case STATUE_TRAP:
X if (lvl < 7) kind = NO_TRAP; break;
X case FIRE_TRAP:
X if (!Inhell) kind = NO_TRAP; break;
X }
X } while (kind == NO_TRAP || kind == MAGIC_PORTAL);
X }
X
X if (kind == TRAPDOOR && !Can_fall_thru(&u.uz)) kind = ROCKTRAP;
X
X if (tm)
X m = *tm;
X else {
X register int tryct = 0;
X
X do {
X if (++tryct > 200)
X return;
X if (mazeflag)
X mazexy(&m);
X else if (!somexy(croom,&m))
X return;
X } while (occupied(m.x, m.y) || is_pool(m.x,m.y) ||
X (sobj_at(BOULDER, m.x, m.y) &&
X (kind == PIT || kind == SPIKED_PIT ||
X kind == TRAPDOOR)));
X }
X
X (void) maketrap(m.x, m.y, kind);
X if (kind == WEB) (void) makemon(&mons[PM_GIANT_SPIDER], m.x, m.y);
X}
X
Xvoid
Xmkstairs(x, y, up, croom)
Xxchar x, y;
Xchar up;
Xstruct mkroom *croom;
X{
X if (! (x || y)) {
X impossible("mkstairs: bogus stair attempt at (%d,%d)", x, y);
X return;
X }
X
X /*
X * We can't make a regular stair off an end of the dungeon. This
X * attempt can happen when a special level is placed at an end and
X * has an up or down stair specified in its description file.
X */
X if ((dunlev(&u.uz) == 1 && up) ||
X (dunlev(&u.uz) == dunlevs_in_dungeon(&u.uz) && !up))
X return;
X
X if(up) {
X xupstair = x;
X yupstair = y;
X upstairs_room = croom;
X } else {
X xdnstair = x;
X ydnstair = y;
X dnstairs_room = croom;
X }
X
X levl[x][y].typ = STAIRS;
X levl[x][y].ladder = up ? LA_UP : LA_DOWN;
X}
X
Xstatic
Xvoid
Xmkfount(mazeflag,croom)
Xregister int mazeflag;
Xregister struct mkroom *croom;
X{
X coord m;
X register int tryct = 0;
X
X do {
X if(++tryct > 200) return;
X if(mazeflag)
X mazexy(&m);
X else
X if (!somexy(croom, &m))
X return;
X } while(occupied(m.x, m.y) || bydoor(m.x, m.y));
X
X /* Put a fountain at m.x, m.y */
X levl[m.x][m.y].typ = FOUNTAIN;
X /* Is it a "blessed" fountain? (affects drinking from fountain) */
X if(!rn2(7)) levl[m.x][m.y].blessedftn = 1;
X
X level.flags.nfountains++;
X}
X
X#ifdef SINKS
Xstatic void
Xmksink(croom)
Xregister struct mkroom *croom;
X{
X coord m;
X register int tryct = 0;
X
X do {
X if(++tryct > 200) return;
X if (!somexy(croom, &m))
X return;
X } while(occupied(m.x, m.y) || bydoor(m.x, m.y));
X
X /* Put a sink at m.x, m.y */
X levl[m.x][m.y].typ = SINK;
X
X level.flags.nsinks++;
X}
X#endif /* SINKS /**/
X
X
Xstatic void
Xmkaltar(croom)
Xregister struct mkroom *croom;
X{
X coord m;
X register int tryct = 0;
X aligntyp al;
X
X if(croom->rtype != OROOM) return;
X
X do {
X if(++tryct > 200) return;
X if (!somexy(croom, &m))
X return;
X } while(occupied(m.x, m.y) || bydoor(m.x, m.y));
X
X /* Put an altar at m.x, m.y */
X levl[m.x][m.y].typ = ALTAR;
X
X /* -1 - A_CHAOTIC, 0 - A_NEUTRAL, 1 - A_LAWFUL */
X al = rn2((int)A_LAWFUL+2) - 1;
X levl[m.x][m.y].altarmask = Align2amask( al );
X}
X
X/*
X * Major level transmutation: add a set of stairs (to the Sanctum) after
X * an earthquake that leaves behind a a new topology, centered at inv_pos.
X * Assumes there are no rooms within the invocation area and that inv_pos
X * is not too close to the edge of the map. Also assume the hero can see.
X */
Xvoid
Xmkinvokearea()
X{
X int dist;
X xchar xmin = inv_pos.x, xmax = inv_pos.x;
X xchar ymin = inv_pos.y, ymax = inv_pos.y;
X register xchar i;
X
X pline("The floor shakes violently under you!");
X pline("The walls around you begin to move and fall down!");
X display_nhwindow(WIN_MESSAGE, TRUE);
X
X for(dist = 1; dist < 7; dist++) {
X xmin--; xmax++;
X
X /* top and bottom */
X if(dist != 3) { /* the area is wider that it is high */
X ymin--; ymax++;
X for(i = xmin+1; i < xmax; i++) {
X mkinvpos(i, ymin, dist);
X mkinvpos(i, ymax, dist);
X }
X }
X
X /* left and right */
X for(i = ymin; i <= ymax; i++) {
X mkinvpos(xmin, i, dist);
X mkinvpos(xmax, i, dist);
X }
X
X flush_screen(1); /* make sure the new glyphs shows up */
X delay_output();
X }
X
X You("are standing at the top of a stairwell leading down!");
X mkstairs(u.ux, u.uy, 0, (struct mkroom *)0); /* down */
X newsym(u.ux, u.uy);
X vision_full_recalc = 1; /* everything changed */
X}
X
X/* Change level topology. Messes with vision tables and ignores things like
X * boulders in the name of a nice effect. Vision will get fixed up again
X * immediately after the effect is complete.
X */
Xstatic void
Xmkinvpos(x,y,dist)
Xxchar x,y;
Xint dist;
X{
X struct trap *ttmp;
X register struct rm *lev = &levl[x][y];
X
X unblock_point(x,y); /* make sure vision knows this location is open */
X
X /* fake out saved state */
X lev->seen = FALSE;
X lev->doormask = 0;
X if(dist < 6) lev->lit = TRUE;
X lev->waslit = TRUE;
X lev->horizontal = FALSE;
X viz_array[y][x] = (dist < 6 ) ?
X (IN_SIGHT|COULD_SEE) : /* short-circuit vision recalc */
X COULD_SEE;
X
X switch(dist) {
X case 1: /* fire traps */
X lev->typ = ROOM;
X if (is_pool(x,y)) break;
X ttmp = maketrap(x, y, FIRE_TRAP);
X ttmp->tseen = TRUE;
X break;
X case 2: /* lit room locations */
X case 3:
X case 6:
X if ((ttmp = t_at(x,y)) != 0) deltrap(ttmp);
X lev->typ = ROOM;
X break;
X case 4: /* pools (aka a wide moat) */
X case 5:
X if ((ttmp = t_at(x,y)) != 0) deltrap(ttmp);
X lev->typ = MOAT;
X break;
X default:
X impossible("mkinvpos called with dist %d", dist);
X break;
X }
X
X /* display new value of position; could have a monster/object on it */
X newsym(x,y);
X}
X
X#ifdef MULDGN
X/*
X * The portal to Ludios is special. The entrance can only occur within a
X * vault in the main dungeon at a depth greater than 10. The Ludios branch
X * structure reflects this by having a bogus "source" dungeon: the value
X * of n_dgns (thus, Is_branchlev() will never find it).
X *
X * Ludios will remain isolated until the branch is corrected by this function.
X */
Xstatic void
Xmk_knox_portal(x, y)
Xxchar x, y;
X{
X extern int n_dgns; /* from dungeon.c */
X d_level *source;
X branch *br;
X xchar u_depth;
X
X br = dungeon_branch("Fort Ludios");
X if (on_level(&knox_level, &br->end1)) {
X source = &br->end2;
X } else {
X /* disallow Knox branch on a level with one branch already */
X if(Is_branchlev(&u.uz))
X return;
X source = &br->end1;
X }
X
X /* Already set or 2/3 chance of deferring until a later level. */
X if (source->dnum < n_dgns || (rn2(3)
X#ifdef WIZARD
X && !wizard
X#endif
X )) return;
X
X if (! (u.uz.dnum == oracle_level.dnum /* in main dungeon */
X && !at_dgn_entrance("The Quest") /* but not Quest's entry */
X && (u_depth = depth(&u.uz)) > 10 /* beneath 10 */
X && u_depth < depth(&medusa_level))) /* and above Medusa */
X return;
X
X /* Adjust source to be current level and re-insert branch. */
X *source = u.uz;
X insert_branch(br, TRUE);
X
X# ifdef DEBUG
X pline("Made knox portal.");
X# endif
X place_branch(br, x, y);
X}
X#endif
X
X/*mklev.c*/
END_OF_FILE
if test 33549 -ne `wc -c <'src/mklev.c'`; then
echo shar: \"'src/mklev.c'\" unpacked with wrong size!
fi
# end of 'src/mklev.c'
fi
if test -f 'src/save.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/save.c'\"
else
echo shar: Extracting \"'src/save.c'\" \(19844 characters\)
sed "s/^X//" >'src/save.c' <<'END_OF_FILE'
X/* SCCS Id: @(#)save.c 3.1 93/01/07 */
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
X/* NetHack may be freely redistributed. See license for details. */
X
X#include "hack.h"
X#include "lev.h"
X
X#ifndef NO_SIGNAL
X#include <signal.h>
X#endif /* !NO_SIGNAL */
X#if defined(EXPLORE_MODE) && !defined(LSC) && !defined(O_WRONLY) && !defined(AZTEC_C)
X#include <fcntl.h>
X#endif /* EXPLORE_MODE */
X
Xboolean hu; /* set during hang-up */
X
X#ifdef MULDGN
X#include "quest.h"
X#endif
X
X#ifdef MFLOPPY
Xextern struct finfo fileinfo[];
Xlong bytes_counted;
Xstatic int count_only;
X#else
Xextern boolean level_exists[];
X#endif
X
X#ifdef MICRO
Xint dotcnt; /* also used in restore */
X#endif
X
X#ifdef ZEROCOMP
Xstatic void FDECL(bputc, (UCHAR_P));
X#endif
Xstatic void FDECL(savelevchn, (int, int));
Xstatic void FDECL(savedamage, (int,struct damage *, int));
Xstatic void FDECL(saveobjchn, (int,struct obj *, int));
Xstatic void FDECL(savemonchn, (int,struct monst *, int));
Xstatic void FDECL(savetrapchn, (int,struct trap *, int));
Xstatic void FDECL(savegenoinfo, (int));
Xstatic void FDECL(savegamestate, (int, int));
X#ifdef MFLOPPY
Xstatic void FDECL(savelev0, (int,XCHAR_P,int));
Xstatic boolean NDECL(swapout_oldest);
Xstatic void FDECL(copyfile, (char *,char *));
X#endif /* MFLOPPY */
X#ifdef GCC_WARN
Xstatic long nulls[10];
X#else
X#define nulls nul
X#endif
X
Xint
Xdosave()
X{
X clear_nhwindow(WIN_MESSAGE);
X if(yn("Really save?") == 'n') {
X clear_nhwindow(WIN_MESSAGE);
X if(multi > 0) nomul(0);
X } else {
X clear_nhwindow(WIN_MESSAGE);
X pline("Saving...");
X mark_synch(); /* flush output */
X hu = FALSE;
X if(dosave0()) {
X /* make sure they see the Saving message */
X display_nhwindow(WIN_MESSAGE, TRUE);
X exit_nhwindows("Be seeing you...");
X terminate(0);
X } else (void)doredraw();
X }
X return 0;
X}
X
X#ifndef NOSAVEONHANGUP
Xint
Xhangup() {
X if(!hu) {
X hu = TRUE;
X (void) dosave0();
X# ifndef VMS
X terminate(1);
X# endif
X }
X return 0;
X}
X#endif
X
X/* returns 1 if save successful */
Xint
Xdosave0()
X{
X register int fd, ofd;
X xchar ltmp;
X#ifdef MFLOPPY
X long fds, needed;
X#endif
X
X if (!SAVEF[0])
X return 0;
X
X#if defined(UNIX) || defined(VMS)
X (void) signal(SIGHUP, SIG_IGN);
X#endif
X#ifndef NO_SIGNAL
X (void) signal(SIGINT, SIG_IGN);
X#endif
X
X#if defined(MICRO) && defined(MFLOPPY)
X if(!hu && !saveDiskPrompt(0)) return 0;
X#endif
X
X#ifdef EXPLORE_MODE
X if(!hu && flags.window_inited) {
X fd = open_savefile();
X if (fd > 0) {
X (void) close(fd);
X clear_nhwindow(WIN_MESSAGE);
X pline("There seems to be an old save file.");
X if (yn("Overwrite the old file?") == 'n') return 0;
X }
X }
X#endif
X
X fd = create_savefile();
X
X if(fd < 0) {
X if(!hu) pline("Cannot open save file.");
X (void) delete_savefile(); /* ab@unido */
X return(0);
X }
X if(flags.moonphase == FULL_MOON) /* ut-sally!fletcher */
X change_luck(-1); /* and unido!ab */
X if(flags.friday13)
X change_luck(1);
X if(flags.window_inited)
X clear_nhwindow(WIN_MESSAGE);
X
X#ifdef MFLOPPY
X if(!hu) {
X dotcnt = 0;
X curs(WIN_MAP, 1, 1);
X putstr(WIN_MAP, 0, "Saving:");
X }
X /* make sure there is enough disk space */
X savelev(fd, ledger_no(&u.uz), COUNT_SAVE);
X savegamestate(fd, COUNT_SAVE);
X needed = bytes_counted;
X for (ltmp = 1; ltmp <= maxledgerno(); ltmp++)
X if (ltmp != ledger_no(&u.uz) && fileinfo[ltmp].where)
X needed += fileinfo[ltmp].size + (sizeof ltmp);
X# ifdef AMIGA
X needed+=ami_wbench_iconsize(SAVEF);
X# endif
X fds = freediskspace(SAVEF);
X if(needed > fds) {
X if(!hu) {
X pline("There is insufficient space on SAVE disk.");
X pline("Require %ld bytes but only have %ld.", needed, fds);
X }
X flushout();
X (void) close(fd);
X (void) delete_savefile();
X return 0;
X }
X#endif /* MFLOPPY */
X
X bufon(fd);
X savelev(fd, ledger_no(&u.uz), WRITE_SAVE | FREE_SAVE);
X savegamestate(fd, WRITE_SAVE | FREE_SAVE);
X
X for(ltmp = (xchar)1; ltmp <= maxledgerno(); ltmp++) {
X if (ltmp == ledger_no(&u.uz)) continue;
X#ifdef MFLOPPY
X if (!fileinfo[ltmp].where) continue;
X#else
X if(!level_exists[ltmp]) continue;
X#endif
X#ifdef MICRO
X if(!hu) {
X curs(WIN_MAP, 8 + dotcnt++, 1);
X putstr(WIN_MAP, 0, ".");
X }
X#endif
X ofd = open_levelfile(ltmp);
X if(ofd < 0) {
X if(!hu) pline("Cannot read level %d.", ltmp);
X (void) close(fd);
X (void) delete_savefile();
X if(!hu) done(TRICKED);
X return(0);
X }
X minit(); /* ZEROCOMP */
X getlev(ofd, hackpid, ltmp, FALSE);
X (void) close(ofd);
X bwrite(fd, (genericptr_t) <mp, sizeof ltmp); /* level number*/
X savelev(fd, ltmp, WRITE_SAVE | FREE_SAVE); /* actual level*/
X delete_levelfile(ltmp);
X }
X bclose(fd);
X
X /* get rid of current level --jgm */
X delete_levelfile(ledger_no(&u.uz));
X delete_levelfile(0);
X compress(SAVEF);
X#ifdef AMIGA
X ami_wbench_iconwrite(SAVEF);
X#endif
X return(1);
X}
X
Xstatic void
Xsavegamestate(fd, mode)
Xregister int fd, mode;
X{
X int tmp; /* not register ! */
X
X#ifdef MFLOPPY
X count_only = (mode & COUNT_SAVE);
X#endif
X saveobjchn(fd, invent, mode);
X saveobjchn(fd, migrating_objs, mode);
X savemonchn(fd, migrating_mons, mode);
X savegenoinfo(fd);
X tmp = getuid();
X bwrite(fd, (genericptr_t) &tmp, sizeof tmp);
X bwrite(fd, (genericptr_t) &flags, sizeof(struct flag));
X bwrite(fd, (genericptr_t) &u, sizeof(struct you));
X save_dungeon(fd);
X bwrite(fd, (genericptr_t) &inv_pos, sizeof inv_pos);
X savelevchn(fd, mode);
X bwrite(fd, (genericptr_t) &moves, sizeof moves);
X bwrite(fd, (genericptr_t) &monstermoves, sizeof monstermoves);
X#ifdef MULDGN
X bwrite(fd, (genericptr_t) &quest_status, sizeof(struct q_score));
X#endif
X bwrite(fd, (genericptr_t) spl_book,
X sizeof(struct spell) * (MAXSPELL + 1));
X save_artifacts(fd);
X save_oracles(fd);
X if(u.ustuck)
X bwrite(fd, (genericptr_t) &(u.ustuck->m_id), sizeof u.ustuck->m_id);
X bwrite(fd, (genericptr_t) pl_character, sizeof pl_character);
X#ifdef TUTTI_FRUTTI
X bwrite(fd, (genericptr_t) pl_fruit, sizeof pl_fruit);
X bwrite(fd, (genericptr_t) ¤t_fruit, sizeof current_fruit);
X savefruitchn(fd, mode);
X#endif
X savenames(fd);
X save_waterlevel(fd);
X bflush(fd);
X}
X
X#ifdef INSURANCE
Xvoid
Xsavestateinlock()
X{
X int fd, hpid;
X static boolean havestate = TRUE;
X
X /* When checkpointing is on, the full state needs to be written
X * on each checkpoint. When checkpointing is off, only the pid
X * needs to be in the level.0 file, so it does not need to be
X * constantly rewritten. When checkpointing is turned off during
X * a game, however, the file has to be rewritten once to truncate
X * it and avoid restoring from outdated information.
X *
X * Restricting havestate to this routine means that an additional
X * noop pid rewriting will take place on the first "checkpoint" after
X * the game is started or restored, if checkpointing is off.
X */
X if (flags.ins_chkpt || havestate) {
X /* save the rest of the current game state in the lock file,
X * following the original int pid, the current level number,
X * and the current savefile name, which should not be subject
X * to any internal compression schemes since they must be
X * readable by an external utility
X */
X fd = open_levelfile(0);
X if (fd < 0) {
X pline("Cannot open level 0.");
X pline("Probably someone removed it.");
X done(TRICKED);
X return;
X }
X
X (void) read(fd, (genericptr_t) &hpid, sizeof(hpid));
X if (hackpid != hpid) {
X pline("Level 0 pid bad!");
X done(TRICKED);
X }
X (void) close(fd);
X
X fd = create_levelfile(0);
X if (fd < 0) {
X pline("Cannot rewrite level 0.");
X done(TRICKED);
X return;
X }
X (void) write(fd, (genericptr_t) &hackpid, sizeof(hackpid));
X if (flags.ins_chkpt) {
X int currlev = ledger_no(&u.uz);
X
X (void) write(fd, (genericptr_t) &currlev, sizeof(currlev));
X save_savefile_name(fd);
X bufon(fd);
X savegamestate(fd, WRITE_SAVE);
X }
X bclose(fd);
X }
X havestate = flags.ins_chkpt;
X}
X#endif
X
X#ifdef MFLOPPY
Xboolean
Xsavelev(fd, lev, mode)
Xint fd;
Xxchar lev;
Xint mode;
X{
X if (mode & COUNT_SAVE) {
X bytes_counted = 0;
X savelev0(fd, lev, COUNT_SAVE);
X while (bytes_counted > freediskspace(levels))
X if (!swapout_oldest())
X return FALSE;
X }
X if (mode & WRITE_SAVE) {
X bytes_counted = 0;
X /* mode is WRITE_SAVE and possibly FREE_SAVE */
X savelev0(fd, lev, mode);
X }
X fileinfo[lev].where = ACTIVE;
X fileinfo[lev].time = moves;
X fileinfo[lev].size = bytes_counted;
X return TRUE;
X}
X
Xstatic void
Xsavelev0(fd,lev,mode)
X#else
Xvoid
Xsavelev(fd,lev,mode)
X#endif
Xint fd;
Xxchar lev;
Xint mode;
X{
X#ifdef TOS
X short tlev;
X#endif
X
X if(fd < 0) panic("Save on bad file!"); /* impossible */
X#ifdef MFLOPPY
X count_only = (mode & COUNT_SAVE);
X#else
X if(lev >= 0 && lev <= maxledgerno()) level_exists[lev] = TRUE;
X#endif
X bwrite(fd,(genericptr_t) &hackpid,sizeof(hackpid));
X#ifdef TOS
X tlev=lev; tlev &= 0x00ff;
X bwrite(fd,(genericptr_t) &tlev,sizeof(tlev));
X#else
X bwrite(fd,(genericptr_t) &lev,sizeof(lev));
X#endif
X#ifdef RLECOMP
X {
X /* perform run-length encoding of rm structs */
X struct rm *prm, *rgrm;
X int x, y;
X uchar match;
X
X rgrm = &levl[0][0]; /* start matching at first rm */
X match = 0;
X
X for (y = 0; y < ROWNO; y++) {
X for (x = 0; x < COLNO; x++) {
X prm = &levl[x][y];
X if (prm->glyph == rgrm->glyph
X && prm->typ == rgrm->typ
X && prm->seen == rgrm->seen
X && prm->lit == rgrm->lit
X && prm->doormask == rgrm->doormask
X && prm->horizontal == rgrm->horizontal
X && prm->waslit == rgrm->waslit
X && prm->roomno == rgrm->roomno
X && prm->edge == rgrm->edge) {
X match++;
X if (match > 254) {
X match = 254; /* undo this match */
X goto writeout;
X }
X } else {
X /* the run has been broken,
X * write out run-length encoding */
X writeout:
X bwrite(fd, (genericptr_t)&match, sizeof(uchar));
X bwrite(fd, (genericptr_t)rgrm, sizeof(struct rm));
X /* start encoding again. we have at least 1 rm
X * in the next run, viz. this one. */
X match = 1;
X rgrm = prm;
X }
X }
X }
X if (match > 0) {
X bwrite(fd, (genericptr_t)&match, sizeof(uchar));
X bwrite(fd, (genericptr_t)rgrm, sizeof(struct rm));
X }
X }
X#else
X bwrite(fd,(genericptr_t) levl,sizeof(levl));
X#endif /* RLECOMP */
X
X bwrite(fd,(genericptr_t) &monstermoves,sizeof(monstermoves));
X bwrite(fd,(genericptr_t) &upstair,sizeof(stairway));
X bwrite(fd,(genericptr_t) &dnstair,sizeof(stairway));
X bwrite(fd,(genericptr_t) &upladder,sizeof(stairway));
X bwrite(fd,(genericptr_t) &dnladder,sizeof(stairway));
X bwrite(fd,(genericptr_t) &sstairs,sizeof(stairway));
X bwrite(fd,(genericptr_t) &updest,sizeof(dest_area));
X bwrite(fd,(genericptr_t) &dndest,sizeof(dest_area));
X bwrite(fd,(genericptr_t) &level.flags,sizeof(level.flags));
X savemonchn(fd, fmon, mode);
X save_worm(fd, mode); /* save worm information */
X savetrapchn(fd, ftrap, mode);
X saveobjchn(fd, fobj, mode);
X saveobjchn(fd, billobjs, mode);
X
X save_engravings(fd, mode);
X save_rooms(fd);
X bwrite(fd,(genericptr_t) doors,sizeof(doors));
X savedamage(fd, level.damagelist, mode);
X if (mode & FREE_SAVE) {
X billobjs = 0;
X ftrap = 0;
X fmon = 0;
X fobj = 0;
X }
X bflush(fd);
X}
X
X#ifdef ZEROCOMP
X/* The runs of zero-run compression are flushed after the game state or a
X * level is written out. This adds a couple bytes to a save file, where
X * the runs could be mashed together, but it allows gluing together game
X * state and level files to form a save file, and it means the flushing
X * does not need to be specifically called for every other time a level
X * file is written out.
X */
X
X#define RLESC '\0' /* Leading character for run of LRESC's */
X#define flushoutrun(ln) (bputc(RLESC), bputc(ln), ln = -1)
X
X#ifndef ZEROCOMP_BUFSIZ
X#define ZEROCOMP_BUFSIZ BUFSZ
X#endif
Xstatic unsigned char NEARDATA outbuf[ZEROCOMP_BUFSIZ];
Xstatic unsigned short NEARDATA outbufp = 0;
Xstatic short NEARDATA outrunlength = -1;
Xstatic int NEARDATA bwritefd;
X
X/*dbg()
X{
X if(!hu) printf("outbufp %d outrunlength %d\n", outbufp,outrunlength);
X}*/
X
Xstatic void
Xbputc(c)
Xunsigned char c;
X{
X#ifdef MFLOPPY
X bytes_counted++;
X if (count_only)
X return;
X#endif
X if (outbufp >= sizeof outbuf) {
X (void) write(bwritefd, outbuf, sizeof outbuf);
X outbufp = 0;
X }
X outbuf[outbufp++] = c;
X}
X
X/*ARGSUSED*/
Xvoid
Xbufon(fd)
X int fd;
X{
X return;
X}
X
Xvoid
Xbflush(fd) /* flush run and buffer */
Xregister int fd;
X{
X bwritefd = fd;
X if (outrunlength >= 0) { /* flush run */
X flushoutrun(outrunlength);
X }
X if (outbufp) {
X#ifdef MFLOPPY
X if (!count_only) /* flush buffer */
X#endif
X (void) write(fd, outbuf, outbufp);
X outbufp = 0;
X }
X /*printf("bflush()"); getret();*/
X}
X
Xvoid
Xbwrite(fd, loc, num)
Xregister int fd;
Xgenericptr_t loc;
Xregister unsigned num;
X{
X bwritefd = fd;
X for (; num; num--, (*(char **)&loc)++) {
X if (*((char *)loc) == RLESC) { /* One more char in run */
X if (++outrunlength == 0xFF) {
X flushoutrun(outrunlength);
X }
X } else { /* end of run */
X if (outrunlength >= 0) { /* flush run */
X flushoutrun(outrunlength);
X }
X bputc(*((char *)loc));
X }
X }
X}
X
Xvoid
Xbclose(fd)
X int fd;
X{
X if (outbufp)
X panic("closing file with buffered data still unwritten");
X (void) close(fd);
X}
X
X#else /* ZEROCOMP */
X
Xstatic int bw_fd = -1;
Xstatic FILE *bw_FILE = 0;
X
Xvoid
Xbufon(fd)
X int fd;
X{
X#ifdef UNIX
X if(bw_fd >= 0)
X panic("double buffering unexpected");
X bw_fd = fd;
X if((bw_FILE = fdopen(fd, "w")) == 0)
X panic("buffering of file %d failed", fd);
X#endif
X}
X
Xvoid
Xbflush(fd)
X int fd;
X{
X#ifdef UNIX
X if(fd == bw_fd) {
X if(fflush(bw_FILE) == EOF)
X panic("flush of savefile failed!");
X }
X#endif
X return;
X}
X
Xvoid
Xbwrite(fd,loc,num)
Xregister int fd;
Xregister genericptr_t loc;
Xregister unsigned num;
X{
X#ifdef MFLOPPY
X bytes_counted += num;
X if (!count_only)
X#endif
X {
X#ifdef UNIX
X if(fd != bw_fd)
X panic("unbuffered write to fd %d (!= %d)", fd, bw_fd);
X
X if(fwrite(loc, (int)num, 1, bw_FILE) != 1)
X/* lint wants the 3rd arg of write to be an int; lint -p an unsigned */
X#else
X# if defined(BSD) || defined(ULTRIX)
X if(write(fd, loc, (int)num) != (int)num)
X# else /* e.g. SYSV, __TURBOC__ */
X if(write(fd, loc, num) != num)
X# endif
X#endif
X {
X if(!hu) panic("cannot write %u bytes to file #%d", num, fd);
X else terminate(1);
X }
X }
X}
X
Xvoid
Xbclose(fd)
X int fd;
X{
X bflush(fd);
X#ifdef UNIX
X if (fd == bw_fd) {
X (void) fclose(bw_FILE);
X bw_fd = -1;
X bw_FILE = 0;
X return;
X }
X#endif
X (void) close(fd);
X}
X#endif /* ZEROCOMP */
X
Xstatic void
Xsavelevchn(fd, mode)
Xregister int fd, mode;
X{
X int cnt = 0;
X s_level *tmplev, *tmplev2;
X
X for(tmplev = sp_levchn; tmplev; tmplev = tmplev->next) cnt++;
X bwrite(fd, (genericptr_t) &cnt, sizeof(int));
X
X for(tmplev = sp_levchn; tmplev; tmplev = tmplev2) {
X
X tmplev2 = tmplev->next;
X bwrite(fd, (genericptr_t) tmplev, sizeof(s_level));
X if (mode & FREE_SAVE)
X free((genericptr_t) tmplev);
X }
X}
X
Xstatic void
Xsavedamage(fd, damageptr, mode)
Xregister int fd, mode;
Xregister struct damage *damageptr;
X{
X register struct damage *tmp_dam;
X unsigned int xl = 0;
X
X for (tmp_dam = damageptr; tmp_dam; tmp_dam = tmp_dam->next)
X xl++;
X bwrite(fd, (genericptr_t) &xl, sizeof(xl));
X while (xl--) {
X bwrite(fd, (genericptr_t) damageptr, sizeof(*damageptr));
X tmp_dam = damageptr;
X damageptr = damageptr->next;
X if (mode & FREE_SAVE)
X free((genericptr_t)tmp_dam);
X }
X if (mode & FREE_SAVE)
X level.damagelist = 0;
X}
X
Xstatic void
Xsaveobjchn(fd,otmp,mode)
Xregister int fd, mode;
Xregister struct obj *otmp;
X{
X register struct obj *otmp2;
X unsigned int xl;
X int minusone = -1;
X
X while(otmp) {
X otmp2 = otmp->nobj;
X xl = otmp->onamelth;
X bwrite(fd, (genericptr_t) &xl, sizeof(int));
X bwrite(fd, (genericptr_t) otmp, xl + sizeof(struct obj));
X
X if (Is_container(otmp) || otmp->otyp == STATUE)
X saveobjchn(fd,otmp->cobj,mode);
X if (mode & FREE_SAVE)
X dealloc_obj(otmp);
X otmp = otmp2;
X }
X bwrite(fd, (genericptr_t) &minusone, sizeof(int));
X}
X
Xstatic void
Xsavemonchn(fd,mtmp,mode)
Xregister int fd, mode;
Xregister struct monst *mtmp;
X{
X register struct monst *mtmp2;
X unsigned int xl;
X int minusone = -1;
X struct permonst *monbegin = &mons[0];
X
X bwrite(fd, (genericptr_t) &monbegin, sizeof(monbegin));
X
X while(mtmp) {
X mtmp2 = mtmp->nmon;
X#ifdef MUSE
X if (mtmp->mw && mtmp->mw != mtmp->minvent) sort_mwep(mtmp);
X#endif
X xl = mtmp->mxlth + mtmp->mnamelth;
X bwrite(fd, (genericptr_t) &xl, sizeof(int));
X bwrite(fd, (genericptr_t) mtmp, xl + sizeof(struct monst));
X if(mtmp->minvent) saveobjchn(fd,mtmp->minvent,mode);
X if (mode & FREE_SAVE)
X dealloc_monst(mtmp);
X mtmp = mtmp2;
X }
X bwrite(fd, (genericptr_t) &minusone, sizeof(int));
X}
X
Xstatic void
Xsavetrapchn(fd,trap,mode)
Xregister int fd,mode;
Xregister struct trap *trap;
X{
X register struct trap *trap2;
X while(trap) {
X trap2 = trap->ntrap;
X bwrite(fd, (genericptr_t) trap, sizeof(struct trap));
X if (mode & FREE_SAVE)
X dealloc_trap(trap);
X trap = trap2;
X }
X bwrite(fd, (genericptr_t)nulls, sizeof(struct trap));
X}
X
X#ifdef TUTTI_FRUTTI
X/* save all the fruit names and ID's; this is used only in saving whole games
X * (not levels) and in saving bones levels. When saving a bones level,
X * we only want to save the fruits which exist on the bones level; the bones
X * level routine marks nonexistent fruits by making the fid negative.
X */
Xvoid
Xsavefruitchn(fd, mode)
Xregister int fd, mode;
X{
X register struct fruit *f2, *f1;
X
X f1 = ffruit;
X while(f1) {
X f2 = f1->nextf;
X if (f1->fid >= 0) {
X bwrite(fd, (genericptr_t) f1, sizeof(struct fruit));
X }
X if (mode & FREE_SAVE)
X dealloc_fruit(f1);
X f1 = f2;
X }
X bwrite(fd, (genericptr_t)nulls, sizeof(struct fruit));
X}
X#endif
X
Xstatic void
Xsavegenoinfo(fd)
Xregister int fd;
X{
X register int i;
X unsigned genolist[NUMMONS];
X
X for (i = 0; i < NUMMONS; i++)
X genolist[i] = mons[i].geno;
X
X bwrite(fd, (genericptr_t) genolist, sizeof(genolist));
X}
X
X#ifdef MFLOPPY
Xboolean
Xswapin_file(lev)
Xint lev;
X{
X char to[PATHLEN], from[PATHLEN];
X
X Sprintf(from, "%s%s", permbones, alllevels);
X Sprintf(to, "%s%s", levels, alllevels);
X set_levelfile_name(from, lev);
X set_levelfile_name(to, lev);
X while (fileinfo[lev].size > freediskspace(to))
X if (!swapout_oldest())
X return FALSE;
X# ifdef WIZARD
X if (wizard) {
X pline("Swapping in `%s'", from);
X wait_synch();
X }
X# endif
X copyfile(from, to);
X (void) unlink(from);
X fileinfo[lev].where = ACTIVE;
X return TRUE;
X}
X
Xstatic boolean
Xswapout_oldest() {
X char to[PATHLEN], from[PATHLEN];
X int i, oldest;
X long oldtime;
X
X if (!ramdisk)
X return FALSE;
X for (i = 1, oldtime = 0, oldest = 0; i <= maxledgerno(); i++)
X if (fileinfo[i].where == ACTIVE
X && (!oldtime || fileinfo[i].time < oldtime)) {
X oldest = i;
X oldtime = fileinfo[i].time;
X }
X if (!oldest)
X return FALSE;
X Sprintf(from, "%s%s", levels, alllevels);
X Sprintf(to, "%s%s", permbones, alllevels);
X set_levelfile_name(from, oldest);
X set_levelfile_name(to, oldest);
X# ifdef WIZARD
X if (wizard) {
X pline("Swapping out `%s'.", from);
X wait_synch();
X }
X# endif
X copyfile(from, to);
X (void) unlink(from);
X fileinfo[oldest].where = SWAPPED;
X return TRUE;
X}
X
Xstatic void
Xcopyfile(from, to)
Xchar *from, *to;
X{
X# ifdef TOS
X
X if (_copyfile(from, to))
X panic("Can't copy %s to %s", from, to);
X# else
X char buf[BUFSIZ]; /* this is system interaction, therefore
X * BUFSIZ instead of NetHack's BUFSZ */
X int nfrom, nto, fdfrom, fdto;
X
X if ((fdfrom = open(from, O_RDONLY | O_BINARY, FCMASK)) < 0)
X panic("Can't copy from %s !?", from);
X if ((fdto = open(to, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK)) < 0)
X panic("Can't copy to %s", to);
X do {
X nfrom = read(fdfrom, buf, BUFSIZ);
X nto = write(fdto, buf, nfrom);
X if (nto != nfrom)
X panic("Copyfile failed!");
X } while (nfrom == BUFSIZ);
X (void) close(fdfrom);
X (void) close(fdto);
X# endif /* TOS */
X}
X
Xvoid
Xco_false() /* see comment in bones.c */
X{
X count_only = FALSE;
X return;
X}
X
X#endif /* MFLOPPY */
X
X/*save.c*/
END_OF_FILE
if test 19844 -ne `wc -c <'src/save.c'`; then
echo shar: \"'src/save.c'\" unpacked with wrong size!
fi
# end of 'src/save.c'
fi
echo shar: End of archive 54 \(of 108\).
cp /dev/null ark54isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 \
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 \
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 \
101 102 103 104 105 106 107 108 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 108 archives.
echo "Now execute 'rebuild.sh'"
rm -f ark10[0-8]isdone ark[1-9]isdone ark[1-9][0-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0