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