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