Annotation of early-roguelike/arogue5/monsters.c, Revision 1.1
1.1 ! rubenllo 1: /*
! 2: * File with various monster functions in it
! 3: *
! 4: * Advanced Rogue
! 5: * Copyright (C) 1984, 1985 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 <stdlib.h>
! 18: #include <ctype.h>
! 19: #include <string.h>
! 20:
! 21:
! 22: /*
! 23: * Check_residue takes care of any effect of the monster
! 24: */
! 25: void
! 26: check_residue(struct thing *tp)
! 27: {
! 28: /*
! 29: * Take care of special abilities
! 30: */
! 31: if (on(*tp, DIDHOLD) && (--hold_count == 0)) turn_off(player, ISHELD);
! 32:
! 33: /* If it has lowered player, give him back a level */
! 34: if (on(*tp, DIDDRAIN)) raise_level(FALSE);
! 35:
! 36: /* If frightened of this monster, stop */
! 37: if (on(player, ISFLEE) &&
! 38: player.t_dest == &tp->t_pos) turn_off(player, ISFLEE);
! 39:
! 40: /* If monster was suffocating player, stop it */
! 41: if (on(*tp, DIDSUFFOCATE)) extinguish(suffocate);
! 42:
! 43: /* If something with fire, may darken */
! 44: if (on(*tp, HASFIRE)) {
! 45: register struct room *rp=roomin(&tp->t_pos);
! 46: register struct linked_list *fire_item;
! 47:
! 48: if (rp) {
! 49: for (fire_item = rp->r_fires; fire_item != NULL;
! 50: fire_item = next(fire_item)) {
! 51: if (THINGPTR(fire_item) == tp) {
! 52: detach(rp->r_fires, fire_item);
! 53: destroy_item(fire_item);
! 54: if (rp->r_fires == NULL) {
! 55: rp->r_flags &= ~HASFIRE;
! 56: if (cansee(tp->t_pos.y, tp->t_pos.x)) light(&hero);
! 57: }
! 58: break;
! 59: }
! 60: }
! 61: }
! 62: }
! 63: }
! 64:
! 65: /*
! 66: * Creat_mons creates the specified monster -- any if 0
! 67: * person: Where to create next to
! 68: */
! 69:
! 70: bool
! 71: creat_mons(struct thing *person, short monster, bool report)
! 72: {
! 73: struct linked_list *nitem;
! 74: register struct thing *tp;
! 75: struct room *rp;
! 76: coord *mp;
! 77:
! 78: if (levtype == POSTLEV)
! 79: return(FALSE);
! 80: if ((mp = fallpos(&(person->t_pos), FALSE, 2)) != NULL) {
! 81: nitem = new_item(sizeof (struct thing));
! 82: new_monster(nitem,
! 83: monster == 0 ? randmonster(FALSE, FALSE)
! 84: : monster,
! 85: mp,
! 86: TRUE);
! 87: tp = THINGPTR(nitem);
! 88: runto(tp, &hero);
! 89: tp->t_no_move = 1; /* since it just got here, it is disoriented */
! 90: carry_obj(tp, monsters[tp->t_index].m_carry/2); /* only half chance */
! 91: if (on(*tp, HASFIRE)) {
! 92: rp = roomin(&tp->t_pos);
! 93: if (rp) {
! 94: register struct linked_list *fire_item;
! 95:
! 96: /* Put the new fellow in the room list */
! 97: fire_item = creat_item();
! 98: ldata(fire_item) = (char *) tp;
! 99: attach(rp->r_fires, fire_item);
! 100:
! 101: rp->r_flags |= HASFIRE;
! 102: }
! 103: }
! 104:
! 105: /*
! 106: * If we can see this monster, set oldch to ' ' to make light()
! 107: * think the creature used to be invisible (ie. not seen here)
! 108: */
! 109: if (cansee(tp->t_pos.y, tp->t_pos.x)) tp->t_oldch = ' ';
! 110: return(TRUE);
! 111: }
! 112: if (report) msg("You hear a faint cry of anguish in the distance.");
! 113: return(FALSE);
! 114: }
! 115:
! 116: /*
! 117: * Genmonsters:
! 118: * Generate at least 'least' monsters for this single room level.
! 119: * 'Treas' indicates whether this is a "treasure" level.
! 120: */
! 121:
! 122: void
! 123: genmonsters(int least, bool treas)
! 124: {
! 125: reg int i;
! 126: reg struct room *rp = &rooms[0];
! 127: reg struct linked_list *item;
! 128: reg struct thing *mp;
! 129: coord tp;
! 130:
! 131: for (i = 0; i < level + least; i++) {
! 132: if (!treas && rnd(100) < 50) /* put in some little buggers */
! 133: continue;
! 134: /*
! 135: * Put the monster in
! 136: */
! 137: item = new_item(sizeof *mp);
! 138: mp = THINGPTR(item);
! 139: do {
! 140: rnd_pos(rp, &tp);
! 141: } until(mvwinch(stdscr, tp.y, tp.x) == FLOOR);
! 142:
! 143: new_monster(item, randmonster(FALSE, FALSE), &tp, FALSE);
! 144: /*
! 145: * See if we want to give it a treasure to carry around.
! 146: */
! 147: carry_obj(mp, monsters[mp->t_index].m_carry);
! 148:
! 149: /* Is it going to give us some light? */
! 150: if (on(*mp, HASFIRE)) {
! 151: register struct linked_list *fire_item;
! 152:
! 153: fire_item = creat_item();
! 154: ldata(fire_item) = (char *) mp;
! 155: attach(rp->r_fires, fire_item);
! 156: rp->r_flags |= HASFIRE;
! 157: }
! 158: }
! 159: }
! 160:
! 161: /*
! 162: * id_monst returns the index of the monster given its letter
! 163: */
! 164:
! 165: short
! 166: id_monst(char monster)
! 167: {
! 168: register short result;
! 169:
! 170: result = NLEVMONS*vlevel;
! 171: if (result > NUMMONST) result = NUMMONST;
! 172:
! 173: for(; result>0; result--)
! 174: if (monsters[result].m_appear == monster) return(result);
! 175: for (result=(NLEVMONS*vlevel)+1; result <= NUMMONST; result++)
! 176: if (monsters[result].m_appear == monster) return(result);
! 177: return(0);
! 178: }
! 179:
! 180:
! 181: /*
! 182: * new_monster:
! 183: * Pick a new monster and add it to the list
! 184: */
! 185:
! 186: void
! 187: new_monster(struct linked_list *item, short type, coord *cp, bool max_monster)
! 188: {
! 189: register struct thing *tp;
! 190: register struct monster *mp;
! 191: register char *ip, *hitp;
! 192: register int i, min_intel, max_intel;
! 193: register int num_dice, num_sides=8, num_extra=0;
! 194:
! 195: attach(mlist, item);
! 196: tp = THINGPTR(item);
! 197: tp->t_turn = TRUE;
! 198: tp->t_pack = NULL;
! 199: tp->t_index = type;
! 200: tp->t_wasshot = FALSE;
! 201: tp->t_type = monsters[type].m_appear;
! 202: tp->t_ctype = C_MONSTER;
! 203: tp->t_no_move = 0;
! 204: tp->t_doorgoal = 0;
! 205: tp->t_quiet = 0;
! 206: tp->t_pos = tp->t_oldpos = *cp;
! 207: tp->t_oldch = CCHAR( mvwinch(cw, cp->y, cp->x) );
! 208: mvwaddch(mw, cp->y, cp->x, tp->t_type);
! 209: mp = &monsters[tp->t_index];
! 210:
! 211: /* Figure out monster's hit points */
! 212: hitp = mp->m_stats.s_hpt;
! 213: num_dice = atoi(hitp);
! 214: if ((hitp = strchr(hitp, 'd')) != NULL) {
! 215: num_sides = atoi(++hitp);
! 216: if ((hitp = strchr(hitp, '+')) != NULL)
! 217: num_extra = atoi(++hitp);
! 218: }
! 219:
! 220: tp->t_stats.s_lvl = mp->m_stats.s_lvl;
! 221: tp->t_stats.s_arm = mp->m_stats.s_arm;
! 222: strncpy(tp->t_stats.s_dmg,mp->m_stats.s_dmg,sizeof(tp->t_stats.s_dmg));
! 223: tp->t_stats.s_str = mp->m_stats.s_str;
! 224: if (vlevel > HARDER) { /* the deeper, the meaner we get */
! 225: tp->t_stats.s_lvl += (vlevel - HARDER);
! 226: num_dice += (vlevel - HARDER)/2;
! 227: }
! 228: if (max_monster)
! 229: tp->t_stats.s_hpt = num_dice * num_sides + num_extra;
! 230: else
! 231: tp->t_stats.s_hpt = roll(num_dice, num_sides) + num_extra;
! 232: tp->t_stats.s_exp = mp->m_stats.s_exp + mp->m_add_exp*tp->t_stats.s_hpt;
! 233:
! 234: /*
! 235: * just initailize others values to something reasonable for now
! 236: * maybe someday will *really* put these in monster table
! 237: */
! 238: tp->t_stats.s_wisdom = 8 + rnd(4);
! 239: tp->t_stats.s_dext = 8 + rnd(4);
! 240: tp->t_stats.s_const = 8 + rnd(4);
! 241: tp->t_stats.s_charisma = 8 + rnd(4);
! 242:
! 243: /* Set the initial flags */
! 244: for (i=0; i<16; i++) tp->t_flags[i] = 0;
! 245: for (i=0; i<MAXFLAGS; i++)
! 246: turn_on(*tp, mp->m_flags[i]);
! 247:
! 248: /* suprising monsters don't always surprise you */
! 249: if (!max_monster && on(*tp, CANSURPRISE) &&
! 250: off(*tp, ISUNIQUE) && rnd(100) < 20)
! 251: turn_off(*tp, CANSURPRISE);
! 252:
! 253: /* If this monster is unique, gen it */
! 254: if (on(*tp, ISUNIQUE)) mp->m_normal = FALSE;
! 255:
! 256: /*
! 257: * if is it the quartermaster, then compute his level and exp pts
! 258: * based on the level. This will make it fair when thieves try to
! 259: * steal and give them reasonable experience if they succeed.
! 260: */
! 261: if (on(*tp, CANSELL)) {
! 262: tp->t_stats.s_exp = vlevel * 100;
! 263: tp->t_stats.s_lvl = vlevel/2 + 1;
! 264: attach(tp->t_pack, new_thing(ALL));
! 265: }
! 266:
! 267: /* Normally scared monsters have a chance to not be scared */
! 268: if (on(*tp, ISFLEE) && (rnd(4) == 0)) turn_off(*tp, ISFLEE);
! 269:
! 270: /* Figure intelligence */
! 271: min_intel = atoi(mp->m_intel);
! 272: if ((ip = (char *) strchr(mp->m_intel, '-')) == NULL)
! 273: tp->t_stats.s_intel = min_intel;
! 274: else {
! 275: max_intel = atoi(++ip);
! 276: if (max_monster)
! 277: tp->t_stats.s_intel = max_intel;
! 278: else
! 279: tp->t_stats.s_intel = min_intel + rnd(max_intel - min_intel);
! 280: }
! 281: if (vlevel > HARDER)
! 282: tp->t_stats.s_intel += ((vlevel - HARDER)/2);
! 283: tp->maxstats = tp->t_stats;
! 284:
! 285: /* If the monster can shoot, it may have a weapon */
! 286: if (on(*tp, CANSHOOT) && ((rnd(100) < (22 + vlevel)) || max_monster)) {
! 287: struct linked_list *item1;
! 288: register struct object *cur, *cur1;
! 289:
! 290: item = new_item(sizeof *cur);
! 291: item1 = new_item(sizeof *cur1);
! 292: cur = OBJPTR(item);
! 293: cur1 = OBJPTR(item1);
! 294: cur->o_hplus = (rnd(4) < 3) ? 0
! 295: : (rnd(3) + 1) * ((rnd(3) < 2) ? 1 : -1);
! 296: cur->o_dplus = (rnd(4) < 3) ? 0
! 297: : (rnd(3) + 1) * ((rnd(3) < 2) ? 1 : -1);
! 298: cur1->o_hplus = (rnd(4) < 3) ? 0
! 299: : (rnd(3) + 1) * ((rnd(3) < 2) ? 1 : -1);
! 300: cur1->o_dplus = (rnd(4) < 3) ? 0
! 301: : (rnd(3) + 1) * ((rnd(3) < 2) ? 1 : -1);
! 302: strcpy(cur->o_damage,"0d0");
! 303: strcpy(cur->o_hurldmg,"0d0");
! 304: strcpy(cur1->o_damage,"0d0");
! 305: strcpy(cur1->o_hurldmg,"0d0");
! 306: cur->o_ac = cur1->o_ac = 11;
! 307: cur->o_count = cur1->o_count = 1;
! 308: cur->o_group = cur1->o_group = 0;
! 309: cur->contents = cur1->contents = NULL;
! 310: if ((cur->o_hplus <= 0) && (cur->o_dplus <= 0)) cur->o_flags = ISCURSED;
! 311: if ((cur1->o_hplus <= 0) && (cur1->o_dplus <= 0))
! 312: cur1->o_flags = ISCURSED;
! 313: cur->o_flags = cur1->o_flags = 0;
! 314: cur->o_type = cur1->o_type = WEAPON;
! 315: cur->o_mark[0] = cur1->o_mark[0] = '\0';
! 316:
! 317: /* The monster may use a crossbow, sling, or an arrow */
! 318: i = rnd(100);
! 319: if (i < 10) {
! 320: cur->o_which = CROSSBOW;
! 321: cur1->o_which = BOLT;
! 322: init_weapon(cur, CROSSBOW);
! 323: init_weapon(cur1, BOLT);
! 324: }
! 325: else if (i < 70) {
! 326: cur->o_which = BOW;
! 327: cur1->o_which = ARROW;
! 328: init_weapon(cur, BOW);
! 329: init_weapon(cur1, ARROW);
! 330: }
! 331: else {
! 332: cur->o_which = SLING;
! 333: cur1->o_which = ROCK;
! 334: init_weapon(cur, SLING);
! 335: init_weapon(cur1, ROCK);
! 336: }
! 337:
! 338: attach(tp->t_pack, item);
! 339: attach(tp->t_pack, item1);
! 340: }
! 341:
! 342:
! 343: if (ISWEARING(R_AGGR))
! 344: runto(tp, &hero);
! 345: if (on(*tp, ISDISGUISE))
! 346: {
! 347: char mch = 0;
! 348:
! 349: if (tp->t_pack != NULL)
! 350: mch = (OBJPTR(tp->t_pack))->o_type;
! 351: else
! 352: switch (rnd(10)) {
! 353: case 0: mch = GOLD;
! 354: when 1: mch = POTION;
! 355: when 2: mch = SCROLL;
! 356: when 3: mch = FOOD;
! 357: when 4: mch = WEAPON;
! 358: when 5: mch = ARMOR;
! 359: when 6: mch = RING;
! 360: when 7: mch = STICK;
! 361: when 8: mch = monsters[randmonster(FALSE, FALSE)].m_appear;
! 362: when 9: mch = MM;
! 363: }
! 364: tp->t_disguise = mch;
! 365: }
! 366: }
! 367:
! 368: /*
! 369: * randmonster:
! 370: * Pick a monster to show up. The lower the level,
! 371: * the meaner the monster.
! 372: */
! 373:
! 374: short
! 375: randmonster(bool wander, bool no_unique)
! 376: {
! 377: register int d, cur_level, range, i;
! 378:
! 379: /*
! 380: * Do we want a merchant? Merchant is always in place 'NUMMONST'
! 381: */
! 382: if (wander && monsters[NUMMONST].m_wander && rnd(100) < 3) return NUMMONST;
! 383:
! 384: cur_level = vlevel;
! 385: range = 4*NLEVMONS;
! 386: i = 0;
! 387: do
! 388: {
! 389: if (i++ > range*10) { /* just in case all have be genocided */
! 390: i = 0;
! 391: if (--cur_level <= 0)
! 392: fatal("Rogue could not find a monster to make");
! 393: }
! 394: d = NLEVMONS*(cur_level - 1) + (rnd(range) - (range - 1 - NLEVMONS));
! 395: if (d < 1)
! 396: d = rnd(NLEVMONS) + 1;
! 397: if (d > NUMMONST - NUMUNIQUE - 1) {
! 398: if (no_unique)
! 399: d = rnd(range) + (NUMMONST - NUMUNIQUE - 1) - (range - 1);
! 400: else if (d > NUMMONST - 1)
! 401: d = rnd(range+NUMUNIQUE) + (NUMMONST-1) - (range+NUMUNIQUE-1);
! 402: }
! 403: }
! 404: while (wander ? !monsters[d].m_wander || !monsters[d].m_normal
! 405: : !monsters[d].m_normal);
! 406: return d;
! 407: }
! 408:
! 409: /* Sell displays a menu of goods from which the player may choose
! 410: * to purchase something.
! 411: */
! 412:
! 413: void
! 414: sell(struct thing *tp)
! 415: {
! 416: register struct linked_list *item;
! 417: register struct object *obj;
! 418: register int i, j, min_worth, nitems, goods = 0, chance, which_item;
! 419: char buffer[LINELEN];
! 420: struct {
! 421: int which;
! 422: int plus1, plus2;
! 423: int count;
! 424: int worth;
! 425: char *name;
! 426: } selection[10];
! 427:
! 428: min_worth = 100000;
! 429: item = find_mons(tp->t_pos.y, tp->t_pos.x); /* Get pointer to monster */
! 430:
! 431: /* Select the items */
! 432: nitems = rnd(6) + 5;
! 433:
! 434: for (i=0; i<nitems; i++) {
! 435: selection[i].worth = selection[i].plus1
! 436: = selection[i].plus2
! 437: = selection[i].which
! 438: = selection[i].count
! 439: = 0;
! 440: }
! 441: switch (rnd(9)) {
! 442: /* Armor */
! 443: case 0:
! 444: case 1:
! 445: goods = ARMOR;
! 446: for (i=0; i<nitems; i++) {
! 447: chance = rnd(100);
! 448: for (j = 0; j < MAXARMORS; j++)
! 449: if (chance < armors[j].a_prob)
! 450: break;
! 451: if (j == MAXARMORS) {
! 452: debug("Picked a bad armor %d", chance);
! 453: j = 0;
! 454: }
! 455: selection[i].which = j;
! 456: selection[i].count = 1;
! 457: if (rnd(100) < 40) selection[i].plus1 = rnd(5) + 1;
! 458: else selection[i].plus1 = 0;
! 459: selection[i].name = armors[j].a_name;
! 460:
! 461: /* Calculate price */
! 462: selection[i].worth = armors[j].a_worth;
! 463: selection[i].worth +=
! 464: 2 * s_magic[S_ALLENCH].mi_worth * selection[i].plus1;
! 465: if (min_worth > selection[i].worth)
! 466: min_worth = selection[i].worth;
! 467: }
! 468: break;
! 469:
! 470: /* Weapon */
! 471: case 2:
! 472: case 3:
! 473: goods = WEAPON;
! 474: for (i=0; i<nitems; i++) {
! 475: selection[i].which = rnd(MAXWEAPONS);
! 476: selection[i].count = 1;
! 477: if (rnd(100) < 35) {
! 478: selection[i].plus1 = rnd(3);
! 479: selection[i].plus2 = rnd(3);
! 480: }
! 481: else {
! 482: selection[i].plus1 = 0;
! 483: selection[i].plus2 = 0;
! 484: }
! 485: if (weaps[selection[i].which].w_flags & ISMANY)
! 486: selection[i].count = rnd(15) + 5;
! 487: selection[i].name = weaps[selection[i].which].w_name;
! 488: /*
! 489: * note: use "count" before adding in the enchantment cost
! 490: * of an item. This will keep the price of arrows
! 491: * and such to a reasonable price.
! 492: */
! 493: j = selection[i].plus1 + selection[i].plus2;
! 494: selection[i].worth = weaps[selection[i].which].w_worth;
! 495: selection[i].worth *= selection[i].count;
! 496: selection[i].worth += 2 * s_magic[S_ALLENCH].mi_worth * j;
! 497: if (min_worth > selection[i].worth)
! 498: min_worth = selection[i].worth;
! 499: }
! 500: break;
! 501:
! 502: /* Staff or wand */
! 503: case 4:
! 504: goods = STICK;
! 505: for (i=0; i<nitems; i++) {
! 506: selection[i].which = pick_one(ws_magic, MAXSTICKS);
! 507: selection[i].plus1 = rnd(11) + 5; /* Charges */
! 508: selection[i].count = 1;
! 509: selection[i].name = ws_magic[selection[i].which].mi_name;
! 510: selection[i].worth = ws_magic[selection[i].which].mi_worth;
! 511: selection[i].worth += 20 * selection[i].plus1;
! 512: if (min_worth > selection[i].worth)
! 513: min_worth = selection[i].worth;
! 514: }
! 515: break;
! 516:
! 517: /* Ring */
! 518: case 5:
! 519: goods = RING;
! 520: for (i=0; i<nitems; i++) {
! 521: selection[i].which = pick_one(r_magic, MAXRINGS);
! 522: selection[i].plus1 = rnd(2) + 1; /* Armor class */
! 523: selection[i].count = 1;
! 524: if (rnd(100) < r_magic[selection[i].which].mi_bless + 10)
! 525: selection[i].plus1 += rnd(2) + 1;
! 526: selection[i].name = r_magic[selection[i].which].mi_name;
! 527: selection[i].worth = r_magic[selection[i].which].mi_worth;
! 528:
! 529: switch (selection[i].which) {
! 530: case R_DIGEST:
! 531: if (selection[i].plus1 > 2) selection[i].plus1 = 2;
! 532: else if (selection[i].plus1 < 1) selection[i].plus1 = 1;
! 533: /* fall thru here to other cases */
! 534: case R_ADDSTR:
! 535: case R_ADDDAM:
! 536: case R_PROTECT:
! 537: case R_ADDHIT:
! 538: case R_ADDINTEL:
! 539: case R_ADDWISDOM:
! 540: if (selection[i].plus1 > 0)
! 541: selection[i].worth += selection[i].plus1 * 50;
! 542: }
! 543: if(min_worth > selection[i].worth)
! 544: min_worth = selection[i].worth;
! 545: }
! 546: break;
! 547:
! 548: /* scroll */
! 549: case 6:
! 550: goods = SCROLL;
! 551: for (i=0; i<nitems; i++) {
! 552: selection[i].which = pick_one(s_magic, MAXSCROLLS);
! 553: selection[i].count = 1;
! 554: selection[i].name = s_magic[selection[i].which].mi_name;
! 555: selection[i].worth = s_magic[selection[i].which].mi_worth;
! 556: if (min_worth > selection[i].worth)
! 557: min_worth = selection[i].worth;
! 558: }
! 559: break;
! 560:
! 561: /* potions */
! 562: case 7:
! 563: goods = POTION;
! 564: for (i=0; i<nitems; i++) {
! 565: selection[i].which = pick_one(p_magic, MAXPOTIONS);
! 566: selection[i].count = 1;
! 567: selection[i].name = p_magic[selection[i].which].mi_name;
! 568: selection[i].worth = p_magic[selection[i].which].mi_worth;
! 569: if (min_worth > selection[i].worth)
! 570: min_worth = selection[i].worth;
! 571: }
! 572: break;
! 573:
! 574: /* Miscellaneous magic */
! 575: case 8:
! 576: goods = MM;
! 577: for (i=0; i<nitems; i++) { /* don't sell as many mm as others */
! 578: selection[i].which = pick_one(m_magic, MAXMM);
! 579: selection[i].count = 1;
! 580: selection[i].name = m_magic[selection[i].which].mi_name;
! 581: selection[i].worth = m_magic[selection[i].which].mi_worth;
! 582:
! 583: switch (selection[i].which) {
! 584: case MM_JUG:
! 585: switch(rnd(9)) {
! 586: case 0: selection[i].plus1 = P_PHASE;
! 587: when 1: selection[i].plus1 = P_CLEAR;
! 588: when 2: selection[i].plus1 = P_SEEINVIS;
! 589: when 3: selection[i].plus1 = P_HEALING;
! 590: when 4: selection[i].plus1 = P_MFIND;
! 591: when 5: selection[i].plus1 = P_TFIND;
! 592: when 6: selection[i].plus1 = P_HASTE;
! 593: when 7: selection[i].plus1 = P_RESTORE;
! 594: when 8: selection[i].plus1 = P_FLY;
! 595: }
! 596: when MM_OPEN:
! 597: case MM_HUNGER:
! 598: case MM_DRUMS:
! 599: case MM_DISAPPEAR:
! 600: case MM_CHOKE:
! 601: case MM_KEOGHTOM:
! 602: selection[i].plus1 = 3 + (rnd(3)+1) * 3;
! 603: selection[i].worth += selection[i].plus1 * 50;
! 604: when MM_BRACERS:
! 605: selection[i].plus1 = rnd(10)+1;
! 606: selection[i].worth += selection[i].plus1 * 75;
! 607: when MM_DISP:
! 608: selection[i].plus1 = 2;
! 609: when MM_PROTECT:
! 610: selection[i].plus1 = rnd(5)+1;
! 611: selection[i].worth += selection[i].plus1 * 100;
! 612: when MM_SKILLS:
! 613: selection[i].plus1 = player.t_ctype;
! 614: otherwise:
! 615: break;
! 616: }
! 617: if(min_worth > selection[i].worth)
! 618: min_worth = selection[i].worth;
! 619: }
! 620: break;
! 621: }
! 622:
! 623: /* See if player can afford an item */
! 624: if (min_worth > purse) {
! 625: msg("The %s eyes your small purse and departs.",
! 626: monsters[NUMMONST].m_name);
! 627: /* Get rid of the monster */
! 628: killed(item, FALSE, FALSE);
! 629: return;
! 630: }
! 631:
! 632: /* Display the goods */
! 633: msg("The %s shows you his wares.--More--", monsters[NUMMONST].m_name);
! 634: wait_for(cw,' ');
! 635: msg("");
! 636: clearok(cw, TRUE);
! 637: touchwin(cw);
! 638:
! 639: wclear(hw);
! 640: touchwin(hw);
! 641: for (i=0; i < nitems; i++) {
! 642: mvwaddch(hw, i+2, 0, '[');
! 643: waddch(hw, (char) ((int) 'a' + i));
! 644: waddstr(hw, "] ");
! 645: switch (goods) {
! 646: case ARMOR:
! 647: waddstr(hw, "Some ");
! 648: when WEAPON:
! 649: if (selection[i].count == 1)
! 650: waddstr(hw, " A ");
! 651: else {
! 652: sprintf(buffer, "%2d ", selection[i].count);
! 653: waddstr(hw, buffer);
! 654: }
! 655: when STICK:
! 656: wprintw(hw, "A %-5s of ", ws_type[selection[i].which]);
! 657: when RING:
! 658: waddstr(hw, "A ring of ");
! 659: when SCROLL:
! 660: waddstr(hw, "A scroll of ");
! 661: when POTION:
! 662: waddstr(hw, "A potion of ");
! 663: }
! 664: if (selection[i].count > 1)
! 665: sprintf(buffer, "%s%s ", selection[i].name, "s");
! 666: else
! 667: sprintf(buffer, "%s ", selection[i].name);
! 668: wprintw(hw, "%-24s", buffer);
! 669: wprintw(hw, " Price:%5d", selection[i].worth);
! 670: }
! 671: sprintf(buffer, "Purse: %d", purse);
! 672: mvwaddstr(hw, nitems+3, 0, buffer);
! 673: mvwaddstr(hw, 0, 0, "How about one of the following goods? ");
! 674: draw(hw);
! 675: /* Get rid of the monster */
! 676: killed(item, FALSE, FALSE);
! 677:
! 678: which_item = (int) (wgetch(hw) - 'a');
! 679: while (which_item < 0 || which_item >= nitems) {
! 680: if (which_item == (int) ESCAPE - (int) 'a') {
! 681: return;
! 682: }
! 683: mvwaddstr(hw, 0, 0, "Please enter one of the listed items. ");
! 684: draw(hw);
! 685: which_item = (int) (wgetch(hw) - 'a');
! 686: }
! 687:
! 688: if (selection[which_item].worth > purse) {
! 689: msg("You cannot afford it.");
! 690: return;
! 691: }
! 692:
! 693: purse -= selection[which_item].worth;
! 694:
! 695: item = spec_item(goods, selection[which_item].which,
! 696: selection[which_item].plus1, selection[which_item].plus2);
! 697:
! 698: obj = OBJPTR(item);
! 699: if (selection[which_item].count > 1) {
! 700: obj->o_count = selection[which_item].count;
! 701: obj->o_group = newgrp();
! 702: }
! 703: /* If a stick or ring, let player know the type */
! 704: switch (goods) {
! 705: case RING: r_know[selection[which_item].which] = TRUE;
! 706: when POTION:p_know[selection[which_item].which] = TRUE;
! 707: when SCROLL:s_know[selection[which_item].which] = TRUE;
! 708: when STICK: ws_know[selection[which_item].which] = TRUE;
! 709: when MM: m_know[selection[which_item].which] = TRUE;
! 710:
! 711: }
! 712:
! 713: if (add_pack(item, FALSE, NULL) == FALSE) {
! 714:
! 715: obj->o_pos = hero;
! 716: fall(item, TRUE);
! 717: }
! 718: }
! 719:
! 720:
! 721:
! 722: /*
! 723: * what to do when the hero steps next to a monster
! 724: */
! 725: struct linked_list *
! 726: wake_monster(int y, int x)
! 727: {
! 728: register struct thing *tp;
! 729: register struct linked_list *it;
! 730: register struct room *trp;
! 731: register const char *mname;
! 732: bool nasty; /* Will the monster "attack"? */
! 733: char ch;
! 734:
! 735: if ((it = find_mons(y, x)) == NULL) {
! 736: msg("Can't find monster in show");
! 737: return (NULL);
! 738: }
! 739: tp = THINGPTR(it);
! 740: ch = tp->t_type;
! 741:
! 742: trp = roomin(&tp->t_pos); /* Current room for monster */
! 743: mname = monsters[tp->t_index].m_name;
! 744:
! 745: /*
! 746: * Let greedy ones in a room guard gold
! 747: * (except in a maze where lots of creatures would all go for the
! 748: * same piece of gold)
! 749: */
! 750: if (on(*tp, ISGREED) && off(*tp, ISRUN) &&
! 751: levtype != MAZELEV && trp != NULL &&
! 752: lvl_obj != NULL) {
! 753: register struct linked_list *item;
! 754: register struct object *cur;
! 755:
! 756: for (item = lvl_obj; item != NULL; item = next(item)) {
! 757: cur = OBJPTR(item);
! 758: if ((cur->o_type == GOLD) &&
! 759: (roomin(&cur->o_pos) == trp)) {
! 760: /* Run to the gold */
! 761: tp->t_dest = &cur->o_pos;
! 762: turn_on(*tp, ISRUN);
! 763: turn_off(*tp, ISDISGUISE);
! 764:
! 765: /* Make it worth protecting */
! 766: cur->o_count += GOLDCALC + GOLDCALC;
! 767: break;
! 768: }
! 769: }
! 770: }
! 771:
! 772: /*
! 773: * Every time he sees mean monster, it might start chasing him
! 774: */
! 775: if (on(*tp, ISMEAN) &&
! 776: off(*tp, ISHELD) &&
! 777: off(*tp, ISRUN) &&
! 778: rnd(100) > 33 &&
! 779: (!is_stealth(&player) || (on(*tp, ISUNIQUE) && rnd(100) > 95)) &&
! 780: (off(player, ISINVIS) || on(*tp, CANSEE)) ||
! 781: (trp != NULL && (trp->r_flags & ISTREAS))) {
! 782: tp->t_dest = &hero;
! 783: turn_on(*tp, ISRUN);
! 784: turn_off(*tp, ISDISGUISE);
! 785: }
! 786:
! 787: /* See if the monster will bother the player */
! 788: nasty = (on(*tp, ISRUN) && cansee(tp->t_pos.y, tp->t_pos.x));
! 789:
! 790: /*
! 791: * Let the creature summon if it can.
! 792: * Also check to see if there is room around the player,
! 793: * if not then the creature will wait
! 794: */
! 795: if (on(*tp, CANSUMMON) && nasty &&
! 796: rnd(40) < tp->t_stats.s_lvl &&
! 797: fallpos(&hero, FALSE, 2) != NULL) {
! 798: const char *helpname;
! 799: int fail;
! 800: register int which, i;
! 801:
! 802: turn_off(*tp, CANSUMMON);
! 803: helpname = monsters[tp->t_index].m_typesum;
! 804: for (which=1; which<NUMMONST; which++) {
! 805: if (strcmp(helpname, monsters[which].m_name) == 0)
! 806: break;
! 807: }
! 808: if (which >= NUMMONST)
! 809: debug("couldn't find summoned one");
! 810: if ((off(*tp, ISINVIS) || on(player, CANSEE)) &&
! 811: (off(*tp, ISSHADOW) || on(player, CANSEE)) &&
! 812: (off(*tp, CANSURPRISE) || ISWEARING(R_ALERT))) {
! 813: if (monsters[which].m_normal == FALSE) { /* genocided? */
! 814: msg("The %s appears dismayed", mname);
! 815: monsters[tp->t_index].m_numsum = 0;
! 816: }
! 817: else {
! 818: sprintf(outstring,"The %s summons %ss for help", mname, helpname);
! 819: msg(outstring);
! 820: }
! 821: }
! 822: else {
! 823: if (monsters[which].m_normal == FALSE) /* genocided? */
! 824: monsters[tp->t_index].m_numsum = 0;
! 825: else
! 826: msg("%ss seem to appear from nowhere!", helpname);
! 827: }
! 828: /*
! 829: * try to make all the creatures around player but remember
! 830: * if unsuccessful
! 831: */
! 832: for (i=0, fail=0; i<monsters[tp->t_index].m_numsum; i++) {
! 833: if (!creat_mons(&player, which, FALSE))
! 834: fail++; /* remember the failures */
! 835: }
! 836: /*
! 837: * try once again to make the buggers
! 838: */
! 839: for (i=0; i<fail; i++)
! 840: creat_mons(tp, which, FALSE);
! 841:
! 842: /* Now let the poor fellow see all the trouble */
! 843: light(&hero);
! 844: }
! 845:
! 846: /*
! 847: * Handle monsters that can gaze and do things while running
! 848: * Player must be able to see the monster and the monster must
! 849: * not be asleep
! 850: */
! 851: if (nasty && !invisible(tp)) {
! 852: /*
! 853: * Confusion
! 854: */
! 855: if (on(*tp, CANHUH) &&
! 856: (off(*tp, ISINVIS) || on(player, CANSEE)) &&
! 857: (off(*tp, CANSURPRISE) || ISWEARING(R_ALERT))) {
! 858: if (!save(VS_MAGIC, &player, 0)) {
! 859: if (off(player, ISCLEAR)) {
! 860: if (find_slot(unconfuse))
! 861: lengthen(unconfuse, rnd(20)+HUHDURATION);
! 862: else {
! 863: fuse(unconfuse, 0, rnd(20)+HUHDURATION, AFTER);
! 864: msg("The %s's gaze has confused you.",mname);
! 865: turn_on(player, ISHUH);
! 866: }
! 867: }
! 868: else msg("You feel dizzy for a moment, but it quickly passes.");
! 869: }
! 870: else if (rnd(100) < 67)
! 871: turn_off(*tp, CANHUH); /* Once you save, maybe that's it */
! 872: }
! 873:
! 874: /* Sleep */
! 875: if(on(*tp, CANSNORE) &&
! 876: no_command == 0 &&
! 877: !save(VS_PARALYZATION, &player, 0)) {
! 878: if (ISWEARING(R_ALERT))
! 879: msg("You feel slightly drowsy for a moment.");
! 880: else {
! 881: msg("The %s's gaze puts you to sleep.", mname);
! 882: no_command += SLEEPTIME;
! 883: if (rnd(100) < 50) turn_off(*tp, CANSNORE);
! 884: }
! 885: }
! 886:
! 887: /* Fear */
! 888: if (on(*tp, CANFRIGHTEN)) {
! 889: turn_off(*tp, CANFRIGHTEN);
! 890: if (!ISWEARING(R_HEROISM) &&
! 891: !save(VS_WAND, &player, 0) &&
! 892: !(on(player, ISFLEE) && (player.t_dest == &tp->t_pos))) {
! 893: turn_on(player, ISFLEE);
! 894: player.t_dest = &tp->t_pos;
! 895: msg("The sight of the %s terrifies you.", mname);
! 896: }
! 897: }
! 898:
! 899: /* blinding creatures */
! 900: if(on(*tp, CANBLIND) &&
! 901: !find_slot(sight) &&
! 902: !save(VS_WAND,&player, 0)){
! 903: msg("The gaze of the %s blinds you", mname);
! 904: turn_on(player, ISBLIND);
! 905: fuse(sight, 0, rnd(30)+20, AFTER);
! 906: light(&hero);
! 907: }
! 908:
! 909: /* the sight of the ghost can age you! */
! 910: if (on(*tp, CANAGE)) {
! 911: turn_off (*tp, CANAGE);
! 912: if (!save(VS_MAGIC, &player, 0)) {
! 913: msg ("The sight of the %s ages you!", mname);
! 914: pstats.s_const--;
! 915: max_stats.s_const--;
! 916: if (pstats.s_const < 0)
! 917: death (D_CONSTITUTION);
! 918: }
! 919: }
! 920:
! 921:
! 922: /* Turning to stone */
! 923: if (on(*tp, LOOKSTONE)) {
! 924: turn_off(*tp, LOOKSTONE);
! 925:
! 926: if (on(player, CANINWALL))
! 927: msg("The gaze of the %s has no effect.", mname);
! 928: else {
! 929: if (!save(VS_PETRIFICATION, &player, 0) && rnd(100) < 15) {
! 930: pstats.s_hpt = -1;
! 931: msg("The gaze of the %s petrifies you.", mname);
! 932: msg("You are turned to stone !!! --More--");
! 933: wait_for(cw,' ');
! 934: death(D_PETRIFY);
! 935: }
! 936: else {
! 937: msg("The gaze of the %s stiffens your limbs.", mname);
! 938: no_command += STONETIME;
! 939: }
! 940: }
! 941: }
! 942: }
! 943:
! 944: return it;
! 945: }
! 946: /*
! 947: * wanderer:
! 948: * A wandering monster has awakened and is headed for the player
! 949: */
! 950:
! 951: void
! 952: wanderer(void)
! 953: {
! 954: register int i;
! 955: register struct room *hr = roomin(&hero);
! 956: register struct linked_list *item;
! 957: register struct thing *tp;
! 958: register const long *attr; /* Points to monsters' attributes */
! 959: int carry; /* Chance of wanderer carrying anything */
! 960: short rmonst; /* Our random wanderer */
! 961: bool canteleport = FALSE, /* Can the monster teleport? */
! 962: seehim; /* Is monster within sight? */
! 963: coord cp;
! 964:
! 965: rmonst = randmonster(TRUE, FALSE); /* Choose a random wanderer */
! 966: attr = &monsters[rmonst].m_flags[0]; /* Start of attributes */
! 967: for (i=0; i<MAXFLAGS; i++)
! 968: if (*attr++ == CANTELEPORT) {
! 969: canteleport = TRUE;
! 970: break;
! 971: }
! 972:
! 973: /* Find a place for it -- avoid the player's room if can't teleport */
! 974: do {
! 975: do {
! 976: i = rnd_room();
! 977: } until (canteleport || hr != &rooms[i] || levtype == MAZELEV ||
! 978: levtype == OUTSIDE || levtype == POSTLEV);
! 979:
! 980: /* Make sure the monster does not teleport on top of the player */
! 981: do {
! 982: rnd_pos(&rooms[i], &cp);
! 983: } while (hr == &rooms[i] && ce(cp, hero));
! 984: } until (step_ok(cp.y, cp.x, NOMONST, NULL));
! 985:
! 986: /* Create a new wandering monster */
! 987: item = new_item(sizeof *tp);
! 988: new_monster(item, rmonst, &cp, FALSE);
! 989: tp = THINGPTR(item);
! 990: turn_on(*tp, ISRUN);
! 991: turn_off(*tp, ISDISGUISE);
! 992: tp->t_dest = &hero;
! 993: tp->t_pos = cp; /* Assign the position to the monster */
! 994: seehim = cansee(tp->t_pos.y, tp->t_pos.x);
! 995: if (on(*tp, HASFIRE)) {
! 996: register struct room *rp;
! 997:
! 998: rp = roomin(&tp->t_pos);
! 999: if (rp) {
! 1000: register struct linked_list *fire_item;
! 1001:
! 1002: fire_item = creat_item();
! 1003: ldata(fire_item) = (char *) tp;
! 1004: attach(rp->r_fires, fire_item);
! 1005:
! 1006: rp->r_flags |= HASFIRE;
! 1007: if (seehim && next(rp->r_fires) == NULL)
! 1008: light(&hero);
! 1009: }
! 1010: }
! 1011:
! 1012: /* See if we give the monster anything */
! 1013: carry = monsters[tp->t_index].m_carry;
! 1014: if (off(*tp, ISUNIQUE)) carry /= 2; /* Non-unique has only a half chance */
! 1015: carry_obj(tp, carry);
! 1016:
! 1017: /* Alert the player if a monster just teleported in */
! 1018: if (hr == &rooms[i] && canteleport && seehim && !invisible(tp)) {
! 1019: msg("A %s just teleported in", monsters[rmonst].m_name);
! 1020: light(&hero);
! 1021: running = FALSE;
! 1022: }
! 1023:
! 1024: if (wizard)
! 1025: msg("Started a wandering %s", monsters[tp->t_index].m_name);
! 1026: }
CVSweb