comparison arogue7/move.c @ 125:adfa37e67084

Import Advanced Rogue 7.7 from the Roguelike Restoration Project (r1490)
author John "Elwin" Edwards
date Fri, 08 May 2015 15:24:40 -0400
parents
children a0a57cf42810
comparison
equal deleted inserted replaced
124:d10fc4a065ac 125:adfa37e67084
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 "rogue.h"
23 #ifdef PC7300
24 #include "menu.h"
25 #endif
26
27 /*
28 * Used to hold the new hero position
29 */
30
31 static coord nh;
32
33 static char Moves[3][3] = {
34 { 'y', 'k', 'u' },
35 { 'h', '.', 'l' },
36 { 'b', 'j', 'n' }
37 };
38
39 /*
40 * be_trapped:
41 * The guy stepped on a trap.... Make him pay.
42 */
43
44 be_trapped(th, tc)
45 register struct thing *th;
46 register 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;
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 msg("You fell into a trap!");
92 if (pstats.s_hpt <= 0) death(D_FALL);
93 new_level(NORMLEV);
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(blessed, cursed)
430 bool blessed, cursed;
431 {
432 register struct room *rp;
433 bool ret_val=FALSE; /* Whether or not affect is known */
434
435 rp = roomin(&hero); /* What room is hero in? */
436
437 /* Darken the room if the magic is cursed */
438 if (cursed) {
439 if ((rp == NULL) || !lit_room(rp)) msg(nothing);
440 else {
441 rp->r_flags |= ISDARK;
442 if (!lit_room(rp) && (levtype != OUTSIDE || !daytime))
443 msg("The %s suddenly goes dark.",
444 levtype == OUTSIDE ? "area" : "room");
445 else msg(nothing);
446 ret_val = TRUE;
447 }
448 }
449 else {
450 ret_val = TRUE;
451 if (rp && !lit_room(rp) &&
452 (levtype != OUTSIDE || !daytime)) {
453 addmsg("The %s is lit", levtype == OUTSIDE ? "area" : "room");
454 if (!terse)
455 addmsg(" by a %s blue light.",
456 blessed ? "bright" : "shimmering");
457 endmsg();
458 }
459 else if (winat(hero.y, hero.x) == PASSAGE)
460 msg("The corridor glows %sand then fades",
461 blessed ? "brightly " : "");
462 else {
463 ret_val = FALSE;
464 msg(nothing);
465 }
466 if (blessed) {
467 register int i; /* Index through rooms */
468
469 for (i=0; i<MAXROOMS; i++)
470 rooms[i].r_flags &= ~ISDARK;
471 }
472 else if (rp) rp->r_flags &= ~ISDARK;
473 }
474
475 /*
476 * Light the room and put the player back up
477 */
478 light(&hero);
479 mvwaddch(cw, hero.y, hero.x, PLAYER);
480 return(ret_val);
481 }
482
483 /*
484 * corr_move:
485 * Check to see that a move is legal. If so, return correct character.
486 * If not, if player came from a legal place, then try to turn him.
487 */
488
489 corr_move(dy, dx)
490 int dy, dx;
491 {
492 int legal=0; /* Number of legal alternatives */
493 register int y, x, /* Indexes though possible positions */
494 locy, locx; /* Hold delta of chosen location */
495
496 /* New position */
497 nh.y = hero.y + dy;
498 nh.x = hero.x + dx;
499
500 /* If it is a legal move, just return */
501 if (nh.x >= 0 && nh.x < cols && nh.y > 0 && nh.y < lines - 2) {
502
503 switch (winat(nh.y, nh.x)) {
504 case WALL:
505 case '|':
506 case '-':
507 break;
508 default:
509 if (diag_ok(&hero, &nh, &player))
510 return;
511 }
512 }
513
514 /* Check legal places surrounding the player -- ignore previous position */
515 for (y = hero.y - 1; y <= hero.y + 1; y++) {
516 if (y < 1 || y > lines - 3)
517 continue;
518 for (x = hero.x - 1; x <= hero.x + 1; x++) {
519 /* Ignore borders of the screen */
520 if (x < 0 || x > cols - 1)
521 continue;
522
523 /*
524 * Ignore where we came from, where we are, and where we couldn't go
525 */
526 if ((x == hero.x - dx && y == hero.y - dy) ||
527 (x == hero.x + dx && y == hero.y + dy) ||
528 (x == hero.x && y == hero.y))
529 continue;
530
531 switch (winat(y, x)) {
532 case WALL:
533 case '|':
534 case '-':
535 break;
536 default:
537 nh.y = y;
538 nh.x = x;
539 if (diag_ok(&hero, &nh, &player)) {
540 legal++;
541 locy = y - (hero.y - 1);
542 locx = x - (hero.x - 1);
543 }
544 }
545 }
546 }
547
548 /* If we have 2 or more legal moves, make no change */
549 if (legal != 1) {
550 return;
551 }
552
553 runch = Moves[locy][locx];
554
555 /*
556 * For mazes, pretend like it is the beginning of a new run at each turn
557 * in order to get the lighting correct.
558 */
559 if (levtype == MAZELEV) firstmove = TRUE;
560 return;
561 }
562
563 /*
564 * dip_it:
565 * Dip an object into a magic pool
566 */
567 dip_it()
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 do_move(dy, dx)
762 int dy, dx;
763 {
764 register struct room *rp, *orp;
765 register char ch;
766 struct linked_list *item;
767 register struct thing *tp;
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 do_run(ch)
1107 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(match, dy, dx)
1123 char match;
1124 int *dy, *dx;
1125 {
1126 register y, x;
1127
1128 for (y = 0; y < 3; y++)
1129 for (x = 0; x < 3; x++)
1130 if (Moves[y][x] == match) {
1131 *dy = y - 1;
1132 *dx = x - 1;
1133 return(TRUE);
1134 }
1135
1136 return(FALSE);
1137 }
1138
1139 /*
1140 * isatrap:
1141 * Returns TRUE if this character is some kind of trap
1142 */
1143 isatrap(ch)
1144 reg char ch;
1145 {
1146 switch(ch) {
1147 case DARTTRAP:
1148 case TELTRAP:
1149 case TRAPDOOR:
1150 case ARROWTRAP:
1151 case SLEEPTRAP:
1152 case BEARTRAP: return(TRUE);
1153 case MAZETRAP:
1154 case POOL: return(levtype != OUTSIDE);
1155 default: return(FALSE);
1156 }
1157 }
1158
1159 /*
1160 * Called to illuminate a room.
1161 * If it is dark, remove anything that might move.
1162 */
1163
1164 light(cp)
1165 coord *cp;
1166 {
1167 register struct room *rp;
1168 register int j, k, x, y;
1169 register char ch, rch, sch;
1170 register struct linked_list *item;
1171 int jlow, jhigh, klow, khigh; /* Boundaries of lit area */
1172
1173 if ((rp = roomin(cp)) != NULL) {
1174 /*
1175 * is he wearing ring of illumination?
1176 */
1177 if (&hero == cp && ISWEARING(R_LIGHT)) /* Must be hero's room */
1178 rp->r_flags &= ~ISDARK;
1179
1180 /* If we are in a maze, don't look at the whole room (level) */
1181 if (levtype == MAZELEV) {
1182 int see_radius;
1183
1184 see_radius = 1;
1185
1186 /* If we are looking at the hero in a rock, broaden our sights */
1187 if (&hero == cp || &player.t_oldpos == cp) {
1188 ch = CCHAR( winat(hero.y, hero.x) );
1189 if (isrock(ch)) see_radius = 2;
1190 ch = CCHAR( winat(player.t_oldpos.y, player.t_oldpos.x) );
1191 if (isrock(ch)) see_radius = 2;
1192 }
1193
1194 jlow = max(0, cp->y - see_radius - rp->r_pos.y);
1195 jhigh = min(rp->r_max.y, cp->y + see_radius + 1 - rp->r_pos.y);
1196 klow = max(0, cp->x - see_radius - rp->r_pos.x);
1197 khigh = min(rp->r_max.x, cp->x + see_radius + 1 - rp->r_pos.x);
1198 }
1199 else {
1200 jlow = klow = 0;
1201 jhigh = rp->r_max.y;
1202 khigh = rp->r_max.x;
1203 }
1204 for (j = 0; j < rp->r_max.y; j++)
1205 {
1206 for (k = 0; k < rp->r_max.x; k++)
1207 {
1208 bool see_here, see_before;
1209
1210 /* Is this in the give area -- needed for maze */
1211 if ((j < jlow || j >= jhigh) && (k < klow || k >= khigh))
1212 continue;
1213
1214 y = rp->r_pos.y + j;
1215 x = rp->r_pos.x + k;
1216
1217 /*
1218 * If we are in a maze do not look at this area unless
1219 * we can see it from where we are or where we last were
1220 * (for erasing purposes).
1221 */
1222 if (levtype == MAZELEV) {
1223 /* If we can't see it from here, could we see it before? */
1224 if ((see_here = maze_view(y, x)) == FALSE) {
1225 coord savhero;
1226
1227 /* Could we see it from where we were? */
1228 savhero = hero;
1229 hero = player.t_oldpos;
1230 see_before = maze_view(y, x);
1231 hero = savhero;
1232
1233 if (!see_before) continue;
1234 }
1235 }
1236
1237 ch = show(y, x);
1238 wmove(cw, y, x);
1239 /*
1240 * Figure out how to display a secret door
1241 */
1242 if (ch == SECRETDOOR) {
1243 if (j == 0 || j == rp->r_max.y - 1)
1244 ch = '-';
1245 else
1246 ch = '|';
1247 }
1248 /* For monsters, if they were previously not seen and
1249 * now can be seen, or vice-versa, make sure that will
1250 * happen. This is for dark rooms as opposed to invisibility.
1251 *
1252 * Call winat() in the test because ch will not reveal
1253 * invisible monsters.
1254 */
1255 if (isalpha(winat(y, x))) {
1256 struct thing *tp; /* The monster */
1257
1258 item = wake_monster(y, x);
1259 tp = THINGPTR(item);
1260
1261 /* Previously not seen -- now can see it */
1262 if (tp->t_oldch == ' ' && cansee(tp->t_pos.y, tp->t_pos.x))
1263 tp->t_oldch = CCHAR( mvinch(y, x) );
1264
1265 /* Previously seen -- now can't see it */
1266 else if (!cansee(tp->t_pos.y, tp->t_pos.x) &&
1267 roomin(&tp->t_pos) != NULL)
1268 switch (tp->t_oldch) {
1269 /*
1270 * Only blank it out if it is in a room and not
1271 * the border (or other wall) of the room.
1272 */
1273 case DOOR:
1274 case SECRETDOOR:
1275 case '-':
1276 case '|':
1277 break;
1278
1279 otherwise:
1280 tp->t_oldch = ' ';
1281 }
1282 }
1283
1284 /*
1285 * If the room is a dark room, we might want to remove
1286 * monsters and the like from it (since they might
1287 * move).
1288 * A dark room.
1289 */
1290 if ((!lit_room(rp) && (levtype != OUTSIDE)) ||
1291 (levtype == OUTSIDE && !daytime) ||
1292 on(player, ISBLIND) ||
1293 (rp->r_flags & FORCEDARK) ||
1294 (levtype == MAZELEV && !see_here && see_before)) {
1295 sch = CCHAR( mvwinch(cw, y, x) ); /* What's seen */
1296 rch = CCHAR( mvinch(y, x) ); /* What's really there */
1297 switch (rch) {
1298 case DOOR:
1299 case SECRETDOOR:
1300 case STAIRS:
1301 case TRAPDOOR:
1302 case TELTRAP:
1303 case BEARTRAP:
1304 case SLEEPTRAP:
1305 case ARROWTRAP:
1306 case DARTTRAP:
1307 case MAZETRAP:
1308 case POOL:
1309 case POST:
1310 case '|':
1311 case '-':
1312 case WALL:
1313 if (isalpha(sch)) ch = rch;
1314 else if (sch != FLOOR) ch = sch;
1315 else ch = ' '; /* Hide undiscoverd things */
1316 when FLOOR:
1317 ch = ' ';
1318 otherwise:
1319 ch = ' ';
1320 }
1321 /* Take care of our magic bookkeeping. */
1322 switch (sch) {
1323 case MAGIC:
1324 case BMAGIC:
1325 case CMAGIC:
1326 ch = sch;
1327 }
1328 }
1329 mvwaddch(cw, y, x, ch);
1330 }
1331 }
1332 }
1333 }
1334
1335 /*
1336 * lit_room:
1337 * Called to see if the specified room is lit up or not.
1338 */
1339
1340 bool
1341 lit_room(rp)
1342 register struct room *rp;
1343 {
1344 register struct linked_list *fire_item;
1345 register struct thing *fire_creature;
1346
1347 if (!(rp->r_flags & ISDARK)) return(TRUE); /* A definitely lit room */
1348
1349 /* Is it lit by fire light? */
1350 if (rp->r_flags & HASFIRE) {
1351 switch ((int)levtype) {
1352 case MAZELEV:
1353 /* See if a fire creature is in line of sight */
1354 for (fire_item = rp->r_fires; fire_item != NULL;
1355 fire_item = next(fire_item)) {
1356 fire_creature = THINGPTR(fire_item);
1357 if (maze_view(fire_creature->t_pos.y,
1358 fire_creature->t_pos.x)) return(TRUE);
1359 }
1360
1361 /* Couldn't find any in line-of-sight */
1362 return(FALSE);
1363
1364 /* We should probably do something special for the outside */
1365 otherwise:
1366 return TRUE;
1367 }
1368 }
1369 return(FALSE);
1370 }
1371
1372 /*
1373 * movement:
1374 * Given a pointer to a player/monster structure, calculate the
1375 * movement rate for that character.
1376 */
1377
1378 short
1379 movement(tp)
1380 register struct thing *tp;
1381 {
1382 register int result;
1383 register int carry; /* Percentage carried */
1384
1385 result = 0;
1386
1387 /* Adjust for armor (player only) */
1388 if (tp == &player && cur_armor) {
1389 int diff; /* Now armor class differs from normal one of same type */
1390
1391 /* Blessed armor adds less */
1392 diff = cur_armor->o_ac - armors[cur_armor->o_which].a_class;
1393 switch (cur_armor->o_which) {
1394 case LEATHER:
1395 case RING_MAIL:
1396 case STUDDED_LEATHER:
1397 case SCALE_MAIL:
1398 case PADDED_ARMOR:
1399 diff += 1;
1400 when CHAIN_MAIL:
1401 case SPLINT_MAIL:
1402 case BANDED_MAIL:
1403 case PLATE_MAIL:
1404 diff += 2;
1405 when PLATE_ARMOR:
1406 diff += 3;
1407 otherwise:
1408 debug("forgot an armor in movement()");
1409 }
1410 if (diff < 0) diff = 0;
1411 result += diff;
1412
1413 }
1414
1415 /* Adjust for the pack */
1416 carry = 100 * tp->t_stats.s_pack / tp->t_stats.s_carry;
1417 if (carry > 75) result++;
1418
1419 /* Get a bonus for dexterity */
1420 result -= dext_plus(tp == &player ? dex_compute() : tp->t_stats.s_dext);
1421
1422 /* only allow adjust for the minus's */
1423 if (result < 0) result = 0;
1424 result += tp->t_movement; /* now add in movement rate */
1425
1426 /* Is the character slowed? */
1427 if (on(*tp, ISSLOW) || on(*tp, ISDANCE)) result *= 2;
1428
1429 /* Is the character hasted? */
1430 if (on(*tp, ISHASTE)) result /= 2;
1431
1432 /* We have a minimum of 1 */
1433 if (result < 1) result = 1;
1434
1435 return(result);
1436 }
1437
1438 /*
1439 * rndmove:
1440 * move in a random direction if the monster/person is confused
1441 */
1442
1443 coord *
1444 rndmove(who)
1445 struct thing *who;
1446 {
1447 register int x, y;
1448 register int ex, ey, nopen = 0;
1449 static coord ret; /* what we will be returning */
1450 static coord dest;
1451
1452 ret = who->t_pos;
1453 /*
1454 * Now go through the spaces surrounding the player and
1455 * set that place in the array to true if the space can be
1456 * moved into
1457 */
1458 ey = ret.y + 1;
1459 ex = ret.x + 1;
1460 for (y = who->t_pos.y - 1; y <= ey; y++)
1461 if (y > 0 && y < lines - 2)
1462 for (x = who->t_pos.x - 1; x <= ex; x++)
1463 {
1464 if (x < 0 || x >= cols)
1465 continue;
1466 if (step_ok(y, x, NOMONST, who) == TRUE)
1467 {
1468 dest.y = y;
1469 dest.x = x;
1470 if (!diag_ok(&who->t_pos, &dest, who))
1471 continue;
1472 if (rnd(++nopen) == 0)
1473 ret = dest;
1474 }
1475 }
1476 return &ret;
1477 }
1478
1479
1480
1481 #define TRAPTYPES 9 /* 9 total trap types that can be set */
1482 #define WIZARDTRAPS 3 /* Only wizards can set 3 of these */
1483
1484 static char *trap_types[TRAPTYPES] = {
1485 "Trap Door",
1486 "Bear Trap",
1487 "Sleep Trap",
1488 "Arrow Trap",
1489 "Teleport Trap",
1490 "Dart Trap",
1491 "Magic pool",
1492 "Maze Trap",
1493 "Trading Post"
1494 };
1495
1496 #ifdef PC7300
1497 #define TRAPWIDTH 13 /* Length of longest named trap from above list */
1498 #define TRAPPREFIX 4 /* Length of prefix (eg. "[9] ") */
1499 static menu_t Display; /* The menu structure */
1500 static mitem_t Dispitems[TRAPTYPES+1]; /* Info for each line */
1501 static char Displines[TRAPTYPES+1][TRAPWIDTH+TRAPPREFIX+1];
1502 #endif
1503
1504 /*
1505 * set_trap:
1506 * set a trap at (y, x) on screen.
1507 */
1508
1509 set_trap(tp, y, x)
1510 register struct thing *tp;
1511 register int y, x;
1512 {
1513 register bool is_player = (tp == &player);
1514 register int selection = rnd(TRAPTYPES-WIZARDTRAPS) + '1';
1515 register int i, num_traps;
1516 register char ch, och;
1517 int thief_bonus = 0;
1518 int s_dext;
1519
1520 if (is_player && player.t_ctype != C_THIEF && player.t_ctype != C_ASSASIN) {
1521 msg("Only thieves and assassins can set traps.");
1522 return;
1523 }
1524 switch (och = CCHAR( mvinch(y, x) )) {
1525 case WALL:
1526 case FLOOR:
1527 case PASSAGE:
1528 break;
1529 default:
1530 if (is_player) msg("The trap failed!");
1531 return;
1532 }
1533
1534 if (is_player) {
1535 int state = 0, /* 0 -> current screen, 1 -> prompt screen, 2 -> done */
1536 units; /* Number of movement units for the given trap */
1537
1538 if (player.t_action == C_SETTRAP) {
1539 selection = player.t_selection;
1540 player.t_selection = 0;
1541 player.t_using = NULL;
1542 player.t_action = A_NIL;
1543 }
1544 else {
1545 msg("Which kind of trap do you wish to set? (* for a list): ");
1546 num_traps = TRAPTYPES - (wizard ? 0 : WIZARDTRAPS);
1547 do {
1548 selection = tolower(readchar());
1549 switch (selection) {
1550 case '*':
1551 if (state != 1) {
1552 #ifdef PC7300
1553 for (i=0; i<TRAPTYPES; i++) {
1554 /*
1555 * Add numbers so the player can use a
1556 * number later, if he knows it. Let's
1557 * put the number on here instead of in
1558 * trap_types in case we want to drop it
1559 * later.
1560 */
1561 sprintf(Displines[i], "[%d] %s",
1562 i+1, trap_types[i]);
1563 Dispitems[i].mi_name = Displines[i];
1564 Dispitems[i].mi_flags = 0;
1565 Dispitems[i].mi_val = i+'1';
1566 }
1567
1568 /* Place an end marker for the items */
1569 Dispitems[num_traps].mi_name = 0;
1570
1571 /* Set up the main menu structure */
1572 Display.m_label = "Trap Creation";
1573 Display.m_title = "Trap Types";
1574 Display.m_prompt = "Select a trap type or press Cancl.";
1575 Display.m_curptr = '\0';
1576 Display.m_markptr = '\0';
1577 Display.m_flags = 0;
1578 Display.m_selcnt = 1;
1579 Display.m_items = Dispitems;
1580 Display.m_curi = 0;
1581
1582 /*
1583 * Try to display the menu. If we don't have a local
1584 * terminal, the call will fail and we will just
1585 * continue with the normal mode.
1586 */
1587 if (menu(&Display) >= 0) {
1588 if (Display.m_selcnt == 0) {
1589 /* Cancelled menu */
1590 msg("");
1591
1592 trap_tries--; /* Don't count this one */
1593 after = FALSE;
1594 return;
1595 }
1596 selection = Display.m_curi->mi_val;
1597 state = 2;
1598 break;
1599 }
1600 #endif
1601
1602 wclear(hw);
1603 touchwin(hw);
1604 for (i=0; i<num_traps; i++) {
1605 wmove(hw, i+2, 0);
1606 wprintw(hw, "[%d] %s", i+1, trap_types[i]);
1607 }
1608 mvwaddstr(hw, 0, 0,
1609 "Which kind of trap do you wish to set? ");
1610
1611 if (menu_overlay)
1612 /*
1613 * Put out the selection. The longest line is
1614 * the prompt line (39 characters long).
1615 */
1616 over_win(cw, hw, num_traps + 3, 41, 0, 39, NULL);
1617 else
1618 draw(hw);
1619 state = 1; /* Now in prompt window */
1620 }
1621 break;
1622
1623 case ESCAPE:
1624 if (state == 1) {
1625 clearok(cw, FALSE); /* Set up for redraw */
1626 touchwin(cw);
1627 }
1628 msg("");
1629
1630 trap_tries--; /* Don't count this one */
1631 after = FALSE;
1632 return;
1633
1634 case '1':
1635 case '2':
1636 case '3':
1637 case '4':
1638 case '5':
1639 case '6':
1640 case '7':
1641 case '8':
1642 case '9':
1643 if (selection < '7' || wizard) {
1644 if (state == 1) { /* In prompt window */
1645 clearok(cw, FALSE); /* Set up for redraw */
1646 touchwin(cw);
1647 }
1648
1649 msg("");
1650
1651 /*
1652 * Make sure there is a floor below us for trap
1653 * doors.
1654 */
1655 if (selection == '1' && level >= nfloors) {
1656 if (state == 1) draw(cw);
1657 msg("There is no level below this one.");
1658 return;
1659 }
1660 state = 2; /* Finished */
1661 break;
1662 }
1663
1664 /* Fall through for non-wizard, unusual trap case */
1665 default:
1666 if (state == 1) { /* In the prompt window */
1667 wmove(hw, 0, 0);
1668 wprintw(hw,
1669 "Please enter a selection between 1 and %d: ",
1670 num_traps);
1671 if (menu_overlay)
1672 /*
1673 * Put out the selection. The longest line is
1674 * the prompt line (43 characters long).
1675 */
1676 over_win(cw, hw, num_traps+3, 45, 0, 43, NULL);
1677 else
1678 draw(hw);
1679 }
1680 else { /* Normal window */
1681 mpos = 0;
1682 msg("Please enter a selection between 1 and %d: ",
1683 num_traps);
1684 }
1685 }
1686 } while (state != 2);
1687
1688 switch ((player.t_selection = selection)) {
1689 case '1': units = 20; /* Trap door */
1690 when '2': units = 5; /* Bear trap */
1691 when '3': units = 6; /* Sleeping gas trap */
1692 when '4': units = 5; /* Arrow trap */
1693 when '5': units = 8; /* Teleport trap */
1694 when '6': units = 5; /* Dart trap */
1695 otherwise: units = 10; /* Unknown trap */
1696 }
1697 player.t_no_move = units * movement(&player);
1698 player.t_action = C_SETTRAP;
1699 player.t_using = NULL;
1700 return;
1701 }
1702 }
1703
1704 if (is_player && player.t_ctype == C_THIEF) thief_bonus = 30;
1705 if (is_player && player.t_ctype == C_ASSASIN) thief_bonus = 20;
1706
1707 s_dext = (tp == &player) ? dex_compute() : tp->t_stats.s_dext;
1708
1709 if (ntraps >= MAXTRAPS || ++trap_tries >= MAXTRPTRY || levtype == POSTLEV ||
1710 rnd(80) >= (s_dext + tp->t_stats.s_lvl/2 + thief_bonus)) {
1711 if (is_player) msg("The trap failed!");
1712 return;
1713 }
1714
1715 switch (selection) {
1716 case '1': ch = TRAPDOOR;
1717 when '2': ch = BEARTRAP;
1718 when '3': ch = SLEEPTRAP;
1719 when '4': ch = ARROWTRAP;
1720 when '5': ch = TELTRAP;
1721 when '6': ch = DARTTRAP;
1722 when '7': ch = POOL;
1723 when '8': ch = MAZETRAP;
1724 when '9': ch = POST;
1725 }
1726
1727 mvaddch(y, x, ch);
1728 traps[ntraps].tr_show = och;
1729 traps[ntraps].tr_type = ch;
1730 traps[ntraps].tr_pos.y = y;
1731 traps[ntraps].tr_pos.x = x;
1732 if (is_player)
1733 traps[ntraps].tr_flags = ISTHIEFSET;
1734 if (ch == POOL || ch == POST) {
1735 traps[ntraps].tr_flags |= ISFOUND;
1736 }
1737
1738 ntraps++;
1739 }
1740
1741 /*
1742 * show:
1743 * returns what a certain thing will display as to the un-initiated
1744 */
1745
1746 show(y, x)
1747 register int y, x;
1748 {
1749 register char ch = CCHAR( winat(y, x) );
1750 register struct linked_list *it;
1751 register struct thing *tp;
1752
1753 if (isatrap(ch)) {
1754 register struct trap *trp = trap_at(y, x);
1755
1756 return (trp->tr_flags & ISFOUND) ? ch : trp->tr_show;
1757 }
1758 else if (isalpha(ch)) {
1759 if ((it = find_mons(y, x)) == NULL) {
1760 msg("Show: Can't find monster in show (%d, %d)", y, x);
1761 return(mvwinch(stdscr, y, x));
1762 }
1763 tp = THINGPTR(it);
1764
1765 if (on(*tp, ISDISGUISE)) ch = tp->t_disguise; /* As a mimic */
1766
1767 /* Hide invisible creatures */
1768 else if (invisible(tp)) {
1769 /* We can't see surprise-type creatures through "see invisible" */
1770 if (off(player,CANSEE) || on(*tp,CANSURPRISE))
1771 ch = CCHAR( mvwinch(stdscr, y, x) ); /* Invisible */
1772 }
1773 else if (on(*tp, CANINWALL)) {
1774 if (isrock(mvwinch(stdscr, y, x))) ch = CCHAR( winch(stdscr) ); /* As Xorn */
1775 }
1776 }
1777 return ch;
1778 }
1779
1780
1781 /*
1782 * trap_at:
1783 * find the trap at (y,x) on screen.
1784 */
1785
1786 struct trap *
1787 trap_at(y, x)
1788 register int y, x;
1789 {
1790 register struct trap *tp, *ep;
1791
1792 ep = &traps[ntraps];
1793 for (tp = traps; tp < ep; tp++)
1794 if (tp->tr_pos.y == y && tp->tr_pos.x == x)
1795 break;
1796 if (tp == ep)
1797 debug((sprintf(prbuf, "Trap at %d,%d not in array", y, x), prbuf));
1798 return tp;
1799 }
1800
1801 /*
1802 * weap_move:
1803 * Calculate how many segments it will take to swing the given
1804 * weapon (note that the weapon may actually be a stick or
1805 * even something else).
1806 */
1807
1808 weap_move(wielder, weap)
1809 register struct thing *wielder; /* Who's wielding the weapon */
1810 register struct object *weap; /* The weapon */
1811 {
1812 register int weap_rate;
1813 int dexterity;
1814 int strength;
1815
1816 if (weap == NULL) return(1); /* hand, claw, bite attacks are quick */
1817
1818 switch (weap->o_type) {
1819 case STICK:
1820 if (EQUAL(ws_type[weap->o_which], "staff"))
1821 weap_rate = 2;
1822 else weap_rate = 1; /* A wand */
1823
1824 when WEAPON:
1825 weap_rate = weaps[weap->o_which].w_rate;
1826
1827 /* Adjust for blessed or cursed weapon */
1828 if (weap->o_hplus < 0) /* Cursed */
1829 weap_rate -= (weap->o_hplus - 2) / 3;
1830 else if (weap_rate > 0) /* Blessed */
1831 weap_rate -= (2*weap->o_hplus + weap_rate - 1) / weap_rate;
1832
1833 when RELIC:
1834 switch (weap->o_which) {
1835 case MUSTY_DAGGER:
1836 case HRUGGEK_MSTAR:
1837 case AXE_AKLAD:
1838 case YEENOGHU_FLAIL:
1839 case MING_STAFF:
1840 case ORCUS_WAND:
1841 case ASMO_ROD:
1842 /* These operate in the blink of an eye */
1843 weap_rate = 1;
1844 otherwise:
1845 /* What is it? */
1846 weap_rate = 10;
1847 debug("unknown weapon in weap_move()");
1848 }
1849 otherwise:
1850 /* What is it? */
1851 weap_rate = 10;
1852 debug("unknown weapon in weap_move()");
1853 }
1854
1855 /* Put in a dexterity bonus */
1856 if (wielder == &player) dexterity = dex_compute();
1857 else dexterity = wielder->t_stats.s_dext;
1858 weap_rate -= dext_plus(dexterity) / 2;
1859
1860 /* Put in a strength bonus */
1861 if (wielder == &player) strength = str_compute();
1862 else strength = wielder->t_stats.s_str;
1863 weap_rate -= str_plus(strength) / 2;
1864
1865 /* It can't speed you up and it must take SOME time */
1866 if (weap_rate <= 0) weap_rate = 1;
1867
1868 /* Do we need to adjust for fast/slow movement? */
1869 if (on(*wielder, ISSLOW) || on(*wielder, ISDANCE)) weap_rate *= 2;
1870 if (on(*wielder, ISHASTE)) weap_rate /= 2;
1871
1872 /* Return the result */
1873 return(weap_rate);
1874 }