comparison arogue7/sticks.c @ 125:adfa37e67084

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