static void savetrapchn(struct memfile *mf, struct trap *trap, struct level *lev) { struct trap *trap2; unsigned short tflags; int count = 0; mfmagic_set(mf, TRAPCHAIN_MAGIC); for (trap2 = trap; trap2; trap2 = trap2->ntrap) count++; mwrite32(mf, count); for (; trap; trap = trap->ntrap) { /* To distinguish traps from each other in tags, we use x/y/z coords */ mtag(mf, ledger_no(&lev->z) + ((int)trap->tx << 8) + ((int)trap->ty << 16), MTAG_TRAP); mwrite8(mf, trap->tx); mwrite8(mf, trap->ty); mwrite8(mf, trap->dst.dnum); mwrite8(mf, trap->dst.dlevel); mwrite8(mf, trap->launch.x); mwrite8(mf, trap->launch.y); tflags = (trap->ttyp << 11) | (trap->tseen << 10) | (trap->once << 9) | (trap->madeby_u << 8); mwrite16(mf, tflags); mwrite16(mf, trap->vl.v_launch_otyp); } }
/* extract a shopkeeper name for the given shop type */ static void nameshk (struct monst *shk, const char *const *nlp) { int i, trycnt, names_avail; const char *shname = 0; struct monst *mtmp; int name_wanted; s_level *sptr; if (nlp == shklight && In_mines(&u.uz) && (sptr = Is_special(&u.uz)) != 0 && sptr->flags.town) { /* special-case minetown lighting shk */ shname = "Izchak"; shk->female = false; } else { /* We want variation from game to game, without needing the save and restore support which would be necessary for randomization; try not to make too many assumptions about time_t's internals; use ledger_no rather than depth to keep mine town distinct. */ int nseed = (int)((long)u.ubirthday / 257L); name_wanted = ledger_no(&u.uz) + (nseed % 13) - (nseed % 5); if (name_wanted < 0) name_wanted += (13 + 5); shk->female = name_wanted & 1; for (names_avail = 0; nlp[names_avail]; names_avail++) continue; for (trycnt = 0; trycnt < 50; trycnt++) { if (nlp == shktools) { shname = shktools[rn2(names_avail)]; shk->female = (*shname == '_'); if (shk->female) shname++; } else if (name_wanted < names_avail) { shname = nlp[name_wanted]; } else if ((i = rn2(names_avail)) != 0) { shname = nlp[i - 1]; } else if (nlp != shkgeneral) { nlp = shkgeneral; /* try general names */ for (names_avail = 0; nlp[names_avail]; names_avail++) continue; continue; /* next `trycnt' iteration */ } else { shname = shk->female ? "Lucrezia" : "Dirk"; } /* is name already in use on this level? */ for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp) || (mtmp == shk) || !mtmp->isshk) continue; if (strcmp(ESHK(mtmp)->shknam, shname)) continue; break; } if (!mtmp) break; /* new name */ } } (void) strncpy(ESHK(shk)->shknam, shname, PL_NSIZ); ESHK(shk)->shknam[PL_NSIZ-1] = 0; }
/** * save_regions : */ void save_regions(struct memfile *mf, struct level *lev) { int i, j; unsigned len1, len2; struct region *r; mfmagic_set(mf, REGION_MAGIC); mtag(mf, ledger_no(&lev->z), MTAG_REGION); mwrite32(mf, save_encode_32(moves, moves, moves)); /* timestamp */ mwrite32(mf, lev->n_regions); /* Note: level regions don't have ID numbers, so we can't tag individual regions; instead, diff efficiency depends on the fact that regions tend to stay in the order and are typically inserted or deleted near the end of the list */ for (i = 0; i < lev->n_regions; i++) { r = lev->regions[i]; save_rect(mf, r->bounding_box); mwrite32(mf, r->attach_2_m); mwrite32(mf, r->effect_id); mwrite32(mf, r->arg); mwrite16(mf, r->nrects); for (j = 0; j < r->nrects; j++) save_rect(mf, r->rects[j]); mwrite16(mf, r->ttl); mwrite16(mf, r->expire_f); mwrite16(mf, r->can_enter_f); mwrite16(mf, r->enter_f); mwrite16(mf, r->can_leave_f); mwrite16(mf, r->leave_f); mwrite16(mf, r->inside_f); mwrite16(mf, r->n_monst); mwrite8(mf, r->player_flags); mwrite8(mf, r->attach_2_u); mwrite8(mf, r->visible); for (j = 0; j < r->n_monst; j++) mwrite32(mf, r->monsters[j]); len1 = r->enter_msg ? strlen(r->enter_msg) + 1 : 0; mwrite16(mf, len1); len2 = r->leave_msg ? strlen(r->leave_msg) + 1 : 0; mwrite16(mf, len2); if (len1 > 0) mwrite(mf, r->enter_msg, len1); if (len2 > 0) mwrite(mf, r->leave_msg, len2); } }
/* * save_rooms : Save all the rooms on disk! */ void save_rooms(struct memfile *mf, struct level *lev) { short i; mfmagic_set(mf, ROOMS_MAGIC); /* "RDAT" */ mtag(mf, ledger_no(&lev->z), MTAG_ROOMS); /* First, write the number of rooms */ mwrite32(mf, lev->nroom); for (i = 0; i < lev->nroom; i++) save_room(mf, &lev->rooms[i]); }
/* Save all light sources of the given range. */ void save_light_sources(struct memfile *mf, struct level *lev, int range) { int count, actual; mtag(mf, 2 * (int)ledger_no(&lev->z) + range, MTAG_LIGHTS); count = maybe_write_ls(mf, lev, range, FALSE); mwrite32(mf, count); actual = maybe_write_ls(mf, lev, range, TRUE); if (actual != count) panic("counted %d light sources, wrote %d! [range=%d]", count, actual, range); }
STATIC_OVL boolean uz_no_bones_level() { extern d_level save_dlevel; /* in do.c */ s_level *sptr; if (ledger_no(&save_dlevel)) assign_level(&u.uz, &save_dlevel); return (boolean) (((sptr = uz_is_special()) != 0 && !sptr->boneid) || !dungeons[u.uz.dnum].boneid /* no bones on the last or multiway branch levels in any dungeon (level 1 isn't multiway) */ || uz_is_botlevel() || (uz_is_branchlev() && u.uz.dlevel > 1) /* no bones in the invocation level */ || (uz_in_hell() && u.uz.dlevel == dunlevs_in_uz_dungeon() - 1)); }
static void savedamage(struct memfile *mf, struct level *lev) { struct damage *damageptr; unsigned int xl = 0; mtag(mf, ledger_no(&lev->z), MTAG_DAMAGE); for (damageptr = lev->damagelist; damageptr; damageptr = damageptr->next) xl++; mwrite32(mf, xl); for (damageptr = lev->damagelist; damageptr; damageptr = damageptr->next) { mtag(mf, damageptr->when, MTAG_DAMAGEVALUE); mwrite32(mf, damageptr->when); mwrite32(mf, damageptr->cost); mwrite8(mf, damageptr->place.x); mwrite8(mf, damageptr->place.y); mwrite8(mf, damageptr->typ); } }
/* * save_worm() * * Save the worm information for later use. The count is the number * of segments, including the dummy. Called from save.c. */ void save_worm(struct memfile *mf, struct level *lev) { int i, count; struct wseg *curr; for (i = 1; i < MAX_NUM_WORMS; i++) { for (count = 0, curr = lev->wtails[i]; curr; curr = curr->nseg) count++; mtag(mf, (int)ledger_no(&lev->z) * MAX_NUM_WORMS + i, MTAG_WORMS); /* Save number of segments */ mwrite32(mf, count); /* Save segment locations of the monster. */ if (count) { for (curr = lev->wtails[i]; curr; curr = curr->nseg) { mwrite8(mf, curr->wx); mwrite8(mf, curr->wy); } mwrite32(mf, lev->wgrowtime[i]); } } }
/* return 0 if still on level, 3 if not */ int mlevel_tele_trap(struct monst *mtmp, struct trap *trap, boolean force_it, int in_sight) { int tt = trap->ttyp; const struct permonst *mptr = mtmp->data; if (mtmp == u.ustuck) /* probably a vortex */ return 0; /* temporary? kludge */ if (teleport_pet(mtmp, force_it)) { d_level tolevel; int migrate_typ = MIGR_RANDOM; if ((tt == HOLE || tt == TRAPDOOR)) { if (Is_stronghold(&u.uz)) { assign_level(&tolevel, &valley_level); } else if (Is_botlevel(&u.uz)) { if (in_sight && trap->tseen) pline("%s avoids the %s.", Monnam(mtmp), (tt == HOLE) ? "hole" : "trap"); return 0; } else { get_level(&tolevel, depth(&u.uz) + 1); } } else if (tt == MAGIC_PORTAL) { if (In_endgame(&u.uz) && (mon_has_amulet(mtmp) || is_home_elemental(&mtmp->dlevel->z, mptr))) { if (in_sight && mptr->mlet != S_ELEMENTAL) { pline("%s seems to shimmer for a moment.", Monnam(mtmp)); seetrap(trap); } return 0; } else { assign_level(&tolevel, &trap->dst); migrate_typ = MIGR_PORTAL; } } else { /* (tt == LEVEL_TELEP) */ int nlev; if (mon_has_amulet(mtmp) || In_endgame(&u.uz)) { if (in_sight) pline("%s seems very disoriented for a moment.", Monnam(mtmp)); return 0; } nlev = random_teleport_level(); if (nlev == depth(&u.uz)) { if (in_sight) pline("%s shudders for a moment.", Monnam(mtmp)); return 0; } get_level(&tolevel, nlev); } if (in_sight) { pline("Suddenly, %s disappears out of sight.", mon_nam(mtmp)); seetrap(trap); } migrate_to_level(mtmp, ledger_no(&tolevel), migrate_typ, NULL); return 3; /* no longer on this level */ } return 0; }
int dosave() { #ifdef KEEP_SAVE /*WAC for reloading*/ register int fd; #endif clear_nhwindow(WIN_MESSAGE); if(yn("Really save?") == 'n') { clear_nhwindow(WIN_MESSAGE); if(multi > 0) nomul(0); } else { clear_nhwindow(WIN_MESSAGE); pline("Saving..."); #if defined(UNIX) || defined(VMS) || defined(__EMX__) program_state.done_hup = 0; #endif #ifdef KEEP_SAVE saverestore = FALSE; if (flags.keep_savefile) if(yn("Really quit?") == 'n') saverestore = TRUE; if(dosave0() && !saverestore) { #else if(dosave0()) { #endif program_state.something_worth_saving = 0; u.uhp = -1; /* universal game's over indicator */ /* make sure they see the Saving message */ display_nhwindow(WIN_MESSAGE, TRUE); exit_nhwindows("Be seeing you..."); terminate(EXIT_SUCCESS); } /*WAC redraw later else (void)doredraw();*/ } #ifdef KEEP_SAVE if (saverestore) { /*WAC pulled this from pcmain.c - restore game from the file just saved*/ fd = create_levelfile(0); if (fd < 0) { raw_print("Cannot create lock file"); } else { hackpid = 1; write(fd, (genericptr_t) &hackpid, sizeof(hackpid)); close(fd); } #ifdef MFLOPPY level_info[0].where = ACTIVE; #endif fd = restore_saved_game(); if (fd >= 0) dorecover(fd); check_special_room(FALSE); flags.move = 0; /*WAC correct these after restore*/ if(flags.moonphase == FULL_MOON) change_luck(1); if(flags.friday13) change_luck(-1); if(iflags.window_inited) clear_nhwindow(WIN_MESSAGE); } saverestore = FALSE; #endif (void)doredraw(); return 0; } #if defined(UNIX) || defined(VMS) || defined (__EMX__) || defined(WIN32) /*ARGSUSED*/ void hangup(sig_unused) /* called as signal() handler, so sent at least one arg */ int sig_unused; { # ifdef NOSAVEONHANGUP (void) signal(SIGINT, SIG_IGN); clearlocks(); # ifndef VMS terminate(EXIT_FAILURE); # endif # else /* SAVEONHANGUP */ if (!program_state.done_hup++) { if (program_state.something_worth_saving) (void) dosave0(); # ifdef VMS /* don't call exit when already within an exit handler; that would cancel any other pending user-mode handlers */ if (!program_state.exiting) # endif { clearlocks(); terminate(EXIT_FAILURE); } } # endif return; } #endif /* returns 1 if save successful */ int dosave0() { const char *fq_save; register int fd, ofd; xchar ltmp; d_level uz_save; char whynot[BUFSZ]; if (!SAVEF[0]) return 0; fq_save = fqname(SAVEF, SAVEPREFIX, 1); /* level files take 0 */ #if defined(UNIX) || defined(VMS) (void) signal(SIGHUP, SIG_IGN); #endif #ifndef NO_SIGNAL (void) signal(SIGINT, SIG_IGN); #endif #if defined(MICRO) && defined(MFLOPPY) if (!saveDiskPrompt(0)) return 0; #endif HUP if (iflags.window_inited) { uncompress_area(fq_save, SAVEF); fd = open_savefile(); if (fd > 0) { (void) close(fd); clear_nhwindow(WIN_MESSAGE); There("seems to be an old save file."); if (yn("Overwrite the old file?") == 'n') { compress_area(fq_save, SAVEF); #ifdef KEEP_SAVE /*WAC don't restore if you didn't save*/ saverestore = FALSE; #endif return 0; } } } HUP mark_synch(); /* flush any buffered screen output */ fd = create_savefile(); if(fd < 0) { HUP pline("Cannot open save file."); (void) delete_savefile(); /* ab@unido */ return(0); } vision_recalc(2); /* shut down vision to prevent problems in the event of an impossible() call */ /* undo date-dependent luck adjustments made at startup time */ if(flags.moonphase == FULL_MOON) /* ut-sally!fletcher */ change_luck(-1); /* and unido!ab */ if(flags.friday13) change_luck(1); if(iflags.window_inited) HUP clear_nhwindow(WIN_MESSAGE); #if defined(MICRO) && defined(TTY_GRAPHICS) if (!strncmpi("tty", windowprocs.name, 3)) { dotcnt = 0; dotrow = 2; curs(WIN_MAP, 1, 1); putstr(WIN_MAP, 0, "Saving:"); } #endif #ifdef MFLOPPY /* make sure there is enough disk space */ if (iflags.checkspace) { long fds, needed; savelev(fd, ledger_no(&u.uz), COUNT_SAVE); savegamestate(fd, COUNT_SAVE); needed = bytes_counted; for (ltmp = 1; ltmp <= maxledgerno(); ltmp++) if (ltmp != ledger_no(&u.uz) && level_info[ltmp].where) needed += level_info[ltmp].size + (sizeof ltmp); fds = freediskspace(fq_save); if (needed > fds) { HUP { There("is insufficient space on SAVE disk."); pline("Require %ld bytes but only have %ld.", needed, fds); } flushout(); (void) close(fd); (void) delete_savefile(); return 0; } co_false(); }
} co_false(); } #endif /* MFLOPPY */ store_version(fd); #ifdef STORE_PLNAME_IN_FILE bwrite(fd, (genericptr_t) plname, PL_NSIZ); #endif ustuck_id = (u.ustuck ? u.ustuck->m_id : 0); #ifdef STEED usteed_id = (u.usteed ? u.usteed->m_id : 0); #endif savelev(fd, ledger_no(&u.uz), WRITE_SAVE | FREE_SAVE); /*Keep things from beeing freed if not restoring*/ /* #ifdef KEEP_SAVE if (saverestore) savegamestate(fd, WRITE_SAVE); else #endif */ savegamestate(fd, WRITE_SAVE | FREE_SAVE); /* While copying level files around, zero out u.uz to keep * parts of the restore code from completely initializing all * in-core data structures, since all we're doing is copying. * This also avoids at least one nasty core dump. */ uz_save = u.uz;
/* returns 1 if save successful */ int dosave0(void) { const char *fq_save; register int fd, ofd; xchar ltmp; d_level uz_save; char whynot[BUFSZ]; #ifdef WHEREIS_FILE delete_whereis(); #endif if (!SAVEF[0]) return 0; fq_save = fqname(SAVEF, SAVEPREFIX, 1); /* level files take 0 */ #if defined(UNIX) || defined(VMS) (void) signal(SIGHUP, SIG_IGN); #endif #ifndef NO_SIGNAL (void) signal(SIGINT, SIG_IGN); #endif #if defined(MICRO) && defined(MFLOPPY) if (!saveDiskPrompt(0)) return 0; #endif HUP if (iflags.window_inited) { uncompress_area(fq_save, SAVEF); fd = open_savefile(); if (fd > 0) { (void) close(fd); clear_nhwindow(WIN_MESSAGE); There("seems to be an old save file."); if (yn("Overwrite the old file?") == 'n') { compress_area(fq_save, SAVEF); return 0; } } } HUP mark_synch(); /* flush any buffered screen output */ fd = create_savefile(); if(fd < 0) { HUP pline("Cannot open save file."); (void) delete_savefile(); /* ab@unido */ return(0); } vision_recalc(2); /* shut down vision to prevent problems in the event of an impossible() call */ /* undo date-dependent luck adjustments made at startup time */ if(flags.moonphase == FULL_MOON) /* ut-sally!fletcher */ change_luck(-1); /* and unido!ab */ if(flags.friday13) change_luck(1); if(iflags.window_inited) HUP clear_nhwindow(WIN_MESSAGE); #ifdef MICRO dotcnt = 0; dotrow = 2; curs(WIN_MAP, 1, 1); if (strncmpi("X11", windowprocs.name, 3)) putstr(WIN_MAP, 0, "Saving:"); #endif #ifdef MFLOPPY /* make sure there is enough disk space */ if (iflags.checkspace) { long fds, needed; savelev(fd, ledger_no(&u.uz), COUNT_SAVE); savegamestate(fd, COUNT_SAVE); needed = bytes_counted; for (ltmp = 1; ltmp <= maxledgerno(); ltmp++) if (ltmp != ledger_no(&u.uz) && level_info[ltmp].where) needed += level_info[ltmp].size + (sizeof ltmp); fds = freediskspace(fq_save); if (needed > fds) { HUP { There("is insufficient space on SAVE disk."); pline("Require %ld bytes but only have %ld.", needed, fds); } flushout(); (void) close(fd); (void) delete_savefile(); return 0; }
void savelev(struct memfile *mf, xchar levnum) { int x, y; unsigned int lflags; struct level *lev = levels[levnum]; /* The purge_monsters count refers to monsters on the current level. */ if (iflags.purge_monsters && levnum == ledger_no(&u.uz)) { /* purge any dead monsters (necessary if we're starting a panic save rather than a normal one, or sometimes when changing levels without taking time -- e.g. create statue trap then immediately level teleport) */ dmonsfree(lev); } /* mtagging for this already done in save_game */ mfmagic_set(mf, LEVEL_MAGIC); mwrite8(mf, lev->z.dnum); mwrite8(mf, lev->z.dlevel); mwrite(mf, lev->levname, sizeof (lev->levname)); for (x = 0; x < COLNO; x++) for (y = 0; y < ROWNO; y++) save_location(mf, &lev->locations[x][y]); mwrite32(mf, lev->lastmoves); mwrite(mf, &lev->upstair, sizeof (stairway)); mwrite(mf, &lev->dnstair, sizeof (stairway)); mwrite(mf, &lev->upladder, sizeof (stairway)); mwrite(mf, &lev->dnladder, sizeof (stairway)); mwrite(mf, &lev->sstairs, sizeof (stairway)); mwrite(mf, &lev->updest, sizeof (dest_area)); mwrite(mf, &lev->dndest, sizeof (dest_area)); mwrite8(mf, lev->flags.nfountains); mwrite8(mf, lev->flags.nsinks); lflags = (lev->flags.has_shop << 31) | (lev->flags.has_vault << 30) | (lev->flags.has_zoo << 29) | (lev->flags.has_court << 28) | (lev->flags.has_morgue << 27) | (lev->flags.has_beehive << 26) | (lev->flags.has_barracks << 25) | (lev->flags.has_temple << 24) | (lev->flags.has_swamp << 23) | (lev->flags.noteleport << 22) | (lev->flags.hardfloor << 21) | (lev->flags.nommap << 20) | (lev->flags.hero_memory << 19) | (lev->flags.shortsighted << 18) | (lev->flags.graveyard << 17) | (lev->flags.is_maze_lev << 16) | (lev->flags.is_cavernous_lev << 15) | (lev->flags.arboreal << 14) | (lev->flags.forgotten << 13); mwrite32(mf, lflags); mwrite(mf, lev->doors, sizeof (lev->doors)); save_rooms(mf, lev); /* no dynamic memory to reclaim */ /* must be saved before mons, objs, and buried objs */ save_timers(mf, lev, RANGE_LEVEL); save_light_sources(mf, lev, RANGE_LEVEL); savemonchn(mf, lev->monlist); save_worm(mf, lev); /* save worm information */ savetrapchn(mf, lev->lev_traps, lev); saveobjchn(mf, lev->objlist); saveobjchn(mf, lev->buriedobjlist); saveobjchn(mf, lev->billobjs); save_engravings(mf, lev); savedamage(mf, lev); save_regions(mf, lev); }
/* extract a shopkeeper name for the given shop type */ static void nameshk(struct monst *shk, const char *const *nlp, struct level *lev) { int i, trycnt, names_avail; const char *shname = 0; struct monst *mtmp; int name_wanted; s_level *sptr; if (nlp == shklight && In_mines(&lev->z) && (sptr = Is_special(&lev->z)) != 0 && sptr->flags.town) { /* special-case minetown lighting shk */ shname = "Izchak"; shk->female = FALSE; } else { /* We want variation from game to game, without needing the save and restore support which would be necessary for randomization; thus use ubirthday for deterministic random numbers, and use ledger_no rather than depth to keep mine town distinct. */ int nseed = ((unsigned)u.ubirthday / 257U); name_wanted = ledger_no(&lev->z) + (nseed % 13) - (nseed % 5); if (name_wanted < 0) name_wanted += (13 + 5); shk->female = name_wanted & 1; for (names_avail = 0; nlp[names_avail]; names_avail++) continue; for (trycnt = 0; trycnt < 50; trycnt++) { if (nlp == shktools) { shname = shktools[rn2(names_avail)]; shk->female = (*shname == '_'); if (shk->female) shname++; } else if (name_wanted < names_avail) { shname = nlp[name_wanted]; } else if ((i = rn2(names_avail)) != 0) { shname = nlp[i - 1]; } else if (nlp != shkgeneral) { nlp = shkgeneral; /* try general names */ for (names_avail = 0; nlp[names_avail]; names_avail++) continue; continue; /* next `trycnt' iteration */ } else { shname = shk->female ? "Lucrezia" : "Dirk"; } /* is name already in use on this level? */ for (mtmp = lev->monlist; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp) || (mtmp == shk) || !mx_eshk(mtmp)) continue; if (mx_name(mtmp) && strcmp(mx_name(mtmp), shname)) continue; break; } if (!mtmp) break; /* new name */ } } christen_monst(shk, shname); }
/* called when you move to another level * pets_only: true for ascension or final escape */ void keepdogs(boolean pets_only) { struct monst *mtmp, *mtmp2; struct obj *obj; int num_segs; boolean stay_behind; for (mtmp = level->monlist; mtmp; mtmp = mtmp2) { mtmp2 = mtmp->nmon; if (DEADMONSTER(mtmp)) continue; if (pets_only && !mtmp->mtame) continue; if (((monnear(mtmp, u.ux, u.uy) && levl_follower(mtmp)) || (mtmp == u.usteed) || /* the wiz will level t-port from anywhere to chase the amulet; if you don't have it, will chase you only if in range. -3. */ (Uhave_amulet && mtmp->iswiz)) && ((!mtmp->msleeping && mtmp->mcanmove) /* eg if level teleport or new trap, steed has no control to avoid following */ || (mtmp == u.usteed)) /* monster won't follow if it hasn't noticed you yet */ && !(mtmp->mstrategy & STRAT_WAITFORU)) { stay_behind = FALSE; if (!pets_only && mtmp->mtame && mtmp->meating) { if (canseemon(mtmp)) pline("%s is still eating.", Monnam(mtmp)); stay_behind = TRUE; } else if (mon_has_amulet(mtmp)) { if (canseemon(mtmp)) pline("%s seems very disoriented for a moment.", Monnam(mtmp)); stay_behind = TRUE; } else if (!pets_only && mtmp->mtame && mtmp->mtrapped) { if (canseemon(mtmp)) pline("%s is still trapped.", Monnam(mtmp)); stay_behind = TRUE; } if (mtmp == u.usteed) stay_behind = FALSE; if (stay_behind) { if (mtmp->mleashed) { pline("%s leash suddenly comes loose.", humanoid(mtmp->data) ? (mtmp->female ? "Her" : "His") : "Its"); m_unleash(mtmp, FALSE); } continue; } if (mtmp->isshk) set_residency(mtmp, TRUE); if (mtmp->wormno) { int cnt; /* NOTE: worm is truncated to # segs = max wormno size */ cnt = count_wsegs(mtmp); num_segs = min(cnt, MAX_NUM_WORMS - 1); wormgone(mtmp); } else num_segs = 0; /* set minvent's obj->no_charge to 0 */ for (obj = mtmp->minvent; obj; obj = obj->nobj) { if (Has_contents(obj)) picked_container(obj); /* does the right thing */ obj->no_charge = 0; } relmon(mtmp); newsym(mtmp->mx, mtmp->my); mtmp->mx = COLNO; /* avoid mnexto()/MON_AT() problem */ mtmp->my = ROWNO; mtmp->wormno = num_segs; mtmp->mlstmv = moves; mtmp->nmon = turnstate.migrating_pets; turnstate.migrating_pets = mtmp; } else if (mtmp->iswiz) { /* we want to be able to find him when his next resurrection chance comes up, but have him resume his present location if player returns to this level before that time */ migrate_to_level(mtmp, ledger_no(&u.uz), MIGR_EXACT_XY, NULL); } else if (mtmp->mleashed) { /* this can happen if your quest leader ejects you from the "home" level while a leashed pet isn't next to you */ pline("%s leash goes slack.", s_suffix(Monnam(mtmp))); m_unleash(mtmp, FALSE); } } }