Annotation of early-roguelike/arogue7/sticks.c, Revision 1.1
1.1 ! rubenllo 1: /*
! 2: * sticks.c - Functions to implement the various sticks one might find
! 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: * Functions to implement the various sticks one might find
! 17: * while wandering around the dungeon.
! 18: */
! 19:
! 20: #include "curses.h"
! 21: #include <ctype.h>
! 22: #include <string.h>
! 23: #include "rogue.h"
! 24:
! 25: void drain(int ymin, int ymax, int xmin, int xmax);
! 26:
! 27: /*
! 28: * zap a stick and see what happens
! 29: */
! 30: void
! 31: do_zap(struct thing *zapper, struct object *obj, coord *direction, int which,
! 32: int flags)
! 33: {
! 34: register struct linked_list *item = NULL;
! 35: register struct thing *tp;
! 36: register int y, x, bonus;
! 37: struct linked_list *nitem;
! 38: struct object *nobj;
! 39: bool cursed, blessed, is_player;
! 40: char *mname = "";
! 41:
! 42: cursed = flags & ISCURSED;
! 43: blessed = flags & ISBLESSED;
! 44:
! 45: if (obj && obj->o_type != RELIC) { /* all relics are chargeless */
! 46: if (obj->o_charges < 1) {
! 47: msg(nothing);
! 48: return;
! 49: }
! 50: obj->o_charges--;
! 51: }
! 52: if (which == WS_WONDER) {
! 53: switch (rnd(14)) {
! 54: case 0: which = WS_ELECT;
! 55: when 1: which = WS_FIRE;
! 56: when 2: which = WS_COLD;
! 57: when 3: which = WS_POLYMORPH;
! 58: when 4: which = WS_MISSILE;
! 59: when 5: which = WS_SLOW_M;
! 60: when 6: which = WS_TELMON;
! 61: when 7: which = WS_CANCEL;
! 62: when 8: which = WS_CONFMON;
! 63: when 9: which = WS_DISINTEGRATE;
! 64: when 10: which = WS_PETRIFY;
! 65: when 11: which = WS_PARALYZE;
! 66: when 12: which = WS_MDEG;
! 67: when 13: which = WS_FEAR;
! 68: }
! 69: if(ws_magic[which].mi_curse>0 && rnd(100)<=ws_magic[which].mi_curse){
! 70: cursed = TRUE;
! 71: blessed = FALSE;
! 72: }
! 73: }
! 74:
! 75: tp = NULL;
! 76: switch (which) {
! 77: case WS_POLYMORPH:
! 78: case WS_SLOW_M:
! 79: case WS_TELMON:
! 80: case WS_CANCEL:
! 81: case WS_CONFMON:
! 82: case WS_DISINTEGRATE:
! 83: case WS_PETRIFY:
! 84: case WS_PARALYZE:
! 85: case WS_MDEG:
! 86: case WS_FEAR:
! 87: y = zapper->t_pos.y;
! 88: x = zapper->t_pos.x;
! 89:
! 90: do {
! 91: y += direction->y;
! 92: x += direction->x;
! 93: }
! 94: while (shoot_ok(winat(y, x)) && !(y == hero.y && x == hero.x));
! 95:
! 96: if (y == hero.y && x == hero.x)
! 97: is_player = TRUE;
! 98: else if (isalpha(mvwinch(mw, y, x))) {
! 99: item = find_mons(y, x);
! 100: tp = THINGPTR(item);
! 101: runto(tp, &hero);
! 102: turn_off(*tp, CANSURPRISE);
! 103: mname = monster_name(tp);
! 104: is_player = FALSE;
! 105:
! 106: /* The monster may not like being shot at */
! 107: if ((zapper == &player) &&
! 108: on(*tp, ISCHARMED) &&
! 109: save(VS_MAGIC, tp, 0)) {
! 110: msg("The eyes of %s turn clear.", prname(mname, FALSE));
! 111: turn_off(*tp, ISCHARMED);
! 112: mname = monster_name(tp);
! 113: }
! 114: }
! 115: else {
! 116: /*
! 117: * if monster misses player because the player dodged then lessen
! 118: * the chances he will use the wand again since the player appears
! 119: * to be rather dextrous
! 120: */
! 121: if (zapper != &player)
! 122: zapper->t_wand = zapper->t_wand * 3 / 4;
! 123: }
! 124: }
! 125: switch (which) {
! 126: case WS_LIGHT:
! 127: /*
! 128: * Reddy Kilowat wand. Light up the room
! 129: */
! 130: blue_light(blessed, cursed);
! 131: when WS_DRAIN:
! 132: /*
! 133: * Take away 1/2 of hero's hit points, then take it away
! 134: * evenly from the monsters in the room or next to hero
! 135: * if he is in a passage (but leave the monsters alone
! 136: * if the stick is cursed)
! 137: */
! 138: if (pstats.s_hpt < 2) {
! 139: msg("You are too weak to use it.");
! 140: }
! 141: else if (cursed)
! 142: pstats.s_hpt /= 2;
! 143: else
! 144: drain(hero.y-1, hero.y+1, hero.x-1, hero.x+1);
! 145:
! 146: when WS_POLYMORPH:
! 147: {
! 148: register char oldch;
! 149: register struct room *rp;
! 150: register struct linked_list *pitem;
! 151: coord delta;
! 152:
! 153: if (tp == NULL)
! 154: break;
! 155: if (save(VS_MAGIC, tp, 0)) {
! 156: msg(nothing);
! 157: break;
! 158: }
! 159: rp = roomin(&tp->t_pos);
! 160: check_residue(tp);
! 161: delta.x = x;
! 162: delta.y = y;
! 163: detach(mlist, item);
! 164: oldch = tp->t_oldch;
! 165: pitem = tp->t_pack; /* save his pack */
! 166: tp->t_pack = NULL;
! 167: new_monster(item,rnd(NUMMONST-NUMUNIQUE-1)+1,&delta,FALSE);
! 168: if (tp->t_pack != NULL)
! 169: o_free_list (tp->t_pack);
! 170: tp->t_pack = pitem;
! 171: if (isalpha(mvwinch(cw, y, x)))
! 172: mvwaddch(cw, y, x, tp->t_type);
! 173: tp->t_oldch = oldch;
! 174: /*
! 175: * should the room light up?
! 176: */
! 177: if (on(*tp, HASFIRE)) {
! 178: if (rp) {
! 179: register struct linked_list *fire_item;
! 180:
! 181: fire_item = creat_item();
! 182: ldata(fire_item) = (char *) tp;
! 183: attach(rp->r_fires, fire_item);
! 184: rp->r_flags |= HASFIRE;
! 185: if (cansee(tp->t_pos.y,tp->t_pos.x) &&
! 186: next(rp->r_fires) == NULL) light(&hero);
! 187: }
! 188: }
! 189: runto(tp, &hero);
! 190: msg(terse ? "A new %s!"
! 191: : "You have created a new %s!",
! 192: monster_name(tp));
! 193: }
! 194:
! 195: when WS_PETRIFY:
! 196: if (tp == NULL)
! 197: break;
! 198: if (save(VS_MAGIC, tp, 0)) {
! 199: msg(nothing);
! 200: break;
! 201: }
! 202: check_residue(tp);
! 203: turn_on(*tp, ISSTONE);
! 204: turn_on(*tp, NOSTONE);
! 205: turn_off(*tp, ISRUN);
! 206: turn_off(*tp, ISINVIS);
! 207: turn_off(*tp, CANSURPRISE);
! 208: turn_off(*tp, ISDISGUISE);
! 209: tp->t_action = A_NIL;
! 210: tp->t_no_move = 0;
! 211: msg("%s is turned to stone!",prname(mname, TRUE));
! 212:
! 213: when WS_TELMON:
! 214: {
! 215: register int rm;
! 216: register struct room *rp;
! 217:
! 218: if (tp == NULL)
! 219: break;
! 220: if (save(VS_MAGIC, tp, 0)) {
! 221: msg(nothing);
! 222: break;
! 223: }
! 224: rp = NULL;
! 225: check_residue(tp);
! 226: tp->t_action = A_FREEZE; /* creature is disoriented */
! 227: tp->t_no_move = 2;
! 228: if (cursed) { /* Teleport monster to player */
! 229: if ((y == (hero.y + direction->y)) &&
! 230: (x == (hero.x + direction->x)))
! 231: msg(nothing);
! 232: else {
! 233: tp->t_pos.y = hero.y + direction->y;
! 234: tp->t_pos.x = hero.x + direction->x;
! 235: }
! 236: }
! 237: else if (blessed) { /* Get rid of monster */
! 238: killed(item, FALSE, TRUE, TRUE);
! 239: return;
! 240: }
! 241: else {
! 242: register int i=0;
! 243:
! 244: do { /* Move monster to another room */
! 245: rm = rnd_room();
! 246: rnd_pos(&rooms[rm], &tp->t_pos);
! 247: }until(winat(tp->t_pos.y,tp->t_pos.x)==FLOOR ||i++>500);
! 248: rp = &rooms[rm];
! 249: }
! 250:
! 251: /* Now move the monster */
! 252: if (isalpha(mvwinch(cw, y, x)))
! 253: mvwaddch(cw, y, x, tp->t_oldch);
! 254: mvwaddch(mw, y, x, ' ');
! 255: mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, tp->t_type);
! 256: if (tp->t_pos.y != y || tp->t_pos.x != x)
! 257: tp->t_oldch = CCHAR( mvwinch(cw, tp->t_pos.y, tp->t_pos.x) );
! 258: /*
! 259: * check to see if room that creature appears in should
! 260: * light up
! 261: */
! 262: if (on(*tp, HASFIRE)) {
! 263: if (rp) {
! 264: register struct linked_list *fire_item;
! 265:
! 266: fire_item = creat_item();
! 267: ldata(fire_item) = (char *) tp;
! 268: attach(rp->r_fires, fire_item);
! 269: rp->r_flags |= HASFIRE;
! 270: if(cansee(tp->t_pos.y, tp->t_pos.x) &&
! 271: next(rp->r_fires) == NULL)
! 272: light(&hero);
! 273: }
! 274: }
! 275: }
! 276: when WS_CANCEL:
! 277: if (tp == NULL)
! 278: break;
! 279: if (save(VS_MAGIC, tp, 0)) {
! 280: msg(nothing);
! 281: break;
! 282: }
! 283: check_residue(tp);
! 284: tp->t_flags[0] &= CANC0MASK;
! 285: tp->t_flags[1] &= CANC1MASK;
! 286: tp->t_flags[2] &= CANC2MASK;
! 287: tp->t_flags[3] &= CANC3MASK;
! 288: tp->t_flags[4] &= CANC4MASK;
! 289: tp->t_flags[5] &= CANC5MASK;
! 290: tp->t_flags[6] &= CANC6MASK;
! 291: tp->t_flags[7] &= CANC7MASK;
! 292: tp->t_flags[8] &= CANC8MASK;
! 293: tp->t_flags[9] &= CANC9MASK;
! 294: tp->t_flags[10] &= CANCAMASK;
! 295: tp->t_flags[11] &= CANCBMASK;
! 296: tp->t_flags[12] &= CANCCMASK;
! 297: tp->t_flags[13] &= CANCDMASK;
! 298: tp->t_flags[14] &= CANCEMASK;
! 299: tp->t_flags[15] &= CANCFMASK;
! 300:
! 301: when WS_MISSILE:
! 302: {
! 303: int dice;
! 304: static struct object bolt =
! 305: {
! 306: MISSILE , {0, 0}, "", 0, "", "1d4 " , NULL, 0, WS_MISSILE, 50, 1
! 307: };
! 308:
! 309: if (!obj)
! 310: dice = zapper->t_stats.s_lvl;
! 311: if (obj->o_type == RELIC)
! 312: dice = 15;
! 313: else if (EQUAL(ws_type[which], "staff"))
! 314: dice = 10;
! 315: else
! 316: dice = 6;
! 317: sprintf(bolt.o_hurldmg, "%dd4", dice);
! 318: do_motion(&bolt, direction->y, direction->x, zapper);
! 319: if (!hit_monster(unc(bolt.o_pos), &bolt, zapper))
! 320: msg("The missile vanishes with a puff of smoke");
! 321: }
! 322: when WS_HIT:
! 323: {
! 324: register char ch;
! 325: struct object strike; /* don't want to change sticks attributes */
! 326:
! 327: direction->y += hero.y;
! 328: direction->x += hero.x;
! 329: ch = CCHAR( winat(direction->y, direction->x) );
! 330: if (isalpha(ch))
! 331: {
! 332: strike = *obj;
! 333: strike.o_hplus = 6;
! 334: if (EQUAL(ws_type[which], "staff"))
! 335: strncpy(strike.o_damage,"3d8",sizeof(strike.o_damage));
! 336: else
! 337: strncpy(strike.o_damage,"2d8",sizeof(strike.o_damage));
! 338: fight(direction, &strike, FALSE);
! 339: }
! 340: }
! 341: when WS_SLOW_M:
! 342: if (is_player) {
! 343: add_slow();
! 344: break;
! 345: }
! 346: if (tp == NULL)
! 347: break;
! 348: if (cursed) {
! 349: if (on(*tp, ISSLOW))
! 350: turn_off(*tp, ISSLOW);
! 351: else
! 352: turn_on(*tp, ISHASTE);
! 353: break;
! 354: }
! 355: if ((on(*tp,ISUNIQUE) && save(VS_MAGIC,tp,0)) || on(*tp,NOSLOW)) {
! 356: msg(nothing);
! 357: break;
! 358: }
! 359: else if (blessed) {
! 360: turn_off(*tp, ISRUN);
! 361: turn_on(*tp, ISHELD);
! 362: }
! 363: /*
! 364: * always slow in case he breaks free of HOLD
! 365: */
! 366: if (on(*tp, ISHASTE))
! 367: turn_off(*tp, ISHASTE);
! 368: else
! 369: turn_on(*tp, ISSLOW);
! 370:
! 371: when WS_CHARGE:
! 372: if (ws_know[WS_CHARGE] != TRUE && obj)
! 373: msg("This is a wand of charging.");
! 374: nitem = get_item(pack, "charge", STICK, FALSE, FALSE);
! 375: if (nitem != NULL) {
! 376: nobj = OBJPTR(nitem);
! 377: if ((++(nobj->o_charges) == 1) && (nobj->o_which == WS_HIT))
! 378: fix_stick(nobj);
! 379: if (blessed) ++(nobj->o_charges);
! 380: if (EQUAL(ws_type[nobj->o_which], "staff")) {
! 381: if (nobj->o_charges > 100)
! 382: nobj->o_charges = 100;
! 383: }
! 384: else {
! 385: if (nobj->o_charges > 50)
! 386: nobj->o_charges = 50;
! 387: }
! 388: }
! 389: when WS_ELECT:
! 390: shoot_bolt( zapper, zapper->t_pos, *direction, TRUE, D_BOLT,
! 391: "lightning bolt", roll(zapper->t_stats.s_lvl,6));
! 392:
! 393: when WS_FIRE:
! 394: shoot_bolt( zapper, zapper->t_pos, *direction, TRUE, D_BOLT,
! 395: "flame", roll(zapper->t_stats.s_lvl,6));
! 396:
! 397: when WS_COLD:
! 398: shoot_bolt( zapper, zapper->t_pos, *direction, TRUE, D_BOLT,
! 399: "ice", roll(zapper->t_stats.s_lvl,6));
! 400:
! 401: when WS_CONFMON:
! 402: if (cursed || is_player) {
! 403: if (!save(VS_WAND, &player, 0)) {
! 404: dsrpt_player();
! 405: confus_player();
! 406: }
! 407: else {
! 408: if (zapper != &player) zapper->t_wand /= 2;
! 409: msg(nothing);
! 410: }
! 411: }
! 412: else {
! 413: if (tp == NULL)
! 414: break;
! 415: if (save(VS_MAGIC, tp, 0) || on(*tp, ISCLEAR))
! 416: msg(nothing);
! 417: else
! 418: turn_on (*tp, ISHUH);
! 419: }
! 420: when WS_PARALYZE:
! 421: if (is_player || cursed) {
! 422: if ((obj && obj->o_type==RELIC) || !save(VS_WAND, &player, 0)){
! 423: player.t_no_move += 2 * movement(&player) * FREEZETIME;
! 424: player.t_action = A_FREEZE;
! 425: msg("You can't move.");
! 426: }
! 427: else {
! 428: if (zapper != &player) zapper->t_wand /= 2;
! 429: msg(nothing);
! 430: }
! 431: }
! 432: else {
! 433: if (tp == NULL)
! 434: break;
! 435: bonus = 0;
! 436: if (blessed) bonus = -3;
! 437: if (((obj && obj->o_type==RELIC) || !save(VS_WAND,tp,bonus)) &&
! 438: off(*tp, NOPARALYZE)) {
! 439: tp->t_no_move += 2 * movement(tp) * FREEZETIME;
! 440: tp->t_action = A_FREEZE;
! 441: }
! 442: else {
! 443: msg(nothing);
! 444: }
! 445: }
! 446: when WS_FEAR:
! 447: if (is_player) {
! 448: if (!on(player, ISFLEE) ||
! 449: ISWEARING(R_HEROISM) ||
! 450: save(VS_WAND, &player, 0)) {
! 451: msg(nothing);
! 452: zapper->t_wand /= 2;
! 453: }
! 454: else {
! 455: turn_on(player, ISFLEE);
! 456: player.t_dest = &zapper->t_pos;
! 457: msg("The sight of %s terrifies you.", prname(mname, FALSE));
! 458: }
! 459: break;
! 460: }
! 461: if (tp == NULL)
! 462: break;
! 463: bonus = 0;
! 464: if (blessed) bonus = -3;
! 465: if(save(VS_WAND, tp,bonus) || on(*tp,ISUNDEAD) || on(*tp,NOFEAR)){
! 466: msg(nothing);
! 467: break;
! 468: }
! 469: turn_on(*tp, ISFLEE);
! 470: turn_on(*tp, WASTURNED);
! 471:
! 472: /* Stop it from attacking us */
! 473: dsrpt_monster(tp, TRUE, cansee(tp->t_pos.y, tp->t_pos.x));
! 474:
! 475: /* If monster was suffocating, stop it */
! 476: if (on(*tp, DIDSUFFOCATE)) {
! 477: turn_off(*tp, DIDSUFFOCATE);
! 478: extinguish(suffocate);
! 479: }
! 480:
! 481: /* If monster held us, stop it */
! 482: if (on(*tp, DIDHOLD) && (--hold_count == 0))
! 483: turn_off(player, ISHELD);
! 484: turn_off(*tp, DIDHOLD);
! 485:
! 486: /* It is okay to turn tail */
! 487: tp->t_oldpos = tp->t_pos;
! 488:
! 489: when WS_MDEG:
! 490: if (is_player) {
! 491: if (save(VS_WAND, &player, 0)) {
! 492: msg (nothing);
! 493: zapper->t_wand /= 2;
! 494: break;
! 495: }
! 496: pstats.s_hpt /= 2;
! 497: if (pstats.s_hpt <= 0) {
! 498: msg("Your life has been sucked from you -- More --");
! 499: wait_for(' ');
! 500: death(zapper->t_index);
! 501: }
! 502: else
! 503: msg("You feel a great drain on your system");
! 504: }
! 505: if (tp == NULL)
! 506: break;
! 507: if (cursed) {
! 508: tp->t_stats.s_hpt *= 2;
! 509: msg("%s appears to be stronger now!", prname(mname, TRUE));
! 510: }
! 511: else if (on(*tp, ISUNIQUE) && save(VS_WAND, tp, 0))
! 512: msg (nothing);
! 513: else {
! 514: tp->t_stats.s_hpt /= 2;
! 515: msg("%s appears to be weaker now", prname(mname, TRUE));
! 516: }
! 517: if (tp->t_stats.s_hpt < 1)
! 518: killed(item, TRUE, TRUE, TRUE);
! 519: when WS_DISINTEGRATE:
! 520: if (tp == NULL)
! 521: break;
! 522: if (cursed) {
! 523: register int m1, m2;
! 524: coord mp;
! 525: struct linked_list *titem;
! 526: char ch;
! 527: struct thing *th;
! 528:
! 529: if (on(*tp, ISUNIQUE)) {
! 530: msg (nothing);
! 531: break;
! 532: }
! 533: for (m1=tp->t_pos.x-1 ; m1 <= tp->t_pos.x+1 ; m1++) {
! 534: for(m2=tp->t_pos.y-1 ; m2<=tp->t_pos.y+1 ; m2++) {
! 535: if (m1 == hero.x && m2 == hero.y)
! 536: continue;
! 537: ch = CCHAR( winat(m2,m1) );
! 538: if (shoot_ok(ch)) {
! 539: mp.x = m1; /* create it */
! 540: mp.y = m2;
! 541: titem = new_item(sizeof(struct thing));
! 542: new_monster(titem,(short)tp->t_index,&mp,FALSE);
! 543: th = THINGPTR(titem);
! 544: turn_on (*th, ISMEAN);
! 545: runto(th,&hero);
! 546: if (on(*th, HASFIRE)) {
! 547: register struct room *rp;
! 548:
! 549: rp = roomin(&th->t_pos);
! 550: if (rp) {
! 551: register struct linked_list *fire_item;
! 552:
! 553: fire_item = creat_item();
! 554: ldata(fire_item) = (char *) th;
! 555: attach(rp->r_fires, fire_item);
! 556: rp->r_flags |= HASFIRE;
! 557: if (cansee(th->t_pos.y, th->t_pos.x) &&
! 558: next(rp->r_fires) == NULL)
! 559: light(&hero);
! 560: }
! 561: }
! 562: }
! 563: }
! 564: }
! 565: }
! 566: else { /* if its a UNIQUE it might still live */
! 567: if (on(*tp, ISUNIQUE) && save(VS_MAGIC, tp, 0)) {
! 568: tp->t_stats.s_hpt /= 2;
! 569: if (tp->t_stats.s_hpt < 1) {
! 570: killed(item, FALSE, TRUE, TRUE);
! 571: msg("You have disintegrated %s", prname(mname, FALSE));
! 572: }
! 573: else {
! 574: msg("%s appears wounded", prname(mname, TRUE));
! 575: }
! 576: }
! 577: else {
! 578: msg("You have disintegrated %s", prname(mname, FALSE));
! 579: killed (item, FALSE, TRUE, TRUE);
! 580: }
! 581: }
! 582: when WS_CURING:
! 583: if (cursed) {
! 584: if (!save(VS_POISON, &player, 0)) {
! 585: msg("You feel extremely sick now");
! 586: pstats.s_hpt /=2;
! 587: if (pstats.s_hpt == 0) death (D_POISON);
! 588: }
! 589: if (!save(VS_WAND, &player, 0) && !ISWEARING(R_HEALTH)) {
! 590: turn_on(player, HASDISEASE);
! 591: turn_on(player, HASINFEST);
! 592: turn_on(player, DOROT);
! 593: fuse(cure_disease, NULL, roll(HEALTIME,SICKTIME), AFTER);
! 594: infest_dam++;
! 595: }
! 596: else msg("You fell momentarily sick");
! 597: }
! 598: else {
! 599: if (on(player, HASDISEASE) || on(player, HASINFEST)) {
! 600: extinguish(cure_disease);
! 601: turn_off(player, HASINFEST);
! 602: infest_dam = 0;
! 603: cure_disease(); /* this prints message */
! 604: }
! 605: if (on(player, DOROT)) {
! 606: msg("You feel your skin returning to normal.");
! 607: turn_off(player, DOROT);
! 608: }
! 609: pstats.s_hpt += roll(pstats.s_lvl, blessed ? 6 : 4);
! 610: if (pstats.s_hpt > max_stats.s_hpt)
! 611: pstats.s_hpt = max_stats.s_hpt;
! 612: msg("You begin to feel %sbetter.", blessed ? "much " : "");
! 613:
! 614: }
! 615: otherwise:
! 616: msg("What a bizarre schtick!");
! 617: }
! 618: }
! 619:
! 620:
! 621: /*
! 622: * drain:
! 623: * Do drain hit points from player shtick
! 624: */
! 625:
! 626: void
! 627: drain(int ymin, int ymax, int xmin, int xmax)
! 628: {
! 629: register int i, j, count;
! 630: register struct thing *ick;
! 631: register struct linked_list *item;
! 632:
! 633: /*
! 634: * First count how many things we need to spread the hit points among
! 635: */
! 636: count = 0;
! 637: for (i = ymin; i <= ymax; i++) {
! 638: if (i < 1 || i > lines - 3)
! 639: continue;
! 640: for (j = xmin; j <= xmax; j++) {
! 641: if (j < 0 || j > cols - 1)
! 642: continue;
! 643: if (isalpha(mvwinch(mw, i, j)))
! 644: count++;
! 645: }
! 646: }
! 647: if (count == 0)
! 648: {
! 649: msg("You have a tingling feeling");
! 650: return;
! 651: }
! 652: count = pstats.s_hpt / count;
! 653: pstats.s_hpt /= 2;
! 654: /*
! 655: * Now zot all of the monsters
! 656: */
! 657: for (i = ymin; i <= ymax; i++) {
! 658: if (i < 1 || i > lines - 3)
! 659: continue;
! 660: for (j = xmin; j <= xmax; j++) {
! 661: if (j < 0 || j > cols - 1)
! 662: continue;
! 663: if (isalpha(mvwinch(mw, i, j)) &&
! 664: ((item = find_mons(i, j)) != NULL)) {
! 665: ick = THINGPTR(item);
! 666: if (on(*ick, ISUNIQUE) && save(VS_MAGIC, ick, 0))
! 667: ick->t_stats.s_hpt -= count / 2;
! 668: else
! 669: ick->t_stats.s_hpt -= count;
! 670: if (ick->t_stats.s_hpt < 1)
! 671: killed(item,
! 672: cansee(i,j)&&(!on(*ick,ISINVIS)||on(player,CANSEE)),
! 673: TRUE, TRUE);
! 674: else {
! 675: runto(ick, &hero);
! 676:
! 677: /*
! 678: * The monster may not like being shot at. Since the
! 679: * shot is not aimed directly at the monster, we will
! 680: * give him a poorer save.
! 681: */
! 682: if (on(*ick, ISCHARMED) && save(VS_MAGIC, ick, -2)) {
! 683: msg("The eyes of %s turn clear.",
! 684: prname(monster_name(ick), FALSE));
! 685: turn_off(*ick, ISCHARMED);
! 686: }
! 687: if (cansee(i,j) && (!on(*ick,ISINVIS)||on(player,CANSEE)))
! 688: msg("%s appears wounded",
! 689: prname(monster_name(ick), TRUE));
! 690: }
! 691: }
! 692: }
! 693: }
! 694: }
! 695:
! 696: /*
! 697: * initialize a stick
! 698: */
! 699: void
! 700: fix_stick(struct object *cur)
! 701: {
! 702: if (EQUAL(ws_type[cur->o_which], "staff")) {
! 703: cur->o_weight = 100;
! 704: cur->o_charges = 5 + rnd(10);
! 705: strncpy(cur->o_damage, "2d3", sizeof(cur->o_damage));
! 706: cur->o_hplus = 1;
! 707: cur->o_dplus = 0;
! 708: switch (cur->o_which) {
! 709: case WS_HIT:
! 710: cur->o_hplus = 3;
! 711: cur->o_dplus = 3;
! 712: strncpy(cur->o_damage, "2d8", sizeof(cur->o_damage));
! 713: when WS_LIGHT:
! 714: cur->o_charges = 20 + rnd(10);
! 715: }
! 716: }
! 717: else {
! 718: strncpy(cur->o_damage, "1d3", sizeof(cur->o_damage));
! 719: cur->o_weight = 60;
! 720: cur->o_hplus = 1;
! 721: cur->o_dplus = 0;
! 722: cur->o_charges = 3 + rnd(5);
! 723: switch (cur->o_which) {
! 724: case WS_HIT:
! 725: cur->o_hplus = 3;
! 726: cur->o_dplus = 3;
! 727: strncpy(cur->o_damage, "1d8", sizeof(cur->o_damage));
! 728: when WS_LIGHT:
! 729: cur->o_charges = 10 + rnd(10);
! 730: }
! 731: }
! 732: strncpy(cur->o_hurldmg, "1d1", sizeof(cur->o_hurldmg));
! 733:
! 734: }
! 735:
! 736: /*
! 737: * Use the wand that our monster is wielding.
! 738: */
! 739: void
! 740: m_use_wand(struct thing *monster)
! 741: {
! 742: register struct object *obj;
! 743:
! 744: /* Make sure we really have it */
! 745: if (monster->t_using)
! 746: obj = OBJPTR(monster->t_using);
! 747: else {
! 748: debug("Stick not set!");
! 749: monster->t_action = A_NIL;
! 750: return;
! 751: }
! 752:
! 753: if (obj->o_type != STICK) {
! 754: debug("Stick not selected!");
! 755: monster->t_action = A_NIL;
! 756: return;
! 757: }
! 758: /*
! 759: * shoot the stick!
! 760: * assume all blessed sticks are normal for now.
! 761: * Note that we don't get here if the wand is cursed.
! 762: */
! 763: msg("%s points a %s at you!", prname(monster_name(monster), TRUE),
! 764: ws_type[obj->o_which]);
! 765: do_zap(monster, obj, &monster->t_newpos, obj->o_which, 0);
! 766: monster->t_wand /= 2; /* chance lowers with each use */
! 767: }
! 768:
! 769: /*
! 770: * type: type of item, NULL means stick
! 771: * which: which item
! 772: */
! 773: bool
! 774: need_dir(int type, int which)
! 775: {
! 776: if (type == STICK || type == 0) {
! 777: switch (which) {
! 778: case WS_LIGHT:
! 779: case WS_DRAIN:
! 780: case WS_CHARGE:
! 781: case WS_CURING:
! 782: return(FALSE);
! 783: default:
! 784: return(TRUE);
! 785: }
! 786: }
! 787: else if (type == RELIC) {
! 788: switch (which) {
! 789: case MING_STAFF:
! 790: case ASMO_ROD:
! 791: case EMORI_CLOAK:
! 792: return(TRUE);
! 793: default:
! 794: return(FALSE);
! 795: }
! 796: }
! 797: return (FALSE); /* hope we don't get here */
! 798: }
! 799: /*
! 800: * let the player zap a stick and see what happens
! 801: */
! 802: bool
! 803: player_zap(int which, int flag)
! 804: {
! 805: register struct linked_list *item;
! 806: register struct object *obj;
! 807:
! 808: obj = NULL;
! 809: if (which == 0) {
! 810: /* This is a stick. It takes 2 movement periods to zap it */
! 811: if (player.t_action != C_ZAP) {
! 812: if ((item = get_item(pack,"zap with",ZAPPABLE,FALSE,FALSE)) == NULL)
! 813: return(FALSE);
! 814:
! 815: obj = OBJPTR(item);
! 816:
! 817: if (need_dir(obj->o_type, obj->o_which)) {
! 818: if (!get_dir(&player.t_newpos))
! 819: return(FALSE);
! 820: }
! 821: player.t_using = item; /* Remember what it is */
! 822: player.t_action = C_ZAP; /* We are quaffing */
! 823: player.t_no_move = 2 * movement(&player);
! 824: return(TRUE);
! 825: }
! 826:
! 827: item = player.t_using;
! 828: /* We've waited our time, let's shoot 'em up! */
! 829: player.t_using = NULL;
! 830: player.t_action = A_NIL;
! 831:
! 832: obj = OBJPTR(item);
! 833:
! 834: /* Handle relics specially here */
! 835: if (obj->o_type == RELIC) {
! 836: switch (obj->o_which) {
! 837: case ORCUS_WAND:
! 838: msg(nothing);
! 839: return(TRUE);
! 840: when MING_STAFF:
! 841: which = WS_MISSILE;
! 842: when EMORI_CLOAK:
! 843: which = WS_PARALYZE;
! 844: obj->o_charges = 0; /* one zap/day(whatever that is) */
! 845: fuse(cloak_charge, obj, CLOAK_TIME, AFTER);
! 846: when ASMO_ROD:
! 847: switch (rnd(3)) {
! 848: case 0: which = WS_ELECT;
! 849: when 1: which = WS_COLD;
! 850: otherwise: which = WS_FIRE;
! 851: }
! 852: }
! 853: }
! 854: else {
! 855: which = obj->o_which;
! 856: ws_know[which] = TRUE;
! 857: flag = obj->o_flags;
! 858: }
! 859: }
! 860: do_zap(&player, obj, &player.t_newpos, which, flag);
! 861: return(TRUE);
! 862: }
! 863:
! 864:
! 865: /*
! 866: * shoot_bolt fires a bolt from the given starting point in the
! 867: * given direction
! 868: */
! 869:
! 870: void
! 871: shoot_bolt(struct thing *shooter, coord start, coord dir, bool get_points,
! 872: short reason, char *name, int damage)
! 873: {
! 874: register char dirch, ch;
! 875: register bool used, change;
! 876: register short y, x, bounces;
! 877: coord pos;
! 878: struct linked_list *target=NULL;
! 879: struct {
! 880: coord place;
! 881: char oldch;
! 882: } spotpos[BOLT_LENGTH];
! 883:
! 884: switch (dir.y + dir.x) {
! 885: case 0: dirch = '/';
! 886: when 1: case -1: dirch = (dir.y == 0 ? '-' : '|');
! 887: when 2: case -2: dirch = '\\';
! 888: }
! 889: pos.y = start.y + dir.y;
! 890: pos.x = start.x + dir.x;
! 891: used = FALSE;
! 892: change = FALSE;
! 893:
! 894: bounces = 0; /* No bounces yet */
! 895: for (y = 0; y < BOLT_LENGTH && !used; y++)
! 896: {
! 897: ch = CCHAR( winat(pos.y, pos.x) );
! 898: spotpos[y].place = pos;
! 899: spotpos[y].oldch = CCHAR( mvwinch(cw, pos.y, pos.x) );
! 900:
! 901: /* Are we at hero? */
! 902: if (ce(pos, hero)) goto at_hero;
! 903:
! 904: switch (ch)
! 905: {
! 906: case SECRETDOOR:
! 907: case '|':
! 908: case '-':
! 909: case ' ':
! 910: if (dirch == '-' || dirch == '|') {
! 911: dir.y = -dir.y;
! 912: dir.x = -dir.x;
! 913: }
! 914: else {
! 915: char chx = CCHAR( mvinch(pos.y-dir.y, pos.x) ),
! 916: chy = CCHAR( mvinch(pos.y, pos.x-dir.x) );
! 917: bool anychange = FALSE; /* Did we change anthing */
! 918:
! 919: if (chy == WALL || chy == SECRETDOOR ||
! 920: chy == '-' || chy == '|') {
! 921: dir.y = -dir.y;
! 922: change ^= TRUE; /* Change at least one direction */
! 923: anychange = TRUE;
! 924: }
! 925: if (chx == WALL || chx == SECRETDOOR ||
! 926: chx == '-' || chx == '|') {
! 927: dir.x = -dir.x;
! 928: change ^= TRUE; /* Change at least one direction */
! 929: anychange = TRUE;
! 930: }
! 931:
! 932: /* If we didn't make any change, make both changes */
! 933: if (!anychange) {
! 934: dir.x = -dir.x;
! 935: dir.y = -dir.y;
! 936: }
! 937: }
! 938:
! 939: /* Do we change how the bolt looks? */
! 940: if (change) {
! 941: change = FALSE;
! 942: if (dirch == '\\') dirch = '/';
! 943: else if (dirch == '/') dirch = '\\';
! 944: }
! 945:
! 946: y--; /* The bounce doesn't count as using up the bolt */
! 947:
! 948: /* Make sure we aren't in an infinite bounce */
! 949: if (++bounces > BOLT_LENGTH) used = TRUE;
! 950: msg("The %s bounces", name);
! 951: break;
! 952: default:
! 953: if (isalpha(ch)) {
! 954: register struct linked_list *item;
! 955: register struct thing *tp;
! 956: register char *mname;
! 957: bool see_monster = cansee(pos.y, pos.x);
! 958:
! 959: item = find_mons(unc(pos));
! 960: tp = THINGPTR(item);
! 961: mname = monster_name(tp);
! 962:
! 963: /*
! 964: * If our prey shot this, let's record the fact that
! 965: * he can shoot, regardless of whether he hits us.
! 966: */
! 967: if ((tp->t_dest != NULL) && ce(*tp->t_dest, shooter->t_pos)) tp->t_wasshot = TRUE;
! 968:
! 969: if (!save(VS_BREATH, tp, -(shooter->t_stats.s_lvl/10))) {
! 970: if (see_monster) {
! 971: if (on(*tp, ISDISGUISE) &&
! 972: (tp->t_type != tp->t_disguise)) {
! 973: msg("Wait! That's a %s!", mname);
! 974: turn_off(*tp, ISDISGUISE);
! 975: }
! 976:
! 977: turn_off(*tp, CANSURPRISE);
! 978: msg("The %s hits %s", name, prname(mname, FALSE));
! 979: }
! 980:
! 981: /* Should we start to chase the shooter? */
! 982: if (shooter != &player &&
! 983: shooter != tp &&
! 984: shooter->t_index != tp->t_index &&
! 985: (tp->t_dest == NULL || rnd(100) < 25)) {
! 986: /*
! 987: * If we're intelligent enough to realize that this
! 988: * is a friendly monster, we will attack the hero
! 989: * instead.
! 990: */
! 991: if (on(*shooter, ISFRIENDLY) &&
! 992: roll(3,6) < tp->t_stats.s_intel)
! 993: runto(tp, &hero);
! 994:
! 995: /* Otherwise, let's chase the monster */
! 996: else runto(tp, &shooter->t_pos);
! 997: }
! 998: else if (shooter == &player) {
! 999: runto(tp, &hero);
! 1000:
! 1001: /*
! 1002: * If the player shot a charmed monster, it may
! 1003: * not like being shot at.
! 1004: */
! 1005: if (on(*tp, ISCHARMED) && save(VS_MAGIC, tp, 0)) {
! 1006: msg("The eyes of %s turn clear.",
! 1007: prname(mname, FALSE));
! 1008: turn_off(*tp, ISCHARMED);
! 1009: mname = monster_name(tp);
! 1010: }
! 1011: }
! 1012:
! 1013: /*
! 1014: * Let the defender know that the attacker has
! 1015: * missiles!
! 1016: */
! 1017: if (ce(*tp->t_dest, shooter->t_pos))
! 1018: tp->t_wasshot = TRUE;
! 1019:
! 1020: used = TRUE;
! 1021:
! 1022: /* Hit the monster -- does it do anything? */
! 1023: if ((EQUAL(name,"ice") &&
! 1024: (on(*tp, NOCOLD) || on(*tp, ISUNDEAD))) ||
! 1025: (EQUAL(name,"flame") && on(*tp, NOFIRE)) ||
! 1026: (EQUAL(name,"acid") && on(*tp, NOACID)) ||
! 1027: (EQUAL(name,"lightning bolt")&& on(*tp,NOBOLT)) ||
! 1028: (EQUAL(name,"nerve gas") &&on(*tp,NOPARALYZE))||
! 1029: (EQUAL(name,"sleeping gas") &&
! 1030: (on(*tp, NOSLEEP) || on(*tp, ISUNDEAD))) ||
! 1031: (EQUAL(name,"slow gas") && on(*tp,NOSLOW)) ||
! 1032: (EQUAL(name,"fear gas") && on(*tp,NOFEAR)) ||
! 1033: (EQUAL(name,"confusion gas") && on(*tp,ISCLEAR)) ||
! 1034: (EQUAL(name,"chlorine gas") && on(*tp,NOGAS))) {
! 1035: if (see_monster)
! 1036: msg("The %s has no effect on %s.",
! 1037: name, prname(mname, FALSE));
! 1038: }
! 1039:
! 1040: else {
! 1041: bool see_him;
! 1042:
! 1043: see_him =
! 1044: off(player, ISBLIND) &&
! 1045: cansee(unc(tp->t_pos)) &&
! 1046: (off(*tp, ISINVIS) || on(player, CANSEE)) &&
! 1047: (off(*tp, ISSHADOW)|| on(player, CANSEE)) &&
! 1048: (off(*tp, CANSURPRISE)||ISWEARING(R_ALERT));
! 1049:
! 1050: /* Did a spell get disrupted? */
! 1051: dsrpt_monster(tp, FALSE, see_him);
! 1052:
! 1053: /*
! 1054: * Check for gas with special effects
! 1055: */
! 1056: if (EQUAL(name, "nerve gas")) {
! 1057: tp->t_no_move = movement(tp) * FREEZETIME;
! 1058: tp->t_action = A_FREEZE;
! 1059: }
! 1060: else if (EQUAL(name, "sleeping gas")) {
! 1061: tp->t_no_move = movement(tp) * SLEEPTIME;
! 1062: tp->t_action = A_FREEZE;
! 1063: }
! 1064: else if (EQUAL(name, "slow gas")) {
! 1065: if (on(*tp, ISHASTE))
! 1066: turn_off(*tp, ISHASTE);
! 1067: else
! 1068: turn_on(*tp, ISSLOW);
! 1069: }
! 1070: else if (EQUAL(name, "fear gas")) {
! 1071: turn_on(*tp, ISFLEE);
! 1072: tp->t_dest = &hero;
! 1073:
! 1074: /* It is okay to turn tail */
! 1075: tp->t_oldpos = tp->t_pos;
! 1076: }
! 1077: else if (EQUAL(name, "confusion gas")) {
! 1078: turn_on(*tp, ISHUH);
! 1079: tp->t_dest = &hero;
! 1080: }
! 1081: else if ((EQUAL(name, "lightning bolt")) &&
! 1082: on(*tp, BOLTDIVIDE)) {
! 1083: if (creat_mons(tp, tp->t_index, FALSE)) {
! 1084: if (see_monster)
! 1085: msg("The %s divides %s.",
! 1086: name,prname(mname, FALSE));
! 1087: light(&hero);
! 1088: }
! 1089: else if (see_monster)
! 1090: msg("The %s has no effect on %s.",
! 1091: name, prname(mname, FALSE));
! 1092: }
! 1093: else {
! 1094: if (save(VS_BREATH, tp,
! 1095: -(shooter->t_stats.s_lvl/10)))
! 1096: damage /= 2;
! 1097:
! 1098: /* The poor fellow got killed! */
! 1099: if ((tp->t_stats.s_hpt -= damage) <= 0) {
! 1100: if (see_monster)
! 1101: msg("The %s kills %s",
! 1102: name, prname(mname, FALSE));
! 1103: else
! 1104: msg("You hear a faint groan in the distance");
! 1105: /*
! 1106: * Instead of calling killed() here, we
! 1107: * will record that the monster was killed
! 1108: * and call it at the end of the routine,
! 1109: * after we restore what was under the bolt.
! 1110: * We have to do this because in the case
! 1111: * of a bolt that first misses the monster
! 1112: * and then gets it on the bounce. If we
! 1113: * call killed here, the 'missed' space in
! 1114: * spotpos puts the monster back on the
! 1115: * screen
! 1116: */
! 1117: target = item;
! 1118: }
! 1119: else { /* Not dead, so just scream */
! 1120: if (!see_monster)
! 1121: msg("You hear a scream in the distance");
! 1122: }
! 1123: }
! 1124: }
! 1125: }
! 1126: else if (isalpha(show(pos.y, pos.x))) {
! 1127: if (see_monster) {
! 1128: if (terse)
! 1129: msg("%s misses", name);
! 1130: else
! 1131: msg("The %s whizzes past %s",
! 1132: name, prname(mname, FALSE));
! 1133: }
! 1134: if (get_points) runto(tp, &hero);
! 1135: }
! 1136: }
! 1137: else if (pos.y == hero.y && pos.x == hero.x) {
! 1138: at_hero: if (!save(VS_BREATH, &player,
! 1139: -(shooter->t_stats.s_lvl/10))){
! 1140: if (terse)
! 1141: msg("The %s hits you", name);
! 1142: else
! 1143: msg("You are hit by the %s", name);
! 1144: used = TRUE;
! 1145:
! 1146: /*
! 1147: * The Amulet of Yendor protects against all "breath"
! 1148: *
! 1149: * The following two if statements could be combined
! 1150: * into one, but it makes the compiler barf, so split
! 1151: * it up
! 1152: */
! 1153: if (cur_relic[YENDOR_AMULET] ||
! 1154: (EQUAL(name,"chlorine gas")&&on(player, NOGAS)) ||
! 1155: (EQUAL(name,"sleeping gas")&&ISWEARING(R_ALERT))){
! 1156: msg("The %s has no affect", name);
! 1157: }
! 1158: else if((EQUAL(name, "flame") && on(player, NOFIRE)) ||
! 1159: (EQUAL(name, "ice") && on(player, NOCOLD)) ||
! 1160: (EQUAL(name,"lightning bolt")&&
! 1161: on(player,NOBOLT)) ||
! 1162: (EQUAL(name,"fear gas")&&ISWEARING(R_HEROISM))){
! 1163: msg("The %s has no affect", name);
! 1164: }
! 1165:
! 1166: else {
! 1167: dsrpt_player();
! 1168:
! 1169: /*
! 1170: * Check for gas with special effects
! 1171: */
! 1172: if (EQUAL(name, "nerve gas")) {
! 1173: msg("The nerve gas paralyzes you.");
! 1174: player.t_no_move +=
! 1175: movement(&player) * FREEZETIME;
! 1176: player.t_action = A_FREEZE;
! 1177: }
! 1178: else if (EQUAL(name, "sleeping gas")) {
! 1179: msg("The sleeping gas puts you to sleep.");
! 1180: player.t_no_move +=
! 1181: movement(&player) * SLEEPTIME;
! 1182: player.t_action = A_FREEZE;
! 1183: }
! 1184: else if (EQUAL(name, "confusion gas")) {
! 1185: if (off(player, ISCLEAR)) {
! 1186: if (on(player, ISHUH))
! 1187: lengthen(unconfuse,
! 1188: rnd(20)+HUHDURATION);
! 1189: else {
! 1190: turn_on(player, ISHUH);
! 1191: fuse(unconfuse, NULL,
! 1192: rnd(20)+HUHDURATION, AFTER);
! 1193: msg(
! 1194: "The confusion gas has confused you.");
! 1195: }
! 1196: }
! 1197: else msg("You feel dizzy for a moment, but it quickly passes.");
! 1198: }
! 1199: else if (EQUAL(name, "slow gas")) {
! 1200: add_slow();
! 1201: }
! 1202: else if (EQUAL(name, "fear gas")) {
! 1203: turn_on(player, ISFLEE);
! 1204: player.t_dest = &shooter->t_pos;
! 1205: msg("The fear gas terrifies you.");
! 1206: }
! 1207: else {
! 1208: if (EQUAL(name, "acid") &&
! 1209: cur_armor != NULL &&
! 1210: !(cur_armor->o_flags & ISPROT) &&
! 1211: !save(VS_BREATH, &player, -2) &&
! 1212: cur_armor->o_ac < pstats.s_arm+1) {
! 1213: msg("Your armor corrodes from the acid");
! 1214: cur_armor->o_ac++;
! 1215: }
! 1216: if (save(VS_BREATH, &player,
! 1217: -(shooter->t_stats.s_lvl/10)))
! 1218: damage /= 2;
! 1219: if ((pstats.s_hpt -= damage) <= 0)
! 1220: death(reason);
! 1221: }
! 1222: }
! 1223: }
! 1224: else
! 1225: msg("The %s whizzes by you", name);
! 1226: }
! 1227:
! 1228: mvwaddch(cw, pos.y, pos.x, dirch);
! 1229: draw(cw);
! 1230: }
! 1231:
! 1232: pos.y += dir.y;
! 1233: pos.x += dir.x;
! 1234: }
! 1235:
! 1236: /* Restore what was under the bolt */
! 1237: for (x = y - 1; x >= 0; x--)
! 1238: mvwaddch(cw, spotpos[x].place.y, spotpos[x].place.x, spotpos[x].oldch);
! 1239:
! 1240: /* If we killed something, do so now. This will also blank the monster. */
! 1241: if (target) killed(target, FALSE, get_points, TRUE);
! 1242: return;
! 1243: }
CVSweb