Annotation of early-roguelike/arogue7/monsters.c, Revision 1.1
1.1 ! rubenllo 1: /*
! 2: * monsters.c - File with various monster functions in it
! 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: /*
! 16: * File with various monster functions in it
! 17: *
! 18: */
! 19:
! 20: #include "curses.h"
! 21: #include "rogue.h"
! 22: #include <ctype.h>
! 23: #include <string.h>
! 24: #include <stdlib.h>
! 25:
! 26:
! 27: /*
! 28: * Check_residue takes care of any effect of the monster
! 29: */
! 30: void
! 31: check_residue(struct thing *tp)
! 32: {
! 33: /*
! 34: * Take care of special abilities
! 35: */
! 36: if (on(*tp, DIDHOLD) && (--hold_count == 0)) {
! 37: turn_off(player, ISHELD);
! 38: turn_off(*tp, DIDHOLD);
! 39: }
! 40:
! 41: /* If frightened of this monster, stop */
! 42: if (on(player, ISFLEE) &&
! 43: player.t_dest == &tp->t_pos) turn_off(player, ISFLEE);
! 44:
! 45: /* If monster was suffocating player, stop it */
! 46: if (on(*tp, DIDSUFFOCATE)) {
! 47: extinguish(suffocate);
! 48: turn_off(*tp, DIDSUFFOCATE);
! 49: }
! 50:
! 51: /* If something with fire, may darken */
! 52: if (on(*tp, HASFIRE)) {
! 53: register struct room *rp=roomin(&tp->t_pos);
! 54: register struct linked_list *fire_item;
! 55:
! 56: if (rp) {
! 57: for (fire_item = rp->r_fires; fire_item != NULL;
! 58: fire_item = next(fire_item)) {
! 59: if (THINGPTR(fire_item) == tp) {
! 60: detach(rp->r_fires, fire_item);
! 61: destroy_item(fire_item);
! 62: if (rp->r_fires == NULL) {
! 63: rp->r_flags &= ~HASFIRE;
! 64: if (cansee(tp->t_pos.y, tp->t_pos.x)) light(&hero);
! 65: }
! 66: break;
! 67: }
! 68: }
! 69: }
! 70: }
! 71: }
! 72:
! 73: /*
! 74: * Creat_mons creates the specified monster -- any if 0
! 75: * person: Where to create next to
! 76: */
! 77:
! 78: bool
! 79: creat_mons(struct thing *person, short monster, bool report)
! 80: {
! 81: struct linked_list *nitem;
! 82: register struct thing *tp;
! 83: struct room *rp;
! 84: coord *mp;
! 85:
! 86: if (levtype == POSTLEV)
! 87: return(FALSE);
! 88: if ((mp = fallpos(&(person->t_pos), FALSE, 2)) != NULL) {
! 89: nitem = new_item(sizeof (struct thing));
! 90: new_monster(nitem,
! 91: monster == 0 ? randmonster(FALSE, FALSE)
! 92: : monster,
! 93: mp,
! 94: TRUE);
! 95: tp = THINGPTR(nitem);
! 96: runto(tp, &hero);
! 97: carry_obj(tp, monsters[tp->t_index].m_carry/2); /* only half chance */
! 98:
! 99: /* since it just got here, it is disoriented */
! 100: tp->t_no_move = 2 * movement(tp);
! 101:
! 102: if (on(*tp, HASFIRE)) {
! 103: rp = roomin(&tp->t_pos);
! 104: if (rp) {
! 105: register struct linked_list *fire_item;
! 106:
! 107: /* Put the new fellow in the room list */
! 108: fire_item = creat_item();
! 109: ldata(fire_item) = (char *) tp;
! 110: attach(rp->r_fires, fire_item);
! 111:
! 112: rp->r_flags |= HASFIRE;
! 113: }
! 114: }
! 115:
! 116: /*
! 117: * If we can see this monster, set oldch to ' ' to make light()
! 118: * think the creature used to be invisible (ie. not seen here)
! 119: */
! 120: if (cansee(tp->t_pos.y, tp->t_pos.x)) tp->t_oldch = ' ';
! 121: return(TRUE);
! 122: }
! 123: if (report) msg("You hear a faint cry of anguish in the distance.");
! 124: return(FALSE);
! 125: }
! 126:
! 127: /*
! 128: * Genmonsters:
! 129: * Generate at least 'least' monsters for this single room level.
! 130: * 'Treas' indicates whether this is a "treasure" level.
! 131: */
! 132:
! 133: void
! 134: genmonsters(int least, bool treas)
! 135: {
! 136: reg int i;
! 137: reg struct room *rp = &rooms[0];
! 138: reg struct linked_list *item;
! 139: reg struct thing *mp;
! 140: coord tp;
! 141:
! 142: for (i = 0; i < level + least; i++) {
! 143: if (!treas && rnd(100) < 50) /* put in some little buggers */
! 144: continue;
! 145: /*
! 146: * Put the monster in
! 147: */
! 148: item = new_item(sizeof *mp);
! 149: mp = THINGPTR(item);
! 150: do {
! 151: rnd_pos(rp, &tp);
! 152: } until(mvwinch(stdscr, tp.y, tp.x) == FLOOR);
! 153:
! 154: new_monster(item, randmonster(FALSE, FALSE), &tp, FALSE);
! 155: /*
! 156: * See if we want to give it a treasure to carry around.
! 157: */
! 158: carry_obj(mp, monsters[mp->t_index].m_carry);
! 159:
! 160: /* Calculate a movement rate */
! 161: mp->t_no_move = movement(mp);
! 162:
! 163: /* Is it going to give us some light? */
! 164: if (on(*mp, HASFIRE)) {
! 165: register struct linked_list *fire_item;
! 166:
! 167: fire_item = creat_item();
! 168: ldata(fire_item) = (char *) mp;
! 169: attach(rp->r_fires, fire_item);
! 170: rp->r_flags |= HASFIRE;
! 171: }
! 172: }
! 173: }
! 174:
! 175: /*
! 176: * id_monst returns the index of the monster given its letter
! 177: */
! 178:
! 179: short
! 180: id_monst(char monster)
! 181: {
! 182: register short result;
! 183:
! 184: result = NLEVMONS*vlevel;
! 185: if (result > NUMMONST) result = NUMMONST;
! 186:
! 187: for(; result>0; result--)
! 188: if (monsters[result].m_appear == monster) return(result);
! 189: for (result=(NLEVMONS*vlevel)+1; result <= NUMMONST; result++)
! 190: if (monsters[result].m_appear == monster) return(result);
! 191: return(0);
! 192: }
! 193:
! 194:
! 195: /*
! 196: * new_monster:
! 197: * Pick a new monster and add it to the list
! 198: */
! 199:
! 200: void
! 201: new_monster(struct linked_list *item, short type, coord *cp, bool max_monster)
! 202: {
! 203: register struct thing *tp;
! 204: register struct monster *mp;
! 205: register char *ip, *hitp;
! 206: register int i, min_intel, max_intel;
! 207: register int num_dice, num_sides=8, num_extra=0;
! 208:
! 209: attach(mlist, item);
! 210: tp = THINGPTR(item);
! 211: tp->t_pack = NULL;
! 212: tp->t_index = type;
! 213: tp->t_wasshot = FALSE;
! 214: tp->t_type = monsters[type].m_appear;
! 215: tp->t_ctype = C_MONSTER;
! 216: tp->t_action = A_NIL;
! 217: tp->t_doorgoal = 0;
! 218: tp->t_quiet = 0;
! 219: tp->t_dest = NULL;
! 220: tp->t_name = NULL;
! 221: tp->t_pos = tp->t_oldpos = *cp;
! 222: tp->t_oldch = CCHAR( mvwinch(cw, cp->y, cp->x) );
! 223: mvwaddch(mw, cp->y, cp->x, tp->t_type);
! 224: mp = &monsters[tp->t_index];
! 225:
! 226: /* Figure out monster's hit points */
! 227: hitp = mp->m_stats.s_hpt;
! 228: num_dice = atoi(hitp);
! 229: if ((hitp = strchr(hitp, 'd')) != NULL) {
! 230: num_sides = atoi(++hitp);
! 231: if ((hitp = strchr(hitp, '+')) != NULL)
! 232: num_extra = atoi(++hitp);
! 233: }
! 234:
! 235: tp->t_stats.s_lvladj = 0;
! 236: tp->t_stats.s_lvl = mp->m_stats.s_lvl;
! 237: tp->t_stats.s_arm = mp->m_stats.s_arm;
! 238: strncpy(tp->t_stats.s_dmg, mp->m_stats.s_dmg, sizeof(tp->t_stats.s_dmg));
! 239: tp->t_stats.s_str = mp->m_stats.s_str;
! 240: tp->t_stats.s_dext = mp->m_stats.s_dex;
! 241: tp->t_movement = mp->m_stats.s_move;
! 242: if (vlevel > HARDER) { /* the deeper, the meaner we get */
! 243: tp->t_stats.s_lvl += (vlevel - HARDER);
! 244: num_dice += (vlevel - HARDER)/2;
! 245: tp->t_stats.s_arm -= (vlevel - HARDER) / 4;
! 246: }
! 247: if (max_monster)
! 248: tp->t_stats.s_hpt = num_dice * num_sides + num_extra;
! 249: else
! 250: tp->t_stats.s_hpt = roll(num_dice, num_sides) + num_extra;
! 251: tp->t_stats.s_exp = mp->m_stats.s_exp + mp->m_add_exp*tp->t_stats.s_hpt;
! 252:
! 253: /*
! 254: * just initailize others values to something reasonable for now
! 255: * maybe someday will *really* put these in monster table
! 256: */
! 257: tp->t_stats.s_wisdom = 8 + rnd(4);
! 258: tp->t_stats.s_const = 8 + rnd(4);
! 259: tp->t_stats.s_charisma = 8 + rnd(4);
! 260:
! 261: /* Set the initial flags */
! 262: for (i=0; i<16; i++) tp->t_flags[i] = 0;
! 263: for (i=0; i<MAXFLAGS; i++)
! 264: turn_on(*tp, mp->m_flags[i]);
! 265:
! 266: /*
! 267: * these are the base chances that a creatures will do something
! 268: * assuming it can. These are(or can be) modified at runtime
! 269: * based on what the creature experiences
! 270: */
! 271: tp->t_breathe = 75; /* base chance of breathing */
! 272: tp->t_artifact = 90; /* base chance of using artifact */
! 273: tp->t_summon = 40; /* base chance of summoning */
! 274: tp->t_cast = 75; /* base chance of casting a spell */
! 275: tp->t_wand = on(*tp, ISUNIQUE) ? 35 : 50; /* base chance of using wands */
! 276:
! 277: /* suprising monsters don't always surprise you */
! 278: if (!max_monster && on(*tp, CANSURPRISE) &&
! 279: off(*tp, ISUNIQUE) && rnd(100) < 20)
! 280: turn_off(*tp, CANSURPRISE);
! 281:
! 282: /* If this monster is unique, gen it */
! 283: if (on(*tp, ISUNIQUE)) mp->m_normal = FALSE;
! 284:
! 285: /*
! 286: * If it is the quartermaster, then compute his level and exp pts
! 287: * based on the level. This will make it fair when thieves try to
! 288: * steal and give them reasonable experience if they succeed.
! 289: * Then fill his pack with his wares.
! 290: */
! 291: if (on(*tp, CANSELL)) {
! 292: tp->t_stats.s_exp = vlevel * 100;
! 293: tp->t_stats.s_lvl = vlevel/2 + 1;
! 294: make_sell_pack(tp);
! 295: }
! 296:
! 297: /* Normally scared monsters have a chance to not be scared */
! 298: if (on(*tp, ISFLEE) && (rnd(4) == 0)) turn_off(*tp, ISFLEE);
! 299:
! 300: /* Figure intelligence */
! 301: min_intel = atoi(mp->m_intel);
! 302: if ((ip = (char *) strchr(mp->m_intel, '-')) == NULL)
! 303: tp->t_stats.s_intel = min_intel;
! 304: else {
! 305: max_intel = atoi(++ip);
! 306: if (max_monster)
! 307: tp->t_stats.s_intel = max_intel;
! 308: else
! 309: tp->t_stats.s_intel = min_intel + rnd(max_intel - min_intel);
! 310: }
! 311: if (vlevel > HARDER)
! 312: tp->t_stats.s_intel += ((vlevel - HARDER)/2);
! 313: tp->maxstats = tp->t_stats;
! 314:
! 315: /* If the monster can shoot, it may have a weapon */
! 316: if (on(*tp, CANSHOOT) && ((rnd(100) < (22 + vlevel)) || max_monster)) {
! 317: struct linked_list *item1;
! 318: register struct object *cur, *cur1;
! 319:
! 320: item = new_item(sizeof *cur);
! 321: item1 = new_item(sizeof *cur1);
! 322: cur = OBJPTR(item);
! 323: cur1 = OBJPTR(item1);
! 324: cur->o_hplus = (rnd(4) < 3) ? 0
! 325: : (rnd(3) + 1) * ((rnd(3) < 2) ? 1 : -1);
! 326: cur->o_dplus = (rnd(4) < 3) ? 0
! 327: : (rnd(3) + 1) * ((rnd(3) < 2) ? 1 : -1);
! 328: cur1->o_hplus = (rnd(4) < 3) ? 0
! 329: : (rnd(3) + 1) * ((rnd(3) < 2) ? 1 : -1);
! 330: cur1->o_dplus = (rnd(4) < 3) ? 0
! 331: : (rnd(3) + 1) * ((rnd(3) < 2) ? 1 : -1);
! 332:
! 333: strncpy(cur->o_damage, "0d0", sizeof(cur->o_damage));
! 334: strncpy(cur->o_hurldmg, "0d0", sizeof(cur->o_hurldmg));
! 335: strncpy(cur1->o_damage, "0d0", sizeof(cur1->o_damage));
! 336: strncpy(cur1->o_hurldmg, "0d0", sizeof(cur1->o_hurldmg));
! 337:
! 338: cur->o_ac = cur1->o_ac = 11;
! 339: cur->o_count = cur1->o_count = 1;
! 340: cur->o_group = cur1->o_group = 0;
! 341: cur->contents = cur1->contents = NULL;
! 342: if ((cur->o_hplus <= 0) && (cur->o_dplus <= 0)) cur->o_flags = ISCURSED;
! 343: if ((cur1->o_hplus <= 0) && (cur1->o_dplus <= 0))
! 344: cur1->o_flags = ISCURSED;
! 345: cur->o_flags = cur1->o_flags = 0;
! 346: cur->o_type = cur1->o_type = WEAPON;
! 347: cur->o_mark[0] = cur1->o_mark[0] = '\0';
! 348:
! 349: /* The monster may use a crossbow, sling, or an arrow */
! 350: i = rnd(100);
! 351: if (i < 10) {
! 352: cur->o_which = CROSSBOW;
! 353: cur1->o_which = BOLT;
! 354: init_weapon(cur, CROSSBOW);
! 355: init_weapon(cur1, BOLT);
! 356: }
! 357: else if (i < 70) {
! 358: cur->o_which = BOW;
! 359: cur1->o_which = ARROW;
! 360: init_weapon(cur, BOW);
! 361: init_weapon(cur1, ARROW);
! 362: }
! 363: else {
! 364: cur->o_which = SLING;
! 365: cur1->o_which = ROCK;
! 366: init_weapon(cur, SLING);
! 367: init_weapon(cur1, ROCK);
! 368: }
! 369:
! 370: attach(tp->t_pack, item);
! 371: attach(tp->t_pack, item1);
! 372: }
! 373:
! 374:
! 375: /* Calculate the initial movement rate */
! 376: updpack(TRUE, tp);
! 377: tp->t_no_move = movement(tp);
! 378:
! 379: if (ISWEARING(R_AGGR))
! 380: runto(tp, &hero);
! 381: if (on(*tp, ISDISGUISE))
! 382: {
! 383: char mch;
! 384:
! 385: if (tp->t_pack != NULL)
! 386: mch = (OBJPTR(tp->t_pack))->o_type;
! 387: else
! 388: switch (rnd(10)) {
! 389: case 0: mch = GOLD;
! 390: when 1: mch = POTION;
! 391: when 2: mch = SCROLL;
! 392: when 3: mch = FOOD;
! 393: when 4: mch = WEAPON;
! 394: when 5: mch = ARMOR;
! 395: when 6: mch = RING;
! 396: when 7: mch = STICK;
! 397: when 8: mch = monsters[randmonster(FALSE, FALSE)].m_appear;
! 398: when 9: mch = MM;
! 399: }
! 400: tp->t_disguise = mch;
! 401: }
! 402: }
! 403:
! 404: /*
! 405: * randmonster:
! 406: * Pick a monster to show up. The lower the level,
! 407: * the meaner the monster.
! 408: */
! 409:
! 410: short
! 411: randmonster(bool wander, bool no_unique)
! 412: {
! 413: register int d, cur_level, range, i;
! 414:
! 415: /*
! 416: * Do we want a merchant? Merchant is always in place 'NUMMONST'
! 417: */
! 418: if (wander && monsters[NUMMONST].m_wander && rnd(100) < pstats.s_charisma/4)
! 419: return NUMMONST;
! 420:
! 421: cur_level = vlevel;
! 422: range = 4*NLEVMONS;
! 423: i = 0;
! 424: do
! 425: {
! 426: if (i++ > range*10) { /* just in case all have be genocided */
! 427: i = 0;
! 428: if (--cur_level <= 0)
! 429: fatal("Rogue could not find a monster to make");
! 430: }
! 431: d = NLEVMONS*(cur_level - 1) + (rnd(range) - (range - 1 - NLEVMONS));
! 432: if (d < 1)
! 433: d = rnd(NLEVMONS) + 1;
! 434: if (d > NUMMONST - NUMUNIQUE - 1) {
! 435: if (no_unique)
! 436: d = rnd(range) + (NUMMONST - NUMUNIQUE - 1) - (range - 1);
! 437: else if (d > NUMMONST - 1)
! 438: d = rnd(range+NUMUNIQUE) + (NUMMONST-1) - (range+NUMUNIQUE-1);
! 439: }
! 440: }
! 441: while (wander ? !monsters[d].m_wander || !monsters[d].m_normal
! 442: : !monsters[d].m_normal);
! 443: return d;
! 444: }
! 445:
! 446: /* Sell displays a menu of goods from which the player may choose
! 447: * to purchase something.
! 448: */
! 449:
! 450: void
! 451: sell(struct thing *tp)
! 452: {
! 453: register struct linked_list *item, *seller;
! 454: register struct linked_list *sellpack;
! 455: register struct object *obj;
! 456: register int worth, min_worth;
! 457: char buffer[LINELEN];
! 458:
! 459:
! 460: /*
! 461: * Get a linked_list pointer to the seller. We need this in case
! 462: * he disappears so we can set monst_dead.
! 463: */
! 464: seller = find_mons(tp->t_pos.y, tp->t_pos.x);
! 465:
! 466: sellpack = tp->t_pack;
! 467: if (sellpack == NULL) {
! 468: msg("%s looks puzzled and departs.", prname(monster_name(tp), TRUE));
! 469:
! 470: /* Get rid of the monster */
! 471: killed(seller, FALSE, FALSE, FALSE);
! 472: return;
! 473: }
! 474:
! 475: /* See how much the minimum pack item is worth */
! 476: min_worth = 100000;
! 477: for (item = sellpack; item != NULL; item = next(item)) {
! 478: obj = OBJPTR(item);
! 479: obj->o_flags |= ISPOST; /* Force a long description of the item */
! 480: worth = get_worth(obj);
! 481: if (worth < min_worth) min_worth = worth;
! 482: }
! 483:
! 484: /* See if player can afford an item */
! 485: if (min_worth > purse) {
! 486: msg("%s eyes your small purse and departs.",
! 487: prname(monster_name(tp), TRUE));
! 488:
! 489: /* Get rid of the monster */
! 490: killed(seller, FALSE, FALSE, FALSE);
! 491: return;
! 492: }
! 493:
! 494: /* Announce our intentions */
! 495: msg("%s opens his pack.--More--", prname(monster_name(tp), TRUE));
! 496: wait_for(' ');
! 497:
! 498: /* Try to sell something */
! 499: sprintf(buffer, "You got %d gold pieces. Buy", purse);
! 500: item = get_item(sellpack, buffer, ALL, TRUE, TRUE);
! 501:
! 502: /* Get rid of the monster */
! 503: if (item != NULL) detach(tp->t_pack, item); /* Take it out of the pack */
! 504: killed(seller, FALSE, FALSE, FALSE);
! 505:
! 506: if (item == NULL) return;
! 507:
! 508: /* Can he afford the selected item? */
! 509: obj = OBJPTR(item);
! 510:
! 511: worth = get_worth(obj);
! 512: if (worth > purse) {
! 513: msg("You cannot afford it.");
! 514: o_discard(item);
! 515: return;
! 516: }
! 517:
! 518: /* Charge him through the nose */
! 519: purse -= worth;
! 520:
! 521: /* If a stick or ring, let player know the type */
! 522: switch (obj->o_type) {
! 523: case RING: r_know[obj->o_which] = TRUE;
! 524: when POTION:p_know[obj->o_which] = TRUE;
! 525: when SCROLL:s_know[obj->o_which] = TRUE;
! 526: when STICK: ws_know[obj->o_which] = TRUE;
! 527: when MM: m_know[obj->o_which] = TRUE;
! 528:
! 529: }
! 530:
! 531: /* Remove the POST flag that we used for get_item() */
! 532: obj->o_flags &= ~ISPOST;
! 533:
! 534: if (add_pack(item, FALSE, NULL) == FALSE) {
! 535: obj->o_pos = hero;
! 536: fall(item, TRUE);
! 537: }
! 538: }
! 539:
! 540:
! 541:
! 542: /*
! 543: * what to do when the hero steps next to a monster
! 544: */
! 545: struct linked_list *
! 546: wake_monster(int y, int x)
! 547: {
! 548: register struct thing *tp;
! 549: register struct linked_list *it;
! 550: register struct room *trp;
! 551: register char *mname;
! 552: bool nasty; /* Will the monster "attack"? */
! 553:
! 554: if ((it = find_mons(y, x)) == NULL) {
! 555: msg("Wake: can't find monster in show (%d, %d)", y, x);
! 556: return (NULL);
! 557: }
! 558: tp = THINGPTR(it);
! 559: if (on(*tp, ISSTONE)) /* if stoned, don't do anything */
! 560: return it;
! 561:
! 562: /*
! 563: * For now, if we are a friendly monster, we won't do any of
! 564: * our special effects.
! 565: */
! 566: if (on(*tp, ISFRIENDLY)) return it;
! 567:
! 568: trp = roomin(&tp->t_pos); /* Current room for monster */
! 569:
! 570: /*
! 571: * Let greedy ones in a room guard gold
! 572: * (except in a maze where lots of creatures would all go for the
! 573: * same piece of gold)
! 574: */
! 575: if (on(*tp, ISGREED) && off(*tp, ISRUN) &&
! 576: levtype != MAZELEV && trp != NULL &&
! 577: lvl_obj != NULL) {
! 578: register struct linked_list *item;
! 579: register struct object *cur;
! 580:
! 581: for (item = lvl_obj; item != NULL; item = next(item)) {
! 582: cur = OBJPTR(item);
! 583: if ((cur->o_type == GOLD) && (roomin(&cur->o_pos) == trp)) {
! 584: /* Run to the gold */
! 585: runto(tp, &cur->o_pos);
! 586:
! 587: /* Make it worth protecting */
! 588: cur->o_count += GOLDCALC + GOLDCALC;
! 589: break;
! 590: }
! 591: }
! 592: }
! 593:
! 594: /*
! 595: * Every time he sees mean monster, it might start chasing him
! 596: */
! 597: if (on(*tp, ISMEAN) &&
! 598: off(*tp, ISHELD) &&
! 599: off(*tp, ISRUN) &&
! 600: rnd(100) > 33 &&
! 601: (!is_stealth(&player) || (on(*tp, ISUNIQUE) && rnd(100) > 50)) &&
! 602: (off(player, ISINVIS) || on(*tp, CANSEE)) ||
! 603: (trp != NULL && (trp->r_flags & ISTREAS))) {
! 604: runto(tp, &hero);
! 605: }
! 606:
! 607: /*
! 608: * Get the name; we don't want to do it until here because we need to
! 609: * know whether the monster is still sleeping or not.
! 610: */
! 611: mname = monster_name(tp);
! 612:
! 613: /* See if the monster will bother the player */
! 614: nasty = (on(*tp, ISRUN) && cansee(tp->t_pos.y, tp->t_pos.x));
! 615:
! 616: /*
! 617: * if the creature is awake and can see the player and the
! 618: * player has the dreaded "eye of vecna" then see if the
! 619: * creature is turned to stone
! 620: */
! 621: if (cur_relic[EYE_VECNA] && nasty && off(*tp, NOSTONE) &&
! 622: (off(player, ISINVIS) || on(*tp, CANSEE))) {
! 623: turn_on(*tp, NOSTONE); /* only have to save once */
! 624: if (!save(VS_PETRIFICATION, tp, -2)) {
! 625: turn_on(*tp, ISSTONE);
! 626: turn_off(*tp, ISRUN);
! 627: turn_off(*tp, ISINVIS);
! 628: turn_off(*tp, CANSURPRISE);
! 629: turn_off(*tp, ISDISGUISE);
! 630: msg("%s is turned to stone!", prname(mname, TRUE));
! 631: return it;
! 632: }
! 633: }
! 634:
! 635: /*
! 636: * Handle monsters that can gaze and do things while running
! 637: * Player must be able to see the monster and the monster must
! 638: * not be asleep
! 639: */
! 640: if (nasty && !invisible(tp)) {
! 641: /*
! 642: * Confusion
! 643: */
! 644: if (on(*tp, CANHUH) &&
! 645: (off(*tp, ISINVIS) || on(player, CANSEE)) &&
! 646: (off(*tp, CANSURPRISE) || ISWEARING(R_ALERT))) {
! 647: if (!save(VS_MAGIC, &player, 0)) {
! 648: if (off(player, ISCLEAR)) {
! 649: if (find_slot(unconfuse))
! 650: lengthen(unconfuse, HUHDURATION);
! 651: else {
! 652: fuse(unconfuse, NULL, HUHDURATION, AFTER);
! 653: msg("%s's gaze has confused you.",prname(mname, TRUE));
! 654: turn_on(player, ISHUH);
! 655: }
! 656: }
! 657: else msg("You feel dizzy for a moment, but it quickly passes.");
! 658: }
! 659: else if (rnd(100) < 67)
! 660: turn_off(*tp, CANHUH); /* Once you save, maybe that's it */
! 661: }
! 662:
! 663: /* Sleep */
! 664: if(on(*tp, CANSNORE) &&
! 665: player.t_action != A_FREEZE &&
! 666: !save(VS_PARALYZATION, &player, 0)) {
! 667: if (ISWEARING(R_ALERT))
! 668: msg("You feel slightly drowsy for a moment.");
! 669: else {
! 670: msg("%s's gaze puts you to sleep.", prname(mname, TRUE));
! 671: player.t_no_move += movement(&player) * SLEEPTIME;
! 672: player.t_action = A_FREEZE;
! 673: if (rnd(100) < 50) turn_off(*tp, CANSNORE);
! 674: }
! 675: }
! 676:
! 677: /* Fear */
! 678: if (on(*tp, CANFRIGHTEN) && !on(player, ISFLEE)) {
! 679: turn_off(*tp, CANFRIGHTEN);
! 680: if (!ISWEARING(R_HEROISM) &&
! 681: !save(VS_WAND, &player, -(tp->t_stats.s_lvl/10))) {
! 682: turn_on(player, ISFLEE);
! 683: player.t_dest = &tp->t_pos;
! 684: msg("The sight of %s terrifies you.", prname(mname, FALSE));
! 685: }
! 686: }
! 687:
! 688: /* blinding creatures */
! 689: if(on(*tp, CANBLIND) && !find_slot(sight)) {
! 690: turn_off(*tp, CANBLIND);
! 691: if (!save(VS_WAND, &player, 0)) {
! 692: msg("The gaze of %s blinds you", prname(mname, FALSE));
! 693: turn_on(player, ISBLIND);
! 694: fuse(sight, NULL, rnd(30)+20, AFTER);
! 695: light(&hero);
! 696: }
! 697: }
! 698:
! 699: /* the sight of the ghost can age you! */
! 700: if (on(*tp, CANAGE)) {
! 701: turn_off (*tp, CANAGE);
! 702: if (!save(VS_MAGIC, &player, 0)) {
! 703: msg ("The sight of %s ages you!", prname(mname, FALSE));
! 704: pstats.s_const--;
! 705: max_stats.s_const--;
! 706: if (pstats.s_const < 0)
! 707: death (D_CONSTITUTION);
! 708: }
! 709: }
! 710:
! 711:
! 712: /* Turning to stone */
! 713: if (on(*tp, LOOKSTONE)) {
! 714: turn_off(*tp, LOOKSTONE);
! 715:
! 716: if (on(player, CANINWALL))
! 717: msg("The gaze of %s has no effect.", prname(mname, FALSE));
! 718: else {
! 719: if (!save(VS_PETRIFICATION, &player, 0) && rnd(100) < 5) {
! 720: pstats.s_hpt = -1;
! 721: msg("The gaze of %s petrifies you.", prname(mname, FALSE));
! 722: msg("You are turned to stone !!! --More--");
! 723: wait_for(' ');
! 724: death(D_PETRIFY);
! 725: }
! 726: else {
! 727: msg("The gaze of %s stiffens your limbs.",
! 728: prname(mname, FALSE));
! 729: player.t_no_move += movement(&player) * STONETIME;
! 730: player.t_action = A_FREEZE;
! 731: }
! 732: }
! 733: }
! 734: }
! 735:
! 736: return it;
! 737: }
! 738: /*
! 739: * wanderer:
! 740: * A wandering monster has awakened and is headed for the player
! 741: */
! 742:
! 743: void
! 744: wanderer(void)
! 745: {
! 746: register int i;
! 747: register struct room *hr = roomin(&hero);
! 748: register struct linked_list *item;
! 749: register struct thing *tp;
! 750: register long *attr; /* Points to monsters' attributes */
! 751: int carry; /* Chance of wanderer carrying anything */
! 752: short rmonst; /* Our random wanderer */
! 753: bool canteleport = FALSE, /* Can the monster teleport? */
! 754: seehim; /* Is monster within sight? */
! 755: coord cp;
! 756:
! 757: rmonst = randmonster(TRUE, FALSE); /* Choose a random wanderer */
! 758: attr = &monsters[rmonst].m_flags[0]; /* Start of attributes */
! 759: for (i=0; i<MAXFLAGS; i++)
! 760: if (*attr++ == CANTELEPORT) {
! 761: canteleport = TRUE;
! 762: break;
! 763: }
! 764:
! 765: /* Find a place for it -- avoid the player's room if can't teleport */
! 766: do {
! 767: do {
! 768: i = rnd_room();
! 769: } until (canteleport || hr != &rooms[i] || levtype == MAZELEV ||
! 770: levtype == OUTSIDE || levtype == POSTLEV);
! 771:
! 772: /* Make sure the monster does not teleport on top of the player */
! 773: do {
! 774: rnd_pos(&rooms[i], &cp);
! 775: } while (hr == &rooms[i] && ce(cp, hero));
! 776: } until (step_ok(cp.y, cp.x, NOMONST, NULL));
! 777:
! 778: /* Create a new wandering monster */
! 779: item = new_item(sizeof *tp);
! 780: new_monster(item, rmonst, &cp, FALSE);
! 781: tp = THINGPTR(item);
! 782: runto(tp, &hero);
! 783: tp->t_pos = cp; /* Assign the position to the monster */
! 784: seehim = cansee(tp->t_pos.y, tp->t_pos.x);
! 785: if (on(*tp, HASFIRE)) {
! 786: register struct room *rp;
! 787:
! 788: rp = roomin(&tp->t_pos);
! 789: if (rp) {
! 790: register struct linked_list *fire_item;
! 791:
! 792: fire_item = creat_item();
! 793: ldata(fire_item) = (char *) tp;
! 794: attach(rp->r_fires, fire_item);
! 795:
! 796: rp->r_flags |= HASFIRE;
! 797: if (seehim && next(rp->r_fires) == NULL)
! 798: light(&hero);
! 799: }
! 800: }
! 801:
! 802: /* See if we give the monster anything */
! 803: carry = monsters[tp->t_index].m_carry;
! 804: if (off(*tp, ISUNIQUE)) carry /= 2; /* Non-unique has only a half chance */
! 805: carry_obj(tp, carry);
! 806:
! 807: /* Calculate its movement rate */
! 808: tp->t_no_move = movement(tp);
! 809:
! 810: /* Alert the player if a monster just teleported in */
! 811: if (hr == &rooms[i] && canteleport && seehim && !invisible(tp)) {
! 812: msg("A %s just teleported in", monster_name(tp));
! 813: light(&hero);
! 814: running = FALSE;
! 815: }
! 816:
! 817: if (wizard)
! 818: msg("Started a wandering %s", monster_name(tp));
! 819: }
CVSweb