static void pre_move_tasks(boolean didmove) { boolean is_on_elbereth = sengr_at("Elbereth", u.ux, u.uy); /* recalc attribute bonuses from items */ calc_attr_bonus(); find_ac(); if (!flags.mv || Blind) special_vision_handling(); /* update "Elbereth" status */ if (was_on_elbereth != is_on_elbereth) { was_on_elbereth = is_on_elbereth; iflags.botl = 1; } if (iflags.botl) bot(); if (didmove && (u.uhave.amulet || Clairvoyant) && !In_endgame(&u.uz) && !BClairvoyant && !(moves % 15) && !rn2(2)) do_vicinity_map(); u.umoved = FALSE; if (multi > 0) { lookaround(); if (!multi) { /* lookaround may clear multi */ flags.move = 0; iflags.botl = 1; } } if (didmove && moves % 100 == 0) realtime_tasks(); update_inventory(); update_location(FALSE); if (didmove) { /* Mark the current square as stepped on unless blind, * since that would imply that we had properly explored it. */ struct rm *loc = &level->locations[u.ux][u.uy]; if (!Blind && !loc->mem_stepped) loc->mem_stepped = 1; } }
boolean nh_start_game(int fd, const char *name, int irole, int irace, int igend, int ialign, enum nh_game_modes playmode) { unsigned int seed = 0; if (!api_entry_checkpoint()) return FALSE; /* init failed; programmer error! */ if (fd == -1 || !name || !*name) goto err_out; if (!program_state.restoring) { turntime = (unsigned long long)time(NULL); seed = turntime ^ get_seedval(); /* initialize the random number generator */ mt_srand(seed); } /* else: turntime and rng seeding are done in logreplay.c */ startup_common(name, playmode); if (!validrole(irole) || !validrace(irole, irace) || !validgend(irole, irace, igend) || !validalign(irole, irace, ialign)) goto err_out; u.initrole = irole; u.initrace = irace; u.initgend = igend; u.initalign = ialign; /* write out a new logfile header "NHGAME ..." with all the initial details */ log_init(); log_newgame(fd, turntime, seed, playmode); newgame(); was_on_elbereth = !sengr_at("Elbereth", u.ux, u.uy); /* force botl update later */ wd_message(); api_exit(); return TRUE; err_out: api_exit(); return FALSE; }
/* Return number of acceptable neighbour positions */ int mfndpos(struct monst *mon, coord poss[9], int info[9], int flag) { int x; int y; int nx; int ny; int cnt = 0; int tmp; struct monst *mtmp; x = mon->mx; y = mon->my; if(mon->mconf != 0) { flag |= ALLOW_ALL; flag &= ~NOTONL; } for(nx = x - 1; nx <= x + 1; ++nx) { for(ny = y - 1; ny <= y + 1; ++ny) { if((nx != x) || (ny != y)) { if(isok(nx, ny) != 0) { tmp = levl[nx][ny].typ; if(tmp >= DOOR) { if((nx == x) || (ny == y) || ((levl[x][y].typ != DOOR) && (tmp != DOOR))) { info[cnt] = 0; if((nx == u.ux) && (ny == u.uy)) { if((flag & ALLOW_U) == 0) { continue; } info[cnt] = ALLOW_U; } else { mtmp = m_at(nx, ny); if(mtmp != 0) { if((flag & ALLOW_M) == 0) { continue; } info[cnt] = ALLOW_M; } if(mtmp->mtame != 0) { if((flag & ALLOW_TM) == 0) { continue; } info[cnt] |= ALLOW_TM; } } if(sobj_at(CLOVE_OF_GARLIC, nx, ny) != 0) { if((flag & NOGARLIC) != 0) { continue; } info[cnt] |= NOGARLIC; } if((sobj_at(SCR_SCARE_MONSTER, nx, ny) != 0) || ((mon->mpeaceful == 0) && (sengr_at("Elbereth", nx, ny) != 0))) { if((flag & ALLOW_SSM) == 0) { continue; } info[cnt] |= ALLOW_SSM; } if(sobj_at(ENORMOUS_ROCK, nx, ny) != 0) { if((flag & ALLOW_ROCK) == 0) { continue; } info[cnt] |= ALLOW_ROCK; } if((Invis == 0) && (online(nx, ny) != 0)) { if((flag & NOTONL) != 0) { continue; } info[cnt] |= NOTONL; } /* We cannot avoid traps of an unknown kind */ struct gen *gtmp = g_at(nx, ny, ftrap); int tt; if(gtmp != NULL) { tt = 1 << (gtmp->gflag & ~SEEN); if((mon->mtrapseen & tt) != 0) { if((flag & tt) == 0) { continue; } info[cnt] |= tt; } } poss[cnt].x = nx; poss[cnt].y = ny; ++cnt; } } } } } } return cnt; }
/* Returns 1 if monster died moving, 0 otherwise */ int dochug(struct monst *mtmp) { struct permonst *mdat; int tmp = 0; if((mtmp->cham != 0) && (rn2(6) == 0)) { newcham(mtmp, &mons[(dlevel + 14) + rn2((CMNUM - 14) - dlevel)]); } mdat = mtmp->data; if(mdat->mlevel < 0) { panic("bad monster %c (%d)", mdat->mlet, mdat->mlevel); } if((((moves % 20) == 0) || (index("ViT", mdat->mlet) != 0)) && (mtmp->mhp < mtmp->orig_hp)) { /* Regenerate monsters. */ ++mtmp->mhp; } if(mtmp->mfroz != 0) { /* Frozen monsters don't do anything. */ return 0; } if(mtmp->msleep != 0) { /* Wake up a monster, or get out of here. */ if((cansee(mtmp->mx, mtmp->my) != 0) && (Stealth == 0) && ((index("NL", mdat->mlet) == 0) || (rn2(50) == 0)) && ((Aggravate_monster != 0) || ((rn2(7) == 0) && (mtmp->mimic == 0)))) { mtmp->msleep = 0; } else { return 0; } } /* Not frozen or sleeping: wipe out texts written in the dust */ wipe_engr_at(mtmp->mx, mtmp->my, 1); /* Confused monsters get unconfused with small probability */ if((mtmp->mconf != 0) && (rn2(50) == 0)) { mtmp->mconf = 0; } /* Some monsters teleport */ if((mtmp->mflee != 0) && (index("tNL", mdat->mlet) != 0) && (rn2(40) == 0)) { rloc(mtmp); return 0; } if(mdat->mmove < rnd(6)) { return 0; } if((mtmp->mflee != 0) || (mtmp->mconf != 0) || ((index("BIuy", mdat->mlet) != 0) && (rn2(4) == 0)) || ((mdat->mlet == 'L') && (u.ugold == 0) && ((mtmp->mgold != 0) || (rn2(2) != 0))) || (dist(mtmp->mx, mtmp->my) > 2) || ((mtmp->mcansee == 0) && (rn2(4) == 0)) || (mtmp->mpeaceful != 0)) { tmp = m_move(mtmp, 0); if((tmp != 0) && (mdat->mmove < 12)) { if(tmp == 2) { return 1; } else { return 0; } } } if(tmp == 2) { /* Monster died moving */ return 1; } if((index("Ea", mdat->mlet) == 0) && (dist(mtmp->mx, mtmp->my) < 3) && (mtmp->mpeaceful == 0) && (u.uhp > 0) && (sengr_at("Elbereth", u.ux, u.uy) == 0) && (sobj_at(SCR_SCARE_MONSTER, u.ux, u.uy) == 0)) { if(mhitu(mtmp) != 0) { /* Monster died (e.g. 'y' or 'F') */ return 1; } } /* Extra movement for fast monsters */ if((mdat->mmove - 12) > rnd(12)) { tmp = m_move(mtmp, 1); } if(tmp == 2) { return 1; } else { return 0; } }
enum nh_restore_status nh_restore_game(int fd, struct nh_window_procs *rwinprocs, boolean force_replay) { int playmode, irole, irace, igend, ialign; char namebuf[PL_NSIZ]; /* some compilers can't cope with the fact that all subsequent stores to error * are not dead, but become important if the error handler longjumps back * volatile is required to prevent invalid optimization based on that wrong * assumption. */ volatile enum nh_restore_status error = GAME_RESTORED; if (fd == -1) return ERR_BAD_ARGS; switch (nh_get_savegame_status(fd, NULL)) { case LS_INVALID: return ERR_BAD_FILE; case LS_DONE: return ERR_GAME_OVER; case LS_CRASHED: force_replay = TRUE; break; case LS_IN_PROGRESS: return ERR_IN_PROGRESS; case LS_SAVED: break; /* default, everything is A-OK */ } if (!api_entry_checkpoint()) goto error_out; error = ERR_BAD_FILE; replay_set_logfile(fd); /* store the fd and try to get a lock or exit */ replay_begin(); program_state.restoring = TRUE; iflags.disable_log = TRUE; /* don't log any of the commands, they're already in the log */ /* Read the log header for this game. */ replay_read_newgame(&turntime, &playmode, namebuf, &irole, &irace, &igend, &ialign); /* set special windowprocs which will autofill requests for user input * with data from the log file */ replay_setup_windowprocs(rwinprocs); startup_common(namebuf, playmode); u.initrole = irole; u.initrace = irace; u.initgend = igend; u.initalign = ialign; if (!force_replay) { error = ERR_RESTORE_FAILED; replay_run_cmdloop(TRUE, FALSE, TRUE); replay_jump_to_endpos(); if (!dorecover_fd(fd)) { replay_undo_jump_to_endpos(); goto error_out2; } replay_undo_jump_to_endpos(); wd_message(); program_state.game_running = 1; post_init_tasks(); } else { replay_run_cmdloop(TRUE, TRUE, FALSE); /* option setup only */ newgame(); /* try replaying instead */ error = ERR_REPLAY_FAILED; replay_run_cmdloop(FALSE, FALSE, TRUE); replay_sync_save(); } /* restore standard window procs */ replay_restore_windowprocs(); program_state.restoring = FALSE; iflags.disable_log = FALSE; /* clean up data used for replay */ replay_end(); log_truncate(); log_init(); /* must be called before we start writing to the log */ /* info might not have reached the ui while alternate window procs were set */ doredraw(); /* nh_start_game() does this via newgame(), but since this function doesn't * call newgame(), we have to do it here instead. */ notify_levelchange(NULL); bot(); flush_screen(); was_on_elbereth = !sengr_at("Elbereth", u.ux, u.uy); /* force botl update later */ welcome(FALSE); realtime_messages(TRUE, TRUE); update_inventory(); api_exit(); return GAME_RESTORED; error_out2: api_exit(); error_out: replay_restore_windowprocs(); program_state.restoring = FALSE; iflags.disable_log = FALSE; replay_end(); unlock_fd(fd); if (error == ERR_RESTORE_FAILED) { raw_printf("Restore failed. Attempting to replay instead.\n"); error = nh_restore_game(fd, rwinprocs, TRUE); } return error; }