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