comparison xrogue/move.c @ 133:e6179860cb76

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