Annotation of early-roguelike/xrogue/actions.c, Revision 1.1
1.1 ! rubenllo 1: /*
! 2: actions.c - functions for dealing with monster actions
! 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 <ctype.h>
! 20: #include <curses.h>
! 21: #include <limits.h>
! 22: #include "rogue.h"
! 23:
! 24: int mf_count = 0; /* move_free counter - see actions.c(m_act()) */
! 25: int mf_jmpcnt = 0; /* move_free counter for # of jumps */
! 26:
! 27: void m_breathe(struct thing *tp);
! 28: void m_select(struct thing *th, bool flee);
! 29: void m_sonic(struct thing *tp);
! 30: void m_spell(struct thing *tp);
! 31: void m_summon(struct thing *tp);
! 32: bool m_use_it(struct thing *tp, bool flee, struct room *rer, struct room *ree);
! 33: bool m_use_pack(struct thing *monster, coord *defend_pos, int dist,
! 34: coord *shoot_dir);
! 35:
! 36: /*
! 37: * Did we disrupt a spell?
! 38: */
! 39: void
! 40: dsrpt_monster(struct thing *tp, bool always, bool see_him)
! 41: {
! 42: switch (tp->t_action) {
! 43: case A_SUMMON:
! 44: case A_MISSILE:
! 45: case A_SLOW:
! 46: tp->t_action = A_NIL; /* Just make the old fellow start over again */
! 47: tp->t_no_move = movement(tp);
! 48: tp->t_using = NULL; /* Just to be on the safe side */
! 49: turn_on(*tp, WASDISRUPTED);
! 50: if (see_him)
! 51: msg("%s's spell has been disrupted.",prname(monster_name(tp),TRUE));
! 52: /*
! 53: * maybe choose something else to do next time since player
! 54: * is disrupting us
! 55: */
! 56: tp->t_summon *= 2;
! 57: tp->t_cast /= 2;
! 58: return;
! 59: }
! 60:
! 61: /* We may want to disrupt other actions, too */
! 62: if (always) {
! 63: tp->t_action = A_NIL; /* Just make the old fellow start over again */
! 64: tp->t_no_move = movement(tp);
! 65: tp->t_using = NULL;/* Just to be on the safe side */
! 66: }
! 67: }
! 68:
! 69: void
! 70: dsrpt_player(void)
! 71: {
! 72: int which, action;
! 73: struct linked_list *item;
! 74: struct object *obj;
! 75:
! 76: action = player.t_action;
! 77: which = player.t_selection;
! 78:
! 79: switch (action) {
! 80: case C_CAST: /* Did we disrupt a spell? */
! 81: case C_PRAY:
! 82: case C_CHANT:
! 83: {
! 84: msg("Your %s was disrupted!", action == C_CAST ? "spell" : "prayer");
! 85:
! 86: /* Charge him 1/4 anyway */
! 87: if (action == C_CAST)
! 88: spell_power += magic_spells[which].s_cost / 4;
! 89: else if (action == C_PRAY)
! 90: pray_time += cleric_spells[which].s_cost / 4;
! 91: else if (action == C_CHANT)
! 92: chant_time += druid_spells[which].s_cost / 4;
! 93: }
! 94: when C_COUNT: /* counting of gold? */
! 95: {
! 96: if (purse > 0) {
! 97: msg("Your gold goes flying everywhere!");
! 98: do {
! 99: item = spec_item(GOLD, 0, 0, 0);
! 100: obj = OBJPTR(item);
! 101: obj->o_count = min(purse, rnd(20)+1);
! 102: purse -= obj->o_count;
! 103: obj->o_pos = hero;
! 104: fall(item, FALSE);
! 105: } while (purse > 0 && rnd(25) != 1);
! 106: }
! 107: }
! 108: when C_EAT:
! 109: msg("Ack! You gag on your food for a moment. ");
! 110: del_pack(player.t_using);
! 111:
! 112: when A_PICKUP:
! 113: msg("You drop what you are picking up! ");
! 114:
! 115: when C_SEARCH: /* searching for traps and secret doors... */
! 116: msg("Ouch! You decide to stop searching. ");
! 117: count = 0; /* don't search again */
! 118:
! 119: when C_SETTRAP:
! 120: msg("Ouch! You can't set a trap right now. ");
! 121:
! 122: when A_NIL:
! 123: default:
! 124: return;
! 125: }
! 126: player.t_no_move = movement(&player); /* disoriented for a while */
! 127: player.t_action = A_NIL;
! 128: player.t_selection = 0;
! 129: }
! 130:
! 131: /*
! 132: * m_act:
! 133: * If the critter isn't doing anything, choose an action for it.
! 134: * Otherwise, let it perform its chosen action.
! 135: */
! 136:
! 137: void
! 138: m_act(struct thing *tp)
! 139: {
! 140: struct object *obj;
! 141: bool flee; /* Are we scared? */
! 142:
! 143: /* What are we planning to do? */
! 144: switch (tp->t_action) {
! 145: default:
! 146: /* An unknown action! */
! 147: msg("Unknown monster action (%d)", tp->t_action);
! 148:
! 149: /* Fall through */
! 150:
! 151: case A_NIL:
! 152: /* If the monster is fairly intelligent and about to die, it
! 153: * may turn tail and run. But if we are a FRIENDLY creature
! 154: * in the hero's service, don't run.
! 155: */
! 156: if (off(*tp, ISFLEE) &&
! 157: tp->t_stats.s_hpt < tp->maxstats.s_hpt &&
! 158: tp->t_stats.s_hpt < max(10, tp->maxstats.s_hpt/6) &&
! 159: (off(*tp, ISFRIENDLY) || tp->t_dest != &hero) &&
! 160: rnd(25) < tp->t_stats.s_intel) {
! 161: turn_on(*tp, ISFLEE);
! 162:
! 163: /* It is okay to turn tail */
! 164: tp->t_oldpos = tp->t_pos;
! 165: }
! 166:
! 167: /* Should the monster run away? */
! 168: flee = on(*tp, ISFLEE) ||
! 169: ((tp->t_dest == &hero) && on(player, ISINWALL) &&
! 170: off(*tp, CANINWALL));
! 171:
! 172: m_select(tp, flee); /* Select an action */
! 173: return;
! 174:
! 175: when A_ATTACK:
! 176: /*
! 177: * We're trying to attack the player or monster at t_newpos
! 178: * if the prey moved, do nothing
! 179: */
! 180: obj = tp->t_using ? OBJPTR(tp->t_using) : NULL;
! 181: if (ce(tp->t_newpos, hero)) {
! 182: attack(tp, obj, FALSE);
! 183: }
! 184: else if (mvwinch(mw, tp->t_newpos.y, tp->t_newpos.x) &&
! 185: step_ok(tp->t_newpos.y, tp->t_newpos.x, FIGHTOK, tp)) {
! 186: skirmish(tp, &tp->t_newpos, obj, FALSE);
! 187: }
! 188:
! 189: when A_SELL:
! 190: /* Is the quartermaster still next to us? */
! 191: if (ce(tp->t_newpos, hero)) sell(tp);
! 192:
! 193: /* The quartermaster moved away */
! 194: else if (off(player, ISBLIND) && cansee(unc(tp->t_pos)) &&
! 195: (off(*tp, ISINVIS) || on(player, CANSEE)) &&
! 196: (off(*tp, ISSHADOW) || on(player, CANSEE)) &&
! 197: (off(*tp, CANSURPRISE) || ISWEARING(R_ALERT)) &&
! 198: (rnd(12) < 4))
! 199: msg("%s grunts with frustration",prname(monster_name(tp),TRUE));
! 200:
! 201: when A_MOVE:
! 202: /* Let's try to move */
! 203: do_chase(tp);
! 204:
! 205: /* If t_no_move > 0, we found that we have to fight! */
! 206: if (tp->t_no_move > 0) return;
! 207:
! 208: when A_BREATHE:
! 209: /* Breathe on the critter */
! 210: m_breathe(tp);
! 211:
! 212: when A_SLOW:
! 213: /* make him move slower */
! 214: add_slow();
! 215: turn_off(*tp, CANSLOW);
! 216:
! 217: when A_MISSILE:
! 218: /* Start up a magic missile spell */
! 219: m_spell(tp);
! 220:
! 221: when A_SONIC:
! 222: /* Let out a sonic blast! */
! 223: m_sonic(tp);
! 224:
! 225: when A_THROW:
! 226: /* We're throwing something (like an arrow) */
! 227: missile(tp->t_newpos.y, tp->t_newpos.x, tp->t_using, tp);
! 228:
! 229: when A_SUMMON:
! 230: /* We're summoning help */
! 231: m_summon(tp);
! 232:
! 233: when A_USERELIC:
! 234: /* Use our relic */
! 235: m_use_relic(tp);
! 236:
! 237: when A_USEWAND:
! 238: /* use the wand we have */
! 239: m_use_wand(tp);
! 240: }
! 241:
! 242: /* Can we in fact move? (we might have solidified in solid rock) */
! 243: if (!step_ok(hero.y, hero.x, NOMONST, &player)) {
! 244:
! 245: if (move_free > 1) goto jump_over; /* avoid messages */
! 246: if (mf_count > 2) goto jump_over; /* limit messages */
! 247:
! 248: if (pstats.s_hpt < 1) {
! 249: pstats.s_hpt = -1;
! 250: msg("You have merged into the surroundings! --More--");
! 251: wait_for(' ');
! 252: death(D_PETRIFY);
! 253: }
! 254: else {
! 255: mf_count += 1; /* count number of times we are here */
! 256: pstats.s_hpt -= rnd(2)+1;
! 257: if (pstats.s_hpt < 1) {
! 258: pstats.s_hpt = -1;
! 259: msg("You have merged into the surroundings! --More--");
! 260: wait_for(' ');
! 261: death(D_PETRIFY);
! 262: }
! 263: }
! 264: switch (rnd(51)) {
! 265: case 0: msg("Arrrggghhhhh!! ");
! 266: when 5: msg("You can't move! ");
! 267: when 10: msg("You motion angrily! ");
! 268: when 15: msg("You feel so weird! ");
! 269: when 20: msg("If only you could phase. ");
! 270: when 25: msg("The rock maggots are closing in! ");
! 271: when 30: msg("You wrench and wrench and wrench... ");
! 272: when 35: msg("You wish you could teleport out of here! ");
! 273: when 40: msg("Your feel your life force ebbing away... ");
! 274: when 45: msg("You partially regain your senses. ");
! 275: when 50: msg("The rock maggots have found you!!! ");
! 276: otherwise: pstats.s_hpt -= rnd(4)+1;
! 277: }
! 278: if (pstats.s_hpt < 1) {
! 279: pstats.s_hpt = -1;
! 280: msg("You lose the urge to live... --More--");
! 281: wait_for(' ');
! 282: death(D_PETRIFY);
! 283: }
! 284: jump_over:
! 285: mf_jmpcnt++; /* count this jump */
! 286: if (mf_jmpcnt > 9) { /* take a few turns, then reset it */
! 287: mf_jmpcnt = 0;
! 288: mf_count = 0;
! 289: }
! 290: }
! 291:
! 292: /* No action now */
! 293: tp->t_action = A_NIL;
! 294: tp->t_using = NULL;
! 295: }
! 296:
! 297: /*
! 298: * m_breathe:
! 299: * Breathe in the chosen direction.
! 300: */
! 301:
! 302: void
! 303: m_breathe(struct thing *tp)
! 304: {
! 305: register int damage;
! 306: register char *breath = NULL;
! 307:
! 308: damage = tp->t_stats.s_hpt;
! 309: turn_off(*tp, CANSURPRISE);
! 310:
! 311: /* Will it breathe at random */
! 312: if (on(*tp, CANBRANDOM)) {
! 313: /* Turn off random breath */
! 314: turn_off(*tp, CANBRANDOM);
! 315:
! 316: /* Select type of breath */
! 317: switch (rnd(10)) {
! 318: case 0: breath = "acid";
! 319: turn_on(*tp, NOACID);
! 320: when 1: breath = "flame";
! 321: turn_on(*tp, NOFIRE);
! 322: when 2: breath = "lightning bolt";
! 323: turn_on(*tp, NOBOLT);
! 324: when 3: breath = "chlorine gas";
! 325: turn_on(*tp, NOGAS);
! 326: when 4: breath = "ice";
! 327: turn_on(*tp, NOCOLD);
! 328: when 5: breath = "nerve gas";
! 329: turn_on(*tp, NOPARALYZE);
! 330: when 6: breath = "sleeping gas";
! 331: turn_on(*tp, NOSLEEP);
! 332: when 7: breath = "slow gas";
! 333: turn_on(*tp, NOSLOW);
! 334: when 8: breath = "confusion gas";
! 335: turn_on(*tp, ISCLEAR);
! 336: when 9: breath = "fear gas";
! 337: turn_on(*tp, NOFEAR);
! 338: }
! 339: }
! 340:
! 341: /* Or can it breathe acid? */
! 342: else if (on(*tp, CANBACID)) {
! 343: turn_off(*tp, CANBACID);
! 344: breath = "acid";
! 345: }
! 346:
! 347: /* Or can it breathe fire */
! 348: else if (on(*tp, CANBFIRE)) {
! 349: turn_off(*tp, CANBFIRE);
! 350: breath = "flame";
! 351: }
! 352:
! 353: /* Or can it breathe electricity? */
! 354: else if (on(*tp, CANBBOLT)) {
! 355: turn_off(*tp, CANBBOLT);
! 356: breath = "lightning bolt";
! 357: }
! 358:
! 359: /* Or can it breathe gas? */
! 360: else if (on(*tp, CANBGAS)) {
! 361: turn_off(*tp, CANBGAS);
! 362: breath = "chlorine gas";
! 363: }
! 364:
! 365: /* Or can it breathe ice? */
! 366: else if (on(*tp, CANBICE)) {
! 367: turn_off(*tp, CANBICE);
! 368: breath = "ice";
! 369: }
! 370:
! 371: else if (on(*tp, CANBPGAS)) {
! 372: turn_off(*tp, CANBPGAS);
! 373: breath = "nerve gas";
! 374: }
! 375:
! 376: /* can it breathe sleeping gas */
! 377: else if (on(*tp, CANBSGAS)) {
! 378: turn_off(*tp, CANBSGAS);
! 379: breath = "sleeping gas";
! 380: }
! 381:
! 382: /* can it breathe slow gas */
! 383: else if (on(*tp, CANBSLGAS)) {
! 384: turn_off(*tp, CANBSLGAS);
! 385: breath = "slow gas";
! 386: }
! 387:
! 388: /* can it breathe confusion gas */
! 389: else if (on(*tp, CANBCGAS)) {
! 390: turn_off(*tp, CANBCGAS);
! 391: breath = "confusion gas";
! 392: }
! 393:
! 394: /* can it breathe fear gas */
! 395: else {
! 396: turn_off(*tp, CANBFGAS);
! 397: breath = "fear gas";
! 398: }
! 399:
! 400: /* Now breathe */
! 401: shoot_bolt(tp, tp->t_pos, tp->t_newpos, FALSE,
! 402: tp->t_index, breath, damage);
! 403:
! 404: running = FALSE;
! 405: if (fight_flush) flushinp();
! 406: }
! 407:
! 408: /*
! 409: * m_select:
! 410: * Select an action for the monster.
! 411: * flee: True if running away or player is inaccessible in wall
! 412: */
! 413:
! 414: void
! 415: m_select(struct thing *th, bool flee)
! 416: {
! 417: register struct room *rer, *ree; /* room of chaser, room of chasee */
! 418: int dist = INT_MIN;
! 419: int mindist = INT_MAX, maxdist = INT_MIN;
! 420: bool rundoor; /* TRUE means run to a door */
! 421: char sch;
! 422: coord *last_door=0, /* Door we just came from */
! 423: this; /* Temporary destination for chaser */
! 424:
! 425: rer = roomin(&th->t_pos); /* Find room of chaser */
! 426: ree = roomin(th->t_dest); /* Find room of chasee */
! 427:
! 428: /* First see if we want to use an ability or weapon */
! 429: if (m_use_it(th, flee, rer, ree)) return;
! 430:
! 431: /*
! 432: * We don't count monsters on doors as inside rooms here because when
! 433: * a monster is in a room and the player is not in that room, the
! 434: * monster looks for the best door out. If we counted doors as part
! 435: * of the room, the monster would already be on the best door out;
! 436: * so he would never move.
! 437: */
! 438: if ((sch = mvwinch(stdscr, th->t_pos.y, th->t_pos.x)) == DOOR ||
! 439: sch == SECRETDOOR || sch == PASSAGE) {
! 440: rer = NULL;
! 441: }
! 442: this = *th->t_dest;
! 443:
! 444: /*
! 445: * If we are in a room heading for the player and the player is not
! 446: * in the room with us, we run to the "best" door.
! 447: * If we are in a room fleeing from the player, then we run to the
! 448: * "best" door if he IS in the same room.
! 449: *
! 450: * Note: We don't bother with doors in mazes or if we can walk
! 451: * through walls.
! 452: */
! 453: if (rer != NULL && levtype != MAZELEV && off(*th, CANINWALL)) {
! 454: if (flee) rundoor = (rer == ree);
! 455: else rundoor = (rer != ree);
! 456: }
! 457: else rundoor = FALSE;
! 458:
! 459: if (rundoor) {
! 460: register struct linked_list *exitptr; /* For looping through exits */
! 461: coord *exit, /* A particular door */
! 462: *entrance; /* Place just inside doorway */
! 463: int exity, exitx; /* Door's coordinates */
! 464: char dch='\0'; /* Door character */
! 465:
! 466: if ((th->t_doorgoal.x != -1) && (th->t_doorgoal.y != -1))
! 467: dch = mvwinch(stdscr, th->t_doorgoal.y, th->t_doorgoal.x);
! 468:
! 469: /* Do we have a valid goal? */
! 470: if ((dch == PASSAGE || dch == DOOR) && /* A real door */
! 471: (!flee || !ce(th->t_doorgoal, *th->t_dest))) { /* Prey should not
! 472: * be at door if
! 473: * we are running
! 474: * away
! 475: */
! 476: /* Make sure the player is not in the doorway, either */
! 477: entrance = doorway(rer, &th->t_doorgoal);
! 478: if (!flee || entrance == NULL || !ce(*entrance, *th->t_dest)) {
! 479: this = th->t_doorgoal;
! 480: dist = 0; /* Indicate that we have our door */
! 481: }
! 482: }
! 483:
! 484: /* Go through all the doors */
! 485: else for (exitptr = rer->r_exit; exitptr; exitptr = next(exitptr)) {
! 486: exit = DOORPTR(exitptr);
! 487: exity = exit->y;
! 488: exitx = exit->x;
! 489:
! 490: /* Make sure it is a real door */
! 491: dch = mvwinch(stdscr, exity, exitx);
! 492: if (dch == PASSAGE || dch == DOOR) {
! 493: /* Don't count a door if we are fleeing from someone and
! 494: * he is standing on it. Also, don't count it if he is
! 495: * standing in the doorway.
! 496: */
! 497: if (flee) {
! 498: if (ce(*exit, *th->t_dest)) continue;
! 499:
! 500: entrance = doorway(rer, exit);
! 501: if (entrance != NULL && ce(*entrance, *th->t_dest))
! 502: continue;
! 503: }
! 504:
! 505: /* Were we just on this door? */
! 506: if (ce(*exit, th->t_oldpos)) last_door = exit;
! 507:
! 508: else {
! 509: dist = DISTANCE(th->t_dest->y, th->t_dest->x, exity, exitx);
! 510:
! 511: /* If fleeing, we want to maximize distance from door to
! 512: * what we flee, and minimize distance from door to us.
! 513: */
! 514: if (flee)
! 515: dist -= DISTANCE(th->t_pos.y, th->t_pos.x, exity, exitx);
! 516:
! 517: /* Maximize distance if fleeing, otherwise minimize it */
! 518: if ((flee && (dist > maxdist)) ||
! 519: (!flee && (dist < mindist))) {
! 520: th->t_doorgoal = *exit; /* Use this door */
! 521: this = *exit;
! 522: mindist = maxdist = dist;
! 523: }
! 524: }
! 525: }
! 526: }
! 527:
! 528: /* Could we not find a door? */
! 529: if (dist == INT_MIN) {
! 530: /* If we were on a door, go ahead and use it */
! 531: if (last_door) {
! 532: th->t_doorgoal = *last_door;
! 533: this = th->t_oldpos;
! 534: dist = 0; /* Indicate that we found a door */
! 535: }
! 536: else th->t_doorgoal.x = th->t_doorgoal.y = -1; /* No more door goal */
! 537: }
! 538:
! 539: /* Indicate that we do not want to flee from the door */
! 540: if (dist != INT_MIN) flee = FALSE;
! 541: }
! 542: else th->t_doorgoal.x = th->t_doorgoal.y = -1; /* Not going to any door */
! 543:
! 544: /* Now select someplace to go and start the action */
! 545: chase(th, &this, rer, ree, flee);
! 546: }
! 547:
! 548: /*
! 549: * m_sonic:
! 550: * The monster is sounding a sonic blast.
! 551: */
! 552:
! 553: void
! 554: m_sonic(struct thing *tp)
! 555: {
! 556: register int damage;
! 557: struct object blast =
! 558: {
! 559: MISSILE, {0, 0}, 0, "", "150" , NULL, 0, 0, 0, 0
! 560: };
! 561:
! 562: turn_off(*tp, CANSONIC);
! 563: turn_off(*tp, CANSURPRISE);
! 564: do_motion(&blast, tp->t_newpos.y, tp->t_newpos.x, tp);
! 565: damage = rnd(61)+40;
! 566: if (save(VS_BREATH, &player, -3))
! 567: damage /= 2;
! 568: msg ("%s's ultra-sonic blast hits you", prname(monster_name(tp), TRUE));
! 569: if ((pstats.s_hpt -= damage) <= 0) {
! 570: pstats.s_hpt = -1;
! 571: death(tp->t_index);
! 572: }
! 573: running = FALSE;
! 574: if (fight_flush) flushinp();
! 575: dsrpt_player();
! 576: }
! 577:
! 578: /*
! 579: * m_spell:
! 580: * The monster casts a spell. Currently this is limited to
! 581: * magic missile.
! 582: */
! 583: void
! 584: m_spell(struct thing *tp)
! 585: {
! 586: struct object missile =
! 587: {
! 588: MISSILE, {0, 0}, 0, "", "0d4 " , NULL, 0, WS_MISSILE, 100, 1
! 589: };
! 590:
! 591: sprintf(missile.o_hurldmg, "%dd4", tp->t_stats.s_lvl);
! 592: do_motion(&missile, tp->t_newpos.y, tp->t_newpos.x, tp);
! 593: hit_monster(unc(missile.o_pos), &missile, tp);
! 594: turn_off(*tp, CANMISSILE);
! 595: turn_off(*tp, CANSURPRISE);
! 596:
! 597: running = FALSE;
! 598: if (fight_flush) flushinp();
! 599: }
! 600:
! 601: /*
! 602: * m_summon:
! 603: * Summon aid.
! 604: */
! 605:
! 606: void
! 607: m_summon(struct thing *tp)
! 608: {
! 609: register char *helpname, *mname;
! 610: int fail, numsum;
! 611: register int which, i;
! 612:
! 613: /* Let's make sure our prey is still here */
! 614: if (!cansee(unc(tp->t_pos)) || fallpos(&hero, FALSE, 2) == NULL) return;
! 615:
! 616: /*
! 617: * Non-uniques can only summon once. Uniques get fewer
! 618: * creatures with each successive summoning. Also, the
! 619: * probability of summoning goes down
! 620: */
! 621: if (off(*tp, ISUNIQUE))
! 622: turn_off(*tp, CANSUMMON);
! 623:
! 624: turn_off(*tp, CANSURPRISE);
! 625: mname = monster_name(tp);
! 626: helpname = monsters[tp->t_index].m_typesum;
! 627: which = findmindex(helpname);
! 628:
! 629: if ((off(*tp, ISINVIS) || on(player, CANSEE)) &&
! 630: (off(*tp, ISSHADOW) || on(player, CANSEE)) &&
! 631: (off(*tp, CANSURPRISE) || ISWEARING(R_ALERT))) {
! 632: if (monsters[which].m_normal == FALSE) { /* genocided? */
! 633: msg("%s appears dismayed", prname(mname, TRUE));
! 634: monsters[tp->t_index].m_numsum = 0;
! 635: }
! 636: else {
! 637: msg("%s summons %ss for help", prname(mname, TRUE), helpname);
! 638: }
! 639: }
! 640: else {
! 641: if (monsters[which].m_normal == FALSE) /* genocided? */
! 642: monsters[tp->t_index].m_numsum = 0;
! 643: else {
! 644: msg("%ss seem to appear from nowhere!", helpname);
! 645: }
! 646: }
! 647: numsum = monsters[tp->t_index].m_numsum;
! 648: if (numsum && on(*tp, ISUNIQUE)) { /* UNIQUEs summon less each time */
! 649: monsters[tp->t_index].m_numsum--;
! 650: tp->t_summon *= 2; /* cut probability in half */
! 651: }
! 652:
! 653: /*
! 654: * try to make all the creatures around player but remember
! 655: * if unsuccessful
! 656: */
! 657: for (i=0, fail=0; i<numsum; i++) {
! 658: if (!creat_mons(&player, which, FALSE))
! 659: fail++; /* remember the failures */
! 660: }
! 661:
! 662: /*
! 663: * try once again to make the buggers
! 664: */
! 665: for (i=0; i<fail; i++)
! 666: creat_mons(tp, which, FALSE);
! 667:
! 668: /* Now let the poor fellow see all the trouble */
! 669: light(&hero);
! 670: turn_on(*tp, HASSUMMONED);
! 671: }
! 672:
! 673: /*
! 674: * m_use_it:
! 675: * See if the monster (tp) has anything useful it can do
! 676: * (ie. an ability or a weapon) other than just move.
! 677: */
! 678:
! 679: bool
! 680: m_use_it(struct thing *tp, bool flee, struct room *rer, struct room *ree)
! 681: {
! 682: int dist;
! 683: register coord *ee = tp->t_dest, *er = &tp->t_pos;
! 684: coord *shoot_dir = NULL;
! 685: coord straight_dir;
! 686: int straight_shot = FALSE;
! 687: struct thing *prey;
! 688: bool dest_player; /* Are we after the player? */
! 689:
! 690: /*
! 691: * If we are fleeing, there's a chance, depending on our
! 692: * intelligence, that we'll just run in terror.
! 693: */
! 694: if (flee && rnd(25) >= tp->t_stats.s_intel) return(FALSE);
! 695:
! 696: /*
! 697: * Make sure that we have a living destination, and record whether
! 698: * it is the player.
! 699: */
! 700: if (ee != NULL) {
! 701: if (ce(*ee, hero)) {
! 702: dest_player = TRUE;
! 703: prey = &player;
! 704: }
! 705: else {
! 706: struct linked_list *item;
! 707:
! 708: dest_player = FALSE;
! 709:
! 710: /* What is the monster we're chasing? */
! 711: item = find_mons(ee->y, ee->x);
! 712: if (item != NULL) prey = THINGPTR(item);
! 713: else return(FALSE);
! 714: }
! 715: }
! 716: else return(FALSE);
! 717:
! 718: /*
! 719: * If we are friendly to the hero, we don't do anything.
! 720: */
! 721: if (on(*tp, ISFRIENDLY) && dest_player) return(FALSE);
! 722:
! 723: /*
! 724: * Also, for now, if our prey is in a wall, we won't do
! 725: * anything. The prey must be in the same room as we are OR
! 726: * we must have a straight shot at him. Note that
! 727: * shoot_dir must get set before rer is checked so
! 728: * that we get a valid value.
! 729: */
! 730:
! 731: if (can_shoot(er, ee, &straight_dir) == 0)
! 732: shoot_dir = &straight_dir;
! 733: else
! 734: shoot_dir = NULL;
! 735:
! 736: if (on(*prey, ISINWALL) ||
! 737: ( (shoot_dir == NULL) && (rer == NULL || rer != ree)))
! 738: return(FALSE);
! 739:
! 740: /*
! 741: * If we can't see the prey then forget it
! 742: */
! 743: if (on(*prey, ISINVIS) && off(*tp, CANSEE))
! 744: return(FALSE);
! 745:
! 746: /* How far are we from our prey? */
! 747: dist = DISTANCE(er->y, er->x, ee->y, ee->x);
! 748:
! 749: /*
! 750: * Shall we summon aid so we don't have to get our hands dirty?
! 751: * For now, we will only summon aid against the player.
! 752: * We'll wait until he's within 2 dots of a missile length.
! 753: */
! 754: if (on(*tp, CANSUMMON) && dest_player &&
! 755: dist < (BOLT_LENGTH+2)*(BOLT_LENGTH+2) &&
! 756: rnd(tp->t_summon) < tp->t_stats.s_lvl &&
! 757: monsters[tp->t_index].m_numsum > 0 &&
! 758: fallpos(&hero, FALSE, 2) != NULL) {
! 759: tp->t_action = A_SUMMON; /* We're going to summon help */
! 760: tp->t_no_move = movement(tp); /* It takes time! */
! 761: return(TRUE);
! 762: }
! 763:
! 764: /*
! 765: * If the creature can cast a slow spell and if the prey is within
! 766: * 2 dots of a missile fire, then see whether we will cast it.
! 767: * if next to player, lessen chance because we don't like being
! 768: * disrupted
! 769: */
! 770: if (on(*tp, CANSLOW) && dest_player &&
! 771: dist < (BOLT_LENGTH+5)*(BOLT_LENGTH+5) &&
! 772: rnd(100) < (dist > 3 ? tp->t_cast : tp->t_cast/2)) {
! 773: tp->t_action = A_SLOW; /* We're going to slow him */
! 774: tp->t_no_move = 3 * movement(tp); /* Takes time! */
! 775: debug("casting slow spell!");
! 776: return(TRUE);
! 777: }
! 778:
! 779: /*
! 780: * If we have a special magic item, we might use it. We will restrict
! 781: * this options to uniques with relics and creatures with wands for now.
! 782: * Also check for the quartermaster. Don't want him shooting wands....
! 783: */
! 784: if ((on(*tp, ISUNIQUE) || on(*tp, CARRYSTICK)) &&
! 785: off(*tp, CANSELL) && dest_player &&
! 786: m_use_pack(tp, ee, dist, shoot_dir)) {
! 787: return(TRUE);
! 788: }
! 789:
! 790: /* From now on, we must have a direct shot at the prey */
! 791: if (!straight_shot) return(FALSE);
! 792:
! 793: /* We may use a sonic blast if we can, only on the player */
! 794: if (on(*tp, CANSONIC) &&
! 795: dest_player &&
! 796: (dist < BOLT_LENGTH*2) &&
! 797: (rnd(100) < tp->t_breathe)) {
! 798: tp->t_newpos = *shoot_dir; /* Save the direction */
! 799: tp->t_action = A_SONIC; /* We're going to sonic blast */
! 800: tp->t_no_move = 2 * movement(tp); /* Takes 2 movement periods */
! 801: }
! 802:
! 803: /* If we can breathe, we may do so */
! 804: else if (on(*tp, CANBREATHE) &&
! 805: (dist < BOLT_LENGTH*BOLT_LENGTH) &&
! 806: (rnd(100) < tp->t_breathe)) {
! 807: tp->t_newpos = *shoot_dir; /* Save the direction */
! 808: tp->t_action = A_BREATHE; /* We're going to breathe */
! 809: tp->t_no_move = movement(tp); /* It takes 1 movement period */
! 810: }
! 811:
! 812: /*
! 813: * We may shoot missiles if we can
! 814: * if next to player, lessen chance so we don't get disrupted as often
! 815: */
! 816: else if (on(*tp,CANMISSILE) &&
! 817: rnd(100) < (dist > 3 ? tp->t_cast : tp->t_cast/2)){
! 818: tp->t_newpos = *shoot_dir; /* Save the direction */
! 819: tp->t_action = A_MISSILE; /* We're going to shoot MM's */
! 820: tp->t_no_move = 3 * movement(tp); /* Takes time! */
! 821: }
! 822:
! 823: /*
! 824: * If we can shoot or throw something, we might do so.
! 825: * If next to player, then forget it
! 826: */
! 827: else if ((on(*tp,CANSHOOT) || on(*tp,CARRYWEAPON) ||
! 828: on(*tp,CARRYDAGGER) || on(*tp, CARRYAXE)) &&
! 829: dist > 3 &&
! 830: off(*tp, CANSELL) &&
! 831: (get_hurl(tp) != NULL)) {
! 832: tp->t_newpos = *shoot_dir; /* Save the direction */
! 833: tp->t_action = A_THROW; /* We're going to throw something */
! 834: tp->t_using = get_hurl(tp); /* Save our weapon */
! 835: tp->t_no_move = 2 * movement(tp); /* Takes 2 movement periods */
! 836: }
! 837:
! 838: /* We couldn't find anything to do */
! 839: else return(FALSE);
! 840:
! 841: return(TRUE);
! 842:
! 843: }
! 844:
! 845: void
! 846: reap(void)
! 847: {
! 848: _t_free_list(&rlist);
! 849: }
! 850:
! 851: /*
! 852: * runners:
! 853: * Make all the awake monsters try to do something.
! 854: * segments: Number of segments since last called
! 855: */
! 856:
! 857: int
! 858: runners(int segments)
! 859: {
! 860: register struct linked_list *item;
! 861: register struct thing *tp = NULL;
! 862: register int min_time = 20; /* Minimum time until a monster can act */
! 863:
! 864: /*
! 865: * loop thru the list of running (wandering) monsters and see what
! 866: * each one will do this time.
! 867: *
! 868: * Note: the special case that one of this buggers kills another.
! 869: * if this happens than we have to see if the monster killed
! 870: * himself or someone else. In case its himself we have to get next
! 871: * one immediately. If it wasn't we have to get next one at very
! 872: * end in case he killed the next one.
! 873: */
! 874: for (item = mlist; item != NULL; item = item->l_next)
! 875: {
! 876: tp = THINGPTR(item);
! 877: turn_on(*tp, NEEDSTOACT);
! 878: }
! 879:
! 880: for(;;)
! 881: {
! 882: for (item = mlist; item != NULL; item = item->l_next)
! 883: {
! 884: tp = THINGPTR(item);
! 885:
! 886: if (on(*tp, NEEDSTOACT))
! 887: break;
! 888: }
! 889:
! 890: if (item == NULL)
! 891: break;
! 892:
! 893: turn_off(*tp, NEEDSTOACT);
! 894:
! 895: /* If we are not awake, just skip us */
! 896:
! 897: if (off(*tp, ISRUN) && off(*tp, ISHELD))
! 898: continue;
! 899:
! 900: /* See if it's our turn */
! 901:
! 902: tp->t_no_move -= segments;
! 903:
! 904: if (tp->t_no_move > 0)
! 905: {
! 906: if (tp->t_no_move < min_time) min_time = tp->t_no_move;
! 907: continue;
! 908: }
! 909:
! 910: /* If we were frozen, we're moving now */
! 911:
! 912: if (tp->t_action == A_FREEZE)
! 913: tp->t_action = A_NIL;
! 914:
! 915: if (on(*tp, ISHELD))
! 916: {
! 917: /* Make sure the action and using are nil */
! 918:
! 919: tp->t_action = A_NIL;
! 920: tp->t_using = NULL;
! 921:
! 922: /* Can we break free? */
! 923:
! 924: if (rnd(tp->t_stats.s_lvl) > 11)
! 925: {
! 926: turn_off(*tp, ISHELD);
! 927:
! 928: runto(tp, &hero);
! 929:
! 930: if (cansee(tp->t_pos.y, tp->t_pos.x))
! 931: msg("%s breaks free from the hold spell",
! 932: prname(monster_name(tp), TRUE));
! 933: }
! 934: else /* Too bad -- try again later */
! 935: tp->t_no_move = movement(tp);
! 936: }
! 937:
! 938: /* Heal the creature if it's not in the middle of some action */
! 939:
! 940: if (tp->t_action == A_NIL)
! 941: doctor(tp);
! 942:
! 943: while (off(*tp, ISELSEWHERE) &&
! 944: off(*tp, ISDEAD) &&
! 945: tp->t_no_move <= 0 &&
! 946: off(*tp, ISHELD) &&
! 947: on(*tp, ISRUN) )
! 948: {
! 949: /* Let's act (or choose an action if t_action = A_NIL) */
! 950:
! 951: m_act(tp);
! 952: }
! 953:
! 954: if ( off(*tp,ISELSEWHERE) && off(*tp,ISDEAD) )
! 955: {
! 956: if (tp->t_no_move < min_time)
! 957: min_time = tp->t_no_move;
! 958:
! 959: if (tp->t_quiet < 0)
! 960: tp->t_quiet = 0;
! 961: }
! 962: }
! 963:
! 964: return(min_time);
! 965: }
! 966:
! 967: /*
! 968: * See if a monster has some magic it can use. Return TRUE if so.
! 969: * Only care about relics and wands for now.
! 970: */
! 971: bool
! 972: m_use_pack(struct thing *monster, coord *defend_pos, int dist, coord *shoot_dir)
! 973: {
! 974: register struct object *obj;
! 975: register struct linked_list *pitem, *relic, *stick;
! 976: register int units = -1;
! 977:
! 978: relic = stick = NULL;
! 979:
! 980: for (pitem=monster->t_pack; pitem; pitem=next(pitem)) {
! 981: obj = OBJPTR(pitem);
! 982: if (obj->o_flags & ISCURSED) continue;
! 983: if (obj->o_type == RELIC) {
! 984: switch (obj->o_which) {
! 985: case MING_STAFF:
! 986: if (shoot_dir != NULL) {
! 987: units = 2; /* Use 2 time units */
! 988: relic = pitem;
! 989: }
! 990:
! 991: when EMORI_CLOAK:
! 992: if (obj->o_charges != 0 &&
! 993: shoot_dir != NULL) {
! 994: units = 2; /* Use 2 time units */
! 995: relic = pitem;
! 996: }
! 997:
! 998: when ASMO_ROD:
! 999: /* The bolt must be able to reach the defendant */
! 1000: if (shoot_dir != NULL &&
! 1001: dist < BOLT_LENGTH * BOLT_LENGTH) {
! 1002: units = 2; /* Use 2 time units */
! 1003: relic = pitem;
! 1004: }
! 1005:
! 1006: when BRIAN_MANDOLIN:
! 1007: /* The defendant must be the player and within 4 spaces */
! 1008: if (ce(*defend_pos, hero) &&
! 1009: dist < 25 &&
! 1010: player.t_action != A_FREEZE) {
! 1011: units = 4;
! 1012: relic = pitem;
! 1013: }
! 1014:
! 1015: when GERYON_HORN:
! 1016: /* The defendant must be the player and within 5 spaces */
! 1017: if (ce(*defend_pos, hero) &&
! 1018: dist < 25 &&
! 1019: (off(player,ISFLEE)|| player.t_dest!=&monster->t_pos)) {
! 1020: units = 3;
! 1021: relic = pitem;
! 1022: }
! 1023: }
! 1024: }
! 1025: if (obj->o_type == STICK) {
! 1026: if (obj->o_charges < 1) continue;
! 1027: switch(obj->o_which) {
! 1028: case WS_ELECT:
! 1029: case WS_FIRE:
! 1030: case WS_COLD:
! 1031: /* The bolt must be able to reach the defendant */
! 1032: if (shoot_dir != NULL &&
! 1033: dist < BOLT_LENGTH * BOLT_LENGTH) {
! 1034: units = 3;
! 1035: stick = pitem;
! 1036: }
! 1037:
! 1038: when WS_MISSILE:
! 1039: case WS_SLOW_M:
! 1040: case WS_CONFMON:
! 1041: case WS_PARALYZE:
! 1042: case WS_MDEG:
! 1043: case WS_FEAR:
! 1044: if (shoot_dir != NULL) {
! 1045: units = 3;
! 1046: stick = pitem;
! 1047: }
! 1048:
! 1049: otherwise:
! 1050: break;
! 1051: }
! 1052: }
! 1053: }
! 1054:
! 1055: /* use relics in preference to all others */
! 1056: if (relic) debug("chance to use relic = %d%%", monster->t_artifact);
! 1057: if (stick) debug("chance to use stick = %d%%", monster->t_wand);
! 1058: if (relic && rnd(100) < monster->t_artifact) {
! 1059: monster->t_action = A_USERELIC;
! 1060: pitem = relic;
! 1061: }
! 1062: else if (stick && rnd(100) < monster->t_wand) {
! 1063: /*
! 1064: * see if the monster will use the wand
! 1065: */
! 1066: pitem = stick;
! 1067: monster->t_action = A_USEWAND;
! 1068: }
! 1069: else {
! 1070: return(FALSE);
! 1071: }
! 1072:
! 1073: monster->t_no_move = units * movement(monster);
! 1074: monster->t_using = pitem;
! 1075: monster->t_newpos = *shoot_dir;
! 1076: return(TRUE);
! 1077: }
! 1078:
CVSweb