comparison xrogue/util.c @ 133:e6179860cb76

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