Mercurial > hg > early-roguelike
view rogue5/misc.c @ 111:7f8f43943b1f
Fix some terribly depressing corruption during restore.
In rogue5/state.c, rs_read_daemons() zeroes out the argument and delay
if the daemon slot is empty. Unfortunately that code ended up on the
wrong side of the brace that closes the for loop, so instead of running
after each daemon, it got run once after the loop exited, when the
index was of course out of bounds.
This tended to manifest, when compiled with -O2, by overwriting hw and
setting it to NULL. When inventory() next ran, hw would be passed to
wgetch(), which returns ERR when it gets a NULL argument. This made
md_readchar() think something was wrong and autosave the game.
Upon investigation, rogue3 was found to commit the same mistake.
rogue4 and srogue don't zero the data. arogue5 already does it
properly.
Someday I am going to run all this through Valgrind. Someday when I
am a kinder person who will not be driven to invoke hordes of trolls
and centaurs upon the original authors.
author | John "Elwin" Edwards |
---|---|
date | Wed, 08 Jan 2014 16:44:16 -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); }