Annotation of early-roguelike/urogue/sticks.c, Revision 1.1.1.1
1.1 rubenllo 1: /*
2: sticks.c - Functions to implement the various sticks one might find
3:
4: UltraRogue: The Ultimate Adventure in the Dungeons of Doom
5: Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
6: All rights reserved.
7:
8: Based on "Advanced Rogue"
9: Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
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 <limits.h>
20: #include <string.h>
21: #include <ctype.h>
22: #include "rogue.h"
23:
24: /* for WS_HIT, WS_WEB, etc */
25:
26: static struct object null_stick =
27: {
28: {0,0},NULL,NULL,"",0,"0d0",0,0,'X',0,0,0,0,0,0,0,0,0,{0}
29: };
30:
31: /*
32: * Mask for cancelling special abilities The flags listed here will be the
33: * ones left on after the cancellation takes place
34: */
35:
36: #define CANC0MASK ( ISBLIND | ISINWALL | ISRUN | \
37: ISFLEE | ISMEAN | ISGREED | \
38: CANSHOOT | ISHELD | ISHUH | \
39: ISSLOW | ISHASTE | ISCLEAR | \
40: ISUNIQUE)
41:
42: #define CANC1MASK ( HASDISEASE | DIDSUFFOCATE | CARRYGOLD | \
43: HASITCH | CANSELL | CANBBURN | \
44: CANSPEAK | CANFLY | ISFRIENDLY)
45:
46: #define CANC2MASK ( HASINFEST | NOMOVE | ISSCAVENGE | \
47: DOROT | HASSTINK | DIDHOLD)
48:
49: #define CANC3MASK ( ISUNDEAD | CANBREATHE | CANCAST | \
50: HASOXYGEN)
51:
52: #define CANC4MASK ( CANTRAMPLE | CANSWIM | CANWIELD | \
53: ISFAST | CANBARGAIN | CANSPORE | \
54: ISLARGE | ISSMALL | ISFLOCK | \
55: ISSWARM | CANSTICK | CANTANGLE | \
56: SHOOTNEEDLE | CANZAP | HASARMOR | \
57: CANTELEPORT | ISBERSERK | ISFAMILIAR | \
58: HASFAMILIAR | SUMMONING)
59:
60: #define CANC5MASK ( CANREFLECT | MAGICATTRACT | HASSHIELD | HASMSHIELD)
61:
62: #define CANC6MASK ( 0 )
63: #define CANC7MASK ( 0 )
64: #define CANC8MASK ( 0 )
65: #define CANC9MASK ( 0 )
66: #define CANCAMASK ( 0 )
67: #define CANCBMASK ( 0 )
68: #define CANCCMASK ( 0 )
69: #define CANCDMASK ( 0 )
70: #define CANCEMASK ( 0 )
71: #define CANCFMASK ( 0 )
72:
73: void
74: fix_stick(struct object *cur)
75: {
76: if (strcmp(ws_type[cur->o_which], "staff") == 0)
77: {
78: cur->o_weight = 100;
79: cur->o_charges = 5 + rnd(10);
80: cur->o_damage = "2d3";
81:
82: switch (cur->o_which)
83: {
84: case WS_HIT:
85: cur->o_hplus = 3;
86: cur->o_dplus = 3;
87: cur->o_damage = "2d8";
88: break;
89:
90: case WS_LIGHT:
91: cur->o_charges = 20 + rnd(10);
92: break;
93: }
94: }
95: else /* A wand */
96: {
97: cur->o_damage = "1d3";
98: cur->o_weight = 60;
99: cur->o_charges = 3 + rnd(5);
100:
101: switch (cur->o_which)
102: {
103: case WS_HIT:
104: cur->o_hplus = 3;
105: cur->o_dplus = 3;
106: cur->o_damage = "1d8";
107: break;
108:
109: case WS_LIGHT:
110: cur->o_charges = 10 + rnd(10);
111: break;
112: }
113: }
114:
115: cur->o_hurldmg = "1d1";
116: }
117:
118: /*
119: do_zap()
120: zap a stick (or effect a stick-like spell)
121: zapper: who does it
122: got_dir: need to ask for direction?
123: which: which WS_STICK (-1 means ask from pack)
124: flags: ISBLESSED, ISCURSED
125: */
126:
127: void
128: do_zap(struct thing *zapper, int which, unsigned long flags)
129: {
130: struct linked_list *item = NULL, *nitem;
131: struct object *obj, *nobj;
132: struct room *rp;
133: struct thing *tp = NULL;
134: char *mname = NULL;
135: int y, x;
136: int blessed = flags & ISBLESSED;
137: int cursed = flags & ISCURSED;
138: int is_stick = (which < 0 ? TRUE : FALSE);
139: int got_one = TRUE;
140:
141: if (zapper != &player)
142: {
143: monster_do_zap(zapper, which, flags);
144: return;
145: }
146:
147: if (is_stick)
148: {
149: if ((obj = get_object(pack, "zap with", 0, bff_zappable)) == NULL)
150: return;
151:
152: if (obj->o_type != STICK && !(obj->o_flags & ISZAPPED))
153: {
154: msg("You can't zap with that!");
155: return;
156: }
157:
158: if (obj->o_type != STICK) /* an electrified weapon */
159: which = WS_ELECT;
160: else
161: which = obj->o_which;
162:
163: if (obj->o_charges < 1)
164: {
165: nothing_message(flags);
166: return;
167: }
168:
169: obj->o_charges--;
170:
171: if (delta.y == 0 && delta.x == 0)
172: do
173: {
174: delta.y = rnd(3) - 1;
175: delta.x = rnd(3) - 1;
176: }
177: while (delta.y == 0 && delta.x == 0);
178:
179: flags = obj->o_flags;
180: cursed = obj->o_flags & ISCURSED;
181: blessed = obj->o_flags & ISBLESSED;
182: }
183: else
184: obj = &null_stick;
185:
186: /* Find out who the target is */
187:
188: y = hero.y;
189: x = hero.x;
190:
191: while(shoot_ok(CCHAR(winat(y, x))))
192: {
193: y += delta.y;
194: x += delta.x;
195: }
196:
197: if (x >= 0 && x < COLS && y >= 1 && y < LINES - 2 &&
198: isalpha(mvwinch(mw, y, x)))
199: {
200: item = find_mons(y, x);
201: tp = THINGPTR(item);
202: mname = on(player, ISBLIND) ? "monster" :
203: monsters[tp->t_index].m_name;
204:
205: if (on(*tp, CANSELL))
206: {
207: luck++;
208: aggravate();
209: }
210: }
211: else
212: got_one = FALSE;
213:
214: debug("Zapping with %d", which);
215:
216: switch(which)
217: {
218: case WS_LIGHT:
219: /* Reddy Kilowat wand. Light up the room */
220: if (blue_light(flags) && is_stick)
221: if (is_stick)
222: know_items[TYP_STICK][WS_LIGHT] = TRUE;
223: break;
224:
225: case WS_DRAIN:
226:
227: /*
228: * Take away 1/2 of hero's hit points, then take it away
229: * evenly from the monsters in the room or next to hero if he
230: * is in a passage. Leave the monsters alone if the stick is
231: * cursed. Drain 1/3rd of hero's hit points if blessed.
232: */
233:
234: if (pstats.s_hpt < 2)
235: {
236: death(D_DRAINLIFE);
237: return;
238: }
239:
240: if (cursed)
241: pstats.s_hpt /= 2;
242: else if ((rp = roomin(hero)) == NULL)
243: drain(hero.y - 1, hero.y + 1, hero.x - 1, hero.x + 1);
244: else
245: drain(rp->r_pos.y, rp->r_pos.y + rp->r_max.y,
246: rp->r_pos.x, rp->r_pos.x + rp->r_max.x);
247:
248: if (blessed)
249: pstats.s_hpt = (int) (pstats.s_hpt * 2.0 / 3.0);
250:
251: break;
252:
253: case WS_POLYMORPH:
254: case WS_MONSTELEP:
255: case WS_CANCEL:
256: {
257: char oldch;
258: int rm;
259: int save_adj = 0;
260:
261: if (got_one)
262: {
263: /* if the monster gets the saving throw, leave the case */
264:
265: if (blessed)
266: save_adj = -5;
267:
268: if (cursed)
269: if (which == WS_POLYMORPH)
270: save_adj = -5; /* not save vs becoming tougher */
271: else
272: save_adj = 5;
273:
274: if (save_throw(VS_MAGIC - save_adj, tp))
275: {
276: nothing_message(flags);
277: break;
278: }
279: else if (is_stick)
280: know_items[TYP_STICK][which] = TRUE;
281:
282: /* Unhold player */
283:
284: if (on(*tp, DIDHOLD))
285: {
286: turn_off(*tp, DIDHOLD);
287:
288: if (--hold_count == 0)
289: turn_off(player, ISHELD);
290: }
291:
292: /* unsuffocate player */
293:
294: if (on(*tp, DIDSUFFOCATE))
295: {
296: turn_off(*tp, DIDSUFFOCATE);
297: extinguish_fuse(FUSE_SUFFOCATE);
298: }
299:
300: if (which == WS_POLYMORPH)
301: {
302: int which_new;
303: int charmed;
304:
305: detach(mlist, item);
306: charmed = on(*tp, ISCHARMED);
307: oldch = tp->t_oldch;
308: delta.y = y;
309: delta.x = x;
310:
311: if (!blessed && !cursed)
312: which_new = randmonster(WANDER, GRAB);
313: else
314: {
315: /* duplicate randmonster() for now */
316: /* Eventually fix to take level */
317:
318: int cur_level = 0, range, i;
319:
320: if (blessed)
321: cur_level = level / 2;
322:
323: if (cursed)
324: cur_level = level * 2;
325:
326: range = 4 * NLEVMONS;
327: i = 0;
328:
329: do
330: {
331: if (i++ > range * 10) /* just in case all have */
332: { /* been genocided */
333: i = 0;
334:
335: if (--cur_level <= 0)
336: fatal("Rogue could not find a monster to make");
337: }
338:
339: which_new = NLEVMONS * (cur_level - 1) + (rnd(range) - (range - 1 - NLEVMONS));
340:
341: if (which_new < 1)
342: which_new = rnd(NLEVMONS) + 1;
343:
344: if (which_new > nummonst - NUMSUMMON - 1)
345: {
346: if (blessed)
347: which_new = rnd(range) + (nummonst - NUMSUMMON - 1) - (range - 1);
348: else if (which_new > nummonst - 1)
349: which_new = rnd(range + NUMSUMMON) + (nummonst - 1) - (range + NUMSUMMON - 1);
350: }
351: }
352: while (!monsters[which_new].m_normal);
353: }
354:
355: new_monster(item, which_new, &delta, NOMAXSTATS);
356: mname = on(player, ISBLIND) ? "monster" : monsters[tp->t_index].m_name;
357:
358: if (!cursed && charmed)
359: turn_on(*tp, ISCHARMED);
360:
361: if (off(*tp, ISRUN))
362: chase_it(&delta, &player);
363:
364: if (isalpha(mvwinch(cw, y, x)))
365: mvwaddch(cw, y, x, tp->t_type);
366:
367: tp->t_oldch = oldch;
368: seemsg("You have created a new %s!", mname);
369: }
370: else if (which == WS_CANCEL)
371: {
372: tp->t_flags[0] &= CANC0MASK;
373: tp->t_flags[1] &= CANC1MASK;
374: tp->t_flags[2] &= CANC2MASK;
375: tp->t_flags[3] &= CANC3MASK;
376: tp->t_flags[4] &= CANC4MASK;
377: tp->t_flags[5] &= CANC5MASK;
378: tp->t_flags[6] &= CANC5MASK;
379: tp->t_flags[7] &= CANC7MASK;
380: tp->t_flags[8] &= CANC8MASK;
381: tp->t_flags[9] &= CANC9MASK;
382: tp->t_flags[10] &= CANCAMASK;
383: tp->t_flags[11] &= CANCBMASK;
384: tp->t_flags[12] &= CANCCMASK;
385: tp->t_flags[13] &= CANCDMASK;
386: tp->t_flags[14] &= CANCEMASK;
387: tp->t_flags[15] &= CANCFMASK;
388: }
389: else /* A teleport stick */
390: {
391: if (cursed) /* Teleport monster to */
392: { /* player */
393: if ((y == (hero.y + delta.y)) &&
394: (x == (hero.x + delta.x)))
395: nothing_message(flags);
396: else
397: {
398: tp->t_pos.y = hero.y + delta.y;
399: tp->t_pos.x = hero.x + delta.x;
400: }
401: }
402: else if (blessed) /* Get rid of monster */
403: {
404: killed(NULL, item, NOMESSAGE, NOPOINTS);
405: return;
406: }
407: else
408: {
409: int i = 0;
410:
411: do /* Move monster to */
412: { /* another room */
413: rm = rnd_room();
414: rnd_pos(&rooms[rm], &tp->t_pos);
415: }
416: while (winat(tp->t_pos.y, tp->t_pos.x) !=
417: FLOOR && i++ < 500);
418: }
419:
420: /* Now move the monster */
421:
422: if (isalpha(mvwinch(cw, y, x)))
423: mvwaddch(cw, y, x, tp->t_oldch);
424:
425: chase_it(&tp->t_pos, &player);
426: mvwaddch(mw, y, x, ' ');
427: mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, tp->t_oldch);
428:
429: if (tp->t_pos.y != y || tp->t_pos.x != x)
430: tp->t_oldch = CCHAR(mvwinch(cw, tp->t_pos.y, tp->t_pos.x));
431: }
432: }
433: }
434: break;
435:
436: case WS_MISSILE:
437: {
438: int damage;
439: int nsides = 4;
440: int ch;
441: coord pos;
442:
443: if (is_stick)
444: know_items[TYP_STICK][which] = TRUE;
445:
446: /* Magic Missiles *always* hit, no saving throw */
447:
448: pos = do_motion('*', delta.y, delta.x, &player);
449: ch = winat(pos.y, pos.x);
450:
451: if (cursed)
452: nsides /= 2;
453: else if (blessed)
454: nsides *= 2;
455:
456: damage = roll(pstats.s_lvl, nsides);
457:
458: if (isalpha(ch))
459: {
460: debug("Missiled %s for %d (%d)",
461: mname, damage, tp->t_stats.s_hpt - damage);
462:
463: if ((tp->t_stats.s_hpt -= damage) <= 0)
464: {
465: seemsg("The missile kills the %s.", mname);
466: killed(&player, item, NOMESSAGE, POINTS);
467: }
468: else
469: {
470: seemsg("The missile hits the %s", mname);
471: chase_it(&pos, &player);
472: summon_help(tp, NOFORCE);
473: }
474: }
475:
476: if (pos.y >= 0 && pos.x >= 0 &&
477: pos.y < LINES && pos.x < COLS)
478: mvwaddch(cw, pos.y, pos.x, show(pos.y, pos.x));
479: }
480: break;
481:
482: case WS_HIT:
483: {
484: coord pos;
485: int ch;
486: struct object strike; /* don't want to change sticks attributes */
487:
488: if (is_stick)
489: know_items[TYP_STICK][which] = TRUE;
490:
491: pos = do_motion('@', delta.y, delta.x, &player);
492: ch = winat(pos.y, pos.x);
493:
494: if (isalpha(ch))
495: {
496: static char buf[20];
497: int nsides, ndice;
498:
499: strike = *obj;
500:
501: if (blessed)
502: strike.o_hplus = 12;
503: else if (cursed)
504: strike.o_hplus = 3;
505: else
506: strike.o_hplus = 6;
507:
508: if (!is_stick || strcmp(ws_type[which], "staff") == 0)
509: ndice = 3;
510: else
511: ndice = 2;
512:
513: if (blessed)
514: nsides = 16;
515: else if (cursed)
516: nsides = 4;
517: else
518: nsides = 8;
519:
520: sprintf(buf, "%dd%d", ndice, nsides);
521:
522: strike.o_damage = buf;
523: fight(&tp->t_pos, &strike, NOTHROWN);
524: }
525: }
526: break;
527:
528: case WS_SLOW_M:
529: if (got_one)
530: {
531: if (cursed)
532: {
533: if (off(*tp, ISSLOW))
534: turn_on(*tp, ISHASTE);
535: else
536: turn_off(*tp, ISSLOW);
537: }
538: else if (blessed)
539: {
540: if (is_stick)
541: know_items[TYP_STICK][which] = TRUE;
542:
543: turn_off(*tp, ISRUN);
544: turn_on(*tp, ISHELD);
545: return;
546: }
547: else
548: {
549: if (is_stick)
550: know_items[TYP_STICK][which] = TRUE;
551:
552: if (off(*tp, ISHASTE))
553: turn_on(*tp, ISSLOW);
554: else
555: turn_off(*tp, ISHASTE);
556:
557: tp->t_turn = TRUE;
558: }
559:
560: delta.y = y;
561: delta.x = x;
562: chase_it(&delta, &player);
563: }
564: break;
565:
566: case WS_CHARGE:
567: if (know_items[TYP_STICK][which] != TRUE && is_stick)
568: {
569: msg("This is a wand of charging.");
570: know_items[TYP_STICK][which] = TRUE;
571: }
572:
573: if ((nitem = get_item("charge", STICK)) != NULL)
574: {
575: nobj = OBJPTR(nitem);
576:
577: if ((nobj->o_charges == 0) && (nobj->o_which != WS_CHARGE))
578: {
579: fix_stick(nobj);
580:
581: if (blessed)
582: nobj->o_charges *= 2;
583: else if (cursed)
584: nobj->o_charges /= 2;
585: }
586: else
587: {
588: if (blessed)
589: nobj->o_charges += 2;
590: else if (cursed)
591: nobj->o_charges -= 1;
592: else
593: nobj->o_charges += 1;
594: }
595: }
596: break;
597:
598: case WS_ELECT:
599: case WS_FIRE:
600: case WS_COLD:
601: {
602: char *name = NULL;
603: int damage;
604: int ndice = 3 + pstats.s_lvl;
605: int nsides;
606:
607: if (is_stick)
608: {
609: know_items[TYP_STICK][which] = TRUE;
610:
611: if (strcmp(ws_type[which], "staff") == 0)
612: nsides = 8;
613: else
614: nsides = 4;
615: }
616: else
617: nsides = 6;
618:
619: if (cursed)
620: nsides /= 2;
621: else if (blessed)
622: nsides *= 2;
623:
624: switch (which)
625: {
626: case WS_ELECT:
627: name = "lightning bolt";
628:
629: if (rnd(2))
630: ndice += rnd(obj->o_charges / 10);
631: else
632: nsides += rnd(obj->o_charges / 10);
633:
634: break;
635:
636: case WS_FIRE:
637: name = "flame";
638: break;
639:
640: case WS_COLD:
641: name = "ice";
642: break;
643: }
644:
645: damage = roll(ndice, nsides);
646: shoot_bolt(&player, hero, delta, POINTS, D_BOLT, name, damage);
647: }
648: break;
649:
650: case WS_ANTIMATTER:
651: {
652: int m1, m2, x1, y1;
653: char ch;
654: struct linked_list *ll;
655: struct thing *lt;
656:
657: if (is_stick)
658: know_items[TYP_STICK][which] = TRUE;
659:
660: y1 = hero.y;
661: x1 = hero.x;
662:
663: do
664: {
665: y1 += delta.y;
666: x1 += delta.x;
667: ch = winat(y1, x1);
668: }
669: while (ch == PASSAGE || ch == FLOOR);
670:
671: for (m1 = x1 - 1; m1 <= x1 + 1; m1++)
672: {
673: for (m2 = y1 - 1; m2 <= y1 + 1; m2++)
674: {
675: ch = winat(m2, m1);
676:
677: if (m1 == hero.x && m2 == hero.y)
678: continue;
679:
680: if (ch != ' ')
681: {
682: ll = find_obj(m2, m1);
683:
684: while (ll != NULL)
685: {
686: rem_obj(ll, TRUE);
687: ll = find_obj(m2, m1);
688: }
689:
690: ll = find_mons(m2, m1);
691:
692: if (ll != NULL)
693: {
694: lt = THINGPTR(ll);
695: if (on(*lt, CANSELL))
696: {
697: luck++;
698: aggravate();
699: }
700:
701: if (off(*lt, CANINWALL))
702: {
703: check_residue(lt);
704: detach(mlist, ll);
705: discard(ll);
706: mvwaddch(mw, m2, m1, ' ');
707: }
708: }
709:
710: mvaddch(m2, m1, ' ');
711: mvwaddch(cw, m2, m1, ' ');
712: }
713: }
714: }
715:
716: touchwin(cw);
717: touchwin(mw);
718: }
719: break;
720:
721: case WS_CONFMON:
722: case WS_PARALYZE:
723: if (got_one)
724: {
725: if (save_throw(VS_MAGIC - (blessed ? 5 : (cursed ? -5 : 0)), tp))
726: nothing_message(flags);
727: else
728: {
729: if (is_stick)
730: know_items[TYP_STICK][which] = TRUE;
731:
732: switch(which)
733: {
734: case WS_CONFMON:
735: seemsg("The %s looks bewildered.", mname);
736: turn_on(*tp, ISHUH);
737: break;
738:
739: case WS_PARALYZE:
740: seemsg("The %s looks stunned.", mname);
741: tp->t_no_move = FREEZETIME;
742: break;
743: }
744: }
745:
746: delta.y = y;
747: delta.x = x;
748: chase_it(&delta, &player);
749: }
750: else
751: nothing_message(flags);
752:
753: break;
754:
755: case WS_XENOHEALING:
756: {
757: int hpt_gain = roll(zapper->t_stats.s_lvl, (blessed ? 8 : 4));
758: int mons_hpt = tp->t_stats.s_hpt;
759:
760: if (got_one)
761: {
762: if (cursed)
763: {
764: if (!save_throw(VS_MAGIC, tp))
765: {
766: if ((mons_hpt -= hpt_gain) <= 0) {
767: seemsg("The %s shrivels up and dies!", mname);
768: killed(&player, item, NOMESSAGE, POINTS);
769: }
770: else
771: seemsg("Wounds appear all over the %s.", mname);
772: }
773: else
774: nothing_message(flags);
775:
776: delta.y = y;
777: delta.x = x;
778: chase_it(&delta, &player);
779: }
780: else
781: {
782: if (is_stick)
783: know_items[TYP_STICK][which] = TRUE;
784:
785: mons_hpt = min(mons_hpt + hpt_gain, tp->maxstats.s_hpt);
786: seemsg("The %s appears less wounded!", mname);
787: }
788: }
789: else
790: nothing_message(flags);
791: }
792: break;
793:
794: case WS_DISINTEGRATE:
795: if (got_one)
796: {
797: if (cursed)
798: {
799: if (on(*tp, ISUNIQUE))
800: {
801: if (on(*tp, CANSUMMON))
802: summon_help(tp, FORCE);
803: else
804: msg("The %s is very upset.", mname);
805:
806: turn_on(*tp, ISHASTE);
807: }
808: else
809: {
810: int m1, m2;
811: coord mp;
812: struct linked_list *titem;
813: int ch;
814: struct thing *th;
815:
816: for (m1 = tp->t_pos.x - 1; m1 <= tp->t_pos.x + 1; m1++)
817: {
818: for (m2 = tp->t_pos.y - 1; m2 <= tp->t_pos.y + 1; m2++)
819: {
820: ch = winat(m2, m1);
821:
822: if (shoot_ok(ch) && ch != PLAYER)
823: {
824: mp.x = m1; /* create it */
825: mp.y = m2;
826: titem = new_item(sizeof(struct thing));
827: new_monster(titem, (short) tp->t_index, &mp, NOMAXSTATS);
828: th = THINGPTR(titem);
829: turn_on(*th, ISMEAN);
830: chase_it(&mp, &player);
831: }
832: }
833: }
834: }
835:
836: delta.y = y;
837: delta.x = x;
838: turn_on(*tp, ISMEAN);
839: chase_it(&delta, &player);
840: }
841: else /* if its a UNIQUE it might still live */
842: {
843: if (is_stick)
844: know_items[TYP_STICK][which] = TRUE;
845:
846: if (on(*tp, ISUNIQUE) &&
847: save_throw(VS_MAGIC - (blessed ? -5 : 0), tp))
848: {
849: tp->t_stats.s_hpt = tp->t_stats.s_hpt / 2 - 1;
850:
851: if (tp->t_stats.s_hpt < 1)
852: {
853: killed(&player, item, NOMESSAGE, POINTS);
854: seemsg("The %s fades away.", mname);
855: }
856: else
857: {
858: delta.y = y;
859: delta.x = x;
860:
861: chase_it(&delta, &player);
862:
863: if (on(*tp, CANSUMMON))
864: summon_help(tp, FORCE);
865: else
866: seemsg("The %s is very upset.", mname);
867: }
868: }
869: else
870: {
871: if (on(*tp, CANSELL))
872: {
873: luck++;
874: aggravate();
875: }
876: seemsg("The %s turns to dust and blows away.", mname);
877: killed(&player, item, NOMESSAGE, POINTS);
878: }
879: }
880: }
881: break;
882:
883: case WS_NOTHING:
884: nothing_message(flags);
885: break;
886:
887: case WS_INVIS:
888: {
889: if (cursed)
890: {
891: int x1, y1, x2, y2;
892: int zapped = FALSE;
893:
894: if ((rp = roomin(hero)) == NULL)
895: {
896: x1 = max(hero.x - 1, 0);
897: y1 = max(hero.y - 1, 0);
898: x2 = min(hero.x + 1, COLS - 1);
899: y2 = min(hero.y + 1, LINES - 3);
900: }
901: else
902: {
903: x1 = rp->r_pos.x;
904: y1 = rp->r_pos.y;
905: x2 = rp->r_pos.x + rp->r_max.x;
906: y2 = rp->r_pos.y + rp->r_max.y;
907: }
908:
909: for (item = mlist; item != NULL; item = next(item))
910: {
911: tp = THINGPTR(item);
912:
913: if (tp->t_pos.x >= x1 && tp->t_pos.x <= x2 &&
914: tp->t_pos.y >= y1 && tp->t_pos.y <= y2)
915: {
916: turn_on(*tp, ISINVIS);
917: turn_on(*tp, ISRUN);
918: turn_off(*tp, ISDISGUISE);
919: chase_it(&tp->t_pos, &player);
920: zapped = TRUE;
921: }
922: }
923:
924: if (zapped)
925: seemsg("The monsters seem to have all disappeared.");
926: else
927: nothing_message(flags);
928: }
929: else
930: {
931: if (got_one)
932: {
933: if (is_stick)
934: know_items[TYP_STICK][which] = TRUE;
935:
936: if (blessed)
937: {
938: turn_off(*tp, ISINVIS);
939: turn_off(*tp, ISSHADOW);
940: seemsg("The %s appears.", mname);
941: }
942: else
943: {
944: turn_on(*tp, ISINVIS);
945: seemsg("The %s disappears.", mname);
946: }
947: }
948: else
949: nothing_message(flags);
950: }
951: light(&hero);
952: }
953: break;
954:
955: case WS_BLAST:
956: {
957: int ch;
958: struct linked_list *itm, *ip;
959: struct object *ob;
960: struct trap *trp;
961:
962: if (is_stick)
963: know_items[TYP_STICK][which] = TRUE;
964:
965: itm = spec_item(WEAPON, GRENADE, 0, 0);
966: ob = OBJPTR(itm);
967: ob->o_count = 1;
968: ob->o_flags |= ISKNOW;
969: hearmsg("BOOOM!");
970: aggravate();
971: ob->o_pos.x = hero.x;
972: ob->o_pos.y = hero.y;
973:
974: for (;;)
975: {
976: ob->o_pos.y += delta.y;
977: ob->o_pos.x += delta.x;
978:
979: if (!ce(ob->o_pos, hero) &&
980: cansee(ob->o_pos.y, ob->o_pos.x) &&
981: mvwinch(cw, ob->o_pos.y, ob->o_pos.x) != ' ')
982: {
983: mvwaddch(cw, ob->o_pos.y, ob->o_pos.x,
984: show(ob->o_pos.y, ob->o_pos.x));
985: }
986:
987: if (shoot_ok(ch = winat(ob->o_pos.y, ob->o_pos.x))
988: && ch != DOOR && !ce(ob->o_pos, hero))
989: {
990: if (cansee(ob->o_pos.y, ob->o_pos.x) &&
991: ntraps + 1 < 2 * MAXTRAPS &&
992: mvwinch(cw, ob->o_pos.y, ob->o_pos.x) != ' ')
993: {
994: mvwaddch(cw, ob->o_pos.y, ob->o_pos.x,TRAPDOOR);
995: wrefresh(cw);
996: }
997:
998: if (isatrap(ch))
999: {
1000: trp = trap_at(ob->o_pos.y, ob->o_pos.x);
1001:
1002: if (trp != NULL)
1003: {
1004: trp->tr_type = TRAPDOOR;
1005: trp->tr_flags |= ISFOUND;
1006: trp->tr_show = TRAPDOOR;
1007: }
1008: }
1009: else if (isalpha(ch))
1010: hit_monster(ob->o_pos.y, ob->o_pos.x, ob, &player);
1011: else if ((ch == FLOOR || ch == PASSAGE)
1012: && ntraps + 1 < 2 * MAXTRAPS)
1013: {
1014: mvaddch(ob->o_pos.y, ob->o_pos.x, TRAPDOOR);
1015: traps[ntraps].tr_type = TRAPDOOR;
1016: traps[ntraps].tr_flags = ISFOUND;
1017: traps[ntraps].tr_show = TRAPDOOR;
1018: traps[ntraps].tr_pos.y = ob->o_pos.y;
1019: traps[ntraps++].tr_pos.x = ob->o_pos.x;
1020: }
1021: else if (ch == POTION || ch == SCROLL || ch == FOOD
1022: || ch == WEAPON || ch == RING || ch == ARMOR
1023: || ch == STICK || ch == ARTIFACT || ch == GOLD)
1024: {
1025: ip = find_obj(ob->o_pos.y, ob->o_pos.x);
1026:
1027: while (ip) /* BOOM destroys all stacked objects */
1028: {
1029: rem_obj(ip, TRUE);
1030: ip = find_obj(ob->o_pos.y, ob->o_pos.x);
1031: }
1032:
1033: mvaddch(ob->o_pos.y, ob->o_pos.x,
1034: (roomin(ob->o_pos) == NULL ? PASSAGE : FLOOR) );
1035: }
1036: continue;
1037: }
1038: break;
1039: }
1040: discard(itm);
1041: }
1042: break;
1043:
1044: case WS_WEB:
1045: {
1046: int ch;
1047: coord pos;
1048:
1049: if (is_stick)
1050: know_items[TYP_STICK][which] = TRUE;
1051:
1052: pos = do_motion('#', delta.y, delta.x, &player);
1053: ch = winat(pos.y, pos.x);
1054:
1055: if (isalpha(ch))
1056: {
1057: if (save_throw(VS_MAGIC, tp))
1058: seemsg("The %s evades your web.", mname);
1059: else
1060: {
1061: seemsg("The %s is webbed.", mname);
1062: turn_off(*tp, ISRUN);
1063: turn_on(*tp, ISHELD);
1064: }
1065: }
1066:
1067: if (pos.y >= 0 && pos.x >= 0 &&
1068: pos.y < LINES && pos.x < COLS)
1069: mvwaddch(cw, pos.y, pos.x, show(pos.y, pos.x));
1070: }
1071: break;
1072:
1073: case WS_KNOCK:
1074: case WS_CLOSE:
1075: if (blessed) /* Do all doors in room */
1076: {
1077: char new_door = (which == WS_KNOCK ? DOOR : SECRETDOOR);
1078: struct room *rmp = roomin(hero);
1079:
1080: if (rmp != NULL)
1081: for (x = 0; x < rmp->r_nexits; x++)
1082: {
1083: move(rmp->r_exit[x].y, rmp->r_exit[x].x);
1084: addch(new_door);
1085: }
1086: else /* Do all adjacent doors */
1087: for (x = hero.x - 1; x <= hero.x + 1; x++)
1088: for (y = hero.y - 1; y <= hero.y + 1; y++)
1089: switch(CCHAR( winat(y, x) ))
1090: {
1091: case DOOR:
1092: case SECRETDOOR:
1093: addch(new_door);
1094: break;
1095: }
1096: light(&hero);
1097: }
1098: else if (cursed)/* do opposite spell */
1099: do_zap(zapper, (which == WS_KNOCK ? WS_CLOSE : WS_KNOCK), ISBLESSED);
1100: else
1101: {
1102: coord zap_loc;
1103: char loc;
1104:
1105: zap_loc.y = hero.y + delta.y;
1106: zap_loc.x = hero.x + delta.x;
1107: loc = winat(zap_loc.y, zap_loc.x);
1108:
1109: switch (loc)
1110: {
1111: case SECRETDOOR:
1112: if (which == WS_KNOCK)
1113: {
1114: mvaddch(zap_loc.y, zap_loc.x, DOOR);
1115: seemsg("A secret door stands revealed before you!");
1116:
1117: if (is_stick)
1118: know_items[TYP_STICK][which] = TRUE;
1119: }
1120: else
1121: nothing_message(flags);
1122: break;
1123:
1124: case DOOR:
1125:
1126: if (which == WS_CLOSE)
1127: {
1128: mvaddch(zap_loc.y, zap_loc.x, SECRETDOOR);
1129: msg("You sucessfully block off the door.")
1130: ;
1131: if (is_stick)
1132: know_items[TYP_STICK][which] = TRUE;
1133: }
1134: else
1135: nothing_message(flags);
1136:
1137: break;
1138:
1139: default:
1140: nothing_message(flags);
1141: }
1142: }
1143:
1144: break;
1145: default:
1146: msg("What a bizarre schtick!");
1147: }
1148: }
1149:
1150: /*
1151: drain()
1152: Do drain hit points from player shtick
1153: */
1154:
1155: void
1156: drain(int ymin, int ymax, int xmin, int xmax)
1157: {
1158: int i, j, cnt;
1159: struct thing *ick;
1160: struct linked_list *item;
1161:
1162: /* First count how many things we need to spread the hit points among */
1163:
1164: for (cnt = 0, i = ymin; i <= ymax; i++)
1165: for (j = xmin; j <= xmax; j++)
1166: if (isalpha(mvwinch(mw, i, j)))
1167: cnt++;
1168:
1169: if (cnt == 0)
1170: {
1171: msg("You have a tingling feeling.");
1172: return;
1173: }
1174: else
1175: msg("You feel weaker.");
1176:
1177: cnt = pstats.s_hpt / cnt;
1178: pstats.s_hpt /= 2;
1179:
1180: /* Now zot all of the monsters */
1181:
1182: for (i = ymin; i <= ymax; i++)
1183: for (j = xmin; j <= xmax; j++)
1184: if (isalpha(mvwinch(mw, i, j)) && ((item = find_mons(i, j)) != NULL))
1185: {
1186: ick = THINGPTR(item);
1187:
1188: if (on(*ick, CANSELL))
1189: {
1190: luck++;
1191: aggravate();
1192: }
1193:
1194: if ((ick->t_stats.s_hpt -= cnt) < 1)
1195: killed(&player, item,
1196: cansee(i, j) && !on(*ick, ISINVIS), POINTS);
1197: }
1198: }
1199:
1200: /*
1201: charge_str()
1202: charge a wand for wizards.
1203: */
1204:
1205: char *
1206: charge_str(struct object *obj, char *buf)
1207: {
1208: if (buf == NULL)
1209: return( "[UltraRogue Bug #103]" );
1210:
1211: if (!(obj->o_flags & ISKNOW))
1212: buf[0] = '\0';
1213: else if (obj->o_charges == 1)
1214: sprintf(buf, " [%d charge]", obj->o_charges);
1215: else
1216: sprintf(buf, " [%d charges]", obj->o_charges);
1217:
1218: return(buf);
1219: }
1220:
1221:
1222: /*
1223: shoot_bolt()
1224: fires a bolt from the given starting point in the given direction
1225: struct thing *shooter;
1226: coord start, dir;
1227: int get_points; should player get exp points?
1228: short reason; reason for dying
1229: char *name; fire, nerve, cold, etc
1230: int damage; make zapee suffer
1231: */
1232:
1233: void
1234: shoot_bolt(struct thing *shooter, coord start, coord dir, int get_points, int reason, char *name, int damage)
1235: {
1236: int ch;
1237: char dirch;
1238: int change;
1239: short y, x;
1240: coord pos;
1241: coord spotpos[BOLT_LENGTH + 1];
1242: int ret_val = FALSE;/* True if breathing monster gets killed */
1243: struct linked_list *item;
1244: struct thing *tp;
1245: char *mname;
1246: int bounced; /* where along BOLT_LENGTH it hit a wall */
1247: int player_damage; /* damage if player saved */
1248: int no_effect; /* zap does not effect zappee */
1249: int take_that[BOLT_LENGTH + 1]; /* damage to each monster */
1250:
1251: /* last spot for player */
1252:
1253: debug("%s does %d damage", name, damage);
1254:
1255: switch (dir.y + dir.x)
1256: {
1257: case 0:
1258: dirch = '/';
1259: break;
1260:
1261: case 1:
1262: case -1:
1263: dirch = (dir.y == 0 ? '-' : '|');
1264: break;
1265:
1266: case 2:
1267: case -2:
1268: dirch = '\\';
1269: break;
1270: }
1271:
1272: pos.y = start.y + dir.y;
1273: pos.x = start.x + dir.x;
1274: change = FALSE;
1275:
1276: for (y = 0; y < BOLT_LENGTH + 1; y++)
1277: take_that[y] = 0;
1278:
1279: bounced = 0;
1280:
1281: for (y = 0; y < BOLT_LENGTH; y++)
1282: {
1283: no_effect = FALSE;
1284: ch = winat(pos.y, pos.x);
1285: spotpos[y] = pos;
1286:
1287: /* Bolt damage dimishes over space */
1288:
1289: damage = max(1, damage - (y / 3));
1290:
1291: /* Are we at hero? */
1292:
1293: if (ce(pos, hero))
1294: goto at_hero;
1295:
1296: switch(ch)
1297: {
1298: case SECRETDOOR:
1299: case '|':
1300: case '-':
1301: case ' ':
1302: bounced = y;
1303: if (dirch == '-' || dirch == '|')
1304: {
1305: dir.y = -dir.y;
1306: dir.x = -dir.x;
1307: }
1308: else
1309: switch (ch)
1310: {
1311: case '|':
1312: case '-':
1313: case SECRETDOOR:
1314: {
1315: struct room *rp;
1316:
1317: rp = roomin(pos);
1318:
1319: if (pos.y == rp->r_pos.y ||
1320: pos.y == rp->r_pos.y + rp->r_max.y - 1)
1321: {
1322: dir.y = -dir.y;
1323: change ^= TRUE;
1324: }
1325:
1326: if (pos.x == rp->r_pos.x ||
1327: pos.x == rp->r_pos.x + rp->r_max.x - 1)
1328: {
1329: dir.x = -dir.x;
1330: change ^= TRUE;
1331: }
1332: }
1333: default: /* A wall */
1334: {
1335: char chy = CCHAR( mvinch(pos.y - dir.y, pos.x + dir.x)), chx = CCHAR( mvinch(pos.y + dir.y, pos.x - dir.x) );
1336:
1337: if (chy != WALL && chy != SECRETDOOR &&
1338: chy != '-' && chy != '|')
1339: {
1340: dir.y = -dir.y;
1341: change = TRUE;
1342: }
1343: else if (chx != WALL && chx != SECRETDOOR &&
1344: chx != '-' && chx != '|')
1345: {
1346: dir.x = -dir.x;
1347: change = TRUE;
1348: }
1349: else
1350: {
1351: dir.y = -dir.y;
1352: dir.x = -dir.x;
1353: }
1354: }
1355: }
1356:
1357: /* Do we change how the bolt looks? */
1358:
1359: if (change)
1360: {
1361: change = FALSE;
1362:
1363: if (dirch == '\\')
1364: dirch = '/';
1365: else if (dirch == '/')
1366: dirch = '\\';
1367: }
1368:
1369: break;
1370:
1371: default:
1372: if (isalpha(ch)) /* hit a monster */
1373: {
1374: item = find_mons(pos.y, pos.x);
1375:
1376: if (item == NULL)
1377: {
1378: debug("Can't find monster %c @ %d %d.",
1379: ch, pos.y, pos.x);
1380:
1381: continue;
1382: }
1383:
1384: tp = THINGPTR(item);
1385: mname = on(player, ISBLIND) ? "monster" : monsters[tp->t_index].m_name;
1386:
1387: /* Disguised monsters stay hidden if they save */
1388:
1389: if (on(*tp, ISDISGUISE) && save_throw(VS_MAGIC, tp) &&
1390: (tp->t_type != tp->t_disguise) && off(player, ISBLIND))
1391: {
1392: msg("Wait! That's a %s!", mname);
1393: turn_off(*tp, ISDISGUISE);
1394: }
1395:
1396: tp->t_wasshot = TRUE;
1397:
1398: if (on(*tp, CANSELL))
1399: {
1400: luck++;
1401: aggravate();
1402: }
1403:
1404: /* Hit the monster -- does it do damage? */
1405:
1406: if (strcmp(name, "ice") == 0)
1407: {
1408: if (on(*tp, NOCOLD) || on(*tp, ISUNDEAD))
1409: no_effect = TRUE;
1410: }
1411: else if (strcmp(name, "flame") == 0)
1412: {
1413: if (on(*tp, NOFIRE))
1414: no_effect = TRUE;
1415:
1416: if (on(*tp, CANBBURN))
1417: {
1418: seemsg("The %s is burned to death by the flame.",
1419: mname);
1420:
1421: take_that[y] += tp->t_stats.s_hpt + 1;
1422: ret_val = TRUE;
1423: }
1424: }
1425: else if (strcmp(name, "lightning bolt") == 0)
1426: {
1427: if (on(*tp, NOBOLT))
1428: no_effect = TRUE;
1429:
1430: if (on(*tp, BOLTDIVIDE))
1431: {
1432: no_effect = TRUE;
1433:
1434: if (creat_mons(tp, tp->t_index, NOMESSAGE))
1435: seemsg("The %s divides the %s.", name, mname);
1436: }
1437: }
1438:
1439: if (no_effect == TRUE)
1440: {
1441: msg("The %s has no effect on the %s.", name,
1442: on(player, ISBLIND) ? "monster" : mname);
1443: }
1444: else
1445: {
1446: take_that[(bounced ? bounced-- : y)] +=
1447: save_throw(VS_MAGIC, tp) ? damage / 2 : damage;
1448: }
1449: }
1450: else if (pos.y == hero.y && pos.x == hero.x)
1451: {
1452: at_hero:
1453: player_damage = damage;
1454: running = fighting = FALSE;
1455: bounced = 0;
1456:
1457: if (cur_armor != NULL &&
1458: cur_armor->o_which == CRYSTAL_ARMOR &&
1459: (strcmp(name, "acid") == 0))
1460: {
1461: player_damage = 0;
1462: msg("The acid splashes harmlessly against your armor!");
1463: }
1464: else if (((cur_armor != NULL &&
1465: cur_armor->o_which == CRYSTAL_ARMOR) ||
1466: (on(player, ISELECTRIC)) ||
1467: is_wearing(R_ELECTRESIST)) &&
1468: (strcmp(name, "lightning bolt") == 0))
1469: {
1470: player_damage = 0;
1471:
1472: if (rnd(100) < 75
1473: && cur_weapon != NULL
1474: && shooter != &player)
1475: {
1476: cur_weapon->o_flags |= ISZAPPED;
1477: cur_weapon->o_charges += (10 + rnd(15));
1478: }
1479:
1480: if (cur_weapon != NULL && cur_armor != NULL)
1481: msg("Your armor and %s are covered with dancing blue lights!", weaps[cur_weapon->o_which].w_name);
1482: else if (cur_armor != NULL)
1483: msg("Your armor is covered with dancing blue lights!");
1484: else if (cur_weapon != NULL)
1485: msg("Your %s is covered with dancing blue lights!", weaps[cur_weapon->o_which].w_name);
1486: else
1487: msg("You are momentarily covered with dancing blue lights.");
1488: }
1489: else if ((is_wearing(R_FIRERESIST) || on(player, NOFIRE)) &&
1490: (strcmp(name, "flame") == 0))
1491: {
1492: player_damage = 0;
1493: msg("The flame bathes you harmlessly.");
1494: }
1495: else if ((is_wearing(R_COLDRESIST) || on(player, NOCOLD)) &&
1496: (strcmp(name, "ice") == 0))
1497: {
1498: player_damage = 0;
1499: msg("The ice cracks and quickly melts around you.");
1500: }
1501: else if (save(VS_MAGIC))
1502: {
1503: take_that[BOLT_LENGTH] += player_damage / 2;
1504: debug("Player dodges %s for %d.", name, player_damage / 2);
1505: }
1506: else
1507: {
1508: debug("Player zapped by %s for %d.", name, player_damage);
1509: take_that[BOLT_LENGTH] += player_damage;
1510: }
1511:
1512: /* Check for gas with special effects */
1513:
1514: if (off(player, HASOXYGEN) && !is_wearing(R_BREATHE) && !save(VS_BREATH))
1515: {
1516: if (strcmp(name, "nerve gas") == 0)
1517: {
1518: if (no_command == 0)
1519: {
1520: msg("The nerve gas paralyzes you.");
1521: no_command = FREEZETIME;
1522: }
1523: }
1524: else if (strcmp(name, "sleeping gas") == 0)
1525: {
1526: if (no_command == 0)
1527: {
1528: msg("The sleeping gas puts you to sleep.");
1529: no_command = SLEEPTIME;
1530: }
1531: }
1532: else if (strcmp(name, "slow gas") == 0
1533: && !is_wearing(R_FREEDOM))
1534: {
1535: msg("You feel yourself moving %sslower.",
1536: on(player, ISSLOW) ? "even " : "");
1537:
1538: if (on(player, ISSLOW))
1539: lengthen_fuse(FUSE_NOSLOW, rnd(10) + 4);
1540: else
1541: {
1542: turn_on(player, ISSLOW);
1543: player.t_turn = TRUE;
1544: light_fuse(FUSE_NOSLOW, 0, rnd(10) + 4, AFTER);
1545: }
1546: }
1547: else if (strcmp(name, "fear gas") == 0)
1548: {
1549: if (!(on(player, ISFLEE) &&
1550: (player.t_chasee==shooter)) &&
1551: (shooter != &player))
1552: {
1553: if (off(player, SUPERHERO)
1554: && player.t_ctype != C_PALADIN)
1555: {
1556: turn_on(player, ISFLEE);
1557: player.t_chasee = shooter;
1558: player.t_ischasing = FALSE;
1559: msg("The fear gas terrifies you.");
1560: }
1561: else
1562: msg("The fear gas has no effect.");
1563: }
1564: }
1565: }
1566: }
1567: mvwaddch(cw, pos.y, pos.x, dirch);
1568: wrefresh(cw);
1569: }
1570: pos.y += dir.y;
1571: pos.x += dir.x;
1572: }
1573:
1574: /*
1575: * Now that we have determined the damage for the length of the bolt,
1576: * apply it to each monster (and then the player) in turn
1577: */
1578:
1579: for (x = 0; x < BOLT_LENGTH; x++)
1580: {
1581: ch = winat(spotpos[x].y, spotpos[x].x);
1582:
1583: if (take_that[x] != 0 && isalpha(ch))
1584: {
1585: if ((item = find_mons(spotpos[x].y, spotpos[x].x)) == NULL)
1586: {
1587: debug("Can't find monster %c @ %d %d.",
1588: ch, spotpos[x].y, spotpos[x].x);
1589:
1590: continue;
1591: }
1592: else
1593: tp = THINGPTR(item);
1594:
1595: mname = on(player, ISBLIND) ? "monster" : monsters[tp->t_index].m_name;
1596:
1597: debug("Zapped %s for %d (%d)",
1598: mname, take_that[x], tp->t_stats.s_hpt - take_that[x]);
1599:
1600: if ((tp->t_stats.s_hpt -= take_that[x]) <= 0)
1601: {
1602: if (cansee(tp->t_pos.y, tp->t_pos.x))
1603: msg("The %s kills the %s.", name,
1604: on(player, ISBLIND) ? "monster" : mname);
1605:
1606: killed(shooter, item, NOMESSAGE, get_points);
1607: ret_val = TRUE;
1608: }
1609: else if (get_points)
1610: {
1611: chase_it(&spotpos[x], &player);
1612: summon_help(tp, NOFORCE);
1613: }
1614: }
1615:
1616: if (spotpos[x].y >= 0 && spotpos[x].x >= 0 &&
1617: spotpos[x].y < LINES && spotpos[x].x < COLS)
1618: mvwaddch(cw, spotpos[x].y, spotpos[x].x,
1619: show(spotpos[x].y, spotpos[x].x));
1620: }
1621:
1622: if (take_that[BOLT_LENGTH] != 0)
1623: {
1624: if (tp != THINGPTR(fam_ptr))
1625: {
1626: msg("You are hit by the %s.", name);
1627:
1628: if ((pstats.s_hpt -= take_that[BOLT_LENGTH]) <= 0)
1629: {
1630: death(reason);
1631: return;
1632: }
1633: }
1634: }
1635:
1636: return;
1637: }
1638:
1639: /*
1640: monster_do_zap()
1641: monster gets the effect
1642: */
1643:
1644: void
1645: monster_do_zap(struct thing *zapper, int which, int flags)
1646: {
1647: struct stats *curp = &(zapper->t_stats);
1648: int blessed = flags & ISBLESSED;
1649: int cursed = flags & ISCURSED;
1650: int shoot = FALSE;
1651: int damage;
1652: int ndice, nsides;
1653: int ch;
1654: char *bolt_name = NULL;
1655: coord pos;
1656:
1657: switch(which)
1658: {
1659: case WS_MISSILE:
1660: bolt_name = "magic missile";
1661: pos = do_motion('*', delta.y, delta.x, zapper);
1662: ch = winat(pos.y, pos.x);
1663: ndice = curp->s_lvl;
1664: nsides = 4;
1665:
1666: if (cursed)
1667: nsides /= 2;
1668: else if (blessed)
1669: nsides *= 2;
1670:
1671: damage = roll(ndice, nsides);
1672:
1673: if (ch == PLAYER)
1674: {
1675: if (save(VS_MAGIC)) /* help the player */
1676: msg("You evade the %s.", bolt_name);
1677: else
1678: {
1679: msg("You are hit by the %s.", bolt_name);
1680:
1681: if ((pstats.s_hpt -= damage) <= 0)
1682: death(D_BOLT);
1683: }
1684: }
1685: else if (isalpha(ch))
1686: {
1687: struct linked_list *item = find_mons(pos.y, pos.x);
1688:
1689: if (item != NULL)
1690: {
1691: struct thing *tp = THINGPTR(item);
1692: int see_it = cansee(pos.y, pos.x);
1693:
1694: if ((tp->t_stats.s_hpt -= damage) <= 0)
1695: killed(zapper, item, see_it, (zapper == THINGPTR(fam_ptr)));
1696: else if (see_it)
1697: msg("The %s hits the monster.", bolt_name);
1698: }
1699: }
1700:
1701: if (pos.y >= 0 && pos.x >= 0 &&
1702: pos.y < LINES && pos.x < COLS)
1703: mvwaddch(cw, pos.y, pos.x, show(pos.y, pos.x));
1704:
1705: break;
1706:
1707: case WS_CANCEL:
1708: cancel_player(off(*zapper, ISUNIQUE));
1709: break;
1710:
1711: case WS_COLD:
1712: shoot = TRUE;
1713: bolt_name = "cold";
1714: break;
1715:
1716: case WS_FIRE:
1717: shoot = TRUE;
1718: bolt_name = "fire";
1719: break;
1720:
1721: case WS_ELECT:
1722: shoot = TRUE;
1723: bolt_name = "lightning";
1724: break;
1725:
1726: default:
1727: debug("'%s' is a strange stick for a monster to zap!",
1728: ws_magic[which].mi_name);
1729: break;
1730: }
1731:
1732: if (shoot)
1733: {
1734: ndice = curp->s_lvl / 2 + 1;
1735: nsides = 6;
1736:
1737: if (cursed)
1738: nsides /= 2;
1739: else if (blessed)
1740: nsides *= 2;
1741:
1742: damage = roll(ndice, nsides);
1743: shoot_bolt(zapper, zapper->t_pos, delta,
1744: (zapper == THINGPTR(fam_ptr)), D_BOLT, bolt_name, damage);
1745: }
1746: }
1747:
1748: struct powers
1749: {
1750: unsigned long p_flag;
1751: int fuse_id;
1752: };
1753:
1754: /* Order in which powers will attempt to be cancelled */
1755:
1756: struct powers player_powers[] =
1757: {
1758: { ISHASTE, FUSE_NOHASTE },
1759: { ISELECTRIC, FUSE_UNELECTRIFY },
1760: { CANINWALL, FUSE_UNPHASE },
1761: { CANFLY, FUSE_UNFLY },
1762: { ISINVIS, FUSE_APPEAR },
1763: { CANREFLECT, FUSE_UNGAZE },
1764: { ISDISGUISE, FUSE_UNDISGUISE },
1765: { HASMSHIELD, FUSE_UNMSHIELD },
1766: { ISREGEN, FUSE_UNREGEN },
1767: { CANSEE, FUSE_UNSEE },
1768: { NOCOLD, FUSE_UNCOLD },
1769: { NOFIRE, FUSE_UNHOT },
1770: { HASOXYGEN, FUSE_UNBREATHE },
1771: { HASSHIELD, FUSE_UNSHIELD },
1772: { ULONG_MAX, FUSE_NULL }
1773: };
1774:
1775: void
1776: cancel_player(int not_unique)
1777: {
1778: struct powers *pp;
1779: int no_effect = TRUE;
1780:
1781: for(pp = player_powers; pp->p_flag != ULONG_MAX; pp++)
1782: {
1783: if (on(player, pp->p_flag) && !save(VS_MAGIC))
1784: {
1785: fuses[pp->fuse_id].func(NULL);
1786: extinguish_fuse(pp->fuse_id);
1787: no_effect = FALSE;
1788:
1789: if (not_unique) /* Gods might cancel everything */
1790: break;
1791: }
1792: }
1793:
1794: if (no_effect)
1795: nothing_message(ISNORMAL);
1796: }
CVSweb