Mercurial > hg > early-roguelike
view urogue/misc.c @ 302:fa70bba6bb3f rel2021.03
Update the README.
author | John "Elwin" Edwards |
---|---|
date | Thu, 18 Mar 2021 20:53:49 -0400 |
parents | c495a4f288c6 |
children | e52a8a7ad4c5 |
line wrap: on
line source
/* misc.c - all sorts of miscellaneous routines UltraRogue: The Ultimate Adventure in the Dungeons of Doom Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong All rights reserved. Based on "Advanced Rogue" Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka All rights reserved. Based on "Rogue: Exploring the Dungeons of Doom" Copyright (C) 1980, 1981 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 <string.h> #include <ctype.h> #include "rogue.h" /* tr_name() print the name of a trap */ char * tr_name(char ch, char *trname) { const char *s = NULL; if (trname == NULL) return(" Your found an error in UltraRogue #100."); switch(ch) { case TRAPDOOR: s = "trapdoor."; break; case BEARTRAP: s = "beartrap."; break; case SLEEPTRAP: s = "sleeping gas trap."; break; case ARROWTRAP: s = "arrow trap."; break; case TELTRAP: s = "teleport trap."; break; case DARTTRAP: s = "dart trap."; break; case POOL: s = "shimmering pool."; break; case MAZETRAP: s = "maze entrance."; break; case FIRETRAP: s = "fire trap."; break; case POISONTRAP: s = "poison pool trap."; break; case LAIR: s = "monster lair."; break; case RUSTTRAP: s = "rust trap."; break; default: ; } sprintf(trname, "You found a %s.", s); return(trname); } /* look() A quick glance all around the player */ void look(int wakeup) { int x, y; char ch, och; int oldx, oldy; int inpass, horizontal, vertical, do_light = FALSE, do_blank = FALSE; int passcount = 0; struct room *rp; int ey, ex; /* Are we moving vertically or horizontally? */ if (runch == 'h' || runch == 'l') horizontal = TRUE; else horizontal = FALSE; if (runch == 'j' || runch == 'k') vertical = TRUE; else vertical = FALSE; getyx(cw, oldy, oldx); /* Save current position */ /* * Blank out the floor around our last position and check for moving * out of a corridor in a maze. */ if (oldrp != NULL && (oldrp->r_flags & ISDARK) && !(oldrp->r_flags & HASFIRE) && off(player, ISBLIND)) do_blank = TRUE; for (x = player.t_oldpos.x - 1; x <= player.t_oldpos.x + 1; x++) for (y = player.t_oldpos.y - 1; y <= player.t_oldpos.y + 1; y++) { ch = show(y, x); if (do_blank && (y != hero.y || x != hero.x) && ch == FLOOR) mvwaddch(cw, y, x, ' '); /* Moving out of a corridor? */ if (levtype == MAZELEV && (ch != '|' && ch != '-') && /* Not a wall */ ((vertical && x != player.t_oldpos.x && y == player.t_oldpos.y) || (horizontal && y != player.t_oldpos.y && x == player.t_oldpos.x))) do_light = TRUE; /* Just came to a turn */ } inpass = ((rp = roomin(hero)) == NULL); /* Are we in a passage? */ /* Are we coming out of a wall into a corridor in a maze? */ och = show(player.t_oldpos.y, player.t_oldpos.x); ch = show(hero.y, hero.x); if (levtype == MAZELEV && (och == '|' || och == '-' || och == SECRETDOOR) && (ch != '|' && ch != '-' && ch != SECRETDOOR)) { do_light = off(player, ISBLIND); /* Light it up if not blind */ } /* Look around the player */ ey = hero.y + 1; ex = hero.x + 1; for (x = hero.x - 1; x <= ex; x++) if (x >= 0 && x < COLS) for (y = hero.y - 1; y <= ey; y++) { if (y <= 0 || y >= LINES - 2) continue; if (isalpha(mvwinch(mw, y, x))) { struct linked_list *it; struct thing *tp; if (wakeup) it = wake_monster(y, x); else it = find_mons(y, x); if (it == NULL) continue; tp = THINGPTR(it); tp->t_oldch = CCHAR( mvinch(y, x) ); if (isatrap(tp->t_oldch)) { struct trap *trp = trap_at(y, x); tp->t_oldch = (trp->tr_flags & ISFOUND) ? tp->t_oldch : trp->tr_show; } if (tp->t_oldch == FLOOR && (rp->r_flags & ISDARK) && !(rp->r_flags & HASFIRE) && off(player, ISBLIND)) tp->t_oldch = ' '; } /* Secret doors show as walls */ if ((ch = show(y, x)) == SECRETDOOR) ch = secretdoor(y, x); /* * Don't show room walls if he is in a * passage and check for maze turns */ if (off(player, ISBLIND)) { if (y == hero.y && x == hero.x || (inpass && (ch == '-' || ch == '|'))) continue; /* Are we at a crossroads in a maze? */ if (levtype == MAZELEV && (ch != '|' && ch != '-') && /* Not a wall */ ((vertical && x != hero.x && y == hero.y) || (horizontal && y != hero.y && x == hero.x))) do_light = TRUE; /* Just came to a turn */ } else if (y != hero.y || x != hero.x) continue; wmove(cw, y, x); waddch(cw, ch); if (door_stop && !firstmove && running) { switch (runch) { case 'h': if (x == ex) continue; break; case 'j': if (y == hero.y - 1) continue; break; case 'k': if (y == ey) continue; break; case 'l': if (x == hero.x - 1) continue; break; case 'y': if ((x + y) - (hero.x + hero.y) >= 1) continue; break; case 'u': if ((y - x) - (hero.y - hero.x) >= 1) continue; break; case 'n': if ((x + y) - (hero.x + hero.y) <= -1) continue; break; case 'b': if ((y - x) - (hero.y - hero.x) <= -1) continue; break; } 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: /* * Stop by new passages in a * maze (floor next to us) */ if ((levtype == MAZELEV) && ((horizontal && x == hero.x && y != hero.y) || (vertical && y == hero.y && x != hero.x))) running = FALSE; case '|': case '-': case ' ': break; default: running = FALSE; break; } } } if (door_stop && !firstmove && passcount > 1) running = FALSE; /* * Do we have to light up the area (just stepped into a new * corridor)? */ if (do_light && wakeup && /* wakeup will be true on a normal move */ !(rp->r_flags & ISDARK) && /* We have some light */ !ce(hero, player.t_oldpos)) /* Don't do anything if we didn't move */ light(&hero); mvwaddch(cw, hero.y, hero.x, PLAYER); wmove(cw, oldy, oldx); if (wakeup) { player.t_oldpos = hero; /* Don't change if we didn't move */ oldrp = rp; } } /* secret_door() Figure out what a secret door looks like. */ char secretdoor(int y, int x) { struct room *rp; coord cp; cp.x = x; cp.y = y; if ((rp = roomin(cp)) != NULL) { if (y == rp->r_pos.y || y == rp->r_pos.y + rp->r_max.y - 1) return ('-'); else return ('|'); } return ('p'); } /* find_obj() find the unclaimed object at y, x */ struct linked_list * find_obj(int y, int x) { struct linked_list *obj, *sobj; struct object *op; sobj = lvl_obj; for (obj = sobj; obj != NULL; obj = next(obj)) { op = OBJPTR(obj); if (op && op->o_pos.y == y && op->o_pos.x == x) return(obj); } return(NULL); } /* eat() He wants to eat something, so let him try */ void eat(void) { struct object *obj; int amount; float scale = (float) (LINES * COLS) / (25.0F * 80.0F); if ((obj = get_object(pack, "eat", FOOD, NULL)) == NULL) return; switch (obj->o_which) { case FD_RATION: amount = (int)(scale * (HUNGERTIME + rnd(400) - 200)); if (rnd(100) > 70) { msg("Yuk, this food tastes awful."); pstats.s_exp++; check_level(); } else msg("Yum, that tasted good."); break; case FD_FRUIT: amount = (int)(scale * (200 + rnd(HUNGERTIME))); msg("My, that was a yummy %s.", fruit); break; case FD_CRAM: amount = (int)(scale * (rnd(HUNGERTIME / 2) + 600)); msg("The cram tastes dry in your mouth."); break; case FD_CAKES: amount = (int)(scale * ((HUNGERTIME / 3) + rnd(600))); msg("Yum, the honey cakes tasted good."); break; case FD_LEMBA: amount = (int)(scale * ((HUNGERTIME / 2) + rnd(900))); quaff(&player, P_HEALING, ISNORMAL); break; case FD_MIRUVOR: amount = (int)(scale * ((HUNGERTIME / 3) + rnd(500))); quaff(&player, P_HEALING, ISNORMAL); quaff(&player, P_RESTORE, ISNORMAL); break; default: msg("What a strange thing to eat!"); amount = (int)(scale * HUNGERTIME); } food_left += amount; if (obj->o_flags & ISBLESSED) { food_left += 2 * amount; msg("You have a tingling feeling in your mouth."); } else if (food_left > scale * STOMACHSIZE) { food_left = (int)(scale * STOMACHSIZE); msg("You feel satiated and too full to move."); no_command = HOLDTIME; } hungry_state = F_OK; updpack(); if (obj == cur_weapon) cur_weapon = NULL; if (--obj->o_count <= 0) /* Remove this pack entry if last of food */ discard_pack(obj); } /* * Used to modify the player's strength it keeps track of the highest it has * been, just in case */ void chg_str(int amt, int both, int lost) { int ring_str; /* ring strengths */ struct stats *ptr; /* for speed */ ptr = &pstats; ring_str = ring_value(R_ADDSTR) + (on(player, POWERSTR) ? 10 : 0) + (on(player, SUPERHERO) ? 10 : 0); ptr->s_str -= ring_str; ptr->s_str += amt; if (ptr->s_str < 3) { ptr->s_str = 3; lost = FALSE; } else if (ptr->s_str > 25) ptr->s_str = 25; if (both) max_stats.s_str = ptr->s_str; if (lost) lost_str -= amt; ptr->s_str += ring_str; if (ptr->s_str < 0) ptr->s_str = 0; updpack(); } /* * Used to modify the player's dexterity it keeps track of the highest it has * been, just in case */ void chg_dext(int amt, int both, int lost) { int ring_dext; /* ring strengths */ struct stats *ptr; /* for speed */ ptr = &pstats; ring_dext = ring_value(R_ADDHIT) + (on(player, POWERDEXT) ? 10 : 0) + (on(player, SUPERHERO) ? 5 : 0); ptr->s_dext -= ring_dext; ptr->s_dext += amt; if (ptr->s_dext < 3) { ptr->s_dext = 3; lost = FALSE; } else if (ptr->s_dext > 25) ptr->s_dext = 25; if (both) max_stats.s_dext = ptr->s_dext; if (lost) lost_dext -= amt; ptr->s_dext += ring_dext; if (ptr->s_dext < 0) ptr->s_dext = 0; } /* add_haste() add a haste to the player */ void add_haste(int blessed) { short hasttime; if (blessed) hasttime = 10; else hasttime = 6; if (on(player, ISSLOW)) /* Is person slow? */ { extinguish_fuse(FUSE_NOSLOW); noslow(NULL); if (blessed) hasttime = 4; else return; } if (on(player, ISHASTE)) { msg("You faint from exhaustion."); no_command += rnd(hasttime); lengthen_fuse(FUSE_NOHASTE, rnd(hasttime) + (roll(1, 4) * hasttime)); } else { turn_on(player, ISHASTE); light_fuse(FUSE_NOHASTE, 0, roll(hasttime, hasttime), AFTER); } } /* aggravate() aggravate all the monsters on this level */ void aggravate(void) { struct linked_list *mi; struct thing *tp; for (mi = mlist; mi != NULL; mi = next(mi)) { tp = THINGPTR(mi); chase_it(&tp->t_pos, &player); } } /* vowelstr() for printfs: if string starts with a vowel, return "n" for an "an" */ char * vowelstr(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_object() see if the object is one of the currently used items */ int is_current(struct object *obj) { if (obj == NULL) return FALSE; if (obj == cur_armor || obj == cur_weapon || obj == cur_ring[LEFT_1] || obj == cur_ring[LEFT_2] || obj == cur_ring[LEFT_3] || obj == cur_ring[LEFT_4] || obj == cur_ring[LEFT_5] || obj == cur_ring[RIGHT_1] || obj == cur_ring[RIGHT_2] || obj == cur_ring[RIGHT_3] || obj == cur_ring[RIGHT_4] || obj == cur_ring[RIGHT_5]) { msg("That's already 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; prompt = "Which direction? "; msg(prompt); do { gotit = TRUE; switch (readchar()) { case 'h': case 'H': delta.y = 0; delta.x = -1; break; case 'j': case 'J': delta.y = 1; delta.x = 0; break; case 'k': case 'K': delta.y = -1; delta.x = 0; break; case 'l': case 'L': delta.y = 0; delta.x = 1; break; case 'y': case 'Y': delta.y = -1; delta.x = -1; break; case 'u': case 'U': delta.y = -1; delta.x = 1; break; case 'b': case 'B': delta.y = 1; delta.x = -1; break; case 'n': case 'N': delta.y = 1; delta.x = 1; break; case ESCAPE: return FALSE; default: mpos = 0; msg(prompt); gotit = FALSE; } } while(!gotit); if (on(player, ISHUH) && rnd(100) > 80) do { delta.y = rnd(3) - 1; delta.x = rnd(3) - 1; } while (delta.y == 0 && delta.x == 0); mpos = 0; return(TRUE); } /* is_wearing() is the hero wearing a particular ring */ int is_wearing(int type) { #define ISRING(h, r) (cur_ring[h] != NULL && cur_ring[h]->o_which == r) return( ISRING(LEFT_1, type) || ISRING(LEFT_2, type) || ISRING(LEFT_3, type) || ISRING(LEFT_4, type) || ISRING(LEFT_5, type) || ISRING(RIGHT_1, type) || ISRING(RIGHT_2, type) || ISRING(RIGHT_3, type) || ISRING(RIGHT_4, type) || ISRING(RIGHT_5, type) ); } /* maze_view() Returns true if the player can see the specified location within the confines of a maze (within one column or row) */ int maze_view(int y, int x) { int start, goal, delt, ycheck = 0, xcheck = 0, absy, absx; int row; /* Get the absolute value of y and x differences */ absy = hero.y - y; absx = hero.x - x; if (absy < 0) absy = -absy; if (absx < 0) absx = -absx; /* Must be within one row or column */ if (absy > 1 && absx > 1) return(FALSE); if (absy <= 1) /* Go along row */ { start = hero.x; goal = x; row = TRUE; ycheck = hero.y; } else /* Go along column */ { start = hero.y; goal = y; row = FALSE; xcheck = hero.x; } if (start <= goal) delt = 1; else delt = -1; while (start != goal) { if (row) xcheck = start; else ycheck = start; switch(CCHAR(winat(ycheck, xcheck))) { case '|': case '-': case WALL: case DOOR: case SECRETDOOR: return(FALSE); default: break; } start += delt; } return(TRUE); } /* listen() listen for monsters less than 5 units away */ void listen(void) { struct linked_list *item; struct thing *tp; int thief_bonus = -50; int mcount = 0; if (player.t_ctype == C_THIEF) thief_bonus = 10; for (item = mlist; item != NULL; item = next(item)) { tp = THINGPTR(item); if (DISTANCE(hero, tp->t_pos) < 81 && rnd(70) < (thief_bonus + 4 * pstats.s_dext + 6 * pstats.s_lvl)) { msg("You hear a%s %s nearby.", vowelstr(monsters[tp->t_index].m_name), monsters[tp->t_index].m_name); mcount++; } } if (mcount == 0) msg("You hear nothing."); } /* * nothing_message - print out "Nothing <adverb> happens." */ static const char *nothings[] = { "", "unusual ", "seems to ", "at all ", "really ", "noticeable ", "different ", "strange ", "wierd ", "bizzare ", "wonky ", "" }; void nothing_message(int flags) { int adverb = rnd(sizeof(nothings) / sizeof(char *)); NOOP(flags); msg("Nothing %shappens.", nothings[adverb]); } /* feel_message() print out "You feel <description>." */ void feel_message(void) { char *charp; switch (rnd(25)) { case 1: charp = "bad"; break; case 2: charp = "hurt"; break; case 3: charp = "sick"; break; case 4: charp = "faint"; break; case 5: charp = "yucky"; break; case 6: charp = "wonky"; break; case 7: charp = "wierd"; break;