Mercurial > hg > early-roguelike
view rogue5/misc.c @ 81:0e212d46b68f
rogue4: don't put savefile metadata into the savefile.
The save_file() function in save.c stored the savefile's device number,
inode number, creation time, and modification time in the file. The
restore() function read them back, and apparently used to compare them
to protect against cheaters.
Unfortunately, the types and sizes of these numbers differ from system
to system, which ruins the Roguelike Restoration Project's fine
portability work. So they have been removed from the savefile.
This BREAKS SAVEFILE COMPATIBILITY, but old files can be converted by
excising the chunk starting at offset 0x22 with length sizeof(ino_t) +
sizeof(dev_t) + 2 * sizeof(time_t). That's 0x14 on i686 and 0x20 on
x86_64, at least with current versions of Linux and glibc.
author | John "Elwin" Edwards |
---|---|
date | Mon, 05 Aug 2013 20:49:41 -0700 |
parents | f502bf60e6e4 |
children |
line wrap: on
line source
/* * All sorts of miscellaneous routines * * @(#)misc.c 4.66 (Berkeley) 08/06/83 * * Rogue: Exploring the Dungeons of Doom * Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman * All rights reserved. * * See the file LICENSE.TXT for full copyright and licensing information. */ #include <stdlib.h> #include <curses.h> #include <string.h> #include <ctype.h> #include "rogue.h" /* * look: * A quick glance all around the player */ #undef DEBUG void look(int wakeup) { int x, y; chtype ch; THING *tp; PLACE *pp; struct room *rp; int ey, ex; int passcount; int pfl, *fp, pch; int sy, sx, sumhero = 0, diffhero = 0; # ifdef DEBUG static int done = FALSE; if (done) return; done = TRUE; # endif /* DEBUG */ passcount = 0; rp = proom; if (!ce(oldpos, hero)) { erase_lamp(&oldpos, oldrp); oldpos = hero; oldrp = rp; } ey = hero.y + 1; ex = hero.x + 1; sx = hero.x - 1; sy = hero.y - 1; if (door_stop && !firstmove && running) { sumhero = hero.y + hero.x; diffhero = hero.y - hero.x; } pp = INDEX(hero.y, hero.x); pch = pp->p_ch; pfl = pp->p_flags; for (y = sy; y <= ey; y++) if (y > 0 && y < NUMLINES - 1) for (x = sx; x <= ex; x++) { if (x < 0 || x >= NUMCOLS) continue; if (!on(player, ISBLIND)) { if (y == hero.y && x == hero.x) continue; } pp = INDEX(y, x); ch = pp->p_ch; if (ch == ' ') /* nothing need be done with a ' ' */ continue; fp = &pp->p_flags; if (pch != DOOR && ch != DOOR) if ((pfl & F_PASS) != (*fp & F_PASS)) continue; if (((*fp & F_PASS) || ch == DOOR) && ((pfl & F_PASS) || pch == DOOR)) { if (hero.x != x && hero.y != y && !step_ok(chat(y, hero.x)) && !step_ok(chat(hero.y, x))) continue; } if ((tp = pp->p_monst) == NULL) ch = trip_ch(y, x, ch); else if (on(player, SEEMONST) && on(*tp, ISINVIS)) { if (door_stop && !firstmove) running = FALSE; continue; } else { if (wakeup) wake_monster(y, x); if (see_monst(tp)) { if (on(player, ISHALU)) ch = rnd(26) + 'A'; else ch = tp->t_disguise; } } if (on(player, ISBLIND) && (y != hero.y || x != hero.x)) continue; move(y, x); if ((proom->r_flags & ISDARK) && !see_floor && ch == FLOOR) ch = ' '; if (tp != NULL || ch != CCHAR( inch() )) addch(ch); if (door_stop && !firstmove && running) { switch (runch) { case 'h': if (x == ex) continue; when 'j': if (y == sy) continue; when 'k': if (y == ey) continue; when 'l': if (x == sx) continue; when 'y': if ((y + x) - sumhero >= 1) continue; when 'u': if ((y - x) - diffhero >= 1) continue; when 'n': if ((y + x) - sumhero <= -1) continue; when 'b': if ((y - x) - diffhero <= -1) continue; } switch (ch) { case DOOR: if (x == hero.x || y == hero.y) running = FALSE; break; case PASSAGE: if (x == hero.x || y == hero.y) passcount++; break; case FLOOR: case '|': case '-': case ' ': break; default: running = FALSE; break; } } } if (door_stop && !firstmove && passcount > 1) running = FALSE; if (!running || !jump) mvaddch(hero.y, hero.x, PLAYER); # ifdef DEBUG done = FALSE; # endif /* DEBUG */ } /* * trip_ch: * Return the character appropriate for this space, taking into * account whether or not the player is tripping. */ int trip_ch(int y, int x, int ch) { if (on(player, ISHALU) && after) switch (ch) { case FLOOR: case ' ': case PASSAGE: case '-': case '|': case DOOR: case TRAP: break; default: if (y != stairs.y || x != stairs.x || !seenstairs) ch = rnd_thing(); break; } return ch; } /* * erase_lamp: * Erase the area shown by a lamp in a dark room. */ void erase_lamp(const coord *pos, const struct room *rp) { int y, x, ey, sy, ex; if (!(see_floor && (rp->r_flags & (ISGONE|ISDARK)) == ISDARK && !on(player,ISBLIND))) return; ey = pos->y + 1; ex = pos->x + 1; sy = pos->y - 1; for (x = pos->x - 1; x <= ex; x++) for (y = sy; y <= ey; y++) { if (y == hero.y && x == hero.x) continue; move(y, x); if (CCHAR( inch() ) == FLOOR) addch(' '); } } /* * show_floor: * Should we show the floor in her room at this time? */ int show_floor(void) { if ((proom->r_flags & (ISGONE|ISDARK)) == ISDARK && !on(player, ISBLIND)) return see_floor; else return TRUE; } /* * find_obj: * Find the unclaimed object at y, x */ THING * find_obj(int y, int x) { THING *obj; for (obj = lvl_obj; obj != NULL; obj = next(obj)) { if (obj->o_pos.y == y && obj->o_pos.x == x) return obj; } #ifdef MASTER sprintf(prbuf, "Non-object %d,%d", y, x); msg(prbuf); return NULL; #else /* NOTREACHED */ return NULL; #endif } /* * eat: * She wants to eat something, so let her try */ void eat(void) { THING *obj; if ((obj = get_item("eat", FOOD)) == NULL) return; if (obj->o_type != FOOD) { if (!terse) msg("ugh, you would get ill if you ate that"); else msg("that's Inedible!"); return; } if (food_left < 0) food_left = 0; if ((food_left += HUNGERTIME - 200 + rnd(400)) > STOMACHSIZE) food_left = STOMACHSIZE; hungry_state = 0; if (obj == cur_weapon) cur_weapon = NULL; if (obj->o_which == 1) msg("my, that was a yummy %s", fruit); else if (rnd(100) > 70) { pstats.s_exp++; msg("%s, this food tastes awful", choose_str("bummer", "yuk")); check_level(); } else msg("%s, that tasted good", choose_str("oh, wow", "yum")); leave_pack(obj, FALSE, FALSE); } /* * check_level: * Check to see if the guy has gone up a level. */ void check_level(void) { int i, add, olevel; for (i = 0; e_levels[i] != 0; i++) if (e_levels[i] > pstats.s_exp) break; i++; olevel = pstats.s_lvl; pstats.s_lvl = i; if (i > olevel) { add = roll(i - olevel, 10); max_hp += add; pstats.s_hpt += add; msg("welcome to level %d", i); } } /* * chg_str: * used to modify the playes strength. It keeps track of the * highest it has been, just in case */ void chg_str(int amt) { int comp; if (amt == 0) return; add_str(&pstats.s_str, amt); comp = pstats.s_str; if (ISRING(LEFT, R_ADDSTR)) add_str(&comp, -cur_ring[LEFT]->o_arm); if (ISRING(RIGHT, R_ADDSTR)) add_str(&comp, -cur_ring[RIGHT]->o_arm); if (comp > max_stats.s_str) max_stats.s_str = comp; } /* * add_str: * Perform the actual add, checking upper and lower bound limits */ void add_str(int *sp, int amt) { if ((*sp += amt) < 3) *sp = 3; else if (*sp > 31) *sp = 31; } /* * add_haste: * Add a haste to the player */ int add_haste(int potion) { if (on(player, ISHASTE)) { no_command += rnd(8); player.t_flags &= ~(ISRUN|ISHASTE); extinguish(nohaste); msg("you faint from exhaustion"); return FALSE; } else { player.t_flags |= ISHASTE; if (potion) fuse(nohaste, 0, rnd(4)+4, AFTER); return TRUE; } } /* * aggravate: * Aggravate all the monsters on this level */ void aggravate(void) { THING *mp; for (mp = mlist; mp != NULL; mp = next(mp)) runto(&mp->t_pos); } /* * vowelstr: * For printfs: if string starts with a vowel, return "n" for an * "an". */ char * vowelstr(const char *str) { switch (*str) { case 'a': case 'A': case 'e': case 'E': case 'i': case 'I': case 'o': case 'O': case 'u': case 'U': return "n"; default: return ""; } } /* * is_current: * See if the object is one of the currently used items */ int is_current(const THING *obj) { if (obj == NULL) return FALSE; if (obj == cur_armor || obj == cur_weapon || obj == cur_ring[LEFT] || obj == cur_ring[RIGHT]) { if (!terse) addmsg("That's already "); msg("in use"); return TRUE; } return FALSE; } /* * get_dir: * Set up the direction co_ordinate for use in varios "prefix" * commands */ int get_dir(void) { char *prompt; int gotit; static coord last_delt= {0,0}; if (again && last_dir != '\0') { delta.y = last_delt.y; delta.x = last_delt.x; dir_ch = last_dir; } else { if (!terse) msg(prompt = "which direction? "); else prompt = "direction: "; do { gotit = TRUE; switch (dir_ch = readchar()) { case 'h': case'H': delta.y = 0; delta.x = -1; when 'j': case'J': delta.y = 1; delta.x = 0; when 'k': case'K': delta.y = -1; delta.x = 0; when 'l': case'L': delta.y = 0; delta.x = 1; when 'y': case'Y': delta.y = -1; delta.x = -1; when 'u': case'U': delta.y = -1; delta.x = 1; when 'b': case'B': delta.y = 1; delta.x = -1; when 'n': case'N': delta.y = 1; delta.x = 1; when ESCAPE: last_dir = '\0'; reset_last(); msg(""); return FALSE; otherwise: mpos = 0; msg(prompt); gotit = FALSE; } } until (gotit); if (isupper(dir_ch)) dir_ch = tolower(dir_ch); last_dir = dir_ch; last_delt.y = delta.y; last_delt.x = delta.x; } if (on(player, ISHUH) && rnd(5) == 0) do { delta.y = rnd(3) - 1; delta.x = rnd(3) - 1; } while (delta.y == 0 && delta.x == 0); mpos = 0; msg(""); return TRUE; } /* * sign: * Return the sign of the number */ int sign(int nm) { if (nm < 0) return -1; else return (nm > 0); } /* * spread: * Give a spread around a given number (+/- 20%) */ int spread(int nm) { return nm - nm / 20 + rnd(nm / 10); } /* * call_it: * Call an object something after use. */ void call_it(struct obj_info *info) { if (info->oi_know) { if (info->oi_guess) { free(info->oi_guess); info->oi_guess = NULL; } } else if (!info->oi_guess) { msg(terse ? "call it: " : "what do you want to call it? "); if (get_str(prbuf, stdscr) == NORM) { if (info->oi_guess != NULL) free(info->oi_guess); info->oi_guess = malloc(strlen(prbuf) + 1); if (info->oi_guess != NULL) strcpy(info->oi_guess, prbuf); } msg(""); } } /* * rnd_thing: * Pick a random thing appropriate for this level */ int rnd_thing(void) { int i; int thing_list[] = { POTION, SCROLL, RING, STICK, FOOD, WEAPON, ARMOR, STAIRS, GOLD, AMULET }; if (level >= AMULETLEVEL) i = rnd(sizeof thing_list / sizeof (int)); else i = rnd(sizeof thing_list / sizeof (int) - 1); return thing_list[i]; } /* str str: * Choose the first or second string depending on whether it the * player is tripping */ const char * choose_str(const char *ts, const char *ns) { return (on(player, ISHALU) ? ts : ns); }