Annotation of early-roguelike/xrogue/move.c, Revision 1.1.1.1
1.1 rubenllo 1: /*
2: move.c - Hero movement commands
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: * Used to hold the new hero position
26: */
27:
28: coord move_nh;
29:
30: static char Moves[3][3] = {
31: { 'y', 'k', 'u' },
32: { 'h', '.', 'l' },
33: { 'b', 'j', 'n' }
34: };
35:
36: /*
37: * be_trapped:
38: * The guy stepped on a trap.... Make him pay.
39: */
40:
41: char
42: be_trapped(struct thing *th, coord *tc)
43: {
44: register struct trap *tp;
45: register char ch, *mname = NULL;
46: register bool is_player = (th == &player),
47: can_see;
48: register struct linked_list *mitem = NULL;
49: register struct thing *mp;
50:
51:
52: /* Can the player see the creature? */
53: can_see = cansee(tc->y, tc->x);
54: can_see &= (is_player || !invisible(th));
55:
56: tp = trap_at(tc->y, tc->x);
57: /*
58: * if he's wearing boots of elvenkind, he won't set off the trap
59: * unless its a magic pool (they're not really traps)
60: */
61: if (is_player &&
62: cur_misc[WEAR_BOOTS] != NULL &&
63: cur_misc[WEAR_BOOTS]->o_which == MM_ELF_BOOTS &&
64: tp->tr_type != POOL)
65: return '\0';
66:
67: /*
68: * if the creature is flying then it won't set off the trap
69: */
70: if (on(*th, ISFLY))
71: return '\0';
72:
73: tp->tr_flags |= ISFOUND;
74:
75: if (!is_player) {
76: mitem = find_mons(th->t_pos.y, th->t_pos.x);
77: mname = monster_name(th);
78: }
79: else {
80: count = running = FALSE;
81: mvwaddch(cw, tp->tr_pos.y, tp->tr_pos.x, tp->tr_type);
82: }
83: switch (ch = tp->tr_type) {
84: case TRAPDOOR:
85: if (is_player) {
86: level++;
87: pstats.s_hpt -= roll(1, 10);
88: if (pstats.s_hpt < 1) {
89: pstats.s_hpt = -1;
90: death(D_FALL);
91: }
92: wclear(cw);
93: wclear(mw);
94: new_level(NORMLEV);
95: msg("You fell through a trap! ");
96: }
97: else {
98: if (can_see) msg("%s fell into a trap!", prname(mname, TRUE));
99:
100: /*
101: * See if the fall killed the monster
102: * don't let a UNIQUE die since it might have an artifact
103: * that we need
104: */
105: if (off(*th,ISUNIQUE) && (th->t_stats.s_hpt-=roll(1,10)) <= 0){
106: killed(mitem, FALSE, FALSE, FALSE);
107: }
108: else { /* Just move monster to next level */
109: check_residue(th);
110:
111: /* Erase the monster from the old position */
112: if (isalpha(mvwinch(cw, th->t_pos.y, th->t_pos.x)))
113: mvwaddch(cw, th->t_pos.y, th->t_pos.x, th->t_oldch);
114: mvwaddch(mw, th->t_pos.y, th->t_pos.x, ' ');
115:
116: /* let him summon on next lvl */
117: if (on (*th, HASSUMMONED)) {
118: turn_off(*th, HASSUMMONED);
119: turn_on(*th, CANSUMMON);
120: }
121: turn_on(*th,ISELSEWHERE);
122: detach(mlist, mitem);
123: attach(tlist, mitem); /* remember him next level */
124:
125: /* Make sure that no one is still chasing us */
126: for (mitem = mlist; mitem != NULL; mitem = next(mitem)) {
127: mp = THINGPTR(mitem);
128: if (mp->t_dest == &th->t_pos) {
129: mp->t_dest = &hero;
130: mp->t_wasshot = FALSE;
131: turn_off(*mp, ISFLEE); /* Don't run away! */
132: }
133: }
134:
135: /* Make sure we were not chasing a monster here */
136: th->t_dest = &hero;
137: if (on(*th, ISFRIENDLY)) turn_off(*th, ISFLEE);
138: }
139: }
140: /* worm hole trap to OUTSIDE */
141: when WORMHOLE:
142: if (is_player) {
143: prev_max = 1000; /* flag used in n_level.c */
144: level++;
145: pstats.s_hpt -= roll(1, 10);
146: if (pstats.s_hpt < 1) {
147: pstats.s_hpt = -1;
148: death(D_FALL);
149: }
150: new_level(OUTSIDE);
151: msg("You suddenly find yourself in strange surroundings! ");
152: return(ch);
153: }
154: else {
155: if (can_see) msg("%s fell into the worm hole! ", prname(mname, TRUE));
156:
157: /*
158: * See if the fall killed the monster
159: * don't let a UNIQUE die since it might have an artifact
160: * that we need
161: */
162: if (off(*th,ISUNIQUE) && (th->t_stats.s_hpt-=roll(1,10)) <= 0){
163: killed(mitem, FALSE, FALSE, FALSE);
164: }
165: else { /* Just move monster to next level */
166: check_residue(th);
167:
168: /* Erase the monster from the old position */
169: if (isalpha(mvwinch(cw, th->t_pos.y, th->t_pos.x)))
170: mvwaddch(cw, th->t_pos.y, th->t_pos.x, th->t_oldch);
171: mvwaddch(mw, th->t_pos.y, th->t_pos.x, ' ');
172:
173: /* let him summon on next lvl */
174: if (on (*th, HASSUMMONED)) {
175: turn_off(*th, HASSUMMONED);
176: turn_on(*th, CANSUMMON);
177: }
178:
179: turn_on(*th,ISELSEWHERE);
180: detach(mlist, mitem);
181: attach(tlist, mitem); /* remember him next level */
182:
183: /* Make sure that no one is still chasing us */
184: for (mitem = mlist; mitem != NULL; mitem = next(mitem)) {
185: mp = THINGPTR(mitem);
186: if (mp->t_dest == &th->t_pos) {
187: mp->t_dest = &hero;
188: mp->t_wasshot = FALSE;
189: turn_off(*mp, ISFLEE); /* Don't run away! */
190: }
191: }
192:
193: /* Make sure we were not chasing a monster here */
194: th->t_dest = &hero;
195: if (on(*th, ISFRIENDLY)) turn_off(*th, ISFLEE);
196: }
197: }
198: when BEARTRAP:
199: if (is_stealth(th)) {
200: if (is_player) msg("You pass a bear trap.");
201: else if (can_see) msg("%s passes a bear trap.",
202: prname(mname, TRUE));
203: }
204: else {
205: th->t_no_move += movement(&player) * BEARTIME;
206: th->t_action = A_FREEZE;
207: if (is_player) msg("You are caught in a bear trap.");
208: else if (can_see) msg("%s is caught in a bear trap.",
209: prname(mname, TRUE));
210: }
211: when SLEEPTRAP:
212: if (is_player) {
213: if (!ISWEARING(R_ALERT)) {
214: msg("A strange white mist envelops you. You fall asleep. ");
215: player.t_no_move += movement(&player) * SLEEPTIME;
216: player.t_action = A_FREEZE;
217: }
218: else {
219: msg("The white mist invigorates you. ");
220: }
221: }
222: else {
223: if (can_see)
224: msg("A strange white mist envelops %s. ",
225: prname(mname, FALSE));
226: if (on(*th, ISUNDEAD)) {
227: if (can_see)
228: msg("The mist doesn't seem to affect %s.",
229: prname(mname, FALSE));
230: }
231: else {
232: th->t_no_move += movement(th) * SLEEPTIME;
233: th->t_action = A_FREEZE;
234: }
235: }
236: when ARROWTRAP:
237: if (swing(th->t_ctype, th->t_stats.s_lvl-1, th->t_stats.s_arm, 1))
238: {
239: if (is_player) {
240: msg("Oh no! An arrow shot you.");
241: if ((pstats.s_hpt -= roll(1, 8)) < 1) {
242: pstats.s_hpt = -1;
243: msg("The arrow killed you. --More--");
244: wait_for(' ');
245: death(D_ARROW);
246: }
247: }
248: else {
249: if (can_see)
250: msg("An arrow shot %s.", prname(mname, FALSE));
251: if ((th->t_stats.s_hpt -= roll(1, 8)) < 1) {
252: if (can_see)
253: msg("The arrow killed %s.", prname(mname, FALSE));
254: killed(mitem, FALSE, FALSE, TRUE);
255: }
256: }
257: }
258: else
259: {
260: register struct linked_list *item;
261: register struct object *arrow;
262:
263: if (is_player) msg("An arrow shoots past you.");
264: else if (can_see)
265: msg("An arrow shoots by %s.", prname(mname, FALSE));
266: item = new_item(sizeof *arrow);
267: arrow = OBJPTR(item);
268: arrow->o_type = WEAPON;
269: arrow->contents = NULL;
270: arrow->o_which = ARROW;
271: arrow->o_hplus = rnd(7) - 1;
272: arrow->o_dplus = rnd(7) - 1;
273: init_weapon(arrow, ARROW);
274: arrow->o_count = 1;
275: arrow->o_pos = *tc;
276: arrow->o_mark[0] = '\0';
277: fall(item, FALSE);
278: }
279: when TELTRAP:
280: if (is_player) teleport();
281: else {
282: register int rm;
283: struct room *old_room; /* old room of monster */
284:
285: /*
286: * Erase the monster from the old position
287: */
288: if (isalpha(mvwinch(cw, th->t_pos.y, th->t_pos.x)))
289: mvwaddch(cw, th->t_pos.y, th->t_pos.x, th->t_oldch);
290: mvwaddch(mw, th->t_pos.y, th->t_pos.x, ' ');
291: /*
292: * check to see if room should go dark
293: */
294: if (on(*th, HASFIRE)) {
295: old_room=roomin(&th->t_pos);
296: if (old_room != NULL) {
297: register struct linked_list *fire_item;
298:
299: for (fire_item = old_room->r_fires; fire_item != NULL;
300: fire_item = next(fire_item)) {
301: if (THINGPTR(fire_item) == th) {
302: detach(old_room->r_fires, fire_item);
303: destroy_item(fire_item);
304:
305: if (old_room->r_fires == NULL) {
306: old_room->r_flags &= ~HASFIRE;
307: if (can_see) light(&hero);
308: }
309: }
310: }
311: }
312: }
313:
314: /* Get a new position */
315: do {
316: rm = rnd_room();
317: rnd_pos(&rooms[rm], &th->t_pos);
318: } until(winat(th->t_pos.y, th->t_pos.x) == FLOOR);
319:
320: /* Put it there */
321: mvwaddch(mw, th->t_pos.y, th->t_pos.x, th->t_type);
322: th->t_oldch = mvwinch(cw, th->t_pos.y, th->t_pos.x);
323: /*
324: * check to see if room that creature appears in should
325: * light up
326: */
327: if (on(*th, HASFIRE)) {
328: register struct linked_list *fire_item;
329:
330: fire_item = creat_item();
331: ldata(fire_item) = (char *) th;
332: attach(rooms[rm].r_fires, fire_item);
333:
334: rooms[rm].r_flags |= HASFIRE;
335: if(cansee(th->t_pos.y, th->t_pos.x) &&
336: next(rooms[rm].r_fires) == NULL)
337: light(&hero);
338: }
339: if (can_see)
340: msg("%s seems to have disappeared!", prname(mname, TRUE));
341: }
342: when DARTTRAP:
343: if (swing(th->t_ctype, th->t_stats.s_lvl+1, th->t_stats.s_arm, 1)) {
344: if (is_player) {
345: msg("A small dart just hit you. ");
346: if ((pstats.s_hpt -= roll(1, 8)) < 1) {
347: pstats.s_hpt = -1;
348: msg("The dart killed you.");
349: wait_for(' ');
350: death(D_DART);
351: }
352:
353: /* Now the poison */
354: if (!save(VS_POISON, &player, 0)) {
355: /* 75% chance it will do point damage - else strength */
356: if (rnd(100) < 75) {
357: pstats.s_hpt /= 2;
358: if (pstats.s_hpt < 1) {
359: pstats.s_hpt = -1;
360: death(D_POISON);
361: }
362: }
363: else if (!ISWEARING(R_SUSABILITY))
364: chg_str(-1);
365: }
366: }
367: else {
368: if (can_see)
369: msg("A small dart stabs the %s. ",
370: prname(mname, FALSE));
371: if ((th->t_stats.s_hpt -= roll(1,8)) < 1) {
372: if (can_see)
373: msg("The dart killed %s.", prname(mname, FALSE));
374: killed(mitem, FALSE, FALSE, TRUE);
375: }
376: if (!save(VS_POISON, th, 0)) {
377: th->t_stats.s_hpt /= 2 + level;
378: if (th->t_stats.s_hpt < 1) {
379: if (can_see)
380: msg("The dart killed %s.", prname(mname,FALSE));
381: killed(mitem, FALSE, FALSE, TRUE);
382: }
383: }
384: }
385: }
386: else {
387: if (is_player)
388: msg("A small dart whizzes by your ear and vanishes.");
389: else if (can_see)
390: msg("A small dart whizzes by %s's ear and vanishes.",
391: prname(mname, FALSE));
392: }
393: when POOL: {
394: register int i;
395:
396: i = rnd(100);
397: if (is_player) {
398: if ((tp->tr_flags & ISGONE)) {
399: if (i < 56) {
400: teleport(); /* teleport away */
401: pool_teleport = TRUE;
402: }
403: else if((i < 72) && level > 4) {
404: level -= rnd(4) + 1;
405: cur_max = level;
406: new_level(NORMLEV);
407: pool_teleport = TRUE;
408: msg("You here a faint groan from below.");
409: }
410: else if(i < 85) {
411: level += rnd(4) + 1;
412: new_level(NORMLEV);
413: pool_teleport = TRUE;
414: msg("You find yourself in strange surroundings.");
415: }
416: else if(i > 96) {
417: msg("Oh no!!! You drown in the pool!!! --More--");
418: wait_for(' ');
419: pstats.s_hpt = -1;
420: death(D_DROWN);
421: }
422: else {
423: new_level(NORMLEV);
424: pool_teleport = TRUE;
425: msg("You are whisked away to another region.");
426: }
427: }
428: }
429: else {
430: if (i < 60) {
431: if (can_see) {
432: /* Drowns */
433: if (i < 50)
434: msg("%s drowned in the pool!", prname(mname, TRUE));
435:
436: /* Teleported to another level */
437: else msg("%s disappeared!", prname(mname, TRUE));
438: }
439: killed(mitem, FALSE, FALSE, TRUE);
440: }
441: }
442: }
443: when MAZETRAP:
444: if (is_player) {
445: pstats.s_hpt -= roll(1, 10);
446: level++;
447: if (pstats.s_hpt < 1) {
448: pstats.s_hpt = -1;
449: death(D_FALL);
450: }
451: wclear(cw);
452: wclear(mw);
453: new_level(MAZELEV);
454: msg("You are surrounded by twisty passages! ");
455: }
456: else {
457: if (can_see) msg("%s fell into a maze trap!", prname(mname, TRUE));
458: if (on(*th, ISUNIQUE)) {
459: check_residue(th);
460:
461: /* Erase the monster from the old position */
462: if (isalpha(mvwinch(cw, th->t_pos.y, th->t_pos.x)))
463: mvwaddch(cw, th->t_pos.y, th->t_pos.x, th->t_oldch);
464: mvwaddch(mw, th->t_pos.y, th->t_pos.x, ' ');
465:
466: /* let him summon on next lvl */
467: if (on (*th, HASSUMMONED)) {
468: turn_off(*th, HASSUMMONED);
469: turn_on(*th, CANSUMMON);
470: }
471: turn_on(*th,ISELSEWHERE);
472: detach(mlist, mitem);
473: attach(tlist, mitem); /* remember him next level */
474:
475: /* Make sure that no one is still chasing us */
476: for (mitem = mlist; mitem != NULL; mitem = next(mitem)) {
477: mp = THINGPTR(mitem);
478: if (mp->t_dest == &th->t_pos) {
479: mp->t_dest = &hero;
480: mp->t_wasshot = FALSE;
481: turn_off(*mp, ISFLEE); /* Don't run away! */
482: }
483: }
484:
485: /* Make sure we were not chasing a monster here */
486: th->t_dest = &hero;
487: if (on(*th, ISFRIENDLY)) turn_off(*th, ISFLEE);
488: }
489: else
490: killed(mitem, FALSE, FALSE, FALSE);
491: }
492: }
493:
494: /* Move the cursor back onto the hero */
495: wmove(cw, hero.y, hero.x);
496:
497: flushinp();
498: return(ch);
499: }
500:
501: /*
502: * blue_light:
503: * magically light up a room (or level or make it dark)
504: */
505:
506: bool
507: blue_light(bool blessed, bool cursed)
508: {
509: register struct room *rp;
510: bool ret_val=FALSE; /* Whether or not affect is known */
511:
512: rp = roomin(&hero); /* What room is hero in? */
513:
514: /* Darken the room if the magic is cursed */
515: if (cursed) {
516: if ((rp == NULL) || !lit_room(rp)) msg(nothing);
517: else {
518: rp->r_flags |= ISDARK;
519: if (!lit_room(rp) && (levtype != OUTSIDE || !daytime) &&
520: !ISWEARING(R_LIGHT))
521: msg("The %s suddenly goes dark.",
522: levtype == OUTSIDE ? "area" : "room");
523: else msg(nothing);
524: ret_val = TRUE;
525: }
526: }
527: else {
528: ret_val = TRUE;
529: if (rp && !lit_room(rp) &&
530: (levtype != OUTSIDE || !daytime)) {
531: addmsg("The %s is lit", levtype == OUTSIDE ? "area" : "room");
532: addmsg(" by a %s blue light.", blessed ? "bright" : "shimmering");
533: endmsg();
534: }
535: else if (winat(hero.y, hero.x) == PASSAGE)
536: msg("The corridor glows %sand then fades",
537: blessed ? "brightly " : "");
538: else {
539: ret_val = FALSE;
540: msg(nothing);
541: }
542: if (blessed) {
543: register int i; /* Index through rooms */
544:
545: for (i=0; i<MAXROOMS; i++)
546: rooms[i].r_flags &= ~ISDARK;
547: }
548: else if (rp) rp->r_flags &= ~ISDARK;
549: }
550:
551: /*
552: * Light the room and put the player back up
553: */
554: light(&hero);
555: mvwaddch(cw, hero.y, hero.x, PLAYER);
556: return(ret_val);
557: }
558:
559: /*
560: * corr_move:
561: * Check to see that a move is legal. If so, return correct character.
562: * If not, if player came from a legal place, then try to turn him.
563: */
564:
565: void
566: corr_move(int dy, int dx)
567: {
568: int legal=0; /* Number of legal alternatives */
569: register int y, x, /* Indexes though possible positions */
570: locy = 0, locx = 0; /* Hold delta of chosen location */
571:
572: /* New position */
573: move_nh.y = hero.y + dy;
574: move_nh.x = hero.x + dx;
575:
576: /* If it is a legal move, just return */
577: if (move_nh.x >= 0 && move_nh.x < cols && move_nh.y > 0 && move_nh.y < lines - 2) {
578:
579: switch (winat(move_nh.y, move_nh.x)) {
580: case WALL:
581: case VERTWALL:
582: case HORZWALL:
583: break;
584: default:
585: if (diag_ok(&hero, &move_nh, &player))
586: return;
587: }
588: }
589:
590: /* Check legal places surrounding the player -- ignore previous position */
591: for (y = hero.y - 1; y <= hero.y + 1; y++) {
592: if (y < 1 || y > lines - 3)
593: continue;
594: for (x = hero.x - 1; x <= hero.x + 1; x++) {
595: /* Ignore borders of the screen */
596: if (x < 0 || x > cols - 1)
597: continue;
598:
599: /*
600: * Ignore where we came from, where we are, and where we couldn't go
601: */
602: if ((x == hero.x - dx && y == hero.y - dy) ||
603: (x == hero.x + dx && y == hero.y + dy) ||
604: (x == hero.x && y == hero.y))
605: continue;
606:
607: switch (winat(y, x)) {
608: case WALL:
609: case VERTWALL:
610: case HORZWALL:
611: break;
612: default:
613: move_nh.y = y;
614: move_nh.x = x;
615: if (diag_ok(&hero, &move_nh, &player)) {
616: legal++;
617: locy = y - (hero.y - 1);
618: locx = x - (hero.x - 1);
619: }
620: }
621: }
622: }
623:
624: /* If we have 2 or more legal moves, make no change */
625: if (legal != 1) {
626: return;
627: }
628:
629: runch = Moves[locy][locx];
630:
631: /*
632: * For mazes, pretend like it is the beginning of a new run at each turn
633: * in order to get the lighting correct.
634: */
635: if (levtype == MAZELEV) firstmove = TRUE;
636: return;
637: }
638:
639: /*
640: * dip_it:
641: * Dip an object into a magic pool
642: */
643:
644: void
645: dip_it(void)
646: {
647: reg struct linked_list *what;
648: reg struct object *ob;
649: reg struct trap *tp;
650: reg int wh, i;
651:
652: tp = trap_at(hero.y,hero.x);
653: if (tp == NULL || tp->tr_type != POOL) {
654: msg("I see no shimmering pool here");
655: return;
656: }
657: if (tp->tr_flags & ISGONE) {
658: msg("This shimmering pool appears to have been used once already.");
659: return;
660: }
661:
662: /* It takes 3 movement periods to dip something */
663: if (player.t_action != C_DIP) {
664: if ((what = get_item(pack, "dip", ALL, FALSE, FALSE)) == NULL) {
665: msg("");
666: after = FALSE;
667: return;
668: }
669:
670: ob = OBJPTR(what);
671: if (ob == cur_armor ||
672: ob == cur_misc[WEAR_BOOTS] ||
673: ob == cur_misc[WEAR_JEWEL] ||
674: ob == cur_misc[WEAR_GAUNTLET] ||
675: ob == cur_misc[WEAR_CLOAK] ||
676: ob == cur_misc[WEAR_BRACERS] ||
677: ob == cur_misc[WEAR_NECKLACE] ||
678: ob == cur_ring[LEFT_1] || ob == cur_ring[LEFT_2] ||
679: ob == cur_ring[LEFT_3] || ob == cur_ring[LEFT_4] ||
680: ob == cur_ring[RIGHT_1] || ob == cur_ring[RIGHT_2] ||
681: ob == cur_ring[RIGHT_3] || ob == cur_ring[RIGHT_4]) {
682: mpos = 0;
683: msg("You'll have to take it off first.");
684: return;
685: }
686:
687: player.t_using = what; /* Remember what it is */
688: player.t_action = C_DIP; /* We are dipping */
689: player.t_no_move = 3 * movement(&player);
690: return;
691: }
692:
693: /* We have waited our time, let's dip it */
694: what = player.t_using;
695: player.t_using = NULL;
696: player.t_action = A_NIL;
697:
698: ob = OBJPTR(what);
699:
700: tp->tr_flags |= ISGONE;
701: if (ob != NULL) {
702: wh = ob->o_which;
703: ob->o_flags |= ISKNOW;
704: i = rnd(100);
705: if (ob->o_group != 0)
706: ob->o_group = newgrp(); /* change the group */
707: switch(ob->o_type) {
708: case WEAPON:
709: if(i < 60) { /* enchant weapon here */
710: if ((ob->o_flags & ISCURSED) == 0) {
711: ob->o_hplus += 1;
712: ob->o_dplus += 1;
713: }
714: else { /* weapon was prev cursed here */
715: ob->o_hplus = rnd(2);
716: ob->o_dplus = rnd(2);
717: }
718: ob->o_flags &= ~ISCURSED;
719: msg("The %s glows blue for a moment.",weaps[wh].w_name);
720: }
721: else if(i < 75) { /* curse weapon here */
722: if ((ob->o_flags & ISCURSED) == 0) {
723: ob->o_hplus = -(rnd(2)+1);
724: ob->o_dplus = -(rnd(2)+1);
725: }
726: else { /* if already cursed */
727: ob->o_hplus--;
728: ob->o_dplus--;
729: }
730: ob->o_flags |= ISCURSED;
731: msg("The %s glows red for a moment.",weaps[wh].w_name);
732: }
733: else
734: msg(nothing);
735: when ARMOR:
736: if (i < 60) { /* enchant armor */
737: if((ob->o_flags & ISCURSED) == 0)
738: ob->o_ac -= rnd(2) + 1;
739: else
740: ob->o_ac = -rnd(3)+ armors[wh].a_class;
741: ob->o_flags &= ~ISCURSED;
742: msg("The %s glows blue for a moment",armors[wh].a_name);
743: }
744: else if(i < 75){ /* curse armor */
745: if ((ob->o_flags & ISCURSED) == 0)
746: ob->o_ac = rnd(3)+ armors[wh].a_class;
747: else
748: ob->o_ac += rnd(2) + 1;
749: ob->o_flags |= ISCURSED;
750: msg("The %s glows red for a moment.",armors[wh].a_name);
751: }
752: else
753: msg(nothing);
754: when STICK: {
755: int j;
756: j = rnd(14) + 1;
757: if(i < 60) { /* add charges */
758: ob->o_charges += j;
759: ws_know[wh] = TRUE;
760: if (ob->o_flags & ISCURSED)
761: ob->o_flags &= ~ISCURSED;
762: msg("The %s %s glows blue for a moment.",
763: ws_made[wh],ws_type[wh]);
764: }
765: else if(i < 75) { /* remove charges */
766: if ((ob->o_charges -= i) < 0)
767: ob->o_charges = 0;
768: ws_know[wh] = TRUE;
769: if (ob->o_flags & ISBLESSED)
770: ob->o_flags &= ~ISBLESSED;
771: else
772: ob->o_flags |= ISCURSED;
773: msg("The %s %s glows red for a moment.",
774: ws_made[wh],ws_type[wh]);
775: }
776: else
777: msg(nothing);
778: }
779: when SCROLL:
780: s_know[wh] = TRUE;
781: msg("The '%s' scroll unfurls.",s_names[wh]);
782: when POTION:
783: p_know[wh] = TRUE;
784: msg("The %s potion bubbles for a moment.. ",p_colors[wh]);
785: when RING:
786: if(i < 60) { /* enchant ring */
787: if ((ob->o_flags & ISCURSED) == 0)
788: ob->o_ac += rnd(2) + 1;
789: else
790: ob->o_ac = rnd(2) + 1;
791: ob->o_flags &= ~ISCURSED;
792: }
793: else if(i < 75) { /* curse ring */
794: if ((ob->o_flags & ISCURSED) == 0)
795: ob->o_ac = -(rnd(2) + 1);
796: else
797: ob->o_ac -= (rnd(2) + 1);
798: ob->o_flags |= ISCURSED;
799: }
800: r_know[wh] = TRUE;
801: msg("The %s ring vibrates for a moment.",r_stones[wh]);
802: when MM:
803: m_know[wh] = TRUE;
804: switch (ob->o_which) {
805: case MM_BRACERS:
806: case MM_PROTECT:
807: if(i < 60) { /* enchant item */
808: if ((ob->o_flags & ISCURSED) == 0)
809: ob->o_ac += rnd(2) + 1;
810: else
811: ob->o_ac = rnd(2) + 1;
812: ob->o_flags &= ~ISCURSED;
813: }
814: else if(i < 75) { /* curse item */
815: if ((ob->o_flags & ISCURSED) == 0)
816: ob->o_ac = -(rnd(2) + 1);
817: else
818: ob->o_ac -= (rnd(2) + 1);
819: ob->o_flags |= ISCURSED;
820: }
821: msg("The item vibrates for a moment.");
822: when MM_CHOKE:
823: case MM_DISAPPEAR:
824: ob->o_ac = 0;
825: msg ("The dust dissolves in the pool!");
826: }
827: otherwise:
828: msg("The pool bubbles up for a moment.. ");
829: }
830: updpack(FALSE, &player);
831: }
832: else
833: msg(nothing);
834: }
835:
836: /*
837: * do_move:
838: * Check to see that a move is legal. If it is handle the
839: * consequences (fighting, picking up, etc.)
840: */
841:
842: void
843: do_move(int dy, int dx)
844: {
845: register struct room *rp, *orp;
846: register unsigned char ch;
847: struct linked_list *item;
848: register struct thing *tp = NULL;
849: coord old_hero;
850: register int wasfirstmove, moved, num_hits;
851: bool changed=FALSE; /* Did we switch places with a friendly monster? */
852:
853: wasfirstmove = firstmove;
854: firstmove = FALSE;
855: curprice = -1; /* if in trading post, we've moved off obj */
856:
857: /*
858: * Do a confused move (maybe)
859: */
860: if (player.t_action == A_NIL &&
861: ((on(player, ISHUH) && rnd(100) < 80) ||
862: (on(player, ISDANCE) && rnd(100) < 90) ||
863: (ISWEARING(R_DELUSION) && rnd(100) < 70)))
864: {
865: /* Get a random move */
866: move_nh = rndmove(&player);
867: dy = move_nh.y - hero.y;
868: dx = move_nh.x - hero.x;
869: }
870: else {
871: move_nh.y = hero.y + dy;
872: move_nh.x = hero.x + dx;
873: }
874:
875: /*
876: * Check if he tried to move off the screen or make an illegal
877: * diagonal move, and stop him if he did.
878: */
879: if (move_nh.x < 0 || move_nh.x > cols-1 || move_nh.y < 1 || move_nh.y >= lines - 2
880: || !diag_ok(&hero, &move_nh, &player))
881: {
882: after = running = FALSE;
883: player.t_action = A_NIL;
884: return;
885: }
886: if (running && ce(hero, move_nh))
887: after = running = FALSE;
888: ch = winat(move_nh.y, move_nh.x);
889:
890: /* Take care of hero trying to move close to something frightening */
891: if (on(player, ISFLEE)) {
892: if (rnd(100) < 12) {
893: turn_off(player, ISFLEE);
894: msg("You regain your composure.");
895: }
896: else if (DISTANCE(move_nh.y, move_nh.x, player.t_dest->y, player.t_dest->x) <
897: DISTANCE(hero.y, hero.x, player.t_dest->y, player.t_dest->x)) {
898: running = FALSE;
899: msg("You are too terrified to move that way");
900: player.t_action = A_NIL;
901: player.t_no_move = movement(&player);
902: return;
903: }
904: }
905:
906: /* If we want to move to a monster, see what it is */
907: if (isalpha(ch)) {
908: item = find_mons(move_nh.y, move_nh.x);
909: if (item == NULL) {
910: debug("Cannot find monster in move.");
911: player.t_action = A_NIL;
912: return;
913: }
914: tp = THINGPTR(item);
915: }
916:
917: /*
918: * Take care of hero being held. If the player is being held, he
919: * can't move unless he is either attacking a non-friendly monster
920: * or attacking a friendly monster that can't move.
921: */
922: if (on(player, ISHELD) &&
923: (!isalpha(ch) || (on(*tp, ISFRIENDLY) && off(*tp, ISHELD)))) {
924: msg("You are being held.");
925: player.t_action = A_NIL;
926: return;
927: }
928:
929: /* See if we have to wait for our movement rate */
930: if (player.t_action == A_NIL) {
931: after = FALSE;
932: firstmove = wasfirstmove; /* Remember if this is first move */
933: player.t_no_move = movement(&player);
934: if (player.t_ctype == C_MONK)
935: player.t_no_move -= pstats.s_lvl/6;
936: if (on(player, ISFLY))
937: player.t_no_move /= 2; /* If flying, speed him up */
938:
939: if (player.t_no_move < 1) player.t_no_move = 1;
940:
941: /* Remember our action */
942: player.t_action = Moves[dy+1][dx+1];
943: return;
944: }
945:
946: /* Now let's forget the old move and just do it */
947: player.t_action = A_NIL;
948:
949: /* If we're moving onto a friendly monster, let's change places. */
950: if (isalpha(ch) && on(*tp, ISFRIENDLY) && off(*tp, ISHELD)) {
951: coord tpos, /* Where monster may have been going */
952: current; /* Current hero position */
953: int action; /* The monster's action */
954:
955: current = hero;
956: tpos = tp->t_newpos;
957: action = tp->t_action;
958:
959: /* Disrupt whatever our friend was doing */
960: tp->t_action = A_NIL;
961:
962: /* Tentatively move us to where he is */
963: hero = tp->t_pos;
964:
965: /* See if we can move him to where we were */
966: tp->t_newpos = current;
967: do_chase(tp);
968:
969: /* Did we succeed? */
970: if (ce(tp->t_pos, current)) {
971: /* Reset our idea of what ch is */
972: ch = winat(move_nh.y, move_nh.x);
973:
974: /* Let it be known that we made the switch */
975: changed = TRUE;
976: old_hero = current;
977:
978: /* Make the monster think it didn't move */
979: tp->t_oldpos = current;
980: tp->t_doorgoal.x = tp->t_doorgoal.y = -1;
981:
982: /* Let the player know something funny happened. */
983: msg("What a sidestep!");
984: }
985: else {
986: /* Restore things -- we couldn't move */
987: hero = current;
988: tp->t_newpos = tpos;
989: tp->t_action = action;
990: }
991: }
992:
993: /* assume he's not in a wall */
994: if (!isalpha(ch)) turn_off(player, ISINWALL);
995:
996: switch (ch) {
997: case VERTWALL:
998: case HORZWALL:
999: if (levtype == OUTSIDE) {
1000: hero = move_nh;
1001: new_level(OUTSIDE);
1002: return;
1003: }
1004: case WALL:
1005: case SECRETDOOR:
1006: if (off(player, CANINWALL) || running) {
1007: after = running = FALSE;
1008:
1009: /* Light if finishing run */
1010: if (levtype == MAZELEV && lit_room(&rooms[0]))
1011: look(FALSE, TRUE);
1012:
1013: after = running = FALSE;
1014:
1015: return;
1016: }
1017: turn_on(player, ISINWALL);
1018: break;
1019: case POOL:
1020: if (levtype == OUTSIDE) {
1021: /* lake_check(&move_nh); */ /* not implemented yet */
1022: running = FALSE;
1023: break;
1024: }
1025: case MAZETRAP:
1026: if (levtype == OUTSIDE) {
1027: running = FALSE;
1028: break;
1029: }
1030: case TRAPDOOR:
1031: case TELTRAP:
1032: case BEARTRAP:
1033: case SLEEPTRAP:
1034: case ARROWTRAP:
1035: case DARTTRAP:
1036: case WORMHOLE:
1037: ch = be_trapped(&player, &move_nh);
1038: if (ch == TRAPDOOR || ch == TELTRAP ||
1039: pool_teleport || ch == MAZETRAP) {
1040: pool_teleport = FALSE;
1041: return;
1042: }
1043: break;
1044: case GOLD:
1045: case POTION:
1046: case SCROLL:
1047: case FOOD:
1048: case WEAPON:
1049: case ARMOR:
1050: case RING:
1051: case MM:
1052: case RELIC:
1053: case STICK:
1054: running = FALSE;
1055: take = ch;
1056: break;
1057: case DOOR:
1058: case STAIRS:
1059: case POST:
1060: running = FALSE;
1061: break;
1062: default:
1063: break;
1064: }
1065:
1066: if (isalpha(ch)) { /* if its a monster then fight it */
1067: /*
1068: * If we were running down a corridor and didn't start right
1069: * next to the critter, don't do anything.
1070: */
1071: if (running && wasfirstmove == FALSE && roomin(&hero) == NULL) {
1072: struct linked_list *item;
1073:
1074: item = find_mons(move_nh.y, move_nh.x);
1075: if (item != NULL && !invisible(THINGPTR(item))) {
1076: after = running = FALSE;
1077: return;
1078: }
1079: }
1080:
1081: /* We have to add time because we're attacking */
1082: player.t_no_move = FIGHTBASE;
1083: player.t_no_move += weap_move(&player, cur_weapon);
1084: if (on(player, ISHASTE))
1085: player.t_no_move /= 2;
1086: else if (on(player, ISSLOW))
1087: player.t_no_move *= 2;
1088:
1089: /* We may attack faster if we're high enough level
1090: * and the right class
1091: */
1092: switch(player.t_ctype) {
1093: case C_FIGHTER: num_hits = player.t_stats.s_lvl/25 + 1;
1094: when C_PALADIN: num_hits = player.t_stats.s_lvl/35 + 1;
1095: when C_RANGER: num_hits = player.t_stats.s_lvl/35 + 1;
1096: when C_MONK: if(cur_weapon) num_hits = player.t_stats.s_lvl/40 + 1;
1097: else num_hits = player.t_stats.s_lvl/30 + 1;
1098: otherwise: num_hits = player.t_stats.s_lvl/60 + 1;
1099: }
1100:
1101: /*
1102: * The player has already moved the initial movement period.
1103: * Let's add that in, do our division, and then subtract it
1104: * out so that the total time is divided, not just the
1105: * additional attack time.
1106: */
1107: moved = movement(&player),
1108: player.t_no_move += moved;
1109: player.t_no_move /= num_hits;
1110: player.t_no_move -= moved;
1111: running = FALSE;
1112:
1113: /* Mark that we are attacking and save the attack coordinate */
1114: player.t_action = A_ATTACK;
1115: player.t_newpos = move_nh;
1116: runch = Moves[dy+1][dx+1]; /* Remember the direction */
1117:
1118: if (player.t_no_move <= 0) after = FALSE;
1119: return;
1120: }
1121:
1122: /*
1123: * if not fighting then move the hero
1124: */
1125: if (changed == FALSE) {
1126: old_hero = hero; /* Save hero's old position */
1127: hero = move_nh; /* Move the hero */
1128: }
1129: rp = roomin(&hero);
1130: orp = roomin(&old_hero);
1131:
1132: /* Unlight any possible cross-corridor */
1133: if (levtype == MAZELEV) {
1134: register bool call_light = FALSE;
1135: register unsigned char wall_check;
1136:
1137: if (wasfirstmove && lit_room(&rooms[0])) {
1138: /* Are we moving out of a corridor? */
1139: switch (runch) {
1140: case 'h':
1141: case 'l':
1142: if (old_hero.y + 1 < lines - 2) {
1143: wall_check = winat(old_hero.y + 1, old_hero.x);
1144: if (!isrock(wall_check)) call_light = TRUE;
1145: }
1146: if (old_hero.y - 1 > 0) {
1147: wall_check = winat(old_hero.y - 1, old_hero.x);
1148: if (!isrock(wall_check)) call_light = TRUE;
1149: }
1150: break;
1151: case 'j':
1152: case 'k':
1153: if (old_hero.x + 1 < cols) {
1154: wall_check = winat(old_hero.y, old_hero.x + 1);
1155: if (!isrock(wall_check)) call_light = TRUE;
1156: }
1157: if (old_hero.x - 1 >= 0) {
1158: wall_check = winat(old_hero.y, old_hero.x - 1);
1159: if (!isrock(wall_check)) call_light = TRUE;
1160: }
1161: break;
1162: default:
1163: call_light = TRUE;
1164: }
1165: player.t_oldpos = old_hero;
1166: if (call_light) light(&old_hero);
1167: }
1168: }
1169:
1170: else if (orp != NULL && rp == NULL) { /* Leaving a room -- darken it */
1171: orp->r_flags |= FORCEDARK; /* Fake darkness */
1172: light(&old_hero);
1173: orp->r_flags &= ~FORCEDARK; /* Restore light state */
1174: }
1175: else if (rp != NULL && orp == NULL){/* Entering a room */
1176: light(&hero);
1177: if (rp->r_flags & ISTREAS)
1178: wake_room(rp);
1179: }
1180: ch = winat(old_hero.y, old_hero.x);
1181: wmove(cw, unc(old_hero));
1182: waddch(cw, ch);
1183: wmove(cw, unc(hero));
1184: waddch(cw, PLAYER);
1185: }
1186:
1187: /*
1188: * do_run:
1189: * Start the hero running
1190: */
1191:
1192: void
1193: do_run(char ch)
1194: {
1195: firstmove = TRUE;
1196: running = TRUE;
1197: after = FALSE;
1198: runch = ch;
1199: }
1200:
1201: /*
1202: * getdelta:
1203: * Takes a movement character (eg. h, j, k, l) and returns the
1204: * y and x delta corresponding to it in the remaining arguments.
1205: * Returns TRUE if it could find it, FALSE otherwise.
1206: */
1207:
1208: bool
1209: getdelta(char match, int *dy, int *dx)
1210: {
1211: register int y, x;
1212:
1213: for (y = 0; y < 3; y++)
1214: for (x = 0; x < 3; x++)
1215: if (Moves[y][x] == match) {
1216: *dy = y - 1;
1217: *dx = x - 1;
1218: return(TRUE);
1219: }
1220:
1221: return(FALSE);
1222: }
1223:
1224: /*
1225: * isatrap:
1226: * Returns TRUE if this character is some kind of trap
1227: */
1228:
1229: bool
1230: isatrap(char ch)
1231: {
1232: switch(ch) {
1233: case WORMHOLE:
1234: case DARTTRAP:
1235: case TELTRAP:
1236: case TRAPDOOR:
1237: case ARROWTRAP:
1238: case SLEEPTRAP:
1239: case BEARTRAP: return(TRUE);
1240: case MAZETRAP:
1241: case POOL: return(levtype != OUTSIDE);
1242: default: return(FALSE);
1243: }
1244: }
1245:
1246: /*
1247: * Called to illuminate a room.
1248: * If it is dark, remove anything that might move.
1249: */
1250:
1251: void
1252: light(coord *cp)
1253: {
1254: register struct room *rp;
1255: register int j, k, x, y;
1256: register unsigned char ch, rch, sch;
1257: register struct linked_list *item;
1258: int jlow, jhigh, klow, khigh; /* Boundaries of lit area */
1259:
1260: if ((rp = roomin(cp)) != NULL) {
1261: /*
1262: * is he wearing ring of illumination?
1263: */
1264: if (&hero == cp && ISWEARING(R_LIGHT)) /* Must be hero's room */
1265: rp->r_flags &= ~ISDARK;
1266:
1267: /* If we are in a maze, don't look at the whole room (level) */
1268: if (levtype == MAZELEV) {
1269: int see_radius;
1270:
1271: see_radius = 1;
1272:
1273: /* If we are looking at the hero in a rock, broaden our sights */
1274: if (&hero == cp || &player.t_oldpos == cp) {
1275: ch = winat(hero.y, hero.x);
1276: if (isrock(ch)) see_radius = 2;
1277: ch = winat(player.t_oldpos.y, player.t_oldpos.x);
1278: if (isrock(ch)) see_radius = 2;
1279: }
1280:
1281: jlow = max(0, cp->y - see_radius - rp->r_pos.y);
1282: jhigh = min(rp->r_max.y, cp->y + see_radius + 1 - rp->r_pos.y);
1283: klow = max(0, cp->x - see_radius - rp->r_pos.x);
1284: khigh = min(rp->r_max.x, cp->x + see_radius + 1 - rp->r_pos.x);
1285: }
1286: else {
1287: jlow = klow = 0;
1288: jhigh = rp->r_max.y;
1289: khigh = rp->r_max.x;
1290: }
1291: for (j = 0; j < rp->r_max.y; j++)
1292: {
1293: for (k = 0; k < rp->r_max.x; k++)
1294: {
1295: bool see_here = 0, see_before = 0;
1296:
1297: /* Is this in the give area -- needed for maze */
1298: if ((j < jlow || j >= jhigh) && (k < klow || k >= khigh))
1299: continue;
1300:
1301: y = rp->r_pos.y + j;
1302: x = rp->r_pos.x + k;
1303:
1304: /*
1305: * If we are in a maze do not look at this area unless
1306: * we can see it from where we are or where we last were
1307: * (for erasing purposes).
1308: */
1309: if (levtype == MAZELEV) {
1310: /* If we can't see it from here, could we see it before? */
1311: if ((see_here = maze_view(y, x)) == FALSE) {
1312: coord savhero;
1313:
1314: /* Could we see it from where we were? */
1315: savhero = hero;
1316: hero = player.t_oldpos;
1317: see_before = maze_view(y, x);
1318: hero = savhero;
1319:
1320: if (!see_before) continue;
1321: }
1322: }
1323:
1324: ch = show(y, x);
1325: wmove(cw, y, x);
1326: /*
1327: * Figure out how to display a secret door
1328: */
1329: if (ch == SECRETDOOR) {
1330: if (j == 0 || j == rp->r_max.y - 1)
1331: ch = HORZWALL;
1332: else
1333: ch = VERTWALL;
1334: }
1335: /* For monsters, if they were previously not seen and
1336: * now can be seen, or vice-versa, make sure that will
1337: * happen. This is for dark rooms as opposed to invisibility.
1338: *
1339: * Call winat() in the test because ch will not reveal
1340: * invisible monsters.
1341: */
1342: if (isalpha(winat(y, x))) {
1343: struct thing *tp; /* The monster */
1344:
1345: item = wake_monster(y, x);
1346: tp = THINGPTR(item);
1347:
1348: /* Previously not seen -- now can see it */
1349: if (tp->t_oldch == ' ' && cansee(tp->t_pos.y, tp->t_pos.x))
1350: tp->t_oldch = mvinch(y, x);
1351:
1352: /* Previously seen -- now can't see it */
1353: else if (!cansee(tp->t_pos.y, tp->t_pos.x) &&
1354: roomin(&tp->t_pos) != NULL)
1355: switch (tp->t_oldch) {
1356: /*
1357: * Only blank it out if it is in a room and not
1358: * the border (or other wall) of the room.
1359: */
1360: case DOOR:
1361: case SECRETDOOR:
1362: case HORZWALL:
1363: case VERTWALL:
1364: break;
1365:
1366: otherwise:
1367: tp->t_oldch = ' ';
1368: }
1369: }
1370:
1371: /*
1372: * If the room is a dark room, we might want to remove
1373: * monsters and the like from it (since they might
1374: * move).
1375: * A dark room.
1376: */
1377: if ((!lit_room(rp) && (levtype != OUTSIDE)) ||
1378: (levtype == OUTSIDE && !daytime) ||
1379: on(player, ISBLIND) ||
1380: (rp->r_flags & FORCEDARK) ||
1381: (levtype == MAZELEV && !see_here && see_before)) {
1382: sch = mvwinch(cw, y, x); /* What's seen */
1383: rch = mvinch(y, x); /* What's really there */
1384: switch (rch) {
1385: case DOOR:
1386: case SECRETDOOR:
1387: case STAIRS:
1388: case TRAPDOOR:
1389: case WORMHOLE:
1390: case TELTRAP:
1391: case BEARTRAP:
1392: case SLEEPTRAP:
1393: case ARROWTRAP:
1394: case DARTTRAP:
1395: case MAZETRAP:
1396: case POOL:
1397: case POST:
1398: case VERTWALL:
1399: case HORZWALL:
1400: case WALL:
1401: if (isalpha(sch)) ch = rch;
1402: else if (sch != FLOOR) ch = sch;
1403: else ch = ' '; /* Hide undiscoverd things */
1404: when FLOOR:
1405: ch = ' ';
1406: otherwise:
1407: ch = ' ';
1408: }
1409: /* Take care of our magic bookkeeping. */
1410: switch (sch) {
1411: case MAGIC:
1412: case BMAGIC:
1413: case CMAGIC:
1414: ch = sch;
1415: }
1416: }
1417: mvwaddch(cw, y, x, ch);
1418: }
1419: }
1420: }
1421: }
1422:
1423: /*
1424: * lit_room:
1425: * Called to see if the specified room is lit up or not.
1426: */
1427:
1428: bool
1429: lit_room(struct room *rp)
1430: {
1431: register struct linked_list *fire_item;
1432: register struct thing *fire_creature;
1433:
1434: if (!(rp->r_flags & ISDARK)) return(TRUE); /* A definitely lit room */
1435:
1436: /* Is it lit by fire light? */
1437: if (rp->r_flags & HASFIRE) {
1438: switch ((int)levtype) {
1439: case MAZELEV:
1440: /* See if a fire creature is in line of sight */
1441: for (fire_item = rp->r_fires; fire_item != NULL;
1442: fire_item = next(fire_item)) {
1443: fire_creature = THINGPTR(fire_item);
1444: if (maze_view(fire_creature->t_pos.y,
1445: fire_creature->t_pos.x)) return(TRUE);
1446: }
1447:
1448: /* Couldn't find any in line-of-sight */
1449: return(FALSE);
1450:
1451: /* We should probably do something special for the outside */
1452: otherwise:
1453: return TRUE;
1454: }
1455: }
1456: return(FALSE);
1457: }
1458:
1459: /*
1460: * movement:
1461: * Given a pointer to a player/monster structure, calculate the
1462: * movement rate for that character.
1463: */
1464:
1465: short
1466: movement(struct thing *tp)
1467: {
1468: register int result;
1469: register int carry; /* Percentage carried */
1470:
1471: result = 0;
1472:
1473: /* Adjust for armor (player only) */
1474: if (tp == &player && cur_armor) {
1475: int diff; /* Now armor class differs from normal one of same type */
1476:
1477: /* Blessed armor adds less */
1478: diff = cur_armor->o_ac - armors[cur_armor->o_which].a_class;
1479: switch (cur_armor->o_which) {
1480: case LEATHER:
1481: case RING_MAIL:
1482: case CHAIN_MAIL:
1483: case SCALE_MAIL:
1484: case PADDED_ARMOR:
1485: diff += 1;
1486: when STUDDED_LEATHER:
1487: case SPLINT_MAIL:
1488: case BANDED_MAIL:
1489: case PLATE_MAIL:
1490: diff += 2;
1491: when PLATE_ARMOR:
1492: diff += 3;
1493: otherwise:
1494: debug("forgot an armor in movement()");
1495: }
1496: if (diff < 0) diff = 0;
1497: result += diff;
1498:
1499: }
1500:
1501: /* Adjust for the pack */
1502: carry = 100 * tp->t_stats.s_pack / tp->t_stats.s_carry;
1503: if (carry > 75) result++;
1504:
1505: /* Get a bonus for dexterity */
1506: result -= dext_plus(tp == &player ? dex_compute() : tp->t_stats.s_dext);
1507:
1508: /* only allow adjust for the minus's */
1509: if (result < 0) result = 0;
1510: result += tp->t_movement; /* now add in movement rate */
1511:
1512: /* Is the character slowed? */
1513: if (on(*tp, ISSLOW) || on(*tp, ISDANCE)) result *= 2;
1514:
1515: /* Is the character hasted? */
1516: if (on(*tp, ISHASTE)) result /= 2;
1517:
1518: /* We have a minimum of 1 */
1519: if (result < 1) result = 1;
1520:
1521: return(result);
1522: }
1523:
1524: /*
1525: * rndmove:
1526: * move in a random direction if the monster/person is confused
1527: */
1528:
1529: coord
1530: rndmove(struct thing *who)
1531: {
1532: register int x, y;
1533: register int ex, ey, nopen = 0;
1534: coord ret; /* what we will be returning */
1535: coord dest;
1536:
1537: ret = who->t_pos;
1538: /*
1539: * Now go through the spaces surrounding the player and
1540: * set that place in the array to true if the space can be
1541: * moved into
1542: */
1543: ey = ret.y + 1;
1544: ex = ret.x + 1;
1545: for (y = who->t_pos.y - 1; y <= ey; y++)
1546: if (y > 0 && y < lines - 2)
1547: for (x = who->t_pos.x - 1; x <= ex; x++)
1548: {
1549: if (x < 0 || x >= cols)
1550: continue;
1551: if (step_ok(y, x, NOMONST, who) == TRUE)
1552: {
1553: dest.y = y;
1554: dest.x = x;
1555: if (!diag_ok(&who->t_pos, &dest, who))
1556: continue;
1557: if (rnd(++nopen) == 0)
1558: ret = dest;
1559: }
1560: }
1561: return ret;
1562: }
1563:
1564: #define TRAPTYPES 9 /* 9 total trap types that can be set */
1565: #define WIZARDTRAPS 3 /* Only wizards can set the last 3 */
1566: /* CTRL(C) to level 400 for POST level */
1567: static const char *trap_types[TRAPTYPES] = {
1568: "Trap Door",
1569: "Bear Trap",
1570: "Sleep Trap",
1571: "Arrow Trap",
1572: "Teleport Trap",
1573: "Dart Trap",
1574: "Magic pool",
1575: "Maze Trap",
1576: "Worm Hole"
1577: };
1578:
1579: /*
1580: * set_trap:
1581: * set a trap at (y, x) on screen.
1582: */
1583:
1584: void
1585: set_trap(struct thing *tp, int y, int x)
1586: {
1587: register bool is_player = (tp == &player);
1588: register int selection = rnd(TRAPTYPES-WIZARDTRAPS) + '1';
1589: register int i, num_traps;
1590: register unsigned char ch = 0, och;
1591: int thief_bonus = 0;
1592: int s_dext;
1593:
1594: /* let wizard in on this too */
1595: if (wizard) goto can_traps;
1596: if (is_player && player.t_ctype != C_THIEF && player.t_ctype !=C_ASSASSIN) {
1597: msg("Only thieves and assassins can set traps. ");
1598: return;
1599: }
1600: can_traps:
1601: switch (och = mvinch(y, x)) {
1602: case WALL:
1603: case FLOOR:
1604: case PASSAGE:
1605: break;
1606: default:
1607: if (is_player) msg("The trap failed!");
1608: return;
1609: }
1610:
1611: if (is_player) {
1612: int state = 0, /* 0 -> current screen, 1 -> prompt screen, 2 -> done */
1613: units; /* Number of movement units for the given trap */
1614:
1615: if (player.t_action == C_SETTRAP) {
1616: selection = player.t_selection;
1617: player.t_selection = 0;
1618: player.t_action = A_NIL;
1619: }
1620: else {
1621: msg("Which kind of trap do you wish to set? (* for a list): ");
1622: num_traps = TRAPTYPES - (wizard ? 0 : WIZARDTRAPS);
1623: do {
1624: selection = wgetch(cw);
1625: switch (selection) {
1626: case '*':
1627: if (state != 1) {
1628: wclear(hw);
1629: touchwin(hw);
1630: for (i=0; i<num_traps; i++) {
1631: wmove(hw, i+2, 0);
1632: wprintw(hw, "[%d] %s", i+1, trap_types[i]);
1633: }
1634: mvwaddstr(hw, 0, 0,
1635: "Which kind of trap do you wish to set? ");
1636:
1637: if (menu_overlay)
1638: /*
1639: * Put out the selection. The longest line is
1640: * the prompt line (39 characters long).
1641: */
1642: over_win(cw, hw, num_traps + 3, 41, 0, 39, '\0');
1643: else
1644: draw(hw);
1645: state = 1; /* Now in prompt window */
1646: }
1647: break;
1648:
1649: case ESC:
1650: if (state == 1) {
1651: clearok(cw, FALSE);
1652: touchwin(cw);
1653: }
1654: msg("");
1655:
1656: trap_tries--; /* Don't count this one */
1657: after = FALSE;
1658: return;
1659:
1660: case '1':
1661: case '2':
1662: case '3':
1663: case '4':
1664: case '5':
1665: case '6':
1666: case '7':
1667: case '8':
1668: case '9':
1669: if (selection < '7' || wizard) {
1670: if (state == 1) { /* In prompt window */
1671: clearok(cw, FALSE); /* Set up for redraw */
1672: touchwin(cw);
1673: }
1674:
1675: msg("");
1676:
1677: /*
1678: * Make sure there is a floor below us for trap
1679: * doors.
1680: */
1681: if (selection == '1' && level >= nfloors) {
1682: if (state == 1) draw(cw);
1683: msg("There is no level below this one.");
1684: return;
1685: }
1686: state = 2; /* Finished */
1687: break;
1688: }
1689:
1690: /* Fall through for non-wizard, unusual trap case */
1691: default:
1692: if (state == 1) { /* In the prompt window */
1693: wmove(hw, 0, 0);
1694: wprintw(hw,
1695: "Please enter a selection between 1 and %d: ",
1696: num_traps);
1697: if (menu_overlay)
1698: /*
1699: * Put out the selection. The longest line is
1700: * the prompt line (43 characters long).
1701: */
1702: over_win(cw, hw, num_traps+3, 45, 0, 43, '\0');
1703: else
1704: draw(hw);
1705: }
1706: else { /* Normal window */
1707: mpos = 0;
1708: msg("Please enter a selection between 1 and %d: ",
1709: num_traps);
1710: }
1711: }
1712: } while (state != 2);
1713:
1714: player.t_selection = selection;
1715:
1716: switch (selection) {
1717: case '1': units = 10; /* Trap door */
1718: when '2': units = 5; /* Bear trap */
1719: when '3': units = 7; /* Sleeping gas trap */
1720: when '4': units = 5; /* Arrow trap */
1721: when '5': units = 10; /* Teleport trap */
1722: when '6': units = 7; /* Dart trap */
1723: otherwise: units = 5; /* Unknown trap */
1724: }
1725: player.t_no_move = units * movement(&player);
1726: player.t_action = C_SETTRAP;
1727: return;
1728: }
1729: }
1730:
1731: if (is_player && player.t_ctype == C_THIEF) thief_bonus = 20;
1732: if (is_player && player.t_ctype == C_ASSASSIN) thief_bonus = 15;
1733: if (is_player && player.t_ctype == C_FIGHTER) thief_bonus = 10;
1734:
1735: s_dext = (tp == &player) ? dex_compute() : tp->t_stats.s_dext;
1736:
1737: if (ntraps >= MAXTRAPS || ++trap_tries >= MAXTRPTRY ||
1738: levtype == POSTLEV || levtype == OUTSIDE ||
1739: rnd(80) >= (s_dext + tp->t_stats.s_lvl/2 + thief_bonus)) {
1740: if (is_player) msg("The trap failed!");
1741: return;
1742: }
1743:
1744: switch (selection) {
1745: case '1': ch = TRAPDOOR;
1746: when '2': ch = BEARTRAP;
1747: when '3': ch = SLEEPTRAP;
1748: when '4': ch = ARROWTRAP;
1749: when '5': ch = TELTRAP;
1750: when '6': ch = DARTTRAP;
1751: when '7': ch = POOL;
1752: when '8': ch = MAZETRAP;
1753: when '9': ch = WORMHOLE;
1754: }
1755:
1756: mvaddch(y, x, ch);
1757: traps[ntraps].tr_show = och;
1758: traps[ntraps].tr_type = ch;
1759: traps[ntraps].tr_pos.y = y;
1760: traps[ntraps].tr_pos.x = x;
1761: if (is_player)
1762: traps[ntraps].tr_flags = ISTHIEFSET;
1763: if (ch == POOL || ch == POST) {
1764: traps[ntraps].tr_flags |= ISFOUND;
1765: }
1766:
1767: ntraps++;
1768: }
1769:
1770: /*
1771: * show:
1772: * returns what a certain thing will display as to the un-initiated
1773: */
1774:
1775: char
1776: show(int y, int x)
1777: {
1778: register unsigned char ch = winat(y, x);
1779: register struct linked_list *it;
1780: register struct thing *tp;
1781:
1782: if (isatrap(ch)) {
1783: register struct trap *trp = trap_at(y, x);
1784:
1785: return (trp->tr_flags & ISFOUND) ? ch : trp->tr_show;
1786: }
1787: else if (isalpha(ch)) {
1788: if ((it = find_mons(y, x)) == NULL) {
1789: msg("Show: Can't find monster in show (%d, %d)", y, x);
1790: return(mvwinch(stdscr, y, x));
1791: }
1792: tp = THINGPTR(it);
1793:
1794: if (on(*tp, ISDISGUISE)) ch = tp->t_disguise; /* As a mimic */
1795:
1796: /* Hide invisible creatures */
1797: else if (invisible(tp)) {
1798: /* We can't see surprise-type creatures through "see invisible" */
1799: if (off(player,CANSEE) || on(*tp,CANSURPRISE))
1800: ch = mvwinch(stdscr, y, x); /* Invisible */
1801: }
1802: else if (on(*tp, CANINWALL)) {
1803: if (isrock(mvwinch(stdscr, y, x))) ch = winch(stdscr); /* As Xorn */
1804: }
1805: }
1806: return ch;
1807: }
1808:
1809:
1810: /*
1811: * trap_at:
1812: * find the trap at (y,x) on screen.
1813: */
1814:
1815: struct trap *
1816: trap_at(int y, int x)
1817: {
1818: register struct trap *tp, *ep;
1819:
1820: ep = &traps[ntraps];
1821: for (tp = traps; tp < ep; tp++)
1822: if (tp->tr_pos.y == y && tp->tr_pos.x == x)
1823: break;
1824: if (tp == ep)
1825: debug((sprintf(prbuf, "Trap at %d,%d not in array", y, x), prbuf));
1826: return tp;
1827: }
1828:
1829: /*
1830: * weap_move:
1831: * Calculate how many segments it will take to swing the given
1832: * weapon (note that the weapon may actually be a stick or
1833: * even something else).
1834: * wielder: Who's wielding the weapon
1835: * weap: The weapon
1836: */
1837:
1838: int
1839: weap_move(struct thing *wielder, struct object *weap)
1840: {
1841: register int weap_rate;
1842: int dexterity;
1843: int strength;
1844:
1845: if (weap == NULL) return(1); /* hand, claw, bite attacks are quick */
1846:
1847: switch (weap->o_type) {
1848: case STICK:
1849: if (EQUAL(ws_type[weap->o_which], "staff"))
1850: weap_rate = 2;
1851: else weap_rate = 1; /* A wand */
1852:
1853: when WEAPON:
1854: weap_rate = weaps[weap->o_which].w_rate;
1855:
1856: /* Adjust for blessed or cursed weapon */
1857: if (weap->o_hplus < 0) /* Cursed */
1858: weap_rate -= (weap->o_hplus - 2) / 3;
1859: else if (weap_rate > 0) /* Blessed */
1860: weap_rate -= (2*weap->o_hplus + weap_rate - 1) / weap_rate;
1861:
1862: when RELIC:
1863: switch (weap->o_which) {
1864: case MUSTY_DAGGER:
1865: case HRUGGEK_MSTAR:
1866: case AXE_AKLAD:
1867: case YEENOGHU_FLAIL:
1868: case MING_STAFF:
1869: case ORCUS_WAND:
1870: case ASMO_ROD:
1871: /* These operate in the blink of an eye */
1872: weap_rate = 1;
1873: otherwise:
1874: /* What is it? */
1875: weap_rate = 10;
1876: debug("unknown weapon in weap_move()");
1877: }
1878: otherwise:
1879: /* What is it? */
1880: weap_rate = 10;
1881: debug("unknown weapon in weap_move()");
1882: }
1883:
1884: /* Put in a dexterity bonus */
1885: if (wielder == &player) dexterity = dex_compute();
1886: else dexterity = wielder->t_stats.s_dext;
1887: weap_rate -= dext_plus(dexterity) / 2;
1888:
1889: /* Put in a strength bonus */
1890: if (wielder == &player) strength = str_compute();
1891: else strength = wielder->t_stats.s_str;
1892: weap_rate -= str_plus(strength) / 2;
1893:
1894: /* It can't speed you up and it must take SOME time */
1895: if (weap_rate <= 0) weap_rate = 1;
1896:
1897: /* Do we need to adjust for fast/slow movement? */
1898: if (on(*wielder, ISSLOW) || on(*wielder, ISDANCE)) weap_rate *= 2;
1899: if (on(*wielder, ISHASTE)) weap_rate /= 2;
1900:
1901: /* Return the result */
1902: return(weap_rate);
1903: }
1904:
CVSweb