Annotation of early-roguelike/arogue7/util.c, Revision 1.1
1.1 ! rubenllo 1: /*
! 2: * util.c - all sorts of miscellaneous routines
! 3: *
! 4: * Advanced Rogue
! 5: * Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T
! 6: * All rights reserved.
! 7: *
! 8: * Based on "Rogue: Exploring the Dungeons of Doom"
! 9: * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
! 10: * All rights reserved.
! 11: *
! 12: * See the file LICENSE.TXT for full copyright and licensing information.
! 13: */
! 14:
! 15: #include "curses.h"
! 16: #include "rogue.h"
! 17: #include <ctype.h>
! 18: #include <string.h>
! 19: #ifdef PC7300
! 20: #include <track.h>
! 21: #include <kcodes.h>
! 22: #include <sys/window.h>
! 23: extern struct uwdata wdata;
! 24: #endif
! 25:
! 26: /*
! 27: * all sorts of miscellaneous routines
! 28: *
! 29: */
! 30:
! 31:
! 32:
! 33:
! 34: /*
! 35: * this routine computes the players current AC without dex bonus's
! 36: */
! 37: int
! 38: ac_compute(bool ignoremetal)
! 39: {
! 40: register int ac;
! 41:
! 42: ac = pstats.s_arm; /* base armor of "skin" */
! 43: if (cur_armor) {
! 44: if (!ignoremetal ||
! 45: (cur_armor->o_which != LEATHER &&
! 46: cur_armor->o_which != STUDDED_LEATHER &&
! 47: cur_armor->o_which != PADDED_ARMOR))
! 48: ac -= (10 - cur_armor->o_ac);
! 49: }
! 50: if (player.t_ctype == C_MONK)
! 51: ac -= pstats.s_lvl * 2 / 3;
! 52: ac -= ring_value(R_PROTECT);
! 53: if (cur_misc[WEAR_BRACERS] != NULL)
! 54: ac -= cur_misc[WEAR_BRACERS]->o_ac;
! 55: if (cur_misc[WEAR_CLOAK] != NULL)
! 56: ac -= cur_misc[WEAR_CLOAK]->o_ac;
! 57:
! 58: /* If player has the cloak, must be wearing it */
! 59: if (cur_relic[EMORI_CLOAK]) ac -= 5;
! 60:
! 61: if (ac > 10)
! 62: ac = 10;
! 63: return(ac);
! 64: }
! 65:
! 66: /*
! 67: * aggravate:
! 68: * aggravate all the monsters on this level
! 69: */
! 70:
! 71: void
! 72: aggravate(bool do_uniques, bool do_good)
! 73: {
! 74: register struct linked_list *mi;
! 75: register struct thing *thingptr;
! 76:
! 77: for (mi = mlist; mi != NULL; mi = next(mi)) {
! 78: thingptr = THINGPTR(mi);
! 79: if (do_good == FALSE && off(*thingptr, ISMEAN)) continue;
! 80: if (do_uniques || off(*thingptr, ISUNIQUE)) runto(thingptr, &hero);
! 81: }
! 82: }
! 83:
! 84: /*
! 85: * cansee:
! 86: * returns true if the hero can see a certain coordinate.
! 87: */
! 88:
! 89: bool
! 90: cansee(int y, int x)
! 91: {
! 92: register struct room *rer;
! 93: register int radius;
! 94: coord tp;
! 95:
! 96: if (on(player, ISBLIND))
! 97: return FALSE;
! 98:
! 99: tp.y = y;
! 100: tp.x = x;
! 101: rer = roomin(&tp);
! 102:
! 103: /* How far can we see? */
! 104: if (levtype == OUTSIDE) {
! 105: if (daytime) radius = 36;
! 106: else if (lit_room(rer)) radius = 9;
! 107: else radius = 3;
! 108: }
! 109: else radius = 3;
! 110:
! 111: /*
! 112: * We can only see if the hero in the same room as
! 113: * the coordinate and the room is lit or if it is close.
! 114: */
! 115: return ((rer != NULL &&
! 116: levtype != OUTSIDE &&
! 117: (levtype != MAZELEV || /* Maze level needs direct line */
! 118: maze_view(tp.y, tp.x)) &&
! 119: rer == roomin(&hero) &&
! 120: lit_room(rer)) ||
! 121: DISTANCE(y, x, hero.y, hero.x) < radius);
! 122: }
! 123:
! 124: /*
! 125: * check_level:
! 126: * Check to see if the guy has gone up a level.
! 127: *
! 128: * Return points needed to obtain next level.
! 129: *
! 130: * These are certain beginning experience levels for all players.
! 131: * All further experience levels are computed by muliplying by 2
! 132: * up through MAXDOUBLE. Then the cap is added in to compute
! 133: * further levels
! 134: */
! 135: long
! 136: check_level(void)
! 137: {
! 138: register int i, j, add = 0;
! 139: register unsigned long exp;
! 140: long retval; /* Return value */
! 141: int nsides;
! 142:
! 143: pstats.s_lvl -= pstats.s_lvladj; /* correct for level adjustment */
! 144: /* See if we are past the doubling stage */
! 145: exp = char_class[player.t_ctype].cap;
! 146: if (pstats.s_exp >= exp) {
! 147: i = pstats.s_exp/exp; /* First get amount above doubling area */
! 148: retval = exp + i * exp; /* Compute next higher boundary */
! 149: i += MAXDOUBLE; /* Add in the previous doubled levels */
! 150: }
! 151: else {
! 152: i = 0;
! 153: exp = char_class[player.t_ctype].start_exp;
! 154: while (exp <= pstats.s_exp) {
! 155: i++;
! 156: exp <<= 1;
! 157: }
! 158: retval = exp;
! 159: }
! 160: if (++i > pstats.s_lvl) {
! 161: nsides = char_class[player.t_ctype].hit_pts;
! 162: for (j=0; j<(i-pstats.s_lvl); j++) /* Take care of multi-level jumps */
! 163: add += max(1, roll(1,nsides) + const_bonus());
! 164: max_stats.s_hpt += add;
! 165: if ((pstats.s_hpt += add) > max_stats.s_hpt)
! 166: pstats.s_hpt = max_stats.s_hpt;
! 167: msg("Welcome, %s, to level %d",
! 168: cnames[player.t_ctype][min(i-1, NUM_CNAMES-1)], i);
! 169: }
! 170: pstats.s_lvl = i;
! 171: pstats.s_lvl += pstats.s_lvladj; /* correct for level adjustment */
! 172: return(retval);
! 173: }
! 174:
! 175: /*
! 176: * Used to modify the players strength
! 177: * it keeps track of the highest it has been, just in case
! 178: */
! 179:
! 180: void
! 181: chg_str(int amt)
! 182: {
! 183: register int ring_str; /* ring strengths */
! 184: register struct stats *ptr; /* for speed */
! 185:
! 186: ptr = &pstats;
! 187: ring_str = ring_value(R_ADDSTR);
! 188: ptr->s_str -= ring_str;
! 189: ptr->s_str += amt;
! 190: if (ptr->s_str > 25)
! 191: ptr->s_str = 25;
! 192: if (ptr->s_str > max_stats.s_str)
! 193: max_stats.s_str = ptr->s_str;
! 194: ptr->s_str += ring_str;
! 195: if (ptr->s_str <= 0)
! 196: death(D_STRENGTH);
! 197: updpack(TRUE, &player);
! 198: }
! 199:
! 200: /*
! 201: * let's confuse the player
! 202: */
! 203: void
! 204: confus_player(void)
! 205: {
! 206: if (off(player, ISCLEAR))
! 207: {
! 208: msg("Wait, what's going on here. Huh? What? Who?");
! 209: if (find_slot(unconfuse))
! 210: lengthen(unconfuse, HUHDURATION);
! 211: else
! 212: fuse(unconfuse, NULL, HUHDURATION, AFTER);
! 213: turn_on(player, ISHUH);
! 214: }
! 215: else msg("You feel dizzy for a moment, but it quickly passes.");
! 216: }
! 217:
! 218: /*
! 219: * this routine computes the players current dexterity
! 220: */
! 221: int
! 222: dex_compute(void)
! 223: {
! 224: if (cur_misc[WEAR_GAUNTLET] != NULL &&
! 225: cur_misc[WEAR_GAUNTLET]->o_which == MM_G_DEXTERITY) {
! 226: if (cur_misc[WEAR_GAUNTLET]->o_flags & ISCURSED)
! 227: return (3);
! 228: else
! 229: return (18);
! 230: }
! 231: else
! 232: return (pstats.s_dext);
! 233: }
! 234:
! 235: /*
! 236: * diag_ok:
! 237: * Check to see if the move is legal if it is diagonal
! 238: */
! 239:
! 240: bool
! 241: diag_ok(coord *sp, coord *ep, struct thing *flgptr)
! 242: {
! 243: register int numpaths = 0;
! 244:
! 245: /* Horizontal and vertical moves are always ok */
! 246: if (ep->x == sp->x || ep->y == sp->y)
! 247: return TRUE;
! 248:
! 249: /* Diagonal moves are not allowed if there is a horizontal or
! 250: * vertical path to the destination
! 251: */
! 252: if (step_ok(ep->y, sp->x, MONSTOK, flgptr)) numpaths++;
! 253: if (step_ok(sp->y, ep->x, MONSTOK, flgptr)) numpaths++;
! 254: return(numpaths != 1);
! 255: }
! 256:
! 257: /*
! 258: * pick a random position around the give (y, x) coordinates
! 259: */
! 260: coord *
! 261: fallpos(coord *pos, bool be_clear, int range)
! 262: {
! 263: register int tried, i, j;
! 264: register char ch;
! 265: static coord ret;
! 266: static short masks[] = {
! 267: 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x100 };
! 268:
! 269: /*
! 270: * Pick a spot at random centered on the position given by 'pos' and
! 271: * up to 'range' squares away from 'pos'
! 272: *
! 273: * If 'be_clear' is TRUE, the spot must be either FLOOR or PASSAGE
! 274: * inorder to be considered valid
! 275: *
! 276: *
! 277: * Generate a number from 0 to 8, representing the position to pick.
! 278: * Note that this DOES include the positon 'pos' itself
! 279: *
! 280: * If this position is not valid, mark it as 'tried', and pick another.
! 281: * Whenever a position is picked that has been tried before,
! 282: * sequentially find the next untried position. This eliminates costly
! 283: * random number generation
! 284: */
! 285:
! 286: tried = 0;
! 287: while( tried != 0x1ff ) {
! 288: i = rnd(9);
! 289: while( tried & masks[i] )
! 290: i = (i + 1) % 9;
! 291:
! 292: tried |= masks[i];
! 293:
! 294: for( j = 1; j <= range; j++ ) {
! 295: ret.x = pos->x + j*grid[i].x;
! 296: ret.y = pos->y + j*grid[i].y;
! 297:
! 298: if (ret.x == hero.x && ret.y == hero.y)
! 299: continue; /* skip the hero */
! 300:
! 301: if (ret.x < 0 || ret.x > cols - 1 ||
! 302: ret.y < 1 || ret.y > lines - 3)
! 303: continue; /* off the screen? */
! 304:
! 305: ch = CCHAR( winat(ret.y, ret.x) );
! 306:
! 307: /*
! 308: * Check to make certain the spot is valid
! 309: */
! 310: switch( ch ) {
! 311: case FLOOR:
! 312: case PASSAGE:
! 313: return( &ret );
! 314: case GOLD:
! 315: case SCROLL:
! 316: case POTION:
! 317: case STICK:
! 318: case RING:
! 319: case WEAPON:
! 320: case ARMOR:
! 321: case MM:
! 322: case FOOD:
! 323: if(!be_clear && levtype != POSTLEV)
! 324: return( &ret );
! 325: default:
! 326: break;
! 327: }
! 328: }
! 329: }
! 330: return( NULL );
! 331: }
! 332:
! 333:
! 334: /*
! 335: * findmindex:
! 336: * Find the index into the monster table of a monster given its name.
! 337: */
! 338:
! 339: int
! 340: findmindex(char *name)
! 341: {
! 342: int which;
! 343:
! 344: for (which=1; which<NUMMONST; which++) {
! 345: if (strcmp(name, monsters[which].m_name) == 0)
! 346: break;
! 347: }
! 348: if (which >= NUMMONST) {
! 349: debug("couldn't find monster index");
! 350: which = 1;
! 351: }
! 352: return(which);
! 353: }
! 354:
! 355: /*
! 356: * find_mons:
! 357: * Find the monster from his coordinates
! 358: */
! 359:
! 360: struct linked_list *
! 361: find_mons(int y, int x)
! 362: {
! 363: register struct linked_list *item;
! 364: register struct thing *th;
! 365:
! 366: for (item = mlist; item != NULL; item = next(item))
! 367: {
! 368: th = THINGPTR(item);
! 369: if (th->t_pos.y == y && th->t_pos.x == x)
! 370: return item;
! 371: }
! 372: return NULL;
! 373: }
! 374:
! 375: /*
! 376: * find_obj:
! 377: * find the unclaimed object at y, x
! 378: */
! 379:
! 380: struct linked_list *
! 381: find_obj(int y, int x)
! 382: {
! 383: register struct linked_list *obj;
! 384: register struct object *op;
! 385:
! 386: for (obj = lvl_obj; obj != NULL; obj = next(obj))
! 387: {
! 388: op = OBJPTR(obj);
! 389: if (op->o_pos.y == y && op->o_pos.x == x)
! 390: return obj;
! 391: }
! 392: return NULL;
! 393: }
! 394:
! 395: /*
! 396: * get coordinates from the player using the cursor keys (or mouse)
! 397: */
! 398: coord
! 399: get_coordinates(void)
! 400: {
! 401: register int which;
! 402: coord c;
! 403: #ifdef PC7300
! 404: struct umdata startmouse, listenmouse; /* Mouse parameters */
! 405: int xmouse, /* x-position of mouse */
! 406: ymouse, /* y-position of mouse */
! 407: bmouse, /* button value of mouse */
! 408: rmouse; /* reason for mouse change */
! 409: #endif
! 410:
! 411: c = hero;
! 412: wmove(cw, hero.y, hero.x);
! 413: draw(cw);
! 414: #ifdef PC7300
! 415: keypad(0, 1); /* Turn on escape sequences */
! 416: ioctl(0, WIOCGETMOUSE, &startmouse); /* Get current mouse parameters */
! 417: listenmouse = startmouse; /* Make a copy */
! 418: listenmouse.um_flags |= MSDOWN; /* Enable detection of button down */
! 419: ioctl(0, WIOCSETMOUSE, &listenmouse); /* Make the change */
! 420: #endif
! 421: for (;;) {
! 422: #ifdef PC7300
! 423: which = wgetc(0);
! 424: #else
! 425: which = (getchar() & 0177);
! 426: #endif
! 427: switch(which) {
! 428: #ifdef PC7300
! 429: case Home:
! 430: c.x = 0; c.y = 1;
! 431: when Beg:
! 432: c.x = 0;
! 433: when End:
! 434: c.x = cols - 1;
! 435: when Mouse:
! 436: case ESCAPE:
! 437: case Cancl:
! 438: case s_Cancl:
! 439: if (which == Mouse) {
! 440: if (wreadmouse(0,&xmouse,&ymouse,&bmouse,&rmouse) != 0 ||
! 441: (rmouse & MSDOWN) == 0)
! 442: break;
! 443: c.y = ymouse / wdata.uw_vs;
! 444: c.x = xmouse / wdata.uw_hs;
! 445: c.y = max(c.y, 1);
! 446: c.y = min(c.y, lines - 3);
! 447: c.x = max(c.x, 0);
! 448: c.x = min(c.x, cols - 1);
! 449: }
! 450: else c = hero;
! 451: wmove(cw, c.y, c.x);
! 452: draw(cw);
! 453: case '\n':
! 454: case '\c':
! 455: keypad(0, 0); /* Turn off escape interpretation */
! 456: ioctl(0, WIOCSETMOUSE, &startmouse); /* No mouse tracking */
! 457: return(c);
! 458: when 'h':
! 459: case 'H':
! 460: case Back:
! 461: case s_Back:
! 462: c.x--;
! 463: when 'j':
! 464: case 'J':
! 465: case Down:
! 466: case RollDn:
! 467: c.y++;
! 468: when 'k':
! 469: case 'K':
! 470: case Up:
! 471: case RollUp:
! 472: c.y--;
! 473: when 'l':
! 474: case 'L':
! 475: case Forward:
! 476: case s_Forward:
! 477: c.x++;
! 478: when 'y':
! 479: case 'Y':
! 480: case Prev:
! 481: c.x--; c.y--;
! 482: when 'u':
! 483: case 'U':
! 484: case Next:
! 485: c.x++; c.y--;
! 486: when 'b':
! 487: case 'B':
! 488: case s_Prev:
! 489: c.x--; c.y++;
! 490: when 'n':
! 491: case 'N':
! 492: case s_Next:
! 493: c.x++; c.y++;
! 494: when '*':
! 495: msg("Select location via mouse, or");
! 496: msg("Use cursor keys,h,j,k,l,y,u,b,or n, then hit return.");
! 497: #else
! 498: case ESCAPE:
! 499: c = hero;
! 500: wmove(cw, c.y, c.x);
! 501: draw(cw);
! 502: case '\n':
! 503: case '\r':
! 504: return(c);
! 505: when 'h':
! 506: case 'H':
! 507: c.x--;
! 508: when 'j':
! 509: case 'J':
! 510: c.y++;
! 511: when 'k':
! 512: case 'K':
! 513: c.y--;
! 514: when 'l':
! 515: case 'L':
! 516: c.x++;
! 517: when 'y':
! 518: case 'Y':
! 519: c.x--; c.y--;
! 520: when 'u':
! 521: case 'U':
! 522: c.x++; c.y--;
! 523: when 'b':
! 524: case 'B':
! 525: c.x--; c.y++;
! 526: when 'n':
! 527: case 'N':
! 528: c.x++; c.y++;
! 529: when '*':
! 530: msg("Use h,j,k,l,y,u,b,n to position cursor, then hit return.");
! 531: #endif
! 532: }
! 533: c.y = max(c.y, 1);
! 534: c.y = min(c.y, lines - 3);
! 535: c.x = max(c.x, 0);
! 536: c.x = min(c.x, cols - 1);
! 537: wmove(cw, c.y, c.x);
! 538: draw(cw);
! 539: }
! 540: }
! 541:
! 542: /*
! 543: * set up the direction co_ordinate for use in various "prefix" commands
! 544: */
! 545: bool
! 546: get_dir(coord *direction)
! 547: {
! 548: register char *prompt;
! 549: register bool gotit;
! 550: int x,y;
! 551:
! 552: prompt = terse ? "Direction?" : "Which direction? ";
! 553: msg(prompt);
! 554: do
! 555: {
! 556: gotit = TRUE;
! 557: switch (md_readchar(msgw))
! 558: {
! 559: case 'h': case'H': direction->y = 0; direction->x = -1;
! 560: when 'j': case'J': direction->y = 1; direction->x = 0;
! 561: when 'k': case'K': direction->y = -1; direction->x = 0;
! 562: when 'l': case'L': direction->y = 0; direction->x = 1;
! 563: when 'y': case'Y': direction->y = -1; direction->x = -1;
! 564: when 'u': case'U': direction->y = -1; direction->x = 1;
! 565: when 'b': case'B': direction->y = 1; direction->x = -1;
! 566: when 'n': case'N': direction->y = 1; direction->x = 1;
! 567: case 0:
! 568: when 3: quit(0);
! 569: return(FALSE);
! 570: when ESCAPE: return (FALSE);
! 571: otherwise:
! 572: mpos = 0;
! 573: msg(prompt);
! 574: gotit = FALSE;
! 575: }
! 576: } until (gotit);
! 577: if ((on(player, ISHUH) || on(player, ISDANCE)) && rnd(100) > 20) {
! 578: do
! 579: {
! 580: *direction = grid[rnd(9)];
! 581: } while (direction->y == 0 && direction->x == 0);
! 582: }
! 583: else if (on(player, ISFLEE)) {
! 584: y = hero.y;
! 585: x = hero.x;
! 586: while (shoot_ok(winat(y, x))) {
! 587: y += direction->y;
! 588: x += direction->x;
! 589: }
! 590: if (isalpha(mvwinch(mw, y, x))) {
! 591: if (y == player.t_dest->y && x == player.t_dest->x) {
! 592: mpos = 0;
! 593: msg("You are too frightened to!");
! 594: return(FALSE);
! 595: }
! 596: }
! 597: }
! 598: mpos = 0;
! 599: return TRUE;
! 600: }
! 601:
! 602: /*
! 603: * see if the object is one of the currently used items
! 604: */
! 605: bool
! 606: is_current(struct object *obj)
! 607: {
! 608: if (obj == NULL)
! 609: return FALSE;
! 610: if (obj == cur_armor || obj == cur_weapon ||
! 611: obj == cur_ring[LEFT_1] || obj == cur_ring[LEFT_2] ||
! 612: obj == cur_ring[LEFT_3] || obj == cur_ring[LEFT_4] ||
! 613: obj == cur_ring[RIGHT_1] || obj == cur_ring[RIGHT_2] ||
! 614: obj == cur_ring[RIGHT_3] || obj == cur_ring[RIGHT_4] ||
! 615: obj == cur_misc[WEAR_BOOTS] || obj == cur_misc[WEAR_JEWEL] ||
! 616: obj == cur_misc[WEAR_BRACERS] || obj == cur_misc[WEAR_CLOAK] ||
! 617: obj == cur_misc[WEAR_GAUNTLET] || obj == cur_misc[WEAR_NECKLACE]) {
! 618:
! 619: return TRUE;
! 620: }
! 621:
! 622: /* Is it a "current" relic? */
! 623: if (obj->o_type == RELIC) {
! 624: switch (obj->o_which) {
! 625: case MUSTY_DAGGER:
! 626: case EMORI_CLOAK:
! 627: case HEIL_ANKH:
! 628: case YENDOR_AMULET:
! 629: case STONEBONES_AMULET:
! 630: case HRUGGEK_MSTAR:
! 631: case AXE_AKLAD:
! 632: case YEENOGHU_FLAIL:
! 633: case SURTUR_RING:
! 634: if (cur_relic[obj->o_which]) return TRUE;
! 635: }
! 636: }
! 637:
! 638: return FALSE;
! 639: }
! 640:
! 641:
! 642: /*
! 643: * Look:
! 644: * A quick glance all around the player
! 645: * wakeup: Should we wake up monsters
! 646: * runend: At end of a run -- for mazes
! 647: */
! 648:
! 649: void
! 650: look(bool wakeup, bool runend)
! 651: {
! 652: register int x, y, radius;
! 653: register char ch, och;
! 654: register int oldx, oldy;
! 655: register bool inpass, horiz, vert, do_light = FALSE, do_blank = FALSE;
! 656: register int passcount = 0, curfloorcount = 0, nextfloorcount = 0;
! 657: register struct room *rp;
! 658: register int ey, ex;
! 659:
! 660: inpass = ((rp = roomin(&hero)) == NULL); /* Are we in a passage? */
! 661:
! 662: /* Are we moving vertically or horizontally? */
! 663: if (runch == 'h' || runch == 'l') horiz = TRUE;
! 664: else horiz = FALSE;
! 665: if (runch == 'j' || runch == 'k') vert = TRUE;
! 666: else vert = FALSE;
! 667:
! 668: /* How far around himself can the player see? */
! 669: if (levtype == OUTSIDE) {
! 670: if (daytime) radius = 6;
! 671: else if (lit_room(rp)) radius = 3;
! 672: else radius = 1;
! 673: }
! 674: else radius = 1;
! 675:
! 676: getyx(cw, oldy, oldx); /* Save current position */
! 677:
! 678: /* Blank out the floor around our last position and check for
! 679: * moving out of a corridor in a maze.
! 680: */
! 681: if (levtype == OUTSIDE) do_blank = !daytime;
! 682: else if (oldrp != NULL && !lit_room(oldrp) && off(player, ISBLIND))
! 683: do_blank = TRUE;
! 684:
! 685: /* Now move around the old position and blank things out */
! 686: ey = player.t_oldpos.y + radius;
! 687: ex = player.t_oldpos.x + radius;
! 688: for (x = player.t_oldpos.x - radius; x <= ex; x++)
! 689: if (x >= 0 && x < cols)
! 690: for (y = player.t_oldpos.y - radius; y <= ey; y++) {
! 691: struct linked_list *it;
! 692: coord here; /* Current <x,y> coordinate */
! 693: char savech; /* Saves character in monster window */
! 694: bool in_room; /* Are we in a room? */
! 695:
! 696: if (y < 1 || y > lines - 3) continue;
! 697:
! 698: /* See what's there -- ignore monsters, just see what they're on */
! 699: savech = CCHAR( mvwinch(mw, y, x) );
! 700: waddch(mw, ' ');
! 701: ch = show(y, x);
! 702: mvwaddch(mw, y, x, savech); /* Restore monster */
! 703:
! 704: /*
! 705: * If we have a monster that we can't see anymore, make sure
! 706: * that we can note that fact.
! 707: */
! 708: if (isalpha(savech) &&
! 709: (y < hero.y - radius || y > hero.y + radius ||
! 710: x < hero.x - radius || x > hero.x + radius)) {
! 711: /* Find the monster */
! 712: it = find_mons(y, x);
! 713: }
! 714: else it = NULL;
! 715:
! 716: /* Are we in a room? */
! 717: here.y = y;
! 718: here.x = x;
! 719: in_room = (roomin(&here) != NULL);
! 720:
! 721: if ((do_blank || !in_room) && (y != hero.y || x != hero.x))
! 722: switch (ch) {
! 723: case DOOR:
! 724: case SECRETDOOR:
! 725: case PASSAGE:
! 726: case STAIRS:
! 727: case TRAPDOOR:
! 728: case TELTRAP:
! 729: case BEARTRAP:
! 730: case SLEEPTRAP:
! 731: case ARROWTRAP:
! 732: case DARTTRAP:
! 733: case MAZETRAP:
! 734: case POOL:
! 735: case POST:
! 736: case '|':
! 737: case '-':
! 738: case WALL:
! 739: /* If there was a monster showing, make it disappear */
! 740: if (isalpha(savech)) {
! 741: mvwaddch(cw, y, x, ch);
! 742:
! 743: /*
! 744: * If we found it (we should!), set it to
! 745: * the right character!
! 746: */
! 747: if (it) (THINGPTR(it))->t_oldch = ch;
! 748: }
! 749: break;
! 750: when FLOOR:
! 751: case FOREST:
! 752: default:
! 753: mvwaddch(cw, y, x, in_room ? ' ' : PASSAGE);
! 754:
! 755: /* If we found a monster, set it to darkness! */
! 756: if (it) (THINGPTR(it))->t_oldch = CCHAR( mvwinch(cw, y, x) );
! 757: }
! 758:
! 759: /* Moving out of a corridor? */
! 760: if (levtype == MAZELEV && !ce(hero, player.t_oldpos) &&
! 761: !running && !isrock(ch) && /* Not running and not a wall */
! 762: ((vert && x != player.t_oldpos.x && y==player.t_oldpos.y) ||
! 763: (horiz && y != player.t_oldpos.y && x==player.t_oldpos.x)))
! 764: do_light = off(player, ISBLIND);
! 765: }
! 766:
! 767: /* Take care of unlighting a corridor */
! 768: if (do_light && lit_room(rp)) light(&player.t_oldpos);
! 769:
! 770: /* Are we coming or going between a wall and a corridor in a maze? */
! 771: och = show(player.t_oldpos.y, player.t_oldpos.x);
! 772: ch = show(hero.y, hero.x);
! 773: if (levtype == MAZELEV &&
! 774: ((isrock(och) && !isrock(ch)) || (isrock(ch) && !isrock(och)))) {
! 775: do_light = off(player, ISBLIND); /* Light it up if not blind */
! 776:
! 777: /* Unlight what we just saw */
! 778: if (do_light && lit_room(&rooms[0])) light(&player.t_oldpos);
! 779: }
! 780:
! 781: /* Look around the player */
! 782: ey = hero.y + radius;
! 783: ex = hero.x + radius;
! 784: for (x = hero.x - radius; x <= ex; x++)
! 785: if (x >= 0 && x < cols) for (y = hero.y - radius; y <= ey; y++) {
! 786: if (y < 1 || y >= lines - 2)
! 787: continue;
! 788: if (isalpha(mvwinch(mw, y, x)))
! 789: {
! 790: register struct linked_list *it;
! 791: register struct thing *tp;
! 792:
! 793: if (wakeup)
! 794: it = wake_monster(y, x);
! 795: else
! 796: it = find_mons(y, x);
! 797:
! 798: if (it) {
! 799: tp = THINGPTR(it);
! 800: tp->t_oldch = CCHAR( mvinch(y, x) );
! 801: if (isatrap(tp->t_oldch)) {
! 802: register struct trap *trp = trap_at(y, x);
! 803:
! 804: tp->t_oldch = (trp->tr_flags & ISFOUND) ? tp->t_oldch
! 805: : trp->tr_show;
! 806: }
! 807: if (tp->t_oldch == FLOOR && !lit_room(rp) &&
! 808: off(player, ISBLIND))
! 809: tp->t_oldch = ' ';
! 810: }
! 811: }
! 812:
! 813: /*
! 814: * Secret doors show as walls
! 815: */
! 816: if ((ch = show(y, x)) == SECRETDOOR)
! 817: ch = secretdoor(y, x);
! 818: /*
! 819: * Don't show room walls if he is in a passage and
! 820: * check for maze turns
! 821: */
! 822: if (off(player, ISBLIND))
! 823: {
! 824: if (y == hero.y && x == hero.x
! 825: || (inpass && (ch == '-' || ch == '|')))
! 826: continue;
! 827:
! 828: /* Did we come to a crossroads in a maze? */
! 829: if (levtype == MAZELEV &&
! 830: (runend || !ce(hero, player.t_oldpos)) &&
! 831: !isrock(ch) && /* Not a wall */
! 832: ((vert && x != hero.x && y == hero.y) ||
! 833: (horiz && y != hero.y && x == hero.x)))
! 834: /* Just came to a turn */
! 835: do_light = off(player, ISBLIND);
! 836: }
! 837: else if (y != hero.y || x != hero.x)
! 838: continue;
! 839:
! 840: wmove(cw, y, x);
! 841: waddch(cw, ch);
! 842: if (door_stop && !firstmove && running)
! 843: {
! 844: switch (runch)
! 845: {
! 846: case 'h':
! 847: if (x == hero.x + 1)
! 848: continue;
! 849: when 'j':
! 850: if (y == hero.y - 1)
! 851: continue;
! 852: when 'k':
! 853: if (y == hero.y + 1)
! 854: continue;
! 855: when 'l':
! 856: if (x == hero.x - 1)
! 857: continue;
! 858: when 'y':
! 859: if ((x + y) - (hero.x + hero.y) >= 1)
! 860: continue;
! 861: when 'u':
! 862: if ((y - x) - (hero.y - hero.x) >= 1)
! 863: continue;
! 864: when 'n':
! 865: if ((x + y) - (hero.x + hero.y) <= -1)
! 866: continue;
! 867: when 'b':
! 868: if ((y - x) - (hero.y - hero.x) <= -1)
! 869: continue;
! 870: }
! 871: switch (ch)
! 872: {
! 873: case DOOR:
! 874: if (x == hero.x || y == hero.y)
! 875: running = FALSE;
! 876: break;
! 877: case PASSAGE:
! 878: if (x == hero.x || y == hero.y)
! 879: passcount++;
! 880: break;
! 881: case FLOOR:
! 882: /* Stop by new passages in a maze (floor next to us) */
! 883: if ((levtype == MAZELEV) &&
! 884: !(hero.y == y && hero.x == x)) {
! 885: if (vert) { /* Moving vertically */
! 886: /* We have a passage on our row */
! 887: if (y == hero.y) curfloorcount++;
! 888:
! 889: /* Some passage on the next row */
! 890: else if (y != player.t_oldpos.y)
! 891: nextfloorcount++;
! 892: }
! 893: else { /* Moving horizontally */
! 894: /* We have a passage on our column */
! 895: if (x == hero.x) curfloorcount++;
! 896:
! 897: /* Some passage in the next column */
! 898: else if (x != player.t_oldpos.x)
! 899: nextfloorcount++;
! 900: }
! 901: }
! 902: case '|':
! 903: case '-':
! 904: case ' ':
! 905: break;
! 906: default:
! 907: running = FALSE;
! 908: break;
! 909: }
! 910: }
! 911: }
! 912:
! 913: /* Have we passed a side passage, with multiple choices? */
! 914: if (curfloorcount > 0 && nextfloorcount > 0) running = FALSE;
! 915:
! 916: else if (door_stop && !firstmove && passcount > 1)
! 917: running = FALSE;
! 918:
! 919: /* Do we have to light up the area (just stepped into a new corridor)? */
! 920: if (do_light && !running && lit_room(rp)) light(&hero);
! 921:
! 922: mvwaddch(cw, hero.y, hero.x, PLAYER);
! 923: wmove(cw, oldy, oldx);
! 924: if (!ce(player.t_oldpos, hero)) {
! 925: player.t_oldpos = hero; /* Don't change if we didn't move */
! 926: oldrp = rp;
! 927: }
! 928: }
! 929:
! 930: /*
! 931: * Lower a level of experience
! 932: */
! 933:
! 934: void
! 935: lower_level(short who)
! 936: {
! 937: int fewer, nsides;
! 938: unsigned int exp;
! 939:
! 940: msg("You suddenly feel less skillful.");
! 941: if (--pstats.s_lvl == 0)
! 942: death(who); /* All levels gone */
! 943: if (pstats.s_lvladj > 0) { /* lose artificial levels first */
! 944: pstats.s_lvladj--;
! 945: return;
! 946: }
! 947: exp = char_class[player.t_ctype].cap;
! 948: if (pstats.s_exp >= exp*2)
! 949: pstats.s_exp -= exp;
! 950: else
! 951: pstats.s_exp /= 2;
! 952:
! 953: nsides = char_class[player.t_ctype].hit_pts;
! 954: fewer = max(1, roll(1,nsides) + const_bonus());
! 955: pstats.s_hpt -= fewer;
! 956: max_stats.s_hpt -= fewer;
! 957: if (pstats.s_hpt < 1)
! 958: pstats.s_hpt = 1;
! 959: if (max_stats.s_hpt < 1)
! 960: death(who);
! 961: }
! 962:
! 963: /*
! 964: * print out the name of a monster
! 965: */
! 966: char *
! 967: monster_name(struct thing *tp)
! 968: {
! 969: prbuf[0] = '\0';
! 970: if (on(*tp, ISFLEE) || on(*tp, WASTURNED))
! 971: strcat(prbuf, "terrified ");
! 972: if (on(*tp, ISHUH))
! 973: strcat(prbuf, "confused ");
! 974: if (on(*tp, ISCHARMED))
! 975: strcat(prbuf, "charmed ");
! 976: else if (on(*tp, ISFLY))
! 977: strcat(prbuf, "flying ");
! 978:
! 979: /* If it is sleeping or stoned, write over any of the above attributes */
! 980: if (off(*tp, ISRUN))
! 981: strcpy(prbuf, "sleeping ");
! 982: if (on(*tp, ISSTONE))
! 983: strcpy(prbuf, "petrified ");
! 984:
! 985: if (tp->t_name) strcat(prbuf, tp->t_name);
! 986: else strcat(prbuf, monsters[tp->t_index].m_name);
! 987:
! 988: return(prbuf);
! 989: }
! 990:
! 991: /*
! 992: * move_hero:
! 993: * Try to move the hero somplace besides next to where he is. We ask him
! 994: * where. There can be restrictions based on why he is moving.
! 995: */
! 996:
! 997: bool
! 998: move_hero(int why)
! 999: {
! 1000: char *action = "";
! 1001: char which;
! 1002: coord c;
! 1003:
! 1004: switch (why) {
! 1005: case H_TELEPORT:
! 1006: action = "teleport";
! 1007: }
! 1008:
! 1009: msg("Where do you wish to %s to? (* for help) ", action);
! 1010: c = get_coordinates();
! 1011: mpos = 0;
! 1012: which = CCHAR( winat(c.y, c.x) );
! 1013: switch (which) {
! 1014: default:
! 1015: if (!isrock(which) || off(player, CANINWALL)) break;
! 1016:
! 1017: case FLOOR:
! 1018: case PASSAGE:
! 1019: case DOOR:
! 1020: case STAIRS:
! 1021: case POST:
! 1022: case GOLD:
! 1023: case POTION:
! 1024: case SCROLL:
! 1025: case FOOD:
! 1026: case WEAPON:
! 1027: case ARMOR:
! 1028: case RING:
! 1029: case MM:
! 1030: case RELIC:
! 1031: case STICK:
! 1032: hero = c;
! 1033: return(TRUE);
! 1034: }
! 1035: return(FALSE);
! 1036: }
! 1037:
! 1038: /*
! 1039: * raise_level:
! 1040: * The guy just magically went up a level.
! 1041: */
! 1042:
! 1043: void
! 1044: raise_level(void)
! 1045: {
! 1046: unsigned long test; /* Next level -- be sure it is not an overflow */
! 1047:
! 1048: test = check_level(); /* Get next boundary */
! 1049:
! 1050: /* Be sure it is higher than what we have no -- else overflow */
! 1051: if (test > pstats.s_exp) pstats.s_exp = test;
! 1052: check_level();
! 1053: }
! 1054:
! 1055: /*
! 1056: * saving throw matrix for character saving throws
! 1057: * this table is indexed by char type and saving throw type
! 1058: */
! 1059: static int st_matrix[NUM_CHARTYPES][5] = {
! 1060: /* Poison, Petrify, wand, Breath, Magic */
! 1061: { 14, 15, 16, 16, 17 },
! 1062: { 14, 15, 16, 16, 17 },
! 1063: { 14, 15, 16, 16, 17 },
! 1064: { 14, 13, 11, 15, 12 },
! 1065: { 10, 13, 14, 16, 15 },
! 1066: { 13, 12, 14, 16, 15 },
! 1067: { 13, 12, 14, 16, 15 },
! 1068: { 10, 13, 14, 16, 15 },
! 1069: { 13, 12, 14, 16, 15 },
! 1070: { 14, 15, 16, 16, 17 }
! 1071: };
! 1072:
! 1073: /*
! 1074: * save:
! 1075: * See if a creature saves against something
! 1076: * which: which type of save
! 1077: * who: who is saving
! 1078: * adj: saving throw adjustment
! 1079: */
! 1080: bool
! 1081: save(int which, struct thing *who, int adj)
! 1082: {
! 1083: register int need, level, protect;
! 1084:
! 1085: protect = 0;
! 1086: level = who->t_stats.s_lvl;
! 1087: need = st_matrix[who->t_ctype][which];
! 1088: switch (who->t_ctype) {
! 1089: case C_FIGHTER:
! 1090: case C_RANGER:
! 1091: case C_PALADIN:
! 1092: case C_MONSTER:
! 1093: need -= (level-1) / 2;
! 1094: when C_MAGICIAN:
! 1095: need -= 2 * (level-1) / 5;
! 1096: when C_CLERIC:
! 1097: case C_DRUID:
! 1098: need -= (level-1) / 3;
! 1099: when C_THIEF:
! 1100: case C_ASSASIN:
! 1101: case C_MONK:
! 1102: need -= 2 * (level-1) / 4;
! 1103: }
! 1104: /*
! 1105: * add in pluses against poison for execeptional constitution
! 1106: */
! 1107: if (which == VS_POISON && who->t_stats.s_const > 18)
! 1108: need -= (who->t_stats.s_const - 17) / 2;
! 1109: if (who == &player) {
! 1110: /*
! 1111: * does the player have a ring of protection on?
! 1112: */
! 1113: protect += ring_value(R_PROTECT);
! 1114: /*
! 1115: * does the player have a cloak of protection on?
! 1116: */
! 1117: if (cur_misc[WEAR_CLOAK])
! 1118: protect += cur_misc[WEAR_CLOAK]->o_ac;
! 1119:
! 1120: protect = min(protect, 4);/* no more than a +4 bonus */
! 1121: need -= protect;
! 1122: }
! 1123: need -= adj;
! 1124: /*
! 1125: * always miss or save on a 1 (except for UNIQUEs
! 1126: */
! 1127: if (who == &player || off(*who, ISUNIQUE))
! 1128: need = max(need, 2);
! 1129: need = min(20, need); /* always make our save on a 20 */
! 1130: debug("need a %d to save", need);
! 1131: return (roll(1, 20) >= need);
! 1132: }
! 1133:
! 1134:
! 1135: /*
! 1136: * secret_door:
! 1137: * Figure out what a secret door looks like.
! 1138: */
! 1139:
! 1140: char
! 1141: secretdoor(int y, int x)
! 1142: {
! 1143: register int i;
! 1144: register struct room *rp;
! 1145: register coord *cpp;
! 1146: static coord cp;
! 1147:
! 1148: cp.y = y;
! 1149: cp.x = x;
! 1150: cpp = &cp;
! 1151: for (rp = rooms, i = 0; i < MAXROOMS; rp++, i++)
! 1152: if (inroom(rp, cpp))
! 1153: if (y == rp->r_pos.y || y == rp->r_pos.y + rp->r_max.y - 1)
! 1154: return('-');
! 1155: else
! 1156: return('|');
! 1157:
! 1158: return('p');
! 1159: }
! 1160:
! 1161: /*
! 1162: * this routine computes the players current strength
! 1163: */
! 1164: int
! 1165: str_compute(void)
! 1166: {
! 1167: if (cur_misc[WEAR_GAUNTLET] != NULL &&
! 1168: cur_misc[WEAR_GAUNTLET]->o_which == MM_G_OGRE) {
! 1169: if (cur_misc[WEAR_GAUNTLET]->o_flags & ISCURSED)
! 1170: return (3);
! 1171: else
! 1172: return (18);
! 1173: }
! 1174: else
! 1175: return (pstats.s_str);
! 1176: }
! 1177:
! 1178: /*
! 1179: * copy string using unctrl for things
! 1180: */
! 1181: void
! 1182: strucpy(char *s1, char *s2, int len)
! 1183: {
! 1184: const char *sp;
! 1185:
! 1186: while (len--)
! 1187: {
! 1188: strcpy(s1, (sp = unctrl(*s2++)));
! 1189: s1 += strlen(sp);
! 1190: }
! 1191: *s1 = '\0';
! 1192: }
! 1193:
! 1194: /*
! 1195: * tr_name:
! 1196: * print the name of a trap
! 1197: */
! 1198:
! 1199: char *
! 1200: tr_name(char ch)
! 1201: {
! 1202: register char *s = "";
! 1203:
! 1204: switch (ch)
! 1205: {
! 1206: case TRAPDOOR:
! 1207: s = terse ? "A trapdoor." : "You found a trapdoor.";
! 1208: when BEARTRAP:
! 1209: s = terse ? "A beartrap." : "You found a beartrap.";
! 1210: when SLEEPTRAP:
! 1211: s = terse ? "A sleeping gas trap.":"You found a sleeping gas trap.";
! 1212: when ARROWTRAP:
! 1213: s = terse ? "An arrow trap." : "You found an arrow trap.";
! 1214: when TELTRAP:
! 1215: s = terse ? "A teleport trap." : "You found a teleport trap.";
! 1216: when DARTTRAP:
! 1217: s = terse ? "A dart trap." : "You found a poison dart trap.";
! 1218: when POOL:
! 1219: s = terse ? "A shimmering pool." : "You found a shimmering pool";
! 1220: when MAZETRAP:
! 1221: s = terse ? "A maze entrance." : "You found a maze entrance";
! 1222: }
! 1223: return s;
! 1224: }
! 1225:
! 1226: /*
! 1227: * for printfs: if string starts with a vowel, return "n" for an "an"
! 1228: */
! 1229: char *
! 1230: vowelstr(char *str)
! 1231: {
! 1232: switch (*str)
! 1233: {
! 1234: case 'a':
! 1235: case 'e':
! 1236: case 'i':
! 1237: case 'o':
! 1238: case 'u':
! 1239: return "n";
! 1240: default:
! 1241: return "";
! 1242: }
! 1243: }
! 1244:
! 1245: /*
! 1246: * wake up a room full (hopefully) of creatures
! 1247: */
! 1248: void
! 1249: wake_room(struct room *rp)
! 1250: {
! 1251: register struct linked_list *item;
! 1252: register struct thing *tp;
! 1253:
! 1254: for (item=mlist; item!=NULL; item=next(item)) {
! 1255: tp = THINGPTR(item);
! 1256: if (off(*tp,ISRUN) && on(*tp,ISMEAN) && roomin(&tp->t_pos) == rp)
! 1257: runto(tp, &hero);
! 1258: }
! 1259: }
! 1260:
! 1261:
! 1262: /*
! 1263: * waste_time:
! 1264: * Do nothing but let other things happen
! 1265: */
! 1266:
! 1267: void
! 1268: waste_time(void)
! 1269: {
! 1270: if (inwhgt) /* if from wghtchk then done */
! 1271: return;
! 1272: do_daemons(BEFORE);
! 1273: do_fuses(BEFORE);
! 1274: do_daemons(AFTER);
! 1275: do_fuses(AFTER);
! 1276: }
CVSweb