Mercurial > hg > early-roguelike
view rogue5/misc.c @ 110:5f51f7d9805f
arogue5: fix some save/restore-related crashes.
The save/restore code took the pointer intended as an argument for the
doctor() daemon and wrote it to the savefile as an int. I don't know
why it took so long to fail horribly. The problem has been avoided by
replacing the value with &player when restoring. That seems to be the
only argument ever actually used.
The code also writes only four bytes for an unsigned long; if
sizeof(long) == 8, it casts to unsigned int first. It failed to do the
cast when reading back, with the result that four bytes were read and
the other half of the number was effectively uninitialized.
It apparently works now, but the save/restore code ought still to be
regarded as decidedly unfortunate.
author | John "Elwin" Edwards |
---|---|
date | Mon, 06 Jan 2014 15:57:17 -0500 |
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); }