Mercurial > hg > early-roguelike
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 } |