Annotation of early-roguelike/arogue5/sticks.c, Revision 1.1.1.1
1.1 rubenllo 1: /*
2: * Functions to implement the various sticks one might find
3: * while wandering around the dungeon.
4: *
5: * Advanced Rogue
6: * Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T
7: * All rights reserved.
8: *
9: * Based on "Rogue: Exploring the Dungeons of Doom"
10: * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
11: * All rights reserved.
12: *
13: * See the file LICENSE.TXT for full copyright and licensing information.
14: */
15:
16: #include "curses.h"
17: #include <ctype.h>
18: #include <string.h>
19: #include "rogue.h"
20:
21: void drain(int ymin, int ymax, int xmin, int xmax);
22:
23: /*
24: * zap a stick and see what happens
25: */
26: bool
27: do_zap(bool gotdir, int which, int flag)
28: {
29: register struct linked_list *item;
30: register struct object *obj = NULL;
31: register struct thing *tp;
32: register int y, x;
33: struct linked_list *nitem;
34: struct object *nobj;
35: bool cursed, blessed, is_stick;
36:
37: blessed = FALSE;
38: cursed = FALSE;
39: is_stick = FALSE;
40:
41: if (which == 0) {
42: if ((item = get_item(pack, "zap with", ZAPPABLE)) == NULL)
43: return(FALSE);
44: obj = OBJPTR(item);
45:
46: /* Handle relics specially here */
47: if (obj->o_type == RELIC) {
48: switch (obj->o_which) {
49: case ORCUS_WAND:
50: msg(nothing);
51: return(TRUE);
52: when MING_STAFF:
53: which = WS_MISSILE;
54: when ASMO_ROD:
55: switch (rnd(3)) {
56: case 0:
57: which = WS_ELECT;
58: when 1:
59: which = WS_COLD;
60: otherwise:
61: which = WS_FIRE;
62: }
63: }
64: cursed = FALSE;
65: blessed = FALSE;
66: }
67: else {
68: which = obj->o_which;
69: ws_know[which] = TRUE;
70: cursed = (obj->o_flags & ISCURSED) != 0;
71: blessed = (obj->o_flags & ISBLESSED) != 0;
72: is_stick = TRUE;
73: }
74: }
75: else {
76: cursed = flag & ISCURSED;
77: blessed = flag & ISBLESSED;
78: }
79: switch (which) { /* no direction for these */
80: case WS_LIGHT:
81: case WS_DRAIN:
82: case WS_CHARGE:
83: case WS_CURING:
84: break;
85:
86: default:
87: if (!get_dir())
88: return(FALSE);
89: if (!gotdir) {
90: do {
91: delta.y = rnd(3) - 1;
92: delta.x = rnd(3) - 1;
93: } while (delta.y == 0 && delta.x == 0);
94: }
95: }
96:
97: if (is_stick) {
98: if (obj->o_charges < 1) {
99: msg(nothing);
100: return(TRUE);
101: }
102: obj->o_charges--;
103: }
104: if (which == WS_WONDER) {
105: switch (rnd(14)) {
106: case 0: which = WS_ELECT;
107: when 1: which = WS_FIRE;
108: when 2: which = WS_COLD;
109: when 3: which = WS_POLYMORPH;
110: when 4: which = WS_MISSILE;
111: when 5: which = WS_SLOW_M;
112: when 6: which = WS_TELMON;
113: when 7: which = WS_CANCEL;
114: when 8: which = WS_CONFMON;
115: when 9: which = WS_DISINTEGRATE;
116: when 10: which = WS_PETRIFY;
117: when 11: which = WS_PARALYZE;
118: when 12: which = WS_MDEG;
119: when 13: which = WS_FEAR;
120: }
121: if(ws_magic[which].mi_curse>0 && rnd(100)<=ws_magic[which].mi_curse){
122: cursed = TRUE;
123: blessed = FALSE;
124: }
125: }
126:
127: switch (which) {
128: case WS_LIGHT:
129: /*
130: * Reddy Kilowat wand. Light up the room
131: */
132: blue_light(blessed, cursed);
133: when WS_DRAIN:
134: /*
135: * Take away 1/2 of hero's hit points, then take it away
136: * evenly from the monsters in the room or next to hero
137: * if he is in a passage (but leave the monsters alone
138: * if the stick is cursed)
139: */
140: if (pstats.s_hpt < 2) {
141: msg("You are too weak to use it.");
142: return(TRUE);
143: }
144: if (cursed)
145: pstats.s_hpt /= 2;
146: else
147: drain(hero.y-1, hero.y+1, hero.x-1, hero.x+1);
148: when WS_POLYMORPH:
149: case WS_TELMON:
150: case WS_CANCEL:
151: {
152: register char monster, oldch;
153: register int rm;
154:
155: y = hero.y;
156: x = hero.x;
157: while (shoot_ok(winat(y, x))) {
158: y += delta.y;
159: x += delta.x;
160: }
161: if (isalpha(monster = CCHAR( mvwinch(mw, y, x) ))) {
162: register struct room *rp;
163:
164: item = find_mons(y, x);
165: tp = THINGPTR(item);
166: /* if the monster gets the saving throw, leave the case */
167: if (save(VS_MAGIC, tp, 0)) {
168: msg(nothing);
169: break;
170: }
171:
172: /* Unhold player */
173: if (on(*tp, DIDHOLD)) {
174: turn_off(*tp, DIDHOLD);
175: if (--hold_count == 0) turn_off(player, ISHELD);
176: }
177: /* unsuffocate player */
178: if (on(*tp, DIDSUFFOCATE)) {
179: turn_off(*tp, DIDSUFFOCATE);
180: extinguish(suffocate);
181: }
182: rp = roomin(&tp->t_pos);
183: /*
184: * check to see if room should go dark
185: */
186: if (on(*tp, HASFIRE)) {
187: if (rp != NULL) {
188: register struct linked_list *fire_item;
189:
190: for (fire_item = rp->r_fires; fire_item != NULL;
191: fire_item = next(fire_item)) {
192: if (THINGPTR(fire_item) == tp) {
193: detach(rp->r_fires, fire_item);
194: destroy_item(fire_item);
195: if (rp->r_fires == NULL) {
196: rp->r_flags &= ~HASFIRE;
197: if(cansee(tp->t_pos.y,tp->t_pos.x))
198: light(&hero);
199: }
200: break;
201: }
202: }
203: }
204: }
205:
206: if (which == WS_POLYMORPH) {
207: register struct linked_list *pitem;
208:
209: delta.x = x;
210: delta.y = y;
211: detach(mlist, item);
212: oldch = tp->t_oldch;
213: pitem = tp->t_pack; /* save his pack */
214: tp->t_pack = NULL;
215: new_monster(item,rnd(NUMMONST-NUMUNIQUE-1)+1,&delta,FALSE);
216: if (tp->t_pack != NULL)
217: o_free_list (tp->t_pack);
218: tp->t_pack = pitem;
219: monster = tp->t_type;
220: if (isalpha(mvwinch(cw, y, x)))
221: mvwaddch(cw, y, x, monster);
222: tp->t_oldch = oldch;
223: /*
224: * should the room light up?
225: */
226: if (on(*tp, HASFIRE)) {
227: if (rp) {
228: register struct linked_list *fire_item;
229:
230: fire_item = creat_item();
231: ldata(fire_item) = (char *) tp;
232: attach(rp->r_fires, fire_item);
233: rp->r_flags |= HASFIRE;
234: if (cansee(tp->t_pos.y,tp->t_pos.x) &&
235: next(rp->r_fires) == NULL) light(&hero);
236: }
237: }
238: msg(terse ? "A new %s!" : "You have created a new %s!",
239: monsters[tp->t_index].m_name);
240: }
241: else if (which == WS_CANCEL) {
242: tp->t_flags[0] &= CANC0MASK;
243: tp->t_flags[1] &= CANC1MASK;
244: tp->t_flags[2] &= CANC2MASK;
245: tp->t_flags[3] &= CANC3MASK;
246: tp->t_flags[4] &= CANC4MASK;
247: tp->t_flags[4] &= CANC5MASK;
248: }
249: else { /* A teleport stick */
250: if (cursed) { /* Teleport monster to player */
251: if ((y == (hero.y + delta.y)) &&
252: (x == (hero.x + delta.x)))
253: msg(nothing);
254: else {
255: tp->t_pos.y = hero.y + delta.y;
256: tp->t_pos.x = hero.x + delta.x;
257: }
258: }
259: else if (blessed) { /* Get rid of monster */
260: killed(item, FALSE, TRUE);
261: return(TRUE);
262: }
263: else {
264: register int i=0;
265:
266: do { /* Move monster to another room */
267: rm = rnd_room();
268: rnd_pos(&rooms[rm], &tp->t_pos);
269: }until(winat(tp->t_pos.y,tp->t_pos.x)==FLOOR ||i++>500);
270: rp = &rooms[rm];
271: }
272:
273: /* Now move the monster */
274: if (isalpha(mvwinch(cw, y, x)))
275: mvwaddch(cw, y, x, tp->t_oldch);
276: turn_off(*tp, ISDISGUISE);
277: mvwaddch(mw, y, x, ' ');
278: mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, monster);
279: if (tp->t_pos.y != y || tp->t_pos.x != x)
280: tp->t_oldch = CCHAR( mvwinch(cw, tp->t_pos.y, tp->t_pos.x) );
281: /*
282: * check to see if room that creature appears in should
283: * light up
284: */
285: if (on(*tp, HASFIRE)) {
286: register struct linked_list *fire_item;
287:
288: fire_item = creat_item();
289: ldata(fire_item) = (char *) tp;
290: attach(rp->r_fires, fire_item);
291: rp->r_flags |= HASFIRE;
292: if(cansee(tp->t_pos.y, tp->t_pos.x) &&
293: next(rp->r_fires) == NULL)
294: light(&hero);
295: }
296: }
297: runto(tp, &hero);
298: }
299: }
300: when WS_MISSILE:
301: {
302: static struct object bolt =
303: {
304: MISSILE , {0, 0}, "", 0, "", "1d4 " , NULL, 0, WS_MISSILE, 50, 1
305: };
306:
307: sprintf(bolt.o_hurldmg, "%dd4", pstats.s_lvl);
308: do_motion(&bolt, delta.y, delta.x, &player);
309: if (!hit_monster(unc(bolt.o_pos), &bolt, &player))
310: msg("The missile vanishes with a puff of smoke");
311: }
312: when WS_HIT:
313: {
314: register char ch;
315: struct object strike; /* don't want to change sticks attributes */
316:
317: delta.y += hero.y;
318: delta.x += hero.x;
319: ch = CCHAR( winat(delta.y, delta.x) );
320: if (isalpha(ch))
321: {
322: strike = *obj;
323: strike.o_hplus = 6;
324: if (EQUAL(ws_type[which], "staff"))
325: strcpy(strike.o_damage,"3d8");
326: else
327: strcpy(strike.o_damage,"2d8");
328: fight(&delta, &strike, FALSE);
329: }
330: }
331: case WS_SLOW_M:
332: y = hero.y;
333: x = hero.x;
334: while (shoot_ok(winat(y, x))) {
335: y += delta.y;
336: x += delta.x;
337: }
338: if (isalpha(mvwinch(mw, y, x))) {
339: item = find_mons(y, x);
340: tp = THINGPTR(item);
341: runto(tp, &hero);
342: if (on(*tp, ISUNIQUE) && save(VS_MAGIC, tp, 0))
343: msg(nothing);
344: else if (on(*tp, NOSLOW))
345: msg(nothing);
346: else if (cursed) {
347: if (on(*tp, ISSLOW))
348: turn_off(*tp, ISSLOW);
349: else
350: turn_on(*tp, ISHASTE);
351: }
352: else if (blessed) {
353: turn_off(*tp, ISRUN);
354: turn_on(*tp, ISHELD);
355: return(TRUE);
356: }
357: else {
358: if (on(*tp, ISHASTE))
359: turn_off(*tp, ISHASTE);
360: else
361: turn_on(*tp, ISSLOW);
362: tp->t_turn = TRUE;
363: }
364: }
365: when WS_CHARGE:
366: if (ws_know[WS_CHARGE] != TRUE && is_stick)
367: msg("This is a wand of charging.");
368: if ((nitem = get_item(pack, "charge", STICK)) != NULL) {
369: nobj = OBJPTR(nitem);
370: if ((++(nobj->o_charges) == 1) && (nobj->o_which == WS_HIT))
371: fix_stick(nobj);
372: if (EQUAL(ws_type[nobj->o_which], "staff")) {
373: if (nobj->o_charges > 100)
374: nobj->o_charges = 100;
375: }
376: else {
377: if (nobj->o_charges > 50)
378: nobj->o_charges = 50;
379: }
380: }
381: when WS_ELECT:
382: case WS_FIRE:
383: case WS_COLD:
384: {
385: char *name;
386:
387: if (which == WS_ELECT)
388: name = "lightning bolt";
389: else if (which == WS_FIRE)
390: name = "flame";
391: else
392: name = "ice";
393:
394: shoot_bolt( &player, hero,
395: delta, TRUE, D_BOLT,
396: name, roll(pstats.s_lvl,6));
397: }
398: when WS_PETRIFY: {
399: reg int m1, m2, x1, y1;
400: reg char ch;
401: reg struct linked_list *ll;
402: reg struct thing *lt;
403:
404: y1 = hero.y;
405: x1 = hero.x;
406: do {
407: y1 += delta.y;
408: x1 += delta.x;
409: ch = CCHAR( winat(y1,x1) );
410: } while (ch == PASSAGE || ch == FLOOR);
411: for (m1 = x1 - 1 ; m1 <= x1 + 1 ; m1++) {
412: for(m2 = y1 - 1 ; m2 <= y1 + 1 ; m2++) {
413: ch = CCHAR( winat(m2,m1) );
414: if (m1 == hero.x && m2 == hero.y)
415: continue;
416: if (ch != ' ') {
417: ll = find_obj(m2,m1);
418: if (ll != NULL) {
419: detach(lvl_obj,ll);
420: o_discard(ll);
421: }
422: ll = find_mons(m2,m1);
423: if (ll != NULL) {
424: lt = THINGPTR(ll);
425: if (on(*lt, ISUNIQUE))
426: monsters[lt->t_index].m_normal = TRUE;
427: check_residue(lt);
428: detach(mlist,ll);
429: t_discard(ll);
430: mvwaddch(mw,m2,m1,' ');
431: }
432: mvaddch(m2,m1,' ');
433: mvwaddch(cw,m2,m1,' ');
434: }
435: }
436: }
437: touchwin(cw);
438: touchwin(mw);
439: }
440: when WS_CONFMON:
441: if (cursed) {
442: if (off(player, ISCLEAR)) {
443: if (on(player, ISHUH))
444: lengthen(unconfuse, rnd(20)+HUHDURATION);
445: else {
446: turn_on(player, ISHUH);
447: fuse(unconfuse,0,rnd(20)+HUHDURATION,AFTER);
448: msg("Wait, what's going on here. Huh? What? Who?");
449: }
450: }
451: else msg("You feel dizzy for a moment, but it quickly passes.");
452: }
453: else {
454: y = hero.y;
455: x = hero.x;
456: while (shoot_ok(winat(y, x)))
457: {
458: y += delta.y;
459: x += delta.x;
460: }
461: if (isalpha(mvwinch(mw, y, x)))
462: {
463: item = find_mons(y, x);
464: tp = THINGPTR(item);
465: if (save(VS_MAGIC, tp, 0) || on(*tp, ISCLEAR))
466: msg(nothing);
467: else
468: turn_on (*tp, ISHUH);
469: runto(tp, &hero);
470: }
471: }
472: when WS_PARALYZE:
473: if (cursed) {
474: no_command += FREEZETIME;
475: msg("You can't move.");
476: }
477: else {
478: y = hero.y;
479: x = hero.x;
480: while (shoot_ok(winat(y, x)))
481: {
482: y += delta.y;
483: x += delta.x;
484: }
485: if (isalpha(mvwinch(mw, y, x)))
486: {
487: item = find_mons(y, x);
488: tp = THINGPTR(item);
489: if (save(VS_WAND, tp, 0) || on(*tp, NOPARALYZE))
490: msg(nothing);
491: else {
492: tp->t_no_move = FREEZETIME;
493: }
494: runto(tp, &hero);
495: }
496: }
497: when WS_FEAR:
498: y = hero.y;
499: x = hero.x;
500: while (shoot_ok(winat(y, x)))
501: {
502: y += delta.y;
503: x += delta.x;
504: }
505: if (isalpha(mvwinch(mw, y, x)))
506: {
507: item = find_mons(y, x);
508: tp = THINGPTR(item);
509: runto(tp, &hero);
510: if (save(VS_WAND, tp, 0) ||
511: on(*tp, ISUNDEAD) ||
512: on(*tp, NOFEAR))
513: msg(nothing);
514: else {
515: turn_on(*tp, ISFLEE);
516: turn_on(*tp, WASTURNED);
517:
518: /* If monster was suffocating, stop it */
519: if (on(*tp, DIDSUFFOCATE)) {
520: turn_off(*tp, DIDSUFFOCATE);
521: extinguish(suffocate);
522: }
523:
524: /* If monster held us, stop it */
525: if (on(*tp, DIDHOLD) && (--hold_count == 0))
526: turn_off(player, ISHELD);
527: turn_off(*tp, DIDHOLD);
528: }
529: }
530: when WS_MDEG:
531: y = hero.y;
532: x = hero.x;
533: while (shoot_ok(winat(y, x)))
534: {
535: y += delta.y;
536: x += delta.x;
537: }
538: if (isalpha(mvwinch(mw, y, x)))
539: {
540: item = find_mons(y, x);
541: tp = THINGPTR(item);
542: if (cursed) {
543: tp->t_stats.s_hpt *= 2;
544: msg("The %s appears to be stronger now!",
545: monsters[tp->t_index].m_name);
546: }
547: else if (on(*tp, ISUNIQUE) && save(VS_WAND, tp, 0))
548: msg (nothing);
549: else {
550: tp->t_stats.s_hpt /= 2;
551: msg("The %s appears to be weaker now",
552: monsters[tp->t_index].m_name);
553: }
554: runto(tp, &hero);
555: if (tp->t_stats.s_hpt < 1)
556: killed(item, TRUE, TRUE);
557: }
558: when WS_DISINTEGRATE:
559: y = hero.y;
560: x = hero.x;
561: while (shoot_ok(winat(y, x))) {
562: y += delta.y;
563: x += delta.x;
564: }
565: if (isalpha(mvwinch(mw, y, x))) {
566: item = find_mons(y, x);
567: tp = THINGPTR(item);
568: turn_on (*tp, ISMEAN);
569: runto(tp, &hero);
570: if (cursed) {
571: register int m1, m2;
572: coord mp;
573: struct linked_list *titem;
574: char ch;
575: struct thing *th;
576:
577: if (on(*tp, ISUNIQUE)) {
578: msg (nothing);
579: break;
580: }
581: for (m1=tp->t_pos.x-1 ; m1 <= tp->t_pos.x+1 ; m1++) {
582: for(m2=tp->t_pos.y-1 ; m2<=tp->t_pos.y+1 ; m2++) {
583: ch = CCHAR( winat(m2,m1) );
584: if (shoot_ok(ch) && ch != PLAYER) {
585: mp.x = m1; /* create it */
586: mp.y = m2;
587: titem = new_item(sizeof(struct thing));
588: new_monster(titem,(short)tp->t_index,&mp,FALSE);
589: th = THINGPTR(titem);
590: turn_on (*th, ISMEAN);
591: runto(th,&hero);
592: if (on(*th, HASFIRE)) {
593: register struct room *rp;
594:
595: rp = roomin(&th->t_pos);
596: if (rp) {
597: register struct linked_list *fire_item;
598:
599: fire_item = creat_item();
600: ldata(fire_item) = (char *) th;
601: attach(rp->r_fires, fire_item);
602: rp->r_flags |= HASFIRE;
603: if (cansee(th->t_pos.y, th->t_pos.x) &&
604: next(rp->r_fires) == NULL)
605: light(&hero);
606: }
607: }
608: }
609: }
610: }
611: }
612: else { /* if its a UNIQUE it might still live */
613: tp = THINGPTR(item);
614: if (on(*tp, ISUNIQUE) && save(VS_MAGIC, tp, 0)) {
615: tp->t_stats.s_hpt /= 2;
616: if (tp->t_stats.s_hpt < 1) {
617: killed(item, FALSE, TRUE);
618: msg("You have disintegrated the %s",
619: monsters[tp->t_index].m_name);
620: }
621: else {
622: msg("The %s appears wounded",
623: monsters[tp->t_index].m_name);
624: }
625: }
626: else {
627: msg("You have disintegrated the %s",
628: monsters[tp->t_index].m_name);
629: killed (item, FALSE, TRUE);
630: }
631: }
632: }
633: when WS_CURING:
634: ws_know[WS_CURING] = TRUE;
635: if (cursed) {
636: if (!save(VS_POISON, &player, 0)) {
637: msg("You feel extremely sick now");
638: pstats.s_hpt /=2;
639: if (pstats.s_hpt == 0) death (D_POISON);
640: }
641: if (!save(VS_WAND, &player, 0) && !ISWEARING(R_HEALTH)) {
642: turn_on(player, HASDISEASE);
643: turn_on(player, HASINFEST);
644: turn_on(player, DOROT);
645: fuse(cure_disease, 0, roll(HEALTIME,SICKTIME), AFTER);
646: infest_dam++;
647: }
648: else msg("You fell momentarily sick");
649: }
650: else {
651: if (on(player, HASDISEASE)) {
652: extinguish(cure_disease);
653: cure_disease();
654: msg(terse ? "You feel yourself improving."
655: : "You begin to feel yourself improving again.");
656: }
657: if (on(player, HASINFEST)) {
658: turn_off(player, HASINFEST);
659: infest_dam = 0;
660: msg(terse ? "You feel yourself improving."
661: : "You begin to feel yourself improving again.");
662: }
663: if (on(player, DOROT)) {
664: msg("You feel your skin returning to normal.");
665: turn_off(player, DOROT);
666: }
667: pstats.s_hpt += roll(pstats.s_lvl, blessed ? 6 : 4);
668: if (pstats.s_hpt > max_stats.s_hpt)
669: pstats.s_hpt = max_stats.s_hpt;
670: msg("You begin to feel %sbetter.", blessed ? "much " : "");
671:
672: }
673: otherwise:
674: msg("What a bizarre schtick!");
675: }
676: return(TRUE);
677: }
678:
679:
680: /*
681: * drain:
682: * Do drain hit points from player shtick
683: */
684:
685: void
686: drain(int ymin, int ymax, int xmin, int xmax)
687: {
688: register int i, j, count;
689: register struct thing *ick;
690: register struct linked_list *item;
691:
692: /*
693: * First count how many things we need to spread the hit points among
694: */
695: count = 0;
696: for (i = ymin; i <= ymax; i++) {
697: if (i < 1 || i > LINES - 3)
698: continue;
699: for (j = xmin; j <= xmax; j++) {
700: if (j < 0 || j > COLS - 1)
701: continue;
702: if (isalpha(mvwinch(mw, i, j)))
703: count++;
704: }
705: }
706: if (count == 0)
707: {
708: msg("You have a tingling feeling");
709: return;
710: }
711: count = pstats.s_hpt / count;
712: pstats.s_hpt /= 2;
713: /*
714: * Now zot all of the monsters
715: */
716: for (i = ymin; i <= ymax; i++) {
717: if (i < 1 || i > LINES - 3)
718: continue;
719: for (j = xmin; j <= xmax; j++) {
720: if (j < 0 || j > COLS - 1)
721: continue;
722: if (isalpha(mvwinch(mw, i, j)) &&
723: ((item = find_mons(i, j)) != NULL)) {
724: ick = THINGPTR(item);
725: if (on(*ick, ISUNIQUE) && save(VS_MAGIC, ick, 0))
726: ick->t_stats.s_hpt -= count / 2;
727: else
728: ick->t_stats.s_hpt -= count;
729: if (ick->t_stats.s_hpt < 1)
730: killed(item,
731: cansee(i,j)&&(!on(*ick,ISINVIS)||on(player,CANSEE)),
732: TRUE);
733: else {
734: runto(ick, &hero);
735: if (cansee(i,j) && (!on(*ick,ISINVIS)||on(player,CANSEE)))
736: msg("The %s appears wounded",
737: monsters[ick->t_index].m_name);
738: }
739: }
740: }
741: }
742: }
743:
744: /*
745: * initialize a stick
746: */
747: void
748: fix_stick(struct object *cur)
749: {
750: if (EQUAL(ws_type[cur->o_which], "staff")) {
751: cur->o_weight = 100;
752: cur->o_charges = 5 + rnd(10);
753: strcpy(cur->o_damage,"2d3");
754: cur->o_hplus = 1;
755: cur->o_dplus = 0;
756: switch (cur->o_which) {
757: case WS_HIT:
758: cur->o_hplus = 3;
759: cur->o_dplus = 3;
760: strcpy(cur->o_damage,"2d8");
761: when WS_LIGHT:
762: cur->o_charges = 20 + rnd(10);
763: }
764: }
765: else {
766: strcpy(cur->o_damage,"1d3");
767: cur->o_weight = 60;
768: cur->o_hplus = 1;
769: cur->o_dplus = 0;
770: cur->o_charges = 3 + rnd(5);
771: switch (cur->o_which) {
772: case WS_HIT:
773: cur->o_hplus = 3;
774: cur->o_dplus = 3;
775: strcpy(cur->o_damage,"1d8");
776: when WS_LIGHT:
777: cur->o_charges = 10 + rnd(10);
778: }
779: }
780: strcpy(cur->o_hurldmg,"1d1");
781:
782: }
783:
784: /*
785: * shoot_bolt fires a bolt from the given starting point in the
786: * given direction
787: */
788:
789: bool
790: shoot_bolt(struct thing *shooter, coord start, coord dir, bool get_points,
791: short reason, char *name, int damage)
792: {
793: register char dirch = 0, ch;
794: register bool used, change;
795: register short y, x, bounces;
796: bool mdead = FALSE;
797: coord pos;
798: struct {
799: coord place;
800: char oldch;
801: } spotpos[BOLT_LENGTH];
802:
803: switch (dir.y + dir.x) {
804: case 0: dirch = '/';
805: when 1: case -1: dirch = (dir.y == 0 ? '-' : '|');
806: when 2: case -2: dirch = '\\';
807: }
808: pos.y = start.y + dir.y;
809: pos.x = start.x + dir.x;
810: used = FALSE;
811: change = FALSE;
812:
813: bounces = 0; /* No bounces yet */
814: for (y = 0; y < BOLT_LENGTH && !used; y++)
815: {
816: ch = CCHAR( winat(pos.y, pos.x) );
817: spotpos[y].place = pos;
818: spotpos[y].oldch = CCHAR( mvwinch(cw, pos.y, pos.x) );
819:
820: /* Are we at hero? */
821: if (ce(pos, hero)) goto at_hero;
822:
823: switch (ch)
824: {
825: case SECRETDOOR:
826: case '|':
827: case '-':
828: case ' ':
829: if (dirch == '-' || dirch == '|') {
830: dir.y = -dir.y;
831: dir.x = -dir.x;
832: }
833: else {
834: char chx = CCHAR( mvinch(pos.y-dir.y, pos.x) ),
835: chy = CCHAR( mvinch(pos.y, pos.x-dir.x) );
836: bool anychange = FALSE; /* Did we change anthing */
837:
838: if (chy == WALL || chy == SECRETDOOR ||
839: chy == '-' || chy == '|') {
840: dir.y = -dir.y;
841: change ^= TRUE; /* Change at least one direction */
842: anychange = TRUE;
843: }
844: if (chx == WALL || chx == SECRETDOOR ||
845: chx == '-' || chx == '|') {
846: dir.x = -dir.x;
847: change ^= TRUE; /* Change at least one direction */
848: anychange = TRUE;
849: }
850:
851: /* If we didn't make any change, make both changes */
852: if (!anychange) {
853: dir.x = -dir.x;
854: dir.y = -dir.y;
855: }
856: }
857:
858: /* Do we change how the bolt looks? */
859: if (change) {
860: change = FALSE;
861: if (dirch == '\\') dirch = '/';
862: else if (dirch == '/') dirch = '\\';
863: }
864:
865: y--; /* The bounce doesn't count as using up the bolt */
866:
867: /* Make sure we aren't in an infinite bounce */
868: if (++bounces > BOLT_LENGTH) used = TRUE;
869: msg("The %s bounces", name);
870: break;
871: default:
872: if (isalpha(ch)) {
873: register struct linked_list *item;
874: register struct thing *tp;
875: register const char *mname;
876: bool see_monster = cansee(pos.y, pos.x);
877:
878: item = find_mons(unc(pos));
879: tp = THINGPTR(item);
880: mname = monsters[tp->t_index].m_name;
881:
882: if (!save(VS_BREATH, tp, -(shooter->t_stats.s_lvl/10))) {
883: if (see_monster) {
884: if (on(*tp, ISDISGUISE) &&
885: (tp->t_type != tp->t_disguise)) {
886: msg("Wait! That's a %s!", mname);
887: turn_off(*tp, ISDISGUISE);
888: }
889:
890: sprintf(outstring,"The %s hits the %s", name, mname);
891: msg(outstring);
892: }
893:
894: tp->t_wasshot = TRUE;
895: runto(tp, &hero);
896: used = TRUE;
897:
898: /* Hit the monster -- does it do anything? */
899: if ((EQUAL(name,"ice") &&
900: (on(*tp, NOCOLD) || on(*tp, ISUNDEAD))) ||
901: (EQUAL(name,"flame") && on(*tp, NOFIRE)) ||
902: (EQUAL(name,"acid") && on(*tp, NOACID)) ||
903: (EQUAL(name,"lightning bolt")&& on(*tp,NOBOLT)) ||
904: (EQUAL(name,"nerve gas") &&on(*tp,NOPARALYZE))||
905: (EQUAL(name,"sleeping gas") &&
906: (on(*tp, NOSLEEP) || on(*tp, ISUNDEAD))) ||
907: (EQUAL(name,"slow gas") && on(*tp,NOSLOW)) ||
908: (EQUAL(name,"fear gas") && on(*tp,NOFEAR)) ||
909: (EQUAL(name,"confusion gas") && on(*tp,ISCLEAR)) ||
910: (EQUAL(name,"chlorine gas") && on(*tp,NOGAS))) {
911: if (see_monster){
912: sprintf(outstring,"The %s has no effect on the %s.",
913: name, mname);
914: msg(outstring);
915: }
916: }
917:
918: /*
919: * Check for gas with special effects
920: */
921: else if (EQUAL(name, "nerve gas")) {
922: tp->t_no_move = FREEZETIME;
923: }
924: else if (EQUAL(name, "sleeping gas")) {
925: tp->t_no_move = SLEEPTIME;
926: }
927: else if (EQUAL(name, "slow gas")) {
928: if (on(*tp, ISHASTE))
929: turn_off(*tp, ISHASTE);
930: else
931: turn_on(*tp, ISSLOW);
932: tp->t_turn = TRUE;
933: }
934: else if (EQUAL(name, "fear gas")) {
935: turn_on(*tp, ISFLEE);
936: tp->t_dest = &hero;
937: }
938: else if (EQUAL(name, "confusion gas")) {
939: turn_on(*tp, ISHUH);
940: tp->t_dest = &hero;
941: }
942: else if ((EQUAL(name, "lightning bolt")) &&
943: on(*tp, BOLTDIVIDE)) {
944: if (creat_mons(tp, tp->t_index, FALSE)) {
945: if (see_monster){
946: sprintf(outstring,"The %s divides the %s.",name,mname);
947: msg(outstring);
948: }
949: light(&hero);
950: }
951: else if (see_monster){
952: sprintf(outstring,"The %s has no effect on the %s.",
953: name, mname);
954: msg(outstring);
955: }
956: }
957: else {
958: if(save(VS_BREATH,tp, -(shooter->t_stats.s_lvl/10)))
959: damage /= 2;
960:
961: /* The poor fellow got killed! */
962: if ((tp->t_stats.s_hpt -= damage) <= 0) {
963: if (see_monster){
964: sprintf(outstring,"The %s kills the %s", name, mname);
965: msg(outstring);
966: }
967: else
968: msg("You hear a faint groan in the distance");
969: killed(item, FALSE, get_points);
970:
971: /* Replace the screen character */
972: spotpos[y].oldch = CCHAR( mvwinch(cw, pos.y, pos.x) );
973:
974: mdead = TRUE;
975: }
976: else { /* Not dead, so just scream */
977: if (!see_monster)
978: msg("You hear a scream in the distance");
979: }
980: }
981: }
982: else if (isalpha(show(pos.y, pos.x))) {
983: if (see_monster) {
984: if (terse)
985: msg("%s misses", name);
986: else {
987: sprintf(outstring,"The %s whizzes past the %s", name, mname);
988: msg(outstring);
989: }
990: }
991: if (get_points) runto(tp, &hero);
992: }
993: }
994: else if (pos.y == hero.y && pos.x == hero.x) {
995: at_hero: if (!save(VS_BREATH, &player,
996: -(shooter->t_stats.s_lvl/10))){
997: if (terse)
998: msg("The %s hits you", name);
999: else
1000: msg("You are hit by the %s", name);
1001: used = TRUE;
1002:
1003: /*
1004: * The Amulet of Yendor protects against all "breath"
1005: *
1006: * The following two if statements could be combined
1007: * into one, but it makes the compiler barf, so split
1008: * it up
1009: */
1010: if (cur_relic[YENDOR_AMULET] ||
1011: (EQUAL(name,"chlorine gas")&&on(player, NOGAS)) ||
1012: (EQUAL(name,"sleeping gas")&&ISWEARING(R_ALERT))){
1013: msg("The %s has no affect", name);
1014: }
1015: else if((EQUAL(name, "flame") && on(player, NOFIRE)) ||
1016: (EQUAL(name, "ice") && on(player, NOCOLD)) ||
1017: (EQUAL(name,"fear gas")&&ISWEARING(R_HEROISM))){
1018: msg("The %s has no affect", name);
1019: }
1020: /*
1021: * Check for gas with special effects
1022: */
1023: else if (EQUAL(name, "nerve gas")) {
1024: msg("The nerve gas paralyzes you.");
1025: no_command += FREEZETIME;
1026: }
1027: else if (EQUAL(name, "sleeping gas")) {
1028: msg("The sleeping gas puts you to sleep.");
1029: no_command += SLEEPTIME;
1030: }
1031: else if (EQUAL(name, "confusion gas")) {
1032: if (off(player, ISCLEAR)) {
1033: if (on(player, ISHUH))
1034: lengthen(unconfuse, rnd(20)+HUHDURATION);
1035: else {
1036: turn_on(player, ISHUH);
1037: fuse(unconfuse,0,rnd(20)+HUHDURATION,AFTER);
1038: msg("The confusion gas has confused you.");
1039: }
1040: }
1041: else msg("You feel dizzy for a moment, but it quickly passes.");
1042: }
1043: else if (EQUAL(name, "slow gas")) {
1044: add_slow();
1045: }
1046: else if (EQUAL(name, "fear gas")) {
1047: turn_on(player, ISFLEE);
1048: player.t_dest = &shooter->t_pos;
1049: msg("The fear gas terrifies you.");
1050: }
1051: else {
1052: if(save(VS_BREATH,&player, -(shooter->t_stats.s_lvl/10)))
1053: damage /= 2;
1054: if ((pstats.s_hpt -= damage) <= 0)
1055: death(reason);
1056: }
1057: }
1058: else
1059: msg("The %s whizzes by you", name);
1060: }
1061:
1062: mvwaddch(cw, pos.y, pos.x, dirch);
1063: draw(cw);
1064: }
1065:
1066: pos.y += dir.y;
1067: pos.x += dir.x;
1068: }
1069: for (x = y - 1; x >= 0; x--)
1070: mvwaddch(cw, spotpos[x].place.y, spotpos[x].place.x, spotpos[x].oldch);
1071: return(mdead);
1072: }
CVSweb