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