Annotation of early-roguelike/arogue7/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: * 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