comparison arogue7/util.c @ 125:adfa37e67084

Import Advanced Rogue 7.7 from the Roguelike Restoration Project (r1490)
author John "Elwin" Edwards
date Fri, 08 May 2015 15:24:40 -0400
parents
children b786053d2f37
comparison
equal deleted inserted replaced
124:d10fc4a065ac 125:adfa37e67084
1 /*
2 * util.c - all sorts of miscellaneous routines
3 *
4 * Advanced Rogue
5 * Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T
6 * All rights reserved.
7 *
8 * Based on "Rogue: Exploring the Dungeons of Doom"
9 * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
10 * All rights reserved.
11 *
12 * See the file LICENSE.TXT for full copyright and licensing information.
13 */
14
15 #include "curses.h"
16 #include "rogue.h"
17 #include <ctype.h>
18 #ifdef PC7300
19 #include <track.h>
20 #include <kcodes.h>
21 #include <sys/window.h>
22 extern struct uwdata wdata;
23 #endif
24
25 /*
26 * all sorts of miscellaneous routines
27 *
28 */
29
30
31
32
33 /*
34 * this routine computes the players current AC without dex bonus's
35 */
36 int
37 ac_compute(ignoremetal)
38 bool ignoremetal;
39 {
40 register int ac;
41
42 ac = pstats.s_arm; /* base armor of "skin" */
43 if (cur_armor) {
44 if (!ignoremetal ||
45 (cur_armor->o_which != LEATHER &&
46 cur_armor->o_which != STUDDED_LEATHER &&
47 cur_armor->o_which != PADDED_ARMOR))
48 ac -= (10 - cur_armor->o_ac);
49 }
50 if (player.t_ctype == C_MONK)
51 ac -= pstats.s_lvl * 2 / 3;
52 ac -= ring_value(R_PROTECT);
53 if (cur_misc[WEAR_BRACERS] != NULL)
54 ac -= cur_misc[WEAR_BRACERS]->o_ac;
55 if (cur_misc[WEAR_CLOAK] != NULL)
56 ac -= cur_misc[WEAR_CLOAK]->o_ac;
57
58 /* If player has the cloak, must be wearing it */
59 if (cur_relic[EMORI_CLOAK]) ac -= 5;
60
61 if (ac > 10)
62 ac = 10;
63 return(ac);
64 }
65
66 /*
67 * aggravate:
68 * aggravate all the monsters on this level
69 */
70
71 aggravate(do_uniques, do_good)
72 bool do_uniques, do_good;
73 {
74 register struct linked_list *mi;
75 register struct thing *thingptr;
76
77 for (mi = mlist; mi != NULL; mi = next(mi)) {
78 thingptr = THINGPTR(mi);
79 if (do_good == FALSE && off(*thingptr, ISMEAN)) continue;
80 if (do_uniques || off(*thingptr, ISUNIQUE)) runto(thingptr, &hero);
81 }
82 }
83
84 /*
85 * cansee:
86 * returns true if the hero can see a certain coordinate.
87 */
88
89 cansee(y, x)
90 register int y, x;
91 {
92 register struct room *rer;
93 register int radius;
94 coord tp;
95
96 if (on(player, ISBLIND))
97 return FALSE;
98
99 tp.y = y;
100 tp.x = x;
101 rer = roomin(&tp);
102
103 /* How far can we see? */
104 if (levtype == OUTSIDE) {
105 if (daytime) radius = 36;
106 else if (lit_room(rer)) radius = 9;
107 else radius = 3;
108 }
109 else radius = 3;
110
111 /*
112 * We can only see if the hero in the same room as
113 * the coordinate and the room is lit or if it is close.
114 */
115 return ((rer != NULL &&
116 levtype != OUTSIDE &&
117 (levtype != MAZELEV || /* Maze level needs direct line */
118 maze_view(tp.y, tp.x)) &&
119 rer == roomin(&hero) &&
120 lit_room(rer)) ||
121 DISTANCE(y, x, hero.y, hero.x) < radius);
122 }
123
124 /*
125 * check_level:
126 * Check to see if the guy has gone up a level.
127 *
128 * Return points needed to obtain next level.
129 *
130 * These are certain beginning experience levels for all players.
131 * All further experience levels are computed by muliplying by 2
132 * up through MAXDOUBLE. Then the cap is added in to compute
133 * further levels
134 */
135 long
136 check_level()
137 {
138 register int i, j, add = 0;
139 register unsigned long exp;
140 long retval; /* Return value */
141 int nsides;
142
143 pstats.s_lvl -= pstats.s_lvladj; /* correct for level adjustment */
144 /* See if we are past the doubling stage */
145 exp = char_class[player.t_ctype].cap;
146 if (pstats.s_exp >= exp) {
147 i = pstats.s_exp/exp; /* First get amount above doubling area */
148 retval = exp + i * exp; /* Compute next higher boundary */
149 i += MAXDOUBLE; /* Add in the previous doubled levels */
150 }
151 else {
152 i = 0;
153 exp = char_class[player.t_ctype].start_exp;
154 while (exp <= pstats.s_exp) {
155 i++;
156 exp <<= 1;
157 }
158 retval = exp;
159 }
160 if (++i > pstats.s_lvl) {
161 nsides = char_class[player.t_ctype].hit_pts;
162 for (j=0; j<(i-pstats.s_lvl); j++) /* Take care of multi-level jumps */
163 add += max(1, roll(1,nsides) + const_bonus());
164 max_stats.s_hpt += add;
165 if ((pstats.s_hpt += add) > max_stats.s_hpt)
166 pstats.s_hpt = max_stats.s_hpt;
167 msg("Welcome, %s, to level %d",
168 cnames[player.t_ctype][min(i-1, NUM_CNAMES-1)], i);
169 }
170 pstats.s_lvl = i;
171 pstats.s_lvl += pstats.s_lvladj; /* correct for level adjustment */
172 return(retval);
173 }
174
175 /*
176 * Used to modify the players strength
177 * it keeps track of the highest it has been, just in case
178 */
179
180 chg_str(amt)
181 register int amt;
182 {
183 register int ring_str; /* ring strengths */
184 register struct stats *ptr; /* for speed */
185
186 ptr = &pstats;
187 ring_str = ring_value(R_ADDSTR);
188 ptr->s_str -= ring_str;
189 ptr->s_str += amt;
190 if (ptr->s_str > 25)
191 ptr->s_str = 25;
192 if (ptr->s_str > max_stats.s_str)
193 max_stats.s_str = ptr->s_str;
194 ptr->s_str += ring_str;
195 if (ptr->s_str <= 0)
196 death(D_STRENGTH);
197 updpack(TRUE, &player);
198 }
199
200 /*
201 * let's confuse the player
202 */
203 confus_player()
204 {
205 if (off(player, ISCLEAR))
206 {
207 msg("Wait, what's going on here. Huh? What? Who?");
208 if (find_slot(unconfuse))
209 lengthen(unconfuse, HUHDURATION);
210 else
211 fuse(unconfuse, 0, HUHDURATION, AFTER);
212 turn_on(player, ISHUH);
213 }
214 else msg("You feel dizzy for a moment, but it quickly passes.");
215 }
216
217 /*
218 * this routine computes the players current dexterity
219 */
220 dex_compute()
221 {
222 if (cur_misc[WEAR_GAUNTLET] != NULL &&
223 cur_misc[WEAR_GAUNTLET]->o_which == MM_G_DEXTERITY) {
224 if (cur_misc[WEAR_GAUNTLET]->o_flags & ISCURSED)
225 return (3);
226 else
227 return (18);
228 }
229 else
230 return (pstats.s_dext);
231 }
232
233 /*
234 * diag_ok:
235 * Check to see if the move is legal if it is diagonal
236 */
237
238 diag_ok(sp, ep, flgptr)
239 register coord *sp, *ep;
240 struct thing *flgptr;
241 {
242 register int numpaths = 0;
243
244 /* Horizontal and vertical moves are always ok */
245 if (ep->x == sp->x || ep->y == sp->y)
246 return TRUE;
247
248 /* Diagonal moves are not allowed if there is a horizontal or
249 * vertical path to the destination
250 */
251 if (step_ok(ep->y, sp->x, MONSTOK, flgptr)) numpaths++;
252 if (step_ok(sp->y, ep->x, MONSTOK, flgptr)) numpaths++;
253 return(numpaths != 1);
254 }
255
256 /*
257 * pick a random position around the give (y, x) coordinates
258 */
259 coord *
260 fallpos(pos, be_clear, range)
261 register coord *pos;
262 bool be_clear;
263 int range;
264 {
265 register int tried, i, j;
266 register char ch;
267 static coord ret;
268 static short masks[] = {
269 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x100 };
270
271 /*
272 * Pick a spot at random centered on the position given by 'pos' and
273 * up to 'range' squares away from 'pos'
274 *
275 * If 'be_clear' is TRUE, the spot must be either FLOOR or PASSAGE
276 * inorder to be considered valid
277 *
278 *
279 * Generate a number from 0 to 8, representing the position to pick.
280 * Note that this DOES include the positon 'pos' itself
281 *
282 * If this position is not valid, mark it as 'tried', and pick another.
283 * Whenever a position is picked that has been tried before,
284 * sequentially find the next untried position. This eliminates costly
285 * random number generation
286 */
287
288 tried = 0;
289 while( tried != 0x1ff ) {
290 i = rnd(9);
291 while( tried & masks[i] )
292 i = (i + 1) % 9;
293
294 tried |= masks[i];
295
296 for( j = 1; j <= range; j++ ) {
297 ret.x = pos->x + j*grid[i].x;
298 ret.y = pos->y + j*grid[i].y;
299
300 if (ret.x == hero.x && ret.y == hero.y)
301 continue; /* skip the hero */
302
303 if (ret.x < 0 || ret.x > cols - 1 ||
304 ret.y < 1 || ret.y > lines - 3)
305 continue; /* off the screen? */
306
307 ch = CCHAR( winat(ret.y, ret.x) );
308
309 /*
310 * Check to make certain the spot is valid
311 */
312 switch( ch ) {
313 case FLOOR:
314 case PASSAGE:
315 return( &ret );
316 case GOLD:
317 case SCROLL:
318 case POTION:
319 case STICK:
320 case RING:
321 case WEAPON:
322 case ARMOR:
323 case MM:
324 case FOOD:
325 if(!be_clear && levtype != POSTLEV)
326 return( &ret );
327 default:
328 break;
329 }
330 }
331 }
332 return( NULL );
333 }
334
335
336 /*
337 * findmindex:
338 * Find the index into the monster table of a monster given its name.
339 */
340
341 findmindex(name)
342 char *name;
343 {
344 int which;
345
346 for (which=1; which<NUMMONST; which++) {
347 if (strcmp(name, monsters[which].m_name) == 0)
348 break;
349 }
350 if (which >= NUMMONST) {
351 debug("couldn't find monster index");
352 which = 1;
353 }
354 return(which);
355 }
356
357 /*
358 * find_mons:
359 * Find the monster from his coordinates
360 */
361
362 struct linked_list *
363 find_mons(y, x)
364 register int y;
365 register int x;
366 {
367 register struct linked_list *item;
368 register struct thing *th;
369
370 for (item = mlist; item != NULL; item = next(item))
371 {
372 th = THINGPTR(item);
373 if (th->t_pos.y == y && th->t_pos.x == x)
374 return item;
375 }
376 return NULL;
377 }
378
379 /*
380 * find_obj:
381 * find the unclaimed object at y, x
382 */
383
384 struct linked_list *
385 find_obj(y, x)
386 register int y;
387 register int x;
388 {
389 register struct linked_list *obj;
390 register struct object *op;
391
392 for (obj = lvl_obj; obj != NULL; obj = next(obj))
393 {
394 op = OBJPTR(obj);
395 if (op->o_pos.y == y && op->o_pos.x == x)
396 return obj;
397 }
398 return NULL;
399 }
400
401 /*
402 * get coordinates from the player using the cursor keys (or mouse)
403 */
404 coord
405 get_coordinates()
406 {
407 register int which;
408 coord c;
409 #ifdef PC7300
410 struct umdata startmouse, listenmouse; /* Mouse parameters */
411 int xmouse, /* x-position of mouse */
412 ymouse, /* y-position of mouse */
413 bmouse, /* button value of mouse */
414 rmouse; /* reason for mouse change */
415 #endif
416
417 c = hero;
418 wmove(cw, hero.y, hero.x);
419 draw(cw);
420 #ifdef PC7300
421 keypad(0, 1); /* Turn on escape sequences */
422 ioctl(0, WIOCGETMOUSE, &startmouse); /* Get current mouse parameters */
423 listenmouse = startmouse; /* Make a copy */
424 listenmouse.um_flags |= MSDOWN; /* Enable detection of button down */
425 ioctl(0, WIOCSETMOUSE, &listenmouse); /* Make the change */
426 #endif
427 for (;;) {
428 #ifdef PC7300
429 which = wgetc(0);
430 #else
431 which = (getchar() & 0177);
432 #endif
433 switch(which) {
434 #ifdef PC7300
435 case Home:
436 c.x = 0; c.y = 1;
437 when Beg:
438 c.x = 0;
439 when End:
440 c.x = cols - 1;
441 when Mouse:
442 case ESCAPE:
443 case Cancl:
444 case s_Cancl:
445 if (which == Mouse) {
446 if (wreadmouse(0,&xmouse,&ymouse,&bmouse,&rmouse) != 0 ||
447 (rmouse & MSDOWN) == 0)
448 break;
449 c.y = ymouse / wdata.uw_vs;
450 c.x = xmouse / wdata.uw_hs;
451 c.y = max(c.y, 1);
452 c.y = min(c.y, lines - 3);
453 c.x = max(c.x, 0);
454 c.x = min(c.x, cols - 1);
455 }
456 else c = hero;
457 wmove(cw, c.y, c.x);
458 draw(cw);
459 case '\n':
460 case '\c':
461 keypad(0, 0); /* Turn off escape interpretation */
462 ioctl(0, WIOCSETMOUSE, &startmouse); /* No mouse tracking */
463 return(c);
464 when 'h':
465 case 'H':
466 case Back:
467 case s_Back:
468 c.x--;
469 when 'j':
470 case 'J':
471 case Down:
472 case RollDn:
473 c.y++;
474 when 'k':
475 case 'K':
476 case Up:
477 case RollUp:
478 c.y--;
479 when 'l':
480 case 'L':
481 case Forward:
482 case s_Forward:
483 c.x++;
484 when 'y':
485 case 'Y':
486 case Prev:
487 c.x--; c.y--;
488 when 'u':
489 case 'U':
490 case Next:
491 c.x++; c.y--;
492 when 'b':
493 case 'B':
494 case s_Prev:
495 c.x--; c.y++;
496 when 'n':
497 case 'N':
498 case s_Next:
499 c.x++; c.y++;
500 when '*':
501 msg("Select location via mouse, or");
502 msg("Use cursor keys,h,j,k,l,y,u,b,or n, then hit return.");
503 #else
504 case ESCAPE:
505 c = hero;
506 wmove(cw, c.y, c.x);
507 draw(cw);
508 case '\n':
509 case '\r':
510 return(c);
511 when 'h':
512 case 'H':
513 c.x--;
514 when 'j':
515 case 'J':
516 c.y++;
517 when 'k':
518 case 'K':
519 c.y--;
520 when 'l':
521 case 'L':
522 c.x++;
523 when 'y':
524 case 'Y':
525 c.x--; c.y--;
526 when 'u':
527 case 'U':
528 c.x++; c.y--;
529 when 'b':
530 case 'B':
531 c.x--; c.y++;
532 when 'n':
533 case 'N':
534 c.x++; c.y++;
535 when '*':
536 msg("Use h,j,k,l,y,u,b,n to position cursor, then hit return.");
537 #endif
538 }
539 c.y = max(c.y, 1);
540 c.y = min(c.y, lines - 3);
541 c.x = max(c.x, 0);
542 c.x = min(c.x, cols - 1);
543 wmove(cw, c.y, c.x);
544 draw(cw);
545 }
546 }
547
548 /*
549 * set up the direction co_ordinate for use in various "prefix" commands
550 */
551 bool
552 get_dir(direction)
553 coord *direction;
554 {
555 register char *prompt;
556 register bool gotit;
557 int x,y;
558
559 prompt = terse ? "Direction?" : "Which direction? ";
560 msg(prompt);
561 do
562 {
563 gotit = TRUE;
564 switch (md_readchar(msgw))
565 {
566 case 'h': case'H': direction->y = 0; direction->x = -1;
567 when 'j': case'J': direction->y = 1; direction->x = 0;
568 when 'k': case'K': direction->y = -1; direction->x = 0;
569 when 'l': case'L': direction->y = 0; direction->x = 1;
570 when 'y': case'Y': direction->y = -1; direction->x = -1;
571 when 'u': case'U': direction->y = -1; direction->x = 1;
572 when 'b': case'B': direction->y = 1; direction->x = -1;
573 when 'n': case'N': direction->y = 1; direction->x = 1;
574 case 0:
575 when 3: quit(0);
576 return(FALSE);
577 when ESCAPE: return (FALSE);
578 otherwise:
579 mpos = 0;
580 msg(prompt);
581 gotit = FALSE;
582 }
583 } until (gotit);
584 if ((on(player, ISHUH) || on(player, ISDANCE)) && rnd(100) > 20) {
585 do
586 {
587 *direction = grid[rnd(9)];
588 } while (direction->y == 0 && direction->x == 0);
589 }
590 else if (on(player, ISFLEE)) {
591 y = hero.y;
592 x = hero.x;
593 while (shoot_ok(winat(y, x))) {
594 y += direction->y;
595 x += direction->x;
596 }
597 if (isalpha(mvwinch(mw, y, x))) {
598 if (y == player.t_dest->y && x == player.t_dest->x) {
599 mpos = 0;
600 msg("You are too frightened to!");
601 return(FALSE);
602 }
603 }
604 }
605 mpos = 0;
606 return TRUE;
607 }
608
609 /*
610 * see if the object is one of the currently used items
611 */
612 is_current(obj)
613 register struct object *obj;
614 {
615 if (obj == NULL)
616 return FALSE;
617 if (obj == cur_armor || obj == cur_weapon ||
618 obj == cur_ring[LEFT_1] || obj == cur_ring[LEFT_2] ||
619 obj == cur_ring[LEFT_3] || obj == cur_ring[LEFT_4] ||
620 obj == cur_ring[RIGHT_1] || obj == cur_ring[RIGHT_2] ||
621 obj == cur_ring[RIGHT_3] || obj == cur_ring[RIGHT_4] ||
622 obj == cur_misc[WEAR_BOOTS] || obj == cur_misc[WEAR_JEWEL] ||
623 obj == cur_misc[WEAR_BRACERS] || obj == cur_misc[WEAR_CLOAK] ||
624 obj == cur_misc[WEAR_GAUNTLET] || obj == cur_misc[WEAR_NECKLACE]) {
625
626 return TRUE;
627 }
628
629 /* Is it a "current" relic? */
630 if (obj->o_type == RELIC) {
631 switch (obj->o_which) {
632 case MUSTY_DAGGER:
633 case EMORI_CLOAK:
634 case HEIL_ANKH:
635 case YENDOR_AMULET:
636 case STONEBONES_AMULET:
637 case HRUGGEK_MSTAR:
638 case AXE_AKLAD:
639 case YEENOGHU_FLAIL:
640 case SURTUR_RING:
641 if (cur_relic[obj->o_which]) return TRUE;
642 }
643 }
644
645 return FALSE;
646 }
647
648
649 /*
650 * Look:
651 * A quick glance all around the player
652 */
653
654 look(wakeup, runend)
655 bool wakeup; /* Should we wake up monsters */
656 bool runend; /* At end of a run -- for mazes */
657 {
658 register int x, y, radius;
659 register char ch, och;
660 register int oldx, oldy;
661 register bool inpass, horiz, vert, do_light = FALSE, do_blank = FALSE;
662 register int passcount = 0, curfloorcount = 0, nextfloorcount = 0;
663 register struct room *rp;
664 register int ey, ex;
665
666 inpass = ((rp = roomin(&hero)) == NULL); /* Are we in a passage? */
667
668 /* Are we moving vertically or horizontally? */
669 if (runch == 'h' || runch == 'l') horiz = TRUE;
670 else horiz = FALSE;
671 if (runch == 'j' || runch == 'k') vert = TRUE;
672 else vert = FALSE;
673
674 /* How far around himself can the player see? */
675 if (levtype == OUTSIDE) {
676 if (daytime) radius = 6;
677 else if (lit_room(rp)) radius = 3;
678 else radius = 1;
679 }
680 else radius = 1;
681
682 getyx(cw, oldy, oldx); /* Save current position */
683
684 /* Blank out the floor around our last position and check for
685 * moving out of a corridor in a maze.
686 */
687 if (levtype == OUTSIDE) do_blank = !daytime;
688 else if (oldrp != NULL && !lit_room(oldrp) && off(player, ISBLIND))
689 do_blank = TRUE;
690
691 /* Now move around the old position and blank things out */
692 ey = player.t_oldpos.y + radius;
693 ex = player.t_oldpos.x + radius;
694 for (x = player.t_oldpos.x - radius; x <= ex; x++)
695 if (x >= 0 && x < cols)
696 for (y = player.t_oldpos.y - radius; y <= ey; y++) {
697 struct linked_list *it;
698 coord here; /* Current <x,y> coordinate */
699 char savech; /* Saves character in monster window */
700 bool in_room; /* Are we in a room? */
701
702 if (y < 1 || y > lines - 3) continue;
703
704 /* See what's there -- ignore monsters, just see what they're on */
705 savech = CCHAR( mvwinch(mw, y, x) );
706 waddch(mw, ' ');
707 ch = show(y, x);
708 mvwaddch(mw, y, x, savech); /* Restore monster */
709
710 /*
711 * If we have a monster that we can't see anymore, make sure
712 * that we can note that fact.
713 */
714 if (isalpha(savech) &&
715 (y < hero.y - radius || y > hero.y + radius ||
716 x < hero.x - radius || x > hero.x + radius)) {
717 /* Find the monster */
718 it = find_mons(y, x);
719 }
720 else it = NULL;
721
722 /* Are we in a room? */
723 here.y = y;
724 here.x = x;
725 in_room = (roomin(&here) != NULL);
726
727 if ((do_blank || !in_room) && (y != hero.y || x != hero.x))
728 switch (ch) {
729 case DOOR:
730 case SECRETDOOR:
731 case PASSAGE:
732 case STAIRS:
733 case TRAPDOOR:
734 case TELTRAP:
735 case BEARTRAP:
736 case SLEEPTRAP:
737 case ARROWTRAP:
738 case DARTTRAP:
739 case MAZETRAP:
740 case POOL:
741 case POST:
742 case '|':
743 case '-':
744 case WALL:
745 /* If there was a monster showing, make it disappear */
746 if (isalpha(savech)) {
747 mvwaddch(cw, y, x, ch);
748
749 /*
750 * If we found it (we should!), set it to
751 * the right character!
752 */
753 if (it) (THINGPTR(it))->t_oldch = ch;
754 }
755 break;
756 when FLOOR:
757 case FOREST:
758 default:
759 mvwaddch(cw, y, x, in_room ? ' ' : PASSAGE);
760
761 /* If we found a monster, set it to darkness! */
762 if (it) (THINGPTR(it))->t_oldch = CCHAR( mvwinch(cw, y, x) );
763 }
764
765 /* Moving out of a corridor? */
766 if (levtype == MAZELEV && !ce(hero, player.t_oldpos) &&
767 !running && !isrock(ch) && /* Not running and not a wall */
768 ((vert && x != player.t_oldpos.x && y==player.t_oldpos.y) ||
769 (horiz && y != player.t_oldpos.y && x==player.t_oldpos.x)))
770 do_light = off(player, ISBLIND);
771 }
772
773 /* Take care of unlighting a corridor */
774 if (do_light && lit_room(rp)) light(&player.t_oldpos);
775
776 /* Are we coming or going between a wall and a corridor in a maze? */
777 och = show(player.t_oldpos.y, player.t_oldpos.x);
778 ch = show(hero.y, hero.x);
779 if (levtype == MAZELEV &&
780 ((isrock(och) && !isrock(ch)) || (isrock(ch) && !isrock(och)))) {
781 do_light = off(player, ISBLIND); /* Light it up if not blind */
782
783 /* Unlight what we just saw */
784 if (do_light && lit_room(&rooms[0])) light(&player.t_oldpos);
785 }
786
787 /* Look around the player */
788 ey = hero.y + radius;
789 ex = hero.x + radius;
790 for (x = hero.x - radius; x <= ex; x++)
791 if (x >= 0 && x < cols) for (y = hero.y - radius; y <= ey; y++) {
792 if (y < 1 || y >= lines - 2)
793 continue;
794 if (isalpha(mvwinch(mw, y, x)))
795 {
796 register struct linked_list *it;
797 register struct thing *tp;
798
799 if (wakeup)
800 it = wake_monster(y, x);
801 else
802 it = find_mons(y, x);
803
804 if (it) {
805 tp = THINGPTR(it);
806 tp->t_oldch = CCHAR( mvinch(y, x) );
807 if (isatrap(tp->t_oldch)) {
808 register struct trap *trp = trap_at(y, x);
809
810 tp->t_oldch = (trp->tr_flags & ISFOUND) ? tp->t_oldch
811 : trp->tr_show;
812 }
813 if (tp->t_oldch == FLOOR && !lit_room(rp) &&
814 off(player, ISBLIND))
815 tp->t_oldch = ' ';
816 }
817 }
818
819 /*
820 * Secret doors show as walls
821 */
822 if ((ch = show(y, x)) == SECRETDOOR)
823 ch = secretdoor(y, x);
824 /*
825 * Don't show room walls if he is in a passage and
826 * check for maze turns
827 */
828 if (off(player, ISBLIND))
829 {
830 if (y == hero.y && x == hero.x
831 || (inpass && (ch == '-' || ch == '|')))
832 continue;
833
834 /* Did we come to a crossroads in a maze? */
835 if (levtype == MAZELEV &&
836 (runend || !ce(hero, player.t_oldpos)) &&
837 !isrock(ch) && /* Not a wall */
838 ((vert && x != hero.x && y == hero.y) ||
839 (horiz && y != hero.y && x == hero.x)))
840 /* Just came to a turn */
841 do_light = off(player, ISBLIND);
842 }
843 else if (y != hero.y || x != hero.x)
844 continue;
845
846 wmove(cw, y, x);
847 waddch(cw, ch);
848 if (door_stop && !firstmove && running)
849 {
850 switch (runch)
851 {
852 case 'h':
853 if (x == hero.x + 1)
854 continue;
855 when 'j':
856 if (y == hero.y - 1)
857 continue;
858 when 'k':
859 if (y == hero.y + 1)
860 continue;
861 when 'l':
862 if (x == hero.x - 1)
863 continue;
864 when 'y':
865 if ((x + y) - (hero.x + hero.y) >= 1)
866 continue;
867 when 'u':
868 if ((y - x) - (hero.y - hero.x) >= 1)
869 continue;
870 when 'n':
871 if ((x + y) - (hero.x + hero.y) <= -1)
872 continue;
873 when 'b':
874 if ((y - x) - (hero.y - hero.x) <= -1)
875 continue;
876 }
877 switch (ch)
878 {
879 case DOOR:
880 if (x == hero.x || y == hero.y)
881 running = FALSE;
882 break;
883 case PASSAGE:
884 if (x == hero.x || y == hero.y)
885 passcount++;
886 break;
887 case FLOOR:
888 /* Stop by new passages in a maze (floor next to us) */
889 if ((levtype == MAZELEV) &&
890 !(hero.y == y && hero.x == x)) {
891 if (vert) { /* Moving vertically */
892 /* We have a passage on our row */
893 if (y == hero.y) curfloorcount++;
894
895 /* Some passage on the next row */
896 else if (y != player.t_oldpos.y)
897 nextfloorcount++;
898 }
899 else { /* Moving horizontally */
900 /* We have a passage on our column */
901 if (x == hero.x) curfloorcount++;
902
903 /* Some passage in the next column */
904 else if (x != player.t_oldpos.x)
905 nextfloorcount++;
906 }
907 }
908 case '|':
909 case '-':
910 case ' ':
911 break;
912 default:
913 running = FALSE;
914 break;
915 }
916 }
917 }
918
919 /* Have we passed a side passage, with multiple choices? */
920 if (curfloorcount > 0 && nextfloorcount > 0) running = FALSE;
921
922 else if (door_stop && !firstmove && passcount > 1)
923 running = FALSE;
924
925 /* Do we have to light up the area (just stepped into a new corridor)? */
926 if (do_light && !running && lit_room(rp)) light(&hero);
927
928 mvwaddch(cw, hero.y, hero.x, PLAYER);
929 wmove(cw, oldy, oldx);
930 if (!ce(player.t_oldpos, hero)) {
931 player.t_oldpos = hero; /* Don't change if we didn't move */
932 oldrp = rp;
933 }
934 }
935
936 /*
937 * Lower a level of experience
938 */
939
940 lower_level(who)
941 short who;
942 {
943 int fewer, nsides;
944 unsigned int exp;
945
946 msg("You suddenly feel less skillful.");
947 if (--pstats.s_lvl == 0)
948 death(who); /* All levels gone */
949 if (pstats.s_lvladj > 0) { /* lose artificial levels first */
950 pstats.s_lvladj--;
951 return;
952 }
953 exp = char_class[player.t_ctype].cap;
954 if (pstats.s_exp >= exp*2)
955 pstats.s_exp -= exp;
956 else
957 pstats.s_exp /= 2;
958
959 nsides = char_class[player.t_ctype].hit_pts;
960 fewer = max(1, roll(1,nsides) + const_bonus());
961 pstats.s_hpt -= fewer;
962 max_stats.s_hpt -= fewer;
963 if (pstats.s_hpt < 1)
964 pstats.s_hpt = 1;
965 if (max_stats.s_hpt < 1)
966 death(who);
967 }
968
969 /*
970 * print out the name of a monster
971 */
972 char *
973 monster_name(tp)
974 register struct thing *tp;
975 {
976 prbuf[0] = '\0';
977 if (on(*tp, ISFLEE) || on(*tp, WASTURNED))
978 strcat(prbuf, "terrified ");
979 if (on(*tp, ISHUH))
980 strcat(prbuf, "confused ");
981 if (on(*tp, ISCHARMED))
982 strcat(prbuf, "charmed ");
983 else if (on(*tp, ISFLY))
984 strcat(prbuf, "flying ");
985
986 /* If it is sleeping or stoned, write over any of the above attributes */
987 if (off(*tp, ISRUN))
988 strcpy(prbuf, "sleeping ");
989 if (on(*tp, ISSTONE))
990 strcpy(prbuf, "petrified ");
991
992 if (tp->t_name) strcat(prbuf, tp->t_name);
993 else strcat(prbuf, monsters[tp->t_index].m_name);
994
995 return(prbuf);
996 }
997
998 /*
999 * move_hero:
1000 * Try to move the hero somplace besides next to where he is. We ask him
1001 * where. There can be restrictions based on why he is moving.
1002 */
1003
1004 bool
1005 move_hero(why)
1006 int why;
1007 {
1008 char *action;
1009 char which;
1010 coord c;
1011
1012 switch (why) {
1013 case H_TELEPORT:
1014 action = "teleport";
1015 }
1016
1017 msg("Where do you wish to %s to? (* for help) ", action);
1018 c = get_coordinates();
1019 mpos = 0;
1020 which = CCHAR( winat(c.y, c.x) );
1021 switch (which) {
1022 default:
1023 if (!isrock(which) || off(player, CANINWALL)) break;
1024
1025 case FLOOR:
1026 case PASSAGE:
1027 case DOOR:
1028 case STAIRS:
1029 case POST:
1030 case GOLD:
1031 case POTION:
1032 case SCROLL:
1033 case FOOD:
1034 case WEAPON:
1035 case ARMOR:
1036 case RING:
1037 case MM:
1038 case RELIC:
1039 case STICK:
1040 hero = c;
1041 return(TRUE);
1042 }
1043 return(FALSE);
1044 }
1045
1046 /*
1047 * raise_level:
1048 * The guy just magically went up a level.
1049 */
1050
1051 raise_level()
1052 {
1053 unsigned long test; /* Next level -- be sure it is not an overflow */
1054
1055 test = check_level(); /* Get next boundary */
1056
1057 /* Be sure it is higher than what we have no -- else overflow */
1058 if (test > pstats.s_exp) pstats.s_exp = test;
1059 check_level();
1060 }
1061
1062 /*
1063 * saving throw matrix for character saving throws
1064 * this table is indexed by char type and saving throw type
1065 */
1066 static int st_matrix[NUM_CHARTYPES][5] = {
1067 /* Poison, Petrify, wand, Breath, Magic */
1068 { 14, 15, 16, 16, 17 },
1069 { 14, 15, 16, 16, 17 },
1070 { 14, 15, 16, 16, 17 },
1071 { 14, 13, 11, 15, 12 },
1072 { 10, 13, 14, 16, 15 },
1073 { 13, 12, 14, 16, 15 },
1074 { 13, 12, 14, 16, 15 },
1075 { 10, 13, 14, 16, 15 },
1076 { 13, 12, 14, 16, 15 },
1077 { 14, 15, 16, 16, 17 }
1078 };
1079
1080 /*
1081 * save:
1082 * See if a creature saves against something
1083 */
1084 save(which, who, adj)
1085 int which; /* which type of save */
1086 struct thing *who; /* who is saving */
1087 int adj; /* saving throw adjustment */
1088 {
1089 register int need, level, protect;
1090
1091 protect = 0;
1092 level = who->t_stats.s_lvl;
1093 need = st_matrix[who->t_ctype][which];
1094 switch (who->t_ctype) {
1095 case C_FIGHTER:
1096 case C_RANGER:
1097 case C_PALADIN:
1098 case C_MONSTER:
1099 need -= (level-1) / 2;
1100 when C_MAGICIAN:
1101 need -= 2 * (level-1) / 5;
1102 when C_CLERIC:
1103 case C_DRUID:
1104 need -= (level-1) / 3;
1105 when C_THIEF:
1106 case C_ASSASIN:
1107 case C_MONK:
1108 need -= 2 * (level-1) / 4;
1109 }
1110 /*
1111 * add in pluses against poison for execeptional constitution
1112 */
1113 if (which == VS_POISON && who->t_stats.s_const > 18)
1114 need -= (who->t_stats.s_const - 17) / 2;
1115 if (who == &player) {
1116 /*
1117 * does the player have a ring of protection on?
1118 */
1119 protect += ring_value(R_PROTECT);
1120 /*
1121 * does the player have a cloak of protection on?
1122 */
1123 if (cur_misc[WEAR_CLOAK])
1124 protect += cur_misc[WEAR_CLOAK]->o_ac;
1125
1126 protect = min(protect, 4);/* no more than a +4 bonus */
1127 need -= protect;
1128 }
1129 need -= adj;
1130 /*
1131 * always miss or save on a 1 (except for UNIQUEs
1132 */
1133 if (who == &player || off(*who, ISUNIQUE))
1134 need = max(need, 2);
1135 need = min(20, need); /* always make our save on a 20 */
1136 debug("need a %d to save", need);
1137 return (roll(1, 20) >= need);
1138 }
1139
1140
1141 /*
1142 * secret_door:
1143 * Figure out what a secret door looks like.
1144 */
1145
1146 secretdoor(y, x)
1147 register int y, x;
1148 {
1149 register int i;
1150 register struct room *rp;
1151 register coord *cpp;
1152 static coord cp;
1153
1154 cp.y = y;
1155 cp.x = x;
1156 cpp = &cp;
1157 for (rp = rooms, i = 0; i < MAXROOMS; rp++, i++)
1158 if (inroom(rp, cpp))
1159 if (y == rp->r_pos.y || y == rp->r_pos.y + rp->r_max.y - 1)
1160 return('-');
1161 else
1162 return('|');
1163
1164 return('p');
1165 }
1166
1167 /*
1168 * this routine computes the players current strength
1169 */
1170 str_compute()
1171 {
1172 if (cur_misc[WEAR_GAUNTLET] != NULL &&
1173 cur_misc[WEAR_GAUNTLET]->o_which == MM_G_OGRE) {
1174 if (cur_misc[WEAR_GAUNTLET]->o_flags & ISCURSED)
1175 return (3);
1176 else
1177 return (18);
1178 }
1179 else
1180 return (pstats.s_str);
1181 }
1182
1183 /*
1184 * copy string using unctrl for things
1185 */
1186 strucpy(s1, s2, len)
1187 register char *s1, *s2;
1188 register int len;
1189 {
1190 register char *sp;
1191
1192 while (len--)
1193 {
1194 strcpy(s1, (sp = unctrl(*s2++)));
1195 s1 += strlen(sp);
1196 }
1197 *s1 = '\0';
1198 }
1199
1200 /*
1201 * tr_name:
1202 * print the name of a trap
1203 */
1204
1205 char *
1206 tr_name(ch)
1207 char ch;
1208 {
1209 register char *s;
1210
1211 switch (ch)
1212 {
1213 case TRAPDOOR:
1214 s = terse ? "A trapdoor." : "You found a trapdoor.";
1215 when BEARTRAP:
1216 s = terse ? "A beartrap." : "You found a beartrap.";
1217 when SLEEPTRAP:
1218 s = terse ? "A sleeping gas trap.":"You found a sleeping gas trap.";
1219 when ARROWTRAP:
1220 s = terse ? "An arrow trap." : "You found an arrow trap.";
1221 when TELTRAP:
1222 s = terse ? "A teleport trap." : "You found a teleport trap.";
1223 when DARTTRAP:
1224 s = terse ? "A dart trap." : "You found a poison dart trap.";
1225 when POOL:
1226 s = terse ? "A shimmering pool." : "You found a shimmering pool";
1227 when MAZETRAP:
1228 s = terse ? "A maze entrance." : "You found a maze entrance";
1229 }
1230 return s;
1231 }
1232
1233 /*
1234 * for printfs: if string starts with a vowel, return "n" for an "an"
1235 */
1236 char *
1237 vowelstr(str)
1238 register char *str;
1239 {
1240 switch (*str)
1241 {
1242 case 'a':
1243 case 'e':
1244 case 'i':
1245 case 'o':
1246 case 'u':
1247 return "n";
1248 default:
1249 return "";
1250 }
1251 }
1252
1253 /*
1254 * wake up a room full (hopefully) of creatures
1255 */
1256 wake_room(rp)
1257 register struct room *rp;
1258 {
1259 register struct linked_list *item;
1260 register struct thing *tp;
1261
1262 for (item=mlist; item!=NULL; item=next(item)) {
1263 tp = THINGPTR(item);
1264 if (off(*tp,ISRUN) && on(*tp,ISMEAN) && roomin(&tp->t_pos) == rp)
1265 runto(tp, &hero);
1266 }
1267 }
1268
1269
1270 /*
1271 * waste_time:
1272 * Do nothing but let other things happen
1273 */
1274
1275 waste_time()
1276 {
1277 if (inwhgt) /* if from wghtchk then done */
1278 return;
1279 do_daemons(BEFORE);
1280 do_fuses(BEFORE);
1281 do_daemons(AFTER);
1282 do_fuses(AFTER);
1283 }