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