comparison arogue5/sticks.c @ 63:0ed67132cf10

Import Advanced Rogue 5.8 from the Roguelike Restoration Project (r1490)
author elwin
date Thu, 09 Aug 2012 22:58:48 +0000
parents
children c49f7927b0fa
comparison
equal deleted inserted replaced
62:0ef99244acb8 63:0ed67132cf10
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 "rogue.h"
19
20
21 /*
22 * zap a stick and see what happens
23 */
24 do_zap(gotdir, which, flag)
25 bool gotdir;
26 int which;
27 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 drain(ymin, ymax, xmin, xmax)
686 int ymin, ymax, xmin, 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 fix_stick(cur)
748 register 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 shoot_bolt(shooter, start, dir, get_points, reason, name, damage)
790 struct thing *shooter;
791 coord start, dir;
792 bool get_points;
793 short reason;
794 char *name;
795 int damage;
796 {
797 register char dirch = 0, ch;
798 register bool used, change;
799 register short y, x, bounces;
800 bool mdead = FALSE;
801 coord pos;
802 struct {
803 coord place;
804 char oldch;
805 } spotpos[BOLT_LENGTH];
806
807 switch (dir.y + dir.x) {
808 case 0: dirch = '/';
809 when 1: case -1: dirch = (dir.y == 0 ? '-' : '|');
810 when 2: case -2: dirch = '\\';
811 }
812 pos.y = start.y + dir.y;
813 pos.x = start.x + dir.x;
814 used = FALSE;
815 change = FALSE;
816
817 bounces = 0; /* No bounces yet */
818 for (y = 0; y < BOLT_LENGTH && !used; y++)
819 {
820 ch = CCHAR( winat(pos.y, pos.x) );
821 spotpos[y].place = pos;
822 spotpos[y].oldch = CCHAR( mvwinch(cw, pos.y, pos.x) );
823
824 /* Are we at hero? */
825 if (ce(pos, hero)) goto at_hero;
826
827 switch (ch)
828 {
829 case SECRETDOOR:
830 case '|':
831 case '-':
832 case ' ':
833 if (dirch == '-' || dirch == '|') {
834 dir.y = -dir.y;
835 dir.x = -dir.x;
836 }
837 else {
838 char chx = CCHAR( mvinch(pos.y-dir.y, pos.x) ),
839 chy = CCHAR( mvinch(pos.y, pos.x-dir.x) );
840 bool anychange = FALSE; /* Did we change anthing */
841
842 if (chy == WALL || chy == SECRETDOOR ||
843 chy == '-' || chy == '|') {
844 dir.y = -dir.y;
845 change ^= TRUE; /* Change at least one direction */
846 anychange = TRUE;
847 }
848 if (chx == WALL || chx == SECRETDOOR ||
849 chx == '-' || chx == '|') {
850 dir.x = -dir.x;
851 change ^= TRUE; /* Change at least one direction */
852 anychange = TRUE;
853 }
854
855 /* If we didn't make any change, make both changes */
856 if (!anychange) {
857 dir.x = -dir.x;
858 dir.y = -dir.y;
859 }
860 }
861
862 /* Do we change how the bolt looks? */
863 if (change) {
864 change = FALSE;
865 if (dirch == '\\') dirch = '/';
866 else if (dirch == '/') dirch = '\\';
867 }
868
869 y--; /* The bounce doesn't count as using up the bolt */
870
871 /* Make sure we aren't in an infinite bounce */
872 if (++bounces > BOLT_LENGTH) used = TRUE;
873 msg("The %s bounces", name);
874 break;
875 default:
876 if (isalpha(ch)) {
877 register struct linked_list *item;
878 register struct thing *tp;
879 register const char *mname;
880 bool see_monster = cansee(pos.y, pos.x);
881
882 item = find_mons(unc(pos));
883 tp = THINGPTR(item);
884 mname = monsters[tp->t_index].m_name;
885
886 if (!save(VS_BREATH, tp, -(shooter->t_stats.s_lvl/10))) {
887 if (see_monster) {
888 if (on(*tp, ISDISGUISE) &&
889 (tp->t_type != tp->t_disguise)) {
890 msg("Wait! That's a %s!", mname);
891 turn_off(*tp, ISDISGUISE);
892 }
893
894 sprintf(outstring,"The %s hits the %s", name, mname);
895 msg(outstring);
896 }
897
898 tp->t_wasshot = TRUE;
899 runto(tp, &hero);
900 used = TRUE;
901
902 /* Hit the monster -- does it do anything? */
903 if ((EQUAL(name,"ice") &&
904 (on(*tp, NOCOLD) || on(*tp, ISUNDEAD))) ||
905 (EQUAL(name,"flame") && on(*tp, NOFIRE)) ||
906 (EQUAL(name,"acid") && on(*tp, NOACID)) ||
907 (EQUAL(name,"lightning bolt")&& on(*tp,NOBOLT)) ||
908 (EQUAL(name,"nerve gas") &&on(*tp,NOPARALYZE))||
909 (EQUAL(name,"sleeping gas") &&
910 (on(*tp, NOSLEEP) || on(*tp, ISUNDEAD))) ||
911 (EQUAL(name,"slow gas") && on(*tp,NOSLOW)) ||
912 (EQUAL(name,"fear gas") && on(*tp,NOFEAR)) ||
913 (EQUAL(name,"confusion gas") && on(*tp,ISCLEAR)) ||
914 (EQUAL(name,"chlorine gas") && on(*tp,NOGAS))) {
915 if (see_monster){
916 sprintf(outstring,"The %s has no effect on the %s.",
917 name, mname);
918 msg(outstring);
919 }
920 }
921
922 /*
923 * Check for gas with special effects
924 */
925 else if (EQUAL(name, "nerve gas")) {
926 tp->t_no_move = FREEZETIME;
927 }
928 else if (EQUAL(name, "sleeping gas")) {
929 tp->t_no_move = SLEEPTIME;
930 }
931 else if (EQUAL(name, "slow gas")) {
932 if (on(*tp, ISHASTE))
933 turn_off(*tp, ISHASTE);
934 else
935 turn_on(*tp, ISSLOW);
936 tp->t_turn = TRUE;
937 }
938 else if (EQUAL(name, "fear gas")) {
939 turn_on(*tp, ISFLEE);
940 tp->t_dest = &hero;
941 }
942 else if (EQUAL(name, "confusion gas")) {
943 turn_on(*tp, ISHUH);
944 tp->t_dest = &hero;
945 }
946 else if ((EQUAL(name, "lightning bolt")) &&
947 on(*tp, BOLTDIVIDE)) {
948 if (creat_mons(tp, tp->t_index, FALSE)) {
949 if (see_monster){
950 sprintf(outstring,"The %s divides the %s.",name,mname);
951 msg(outstring);
952 }
953 light(&hero);
954 }
955 else if (see_monster){
956 sprintf(outstring,"The %s has no effect on the %s.",
957 name, mname);
958 msg(outstring);
959 }
960 }
961 else {
962 if(save(VS_BREATH,tp, -(shooter->t_stats.s_lvl/10)))
963 damage /= 2;
964
965 /* The poor fellow got killed! */
966 if ((tp->t_stats.s_hpt -= damage) <= 0) {
967 if (see_monster){
968 sprintf(outstring,"The %s kills the %s", name, mname);
969 msg(outstring);
970 }
971 else
972 msg("You hear a faint groan in the distance");
973 killed(item, FALSE, get_points);
974
975 /* Replace the screen character */
976 spotpos[y].oldch = CCHAR( mvwinch(cw, pos.y, pos.x) );
977
978 mdead = TRUE;
979 }
980 else { /* Not dead, so just scream */
981 if (!see_monster)
982 msg("You hear a scream in the distance");
983 }
984 }
985 }
986 else if (isalpha(show(pos.y, pos.x))) {
987 if (see_monster) {
988 if (terse)
989 msg("%s misses", name);
990 else {
991 sprintf(outstring,"The %s whizzes past the %s", name, mname);
992 msg(outstring);
993 }
994 }
995 if (get_points) runto(tp, &hero);
996 }
997 }
998 else if (pos.y == hero.y && pos.x == hero.x) {
999 at_hero: if (!save(VS_BREATH, &player,
1000 -(shooter->t_stats.s_lvl/10))){
1001 if (terse)
1002 msg("The %s hits you", name);
1003 else
1004 msg("You are hit by the %s", name);
1005 used = TRUE;
1006
1007 /*
1008 * The Amulet of Yendor protects against all "breath"
1009 *
1010 * The following two if statements could be combined
1011 * into one, but it makes the compiler barf, so split
1012 * it up
1013 */
1014 if (cur_relic[YENDOR_AMULET] ||
1015 (EQUAL(name,"chlorine gas")&&on(player, NOGAS)) ||
1016 (EQUAL(name,"sleeping gas")&&ISWEARING(R_ALERT))){
1017 msg("The %s has no affect", name);
1018 }
1019 else if((EQUAL(name, "flame") && on(player, NOFIRE)) ||
1020 (EQUAL(name, "ice") && on(player, NOCOLD)) ||
1021 (EQUAL(name,"fear gas")&&ISWEARING(R_HEROISM))){
1022 msg("The %s has no affect", name);
1023 }
1024 /*
1025 * Check for gas with special effects
1026 */
1027 else if (EQUAL(name, "nerve gas")) {
1028 msg("The nerve gas paralyzes you.");
1029 no_command += FREEZETIME;
1030 }
1031 else if (EQUAL(name, "sleeping gas")) {
1032 msg("The sleeping gas puts you to sleep.");
1033 no_command += SLEEPTIME;
1034 }
1035 else if (EQUAL(name, "confusion gas")) {
1036 if (off(player, ISCLEAR)) {
1037 if (on(player, ISHUH))
1038 lengthen(unconfuse, rnd(20)+HUHDURATION);
1039 else {
1040 turn_on(player, ISHUH);
1041 fuse(unconfuse,0,rnd(20)+HUHDURATION,AFTER);
1042 msg("The confusion gas has confused you.");
1043 }
1044 }
1045 else msg("You feel dizzy for a moment, but it quickly passes.");
1046 }
1047 else if (EQUAL(name, "slow gas")) {
1048 add_slow();
1049 }
1050 else if (EQUAL(name, "fear gas")) {
1051 turn_on(player, ISFLEE);
1052 player.t_dest = &shooter->t_pos;
1053 msg("The fear gas terrifies you.");
1054 }
1055 else {
1056 if(save(VS_BREATH,&player, -(shooter->t_stats.s_lvl/10)))
1057 damage /= 2;
1058 if ((pstats.s_hpt -= damage) <= 0)
1059 death(reason);
1060 }
1061 }
1062 else
1063 msg("The %s whizzes by you", name);
1064 }
1065
1066 mvwaddch(cw, pos.y, pos.x, dirch);
1067 draw(cw);
1068 }
1069
1070 pos.y += dir.y;
1071 pos.x += dir.x;
1072 }
1073 for (x = y - 1; x >= 0; x--)
1074 mvwaddch(cw, spotpos[x].place.y, spotpos[x].place.x, spotpos[x].oldch);
1075 return(mdead);
1076 }