comparison urogue/misc.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 misc.c - all sorts of miscellaneous routines
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 <stdlib.h>
20 #include <string.h>
21 #include <ctype.h>
22 #include "rogue.h"
23
24 /*
25 tr_name()
26 print the name of a trap
27 */
28
29 char *
30 tr_name(char ch, char *trname)
31 {
32 const char *s = NULL;
33
34 if (trname == NULL)
35 return(" Your found an error in UltraRogue #100.");
36
37 switch(ch)
38 {
39 case TRAPDOOR:
40 s = "trapdoor.";
41 break;
42 case BEARTRAP:
43 s = "beartrap.";
44 break;
45 case SLEEPTRAP:
46 s = "sleeping gas trap.";
47 break;
48 case ARROWTRAP:
49 s = "arrow trap.";
50 break;
51 case TELTRAP:
52 s = "teleport trap.";
53 break;
54 case DARTTRAP:
55 s = "dart trap.";
56 break;
57 case POOL:
58 s = "shimmering pool.";
59 break;
60 case MAZETRAP:
61 s = "maze entrance.";
62 break;
63 case FIRETRAP:
64 s = "fire trap.";
65 break;
66 case POISONTRAP:
67 s = "poison pool trap.";
68 break;
69 case LAIR:
70 s = "monster lair.";
71 break;
72 case RUSTTRAP:
73 s = "rust trap.";
74 break;
75 default:
76 ;
77 }
78
79 sprintf(trname, "You found a %s.", s);
80
81 return(trname);
82 }
83
84 /*
85 look()
86 A quick glance all around the player
87 */
88
89 void
90 look(int wakeup)
91 {
92 int x, y;
93 char ch, och;
94 int oldx, oldy;
95 int inpass, horizontal, vertical, do_light = FALSE, do_blank = FALSE;
96 int passcount = 0;
97 struct room *rp;
98 int ey, ex;
99
100 /* Are we moving vertically or horizontally? */
101
102 if (runch == 'h' || runch == 'l')
103 horizontal = TRUE;
104 else
105 horizontal = FALSE;
106
107 if (runch == 'j' || runch == 'k')
108 vertical = TRUE;
109 else
110 vertical = FALSE;
111
112 getyx(cw, oldy, oldx); /* Save current position */
113
114 /*
115 * Blank out the floor around our last position and check for moving
116 * out of a corridor in a maze.
117 */
118
119 if (oldrp != NULL && (oldrp->r_flags & ISDARK) &&
120 !(oldrp->r_flags & HASFIRE) && off(player, ISBLIND))
121 do_blank = TRUE;
122
123 for (x = player.t_oldpos.x - 1; x <= player.t_oldpos.x + 1; x++)
124 for (y = player.t_oldpos.y - 1; y <= player.t_oldpos.y + 1;
125 y++)
126 {
127 ch = show(y, x);
128
129 if (do_blank && (y != hero.y || x != hero.x) && ch == FLOOR)
130 mvwaddch(cw, y, x, ' ');
131
132 /* Moving out of a corridor? */
133
134 if (levtype == MAZELEV &&
135 (ch != '|' && ch != '-') && /* Not a wall */
136 ((vertical && x != player.t_oldpos.x &&
137 y == player.t_oldpos.y) ||
138 (horizontal && y != player.t_oldpos.y &&
139 x == player.t_oldpos.x)))
140 do_light = TRUE; /* Just came to a turn */
141 }
142
143 inpass = ((rp = roomin(hero)) == NULL); /* Are we in a passage? */
144
145 /* Are we coming out of a wall into a corridor in a maze? */
146 och = show(player.t_oldpos.y, player.t_oldpos.x);
147 ch = show(hero.y, hero.x);
148
149 if (levtype == MAZELEV && (och == '|' || och == '-' ||
150 och == SECRETDOOR) && (ch != '|' && ch != '-' && ch != SECRETDOOR))
151 {
152 do_light = off(player, ISBLIND); /* Light it up if not blind */
153 }
154
155 /* Look around the player */
156
157 ey = hero.y + 1;
158 ex = hero.x + 1;
159
160 for (x = hero.x - 1; x <= ex; x++)
161 if (x >= 0 && x < COLS)
162 for (y = hero.y - 1; y <= ey; y++)
163 {
164 if (y <= 0 || y >= LINES - 2)
165 continue;
166
167 if (isalpha(mvwinch(mw, y, x)))
168 {
169 struct linked_list *it;
170 struct thing *tp;
171
172 if (wakeup)
173 it = wake_monster(y, x);
174 else
175 it = find_mons(y, x);
176
177 if (it == NULL)
178 continue;
179
180 tp = THINGPTR(it);
181 tp->t_oldch = CCHAR( mvinch(y, x) );
182
183 if (isatrap(tp->t_oldch))
184 {
185 struct trap *trp = trap_at(y, x);
186
187 tp->t_oldch = (trp->tr_flags & ISFOUND) ? tp->t_oldch
188 : trp->tr_show;
189 }
190
191 if (tp->t_oldch == FLOOR &&
192 (rp->r_flags & ISDARK)
193 && !(rp->r_flags & HASFIRE) &&
194 off(player, ISBLIND))
195 tp->t_oldch = ' ';
196 }
197
198 /* Secret doors show as walls */
199
200 if ((ch = show(y, x)) == SECRETDOOR)
201 ch = secretdoor(y, x);
202
203 /*
204 * Don't show room walls if he is in a
205 * passage and check for maze turns
206 */
207
208 if (off(player, ISBLIND))
209 {
210 if (y == hero.y && x == hero.x || (inpass && (ch == '-' ||
211 ch == '|')))
212 continue;
213
214 /* Are we at a crossroads in a maze? */
215
216 if (levtype == MAZELEV && (ch != '|' && ch != '-') &&
217 /* Not a wall */
218 ((vertical && x != hero.x && y == hero.y) ||
219 (horizontal && y != hero.y && x == hero.x)))
220 do_light = TRUE;
221 /* Just came to a turn */
222 }
223 else if (y != hero.y || x != hero.x)
224 continue;
225
226 wmove(cw, y, x);
227 waddch(cw, ch);
228
229 if (door_stop && !firstmove && running)
230 {
231 switch (runch)
232 {
233 case 'h':
234 if (x == ex)
235 continue;
236 break;
237 case 'j':
238 if (y == hero.y - 1)
239 continue;
240 break;
241 case 'k':
242 if (y == ey)
243 continue;
244 break;
245 case 'l':
246 if (x == hero.x - 1)
247 continue;
248 break;
249 case 'y':
250 if ((x + y) - (hero.x + hero.y) >= 1)
251 continue;
252 break;
253 case 'u':
254 if ((y - x) - (hero.y - hero.x) >= 1)
255 continue;
256 break;
257 case 'n':
258 if ((x + y) - (hero.x + hero.y) <= -1)
259 continue;
260 break;
261 case 'b':
262 if ((y - x) - (hero.y - hero.x) <= -1)
263 continue;
264 break;
265 }
266
267 switch (ch)
268 {
269 case DOOR:
270 if (x == hero.x || y == hero.y)
271 running = FALSE;
272 break;
273 case PASSAGE:
274 if (x == hero.x || y == hero.y)
275 passcount++;
276 break;
277 case FLOOR:
278
279 /*
280 * Stop by new passages in a
281 * maze (floor next to us)
282 */
283 if ((levtype == MAZELEV) &&
284 ((horizontal && x == hero.x && y != hero.y) ||
285 (vertical && y == hero.y && x != hero.x)))
286 running = FALSE;
287
288 case '|':
289 case '-':
290 case ' ':
291 break;
292
293 default:
294 running = FALSE;
295 break;
296 }
297 }
298 }
299
300 if (door_stop && !firstmove && passcount > 1)
301 running = FALSE;
302
303 /*
304 * Do we have to light up the area (just stepped into a new
305 * corridor)?
306 */
307
308 if (do_light && wakeup && /* wakeup will be true on a normal move */
309 !(rp->r_flags & ISDARK) && /* We have some light */
310 !ce(hero, player.t_oldpos)) /* Don't do anything if we didn't move */
311 light(&hero);
312
313 mvwaddch(cw, hero.y, hero.x, PLAYER);
314 wmove(cw, oldy, oldx);
315
316 if (wakeup)
317 {
318 player.t_oldpos = hero; /* Don't change if we didn't move */
319 oldrp = rp;
320 }
321 }
322
323 /*
324 secret_door()
325 Figure out what a secret door looks like.
326 */
327
328 char
329 secretdoor(int y, int x)
330 {
331 struct room *rp;
332 coord cp;
333
334 cp.x = x;
335 cp.y = y;
336
337 if ((rp = roomin(cp)) != NULL)
338 {
339 if (y == rp->r_pos.y || y == rp->r_pos.y + rp->r_max.y - 1)
340 return ('-');
341 else
342 return ('|');
343 }
344 return ('p');
345 }
346
347 /*
348 find_obj()
349 find the unclaimed object at y, x
350 */
351
352 struct linked_list *
353 find_obj(int y, int x)
354 {
355 struct linked_list *obj, *sobj;
356 struct object *op;
357
358 sobj = lvl_obj;
359
360 for (obj = sobj; obj != NULL; obj = next(obj))
361 {
362 op = OBJPTR(obj);
363
364 if (op && op->o_pos.y == y && op->o_pos.x == x)
365 return(obj);
366 }
367
368 return(NULL);
369 }
370
371 /*
372 eat()
373 He wants to eat something, so let him try
374 */
375
376 void
377 eat(void)
378 {
379 struct object *obj;
380 int amount;
381 float scale = (float) (LINES * COLS) / (25.0F * 80.0F);
382
383 if ((obj = get_object(pack, "eat", FOOD, NULL)) == NULL)
384 return;
385
386 switch (obj->o_which)
387 {
388 case FD_RATION:
389 amount = (int)(scale * (HUNGERTIME + rnd(400) - 200));
390
391 if (rnd(100) > 70)
392 {
393 msg("Yuk, this food tastes awful.");
394 pstats.s_exp++;
395 check_level();
396 }
397 else
398 msg("Yum, that tasted good.");
399 break;
400
401 case FD_FRUIT:
402 amount = (int)(scale * (200 + rnd(HUNGERTIME)));
403 msg("My, that was a yummy %s.", fruit);
404 break;
405
406 case FD_CRAM:
407 amount = (int)(scale * (rnd(HUNGERTIME / 2) + 600));
408 msg("The cram tastes dry in your mouth.");
409 break;
410
411 case FD_CAKES:
412 amount = (int)(scale * ((HUNGERTIME / 3) + rnd(600)));
413 msg("Yum, the honey cakes tasted good.");
414 break;
415
416 case FD_LEMBA:
417 amount = (int)(scale * ((HUNGERTIME / 2) + rnd(900)));
418 quaff(&player, P_HEALING, ISNORMAL);
419 break;
420
421 case FD_MIRUVOR:
422 amount = (int)(scale * ((HUNGERTIME / 3) + rnd(500)));
423 quaff(&player, P_HEALING, ISNORMAL);
424 quaff(&player, P_RESTORE, ISNORMAL);
425 break;
426
427 default:
428 msg("What a strange thing to eat!");
429 amount = (int)(scale * HUNGERTIME);
430 }
431
432 food_left += amount;
433
434 if (obj->o_flags & ISBLESSED)
435 {
436 food_left += 2 * amount;
437 msg("You have a tingling feeling in your mouth.");
438 }
439 else if (food_left > scale * STOMACHSIZE)
440 {
441 food_left = (int)(scale * STOMACHSIZE);
442 msg("You feel satiated and too full to move.");
443 no_command = HOLDTIME;
444 }
445
446 hungry_state = F_OK;
447 updpack();
448
449 if (obj == cur_weapon)
450 cur_weapon = NULL;
451
452 if (--obj->o_count <= 0) /* Remove this pack entry if last of food */
453 discard_pack(obj);
454 }
455
456 /*
457 * Used to modify the player's strength it keeps track of the highest it has
458 * been, just in case
459 */
460
461 void
462 chg_str(int amt, int both, int lost)
463 {
464 int ring_str; /* ring strengths */
465 struct stats *ptr; /* for speed */
466
467 ptr = &pstats;
468
469 ring_str = ring_value(R_ADDSTR) + (on(player, POWERSTR) ? 10 : 0) +
470 (on(player, SUPERHERO) ? 10 : 0);
471
472 ptr->s_str -= ring_str;
473 ptr->s_str += amt;
474
475 if (ptr->s_str < 3)
476 {
477 ptr->s_str = 3;
478 lost = FALSE;
479 }
480 else if (ptr->s_str > 25)
481 ptr->s_str = 25;
482
483 if (both)
484 max_stats.s_str = ptr->s_str;
485
486 if (lost)
487 lost_str -= amt;
488
489 ptr->s_str += ring_str;
490
491 if (ptr->s_str < 0)
492 ptr->s_str = 0;
493
494 updpack();
495 }
496
497 /*
498 * Used to modify the player's dexterity it keeps track of the highest it has
499 * been, just in case
500 */
501
502 void
503 chg_dext(int amt, int both, int lost)
504 {
505 int ring_dext; /* ring strengths */
506 struct stats *ptr; /* for speed */
507
508 ptr = &pstats;
509
510 ring_dext = ring_value(R_ADDHIT) + (on(player, POWERDEXT) ? 10 : 0) +
511 (on(player, SUPERHERO) ? 5 : 0);
512
513 ptr->s_dext -= ring_dext;
514 ptr->s_dext += amt;
515
516 if (ptr->s_dext < 3)
517 {
518 ptr->s_dext = 3;
519 lost = FALSE;
520 }
521 else if (ptr->s_dext > 25)
522 ptr->s_dext = 25;
523
524 if (both)
525 max_stats.s_dext = ptr->s_dext;
526
527 if (lost)
528 lost_dext -= amt;
529
530 ptr->s_dext += ring_dext;
531
532 if (ptr->s_dext < 0)
533 ptr->s_dext = 0;
534 }
535
536 /*
537 add_haste()
538 add a haste to the player
539 */
540
541 void
542 add_haste(int blessed)
543 {
544 short hasttime;
545
546 if (blessed)
547 hasttime = 10;
548 else
549 hasttime = 6;
550
551 if (on(player, ISSLOW)) /* Is person slow? */
552 {
553 extinguish_fuse(FUSE_NOSLOW);
554 noslow(NULL);
555
556 if (blessed)
557 hasttime = 4;
558 else
559 return;
560 }
561
562 if (on(player, ISHASTE))
563 {
564 msg("You faint from exhaustion.");
565 no_command += rnd(hasttime);
566 lengthen_fuse(FUSE_NOHASTE, rnd(hasttime) + (roll(1, 4) * hasttime));
567 }
568 else
569 {
570 turn_on(player, ISHASTE);
571 light_fuse(FUSE_NOHASTE, 0, roll(hasttime, hasttime), AFTER);
572 }
573 }
574
575 /*
576 aggravate()
577 aggravate all the monsters on this level
578 */
579
580 void
581 aggravate(void)
582 {
583 struct linked_list *mi;
584 struct thing *tp;
585
586 for (mi = mlist; mi != NULL; mi = next(mi))
587 {
588 tp = THINGPTR(mi);
589 chase_it(&tp->t_pos, &player);
590 }
591 }
592
593 /*
594 vowelstr()
595 for printfs: if string starts with a vowel, return "n" for an "an"
596 */
597
598 char *
599 vowelstr(char *str)
600 {
601 switch (*str)
602 {
603 case 'a':
604 case 'A':
605 case 'e':
606 case 'E':
607 case 'i':
608 case 'I':
609 case 'o':
610 case 'O':
611 case 'u':
612 case 'U':
613 return "n";
614 default:
615 return "";
616 }
617 }
618
619 /*
620 is_object()
621 see if the object is one of the currently used items
622 */
623
624 int
625 is_current(struct object *obj)
626 {
627 if (obj == NULL)
628 return FALSE;
629
630 if (obj == cur_armor || obj == cur_weapon ||
631 obj == cur_ring[LEFT_1] || obj == cur_ring[LEFT_2] ||
632 obj == cur_ring[LEFT_3] || obj == cur_ring[LEFT_4] ||
633 obj == cur_ring[LEFT_5] ||
634 obj == cur_ring[RIGHT_1] || obj == cur_ring[RIGHT_2] ||
635 obj == cur_ring[RIGHT_3] || obj == cur_ring[RIGHT_4] ||
636 obj == cur_ring[RIGHT_5]) {
637 msg("That's already in use.");
638 return TRUE;
639 }
640
641 return FALSE;
642 }
643
644 /*
645 get_dir()
646 set up the direction co_ordinate for use in varios "prefix" commands
647 */
648
649 int
650 get_dir(void)
651 {
652 char *prompt;
653 int gotit;
654
655 prompt = "Which direction? ";
656 msg(prompt);
657
658 do
659 {
660 gotit = TRUE;
661
662 switch (readchar())
663 {
664 case 'h':
665 case 'H':
666 delta.y = 0;
667 delta.x = -1;
668 break;
669
670 case 'j':
671 case 'J':
672 delta.y = 1;
673 delta.x = 0;
674 break;
675
676 case 'k':
677 case 'K':
678 delta.y = -1;
679 delta.x = 0;
680 break;
681
682 case 'l':
683 case 'L':
684 delta.y = 0;
685 delta.x = 1;
686 break;
687
688 case 'y':
689 case 'Y':
690 delta.y = -1;
691 delta.x = -1;
692 break;
693
694 case 'u':
695 case 'U':
696 delta.y = -1;
697 delta.x = 1;
698 break;
699
700 case 'b':
701 case 'B':
702 delta.y = 1;
703 delta.x = -1;
704 break;
705
706 case 'n':
707 case 'N':
708 delta.y = 1;
709 delta.x = 1;
710 break;
711
712 case ESCAPE:
713 return FALSE;
714
715 default:
716 mpos = 0;
717 msg(prompt);
718 gotit = FALSE;
719 }
720 }
721 while(!gotit);
722
723 if (on(player, ISHUH) && rnd(100) > 80)
724 do
725 {
726 delta.y = rnd(3) - 1;
727 delta.x = rnd(3) - 1;
728 }
729 while (delta.y == 0 && delta.x == 0);
730
731 mpos = 0;
732
733 return(TRUE);
734 }
735
736 /*
737 is_wearing()
738 is the hero wearing a particular ring
739 */
740
741 int
742 is_wearing(int type)
743 {
744 #define ISRING(h, r) (cur_ring[h] != NULL && cur_ring[h]->o_which == r)
745
746 return(
747 ISRING(LEFT_1, type) || ISRING(LEFT_2, type) ||
748 ISRING(LEFT_3, type) || ISRING(LEFT_4, type) ||
749 ISRING(LEFT_5, type) ||
750 ISRING(RIGHT_1, type) || ISRING(RIGHT_2, type) ||
751 ISRING(RIGHT_3, type) || ISRING(RIGHT_4, type) ||
752 ISRING(RIGHT_5, type) );
753 }
754
755 /*
756 maze_view()
757 Returns true if the player can see the specified location
758 within the confines of a maze (within one column or row)
759 */
760
761 int
762 maze_view(int y, int x)
763 {
764 int start, goal, delt, ycheck = 0, xcheck = 0, absy, absx;
765 int row;
766
767 /* Get the absolute value of y and x differences */
768
769 absy = hero.y - y;
770 absx = hero.x - x;
771
772 if (absy < 0)
773 absy = -absy;
774
775 if (absx < 0)
776 absx = -absx;
777
778 /* Must be within one row or column */
779
780 if (absy > 1 && absx > 1)
781 return(FALSE);
782
783 if (absy <= 1) /* Go along row */
784 {
785 start = hero.x;
786 goal = x;
787 row = TRUE;
788 ycheck = hero.y;
789 }
790 else /* Go along column */
791 {
792 start = hero.y;
793 goal = y;
794 row = FALSE;
795 xcheck = hero.x;
796 }
797
798 if (start <= goal)
799 delt = 1;
800 else
801 delt = -1;
802
803 while (start != goal)
804 {
805 if (row)
806 xcheck = start;
807 else
808 ycheck = start;
809
810 switch(CCHAR(winat(ycheck, xcheck)))
811 {
812 case '|':
813 case '-':
814 case WALL:
815 case DOOR:
816 case SECRETDOOR:
817 return(FALSE);
818
819 default:
820 break;
821 }
822 start += delt;
823 }
824
825 return(TRUE);
826 }
827
828 /*
829 listen()
830 listen for monsters less than 5 units away
831 */
832
833 void
834 listen(void)
835 {
836 struct linked_list *item;
837 struct thing *tp;
838 int thief_bonus = -50;
839 int mcount = 0;
840
841 if (player.t_ctype == C_THIEF)
842 thief_bonus = 10;
843
844 for (item = mlist; item != NULL; item = next(item))
845 {
846 tp = THINGPTR(item);
847
848 if (DISTANCE(hero, tp->t_pos) < 81
849 && rnd(70) < (thief_bonus + 4 * pstats.s_dext +
850 6 * pstats.s_lvl))
851 {
852 msg("You hear a%s %s nearby.",
853 vowelstr(monsters[tp->t_index].m_name),
854 monsters[tp->t_index].m_name);
855 mcount++;
856 }
857 }
858
859 if (mcount == 0)
860 msg("You hear nothing.");
861 }
862
863 /*
864 * nothing_message - print out "Nothing <adverb> happens."
865 */
866
867 static const char *nothings[] =
868 {
869 "",
870 "unusual ",
871 "seems to ",
872 "at all ",
873 "really ",
874 "noticeable ",
875 "different ",
876 "strange ",
877 "wierd ",
878 "bizzare ",
879 "wonky ",
880 ""
881 };
882
883 void
884 nothing_message(int flags)
885 {
886 int adverb = rnd(sizeof(nothings) / sizeof(char *));
887
888 NOOP(flags);
889
890 msg("Nothing %shappens.", nothings[adverb]);
891 }
892
893 /*
894 feel_message()
895 print out "You feel <description>."
896 */
897
898 void
899 feel_message(void)
900 {
901 char *charp;
902
903 switch (rnd(25))
904 {
905 case 1: charp = "bad"; break;
906 case 2: charp = "hurt"; break;
907 case 3: charp = "sick"; break;
908 case 4: charp = "faint"; break;
909 case 5: charp = "yucky"; break;
910 case 6: charp = "wonky"; break;
911 case 7: charp = "wierd"; break;
912 case 8: charp = "queasy"; break;
913 case 9: charp = "wounded"; break;
914 case 11: charp = "unusual"; break;
915 case 12: charp = "no pain"; break;
916 case 13: charp = "strange"; break;
917 case 14: charp = "noticable"; break;
918 case 15: charp = "bizzare"; break;
919 case 16: charp = "distressed";break;
920 case 17: charp = "different"; break;
921 case 18: charp = "a touch of ague"; break;
922 case 19: charp = "a migrane coming on"; break;
923 case 20: charp = "Excedrin headache #666"; break;
924 case 21: charp = "a disturbance in the force"; break;
925 case 22: charp = "like someone dropped a house on you"; break;
926 case 23: charp = "as if every nerve in your body is on fire"; break;
927 case 24: charp = "like thousands of red-hot army ants are crawling under your skin";
928 break;
929
930 default:
931 charp = "ill";
932 break;
933 }
934 msg("You feel %s.", charp);
935 }
936
937 /*
938 const_bonus()
939 Hit point adjustment for changing levels
940 */
941
942 int
943 const_bonus(void)
944 {
945 int ret_val = -2;
946
947 if (pstats.s_const > 12)
948 ret_val = pstats.s_const - 12;
949 else if (pstats.s_const > 6)
950 ret_val = 0;
951 else if (pstats.s_const > 3)
952 ret_val = -1;
953
954 return(ret_val);
955 }
956
957 /*
958 int_wis_bonus()
959 Spell point adjustment for changing levels
960 */
961
962 int
963 int_wis_bonus(void)
964 {
965 int ret_val = -2;
966 int casters_stat;
967
968 switch (player.t_ctype)
969 {
970 case C_PALADIN:
971 case C_CLERIC:
972 casters_stat = pstats.s_wisdom;
973 break;
974 case C_RANGER:
975 case C_DRUID:
976 casters_stat = pstats.s_wisdom;
977 break;
978 case C_MAGICIAN:
979 casters_stat = pstats.s_intel;
980 break;
981 case C_ILLUSION:
982 casters_stat = pstats.s_intel;
983 break;
984
985 default:
986 if (is_wearing(R_WIZARD))
987 casters_stat = pstats.s_intel;
988 else if (is_wearing(R_PIETY))
989 casters_stat = pstats.s_wisdom;
990 else
991 casters_stat = (rnd(2) ? pstats.s_wisdom :
992 pstats.s_intel);
993 }
994
995 if (casters_stat > 12)
996 ret_val = casters_stat - 12;
997 else if (casters_stat > 6)
998 ret_val = 0;
999 else if (casters_stat > 3)
1000 ret_val = -1;
1001
1002 return(ret_val);
1003 }
1004
1005 void
1006 electrificate(void)
1007 {
1008 int affect_dist = 4 + player.t_stats.s_lvl / 4;
1009 struct linked_list *item, *nitem;
1010
1011 for (item = mlist; item != NULL; item = nitem)
1012 {
1013 struct thing *tp = THINGPTR(item);
1014 char *mname = monsters[tp->t_index].m_name;
1015
1016 nitem = next(item);
1017
1018 if (DISTANCE(tp->t_pos, hero) < affect_dist)
1019 {
1020 int damage = roll(2, player.t_stats.s_lvl);
1021
1022 debug("Charge does %d (%d)", damage, tp->t_stats.s_hpt - damage);
1023
1024 if (on(*tp, NOBOLT))
1025 continue;
1026
1027 if ((tp->t_stats.s_hpt -= damage) <= 0)
1028 {
1029 msg("The %s is killed by an electric shock.", mname);
1030 killed(&player, item, NOMESSAGE, POINTS);
1031 continue;
1032 }
1033
1034 if (rnd(tp->t_stats.s_intel / 5) == 0)
1035 {
1036 turn_on(*tp, ISFLEE);
1037 msg("The %s is shocked by electricity.", mname);
1038 }
1039 else
1040 msg("The %s is zapped by your electricity.", mname);
1041
1042 summon_help(tp, NOFORCE);
1043 turn_off(*tp, ISFRIENDLY);
1044 turn_off(*tp, ISCHARMED);
1045 turn_on(*tp, ISRUN);
1046 turn_off(*tp, ISDISGUISE);
1047 chase_it(&tp->t_pos, &player);
1048 fighting = after = running = FALSE;
1049 }
1050 }
1051 }
1052
1053 /*
1054 feed_me - Print out interesting messages about food consumption
1055 */
1056
1057 static char *f_hungry[] =
1058 {
1059 "want a cookie",
1060 "feel like a snack",
1061 "feel like some fruit",
1062 "start having the munchies",
1063 "are starting to get hungry"
1064 };
1065
1066 static char *f_weak[] =
1067 {
1068 "are really hungry",
1069 "could eat a horse",
1070 "want some food - now",
1071 "are starting to feel weak",
1072 "feel a gnawing in your stomach",
1073 "are even willing to eat up cram",
1074 "feel lightheaded from not eating"
1075 };
1076
1077 static char *f_faint[] =
1078 {
1079 "get dizzy from not eating",
1080 "are starving for nutrients",
1081 "feel too weak from lack of food",
1082 "see a mirage of an incredible banquet",
1083 "have incredible cramps in your stomach"
1084 };
1085
1086 static char *f_plop[] =
1087 {
1088 "faint",
1089 "pass out",
1090 "keel over",
1091 "black out"
1092 };
1093
1094 void
1095 feed_me(int hunger)
1096 {
1097 char *charp = NULL, *charp2 = NULL;
1098
1099 switch (hunger)
1100 {
1101 case F_OK:
1102 default:
1103 debug("feed_me(%d) called.", hunger);
1104 break;
1105
1106 case F_HUNGRY:
1107 charp = f_hungry[rnd(sizeof(f_hungry) /
1108 sizeof(char *))];
1109 break;
1110
1111 case F_WEAK:
1112 charp = f_weak[rnd(sizeof(f_weak) / sizeof(char *))];
1113 break;
1114
1115 case F_FAINT:
1116 charp = f_faint[rnd(sizeof(f_faint) / sizeof(char *))];
1117 charp2 = f_plop[rnd(sizeof(f_plop) / sizeof(char *))];
1118 break;
1119 }
1120
1121 msg("You %s.", charp);
1122
1123 if (hunger == F_FAINT)
1124 msg("You %s.", charp2);
1125 }
1126
1127
1128 /*
1129 get_monster_number()
1130 prompt player for a monster on list returns 0 if none selected
1131 */
1132
1133 int
1134 get_monster_number(char *message)
1135 {
1136 int i;
1137 int pres_monst = 1;
1138 int ret_val = -1;
1139 char buf[2 * LINELEN];
1140 char monst_name[2 * LINELEN];
1141
1142 while (ret_val == -1)
1143 {
1144 msg("Which monster do you wish to %s? (* for list)", message);
1145
1146 if ((get_string(buf, cw)) != NORM)
1147 return(0);
1148
1149 if ((i = atoi(buf)) != 0)
1150 ret_val = i;
1151 else if (buf[0] != '*')
1152 {
1153 for (i = 1; i < nummonst; i++)
1154 if ((strcmp(monsters[i].m_name, buf) == 0))
1155 ret_val = i;
1156 }
1157 /* The following hack should be redone by the windowing code */
1158 else
1159 while (pres_monst < nummonst) /* Print out the monsters */
1160 {
1161 int num_lines = LINES - 3;
1162
1163 wclear(hw);
1164 touchwin(hw);
1165
1166 wmove(hw, 2, 0);
1167
1168 for (i = 0; i < num_lines && pres_monst < nummonst; i++)
1169 {
1170 sprintf(monst_name, "[%d] %s\n", pres_monst,
1171 monsters[pres_monst].m_name);
1172 waddstr(hw, monst_name);
1173 pres_monst++;
1174 }
1175
1176 if (pres_monst < nummonst)
1177 {
1178 mvwaddstr(hw, LINES - 1, 0, morestr);
1179 wrefresh(hw);
1180 wait_for(' ');
1181 }
1182 else
1183 {
1184 mvwaddstr(hw, 0, 0, "Which monster");
1185 waddstr(hw, "? ");
1186 wrefresh(hw);
1187 }
1188 }
1189
1190 get_monst:
1191 get_string(monst_name, hw);
1192 ret_val = atoi(monst_name);
1193
1194 if ((ret_val < 1 || ret_val > nummonst - 1))
1195 {
1196 mvwaddstr(hw, 0, 0, "Please enter a number in the displayed range -- ");
1197 wrefresh(hw);
1198 goto get_monst;
1199 }
1200
1201 /* Set up for redraw */
1202
1203 clearok(cw, TRUE);
1204 touchwin(cw);
1205 }
1206
1207 return(ret_val);
1208 }