comparison arogue5/move.c @ 63:0ed67132cf10

Import Advanced Rogue 5.8 from the Roguelike Restoration Project (r1490)
author elwin
date Thu, 09 Aug 2012 22:58:48 +0000
parents
children a0a57cf42810
comparison
equal deleted inserted replaced
62:0ef99244acb8 63:0ed67132cf10
1 /*
2 * Hero movement commands
3 *
4 * Advanced Rogue
5 * Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T
6 * All rights reserved.
7 *
8 * Based on "Super-Rogue"
9 * Copyright (C) 1984 Robert D. Kindelberger
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 static coord nh;
28
29 static const char Moves[3][3] = {
30 { 'y', 'k', 'u' },
31 { 'h', '\0', '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;
46 register const char *mname = NULL;
47 register bool is_player = (th == &player),
48 can_see;
49 register struct linked_list *mitem = NULL;
50
51
52 /* Can the player see the creature? */
53 can_see = (cansee(tc->y, tc->x) && (is_player || !invisible(th)));
54
55 tp = trap_at(tc->y, tc->x);
56 /*
57 * if he's wearing boots of elvenkind, he won't set off the trap
58 * unless its a magic pool (they're not really traps)
59 */
60 if (is_player &&
61 cur_misc[WEAR_BOOTS] != NULL &&
62 cur_misc[WEAR_BOOTS]->o_which == MM_ELF_BOOTS &&
63 tp->tr_type != POOL)
64 return '\0';
65
66 /*
67 * if the creature is flying then it won't set off the trap
68 */
69 if (on(*th, ISFLY))
70 return '\0';
71
72 tp->tr_flags |= ISFOUND;
73
74 if (!is_player) {
75 mitem = find_mons(th->t_pos.y, th->t_pos.x);
76 mname = monsters[th->t_index].m_name;
77 }
78 else {
79 count = running = FALSE;
80 mvwaddch(cw, tp->tr_pos.y, tp->tr_pos.x, tp->tr_type);
81 }
82 switch (ch = tp->tr_type) {
83 case TRAPDOOR:
84 if (is_player) {
85 level++;
86 pstats.s_hpt -= roll(1, 10);
87 msg("You fell into a trap!");
88 if (pstats.s_hpt <= 0) death(D_FALL);
89 new_level(NORMLEV);
90 }
91 else {
92 if (can_see) msg("The %s fell into a trap!", mname);
93
94 /* See if the fall killed the monster */
95 if ((th->t_stats.s_hpt -= roll(1, 10)) <= 0) {
96 killed(mitem, FALSE, FALSE);
97 }
98 else { /* Just move monster to next level */
99 check_residue(th);
100
101 /* Erase the monster from the old position */
102 if (isalpha(mvwinch(cw, th->t_pos.y, th->t_pos.x)))
103 mvwaddch(cw, th->t_pos.y, th->t_pos.x, th->t_oldch);
104 mvwaddch(mw, th->t_pos.y, th->t_pos.x, ' ');
105 turn_on(*th, ISELSEWHERE);
106 detach(mlist, mitem);
107 attach(tlist, mitem); /* remember him next level */
108 }
109 }
110 when BEARTRAP:
111 if (is_stealth(th)) {
112 if (is_player) msg("You pass a bear trap.");
113 else if (can_see) msg("The %s passes a bear trap.", mname);
114 }
115 else {
116 th->t_no_move += BEARTIME;
117 if (is_player) msg("You are caught in a bear trap.");
118 else if (can_see) msg("The %s is caught in a bear trap.",
119 mname);
120 }
121 when SLEEPTRAP:
122 if (is_player) {
123 msg("A strange white mist envelops you.");
124 if (!ISWEARING(R_ALERT)) {
125 msg("You fall asleep.");
126 no_command += SLEEPTIME;
127 }
128 }
129 else {
130 if (can_see)
131 msg("A strange white mist envelops the %s.",mname);
132 if (on(*th, ISUNDEAD)) {
133 if (can_see)
134 msg("The mist doesn't seem to affect the %s.",mname);
135 }
136 else {
137 th->t_no_move += SLEEPTIME;
138 }
139 }
140 when ARROWTRAP:
141 if (swing(th->t_ctype, th->t_stats.s_lvl-1, th->t_stats.s_arm, 1))
142 {
143 if (is_player) {
144 msg("Oh no! An arrow shot you.");
145 if ((pstats.s_hpt -= roll(1, 6)) <= 0) {
146 msg("The arrow killed you.");
147 death(D_ARROW);
148 }
149 }
150 else {
151 if (can_see) msg("An arrow shot the %s.", mname);
152 if ((th->t_stats.s_hpt -= roll(1, 6)) <= 0) {
153 if (can_see) msg("The arrow killed the %s.", mname);
154 killed(mitem, FALSE, FALSE);
155 }
156 }
157 }
158 else
159 {
160 register struct linked_list *item;
161 register struct object *arrow;
162
163 if (is_player) msg("An arrow shoots past you.");
164 else if (can_see) msg("An arrow shoots by the %s.", mname);
165 item = new_item(sizeof *arrow);
166 arrow = OBJPTR(item);
167 arrow->o_type = WEAPON;
168 arrow->contents = NULL;
169 arrow->o_which = ARROW;
170 arrow->o_hplus = rnd(3) - 1;
171 arrow->o_dplus = rnd(3) - 1;
172 init_weapon(arrow, ARROW);
173 arrow->o_count = 1;
174 arrow->o_pos = *tc;
175 arrow->o_mark[0] = '\0';
176 fall(item, FALSE);
177 }
178 when TELTRAP:
179 if (is_player) teleport();
180 else {
181 register int rm;
182 struct room *old_room; /* old room of monster */
183
184 /*
185 * Erase the monster from the old position
186 */
187 if (isalpha(mvwinch(cw, th->t_pos.y, th->t_pos.x)))
188 mvwaddch(cw, th->t_pos.y, th->t_pos.x, th->t_oldch);
189 mvwaddch(mw, th->t_pos.y, th->t_pos.x, ' ');
190 /*
191 * check to see if room should go dark
192 */
193 if (on(*th, HASFIRE)) {
194 old_room=roomin(&th->t_pos);
195 if (old_room != NULL) {
196 register struct linked_list *fire_item;
197
198 for (fire_item = old_room->r_fires; fire_item != NULL;
199 fire_item = next(fire_item)) {
200 if (THINGPTR(fire_item) == th) {
201 detach(old_room->r_fires, fire_item);
202 destroy_item(fire_item);
203
204 if (old_room->r_fires == NULL) {
205 old_room->r_flags &= ~HASFIRE;
206 if (can_see) light(&hero);
207 }
208 }
209 }
210 }
211 }
212
213 /* Get a new position */
214 do {
215 rm = rnd_room();
216 rnd_pos(&rooms[rm], &th->t_pos);
217 } until(winat(th->t_pos.y, th->t_pos.x) == FLOOR);
218
219 /* Put it there */
220 mvwaddch(mw, th->t_pos.y, th->t_pos.x, th->t_type);
221 th->t_oldch = CCHAR( mvwinch(cw, th->t_pos.y, th->t_pos.x) );
222 /*
223 * check to see if room that creature appears in should
224 * light up
225 */
226 if (on(*th, HASFIRE)) {
227 register struct linked_list *fire_item;
228
229 fire_item = creat_item();
230 ldata(fire_item) = (char *) th;
231 attach(rooms[rm].r_fires, fire_item);
232
233 rooms[rm].r_flags |= HASFIRE;
234 if(cansee(th->t_pos.y, th->t_pos.x) &&
235 next(rooms[rm].r_fires) == NULL)
236 light(&hero);
237 }
238 if (can_see) msg("The %s seems to have disappeared!", mname);
239 }
240 when DARTTRAP:
241 if (swing(th->t_ctype, th->t_stats.s_lvl+1, th->t_stats.s_arm, 1)) {
242 if (is_player) {
243 msg("A small dart just hit you in the shoulder.");
244 if ((pstats.s_hpt -= roll(1, 4)) <= 0) {
245 msg("The dart killed you.");
246 death(D_DART);
247 }
248
249 /* Now the poison */
250 if (!save(VS_POISON, &player, 0)) {
251 /* 75% chance it will do point damage - else strength */
252 if (rnd(100) < 75) {
253 pstats.s_hpt /= 2;
254 if (pstats.s_hpt == 0) death(D_POISON);
255 }
256 else if (!ISWEARING(R_SUSABILITY))
257 chg_str(-1);
258 }
259 }
260 else {
261 if (can_see)
262 msg("A small dart just hit the %s in the shoulder.",
263 mname);
264 if ((th->t_stats.s_hpt -= roll(1,4)) <= 0) {
265 if (can_see) msg("The dart killed the %s.", mname);
266 killed(mitem, FALSE, FALSE);
267 }
268 if (!save(VS_POISON, th, 0)) {
269 th->t_stats.s_hpt /= 2;
270 if (th->t_stats.s_hpt <= 0) {
271 if (can_see) msg("The dart killed the %s.", mname);
272 killed(mitem, FALSE, FALSE);
273 }
274 }
275 }
276 }
277 else {
278 if (is_player)
279 msg("A small dart whizzes by your ear and vanishes.");
280 else if (can_see)
281 msg("A small dart whizzes by the %s's ear and vanishes.",
282 mname);
283 }
284 when POOL: {
285 register int i;
286
287 i = rnd(100);
288 if (is_player) {
289 if ((tp->tr_flags & ISGONE)) {
290 if (i < 30) {
291 teleport(); /* teleport away */
292 pool_teleport = TRUE;
293 }
294 else if((i < 45) && level > 2) {
295 level -= rnd(2) + 1;
296 cur_max = level;
297 new_level(NORMLEV);
298 pool_teleport = TRUE;
299 msg("You here a faint groan from below.");
300 }
301 else if(i < 70) {
302 level += rnd(4) + 1;
303 new_level(NORMLEV);
304 pool_teleport = TRUE;
305 msg("You find yourself in strange surroundings.");
306 }
307 else if(i > 95) {
308 msg("Oh no!!! You drown in the pool!!! --More--");
309 wait_for(cw,' ');
310 death(D_DROWN);
311 }
312 }
313 }
314 else {
315 if (i < 60) {
316 if (can_see) {
317 /* Drowns */
318 if (i < 30) msg("The %s drowned in the pool!", mname);
319
320 /* Teleported to another level */
321 else msg("The %s disappeared!", mname);
322 }
323 killed(mitem, FALSE, FALSE);
324 }
325 }
326 }
327 when MAZETRAP:
328 if (is_player) {
329 pstats.s_hpt -= roll(1, 10);
330 level++;
331 msg("You fell through a trap door!");
332 if (pstats.s_hpt <= 0) death(D_FALL);
333 new_level(MAZELEV);
334 msg("You are surrounded by twisty passages!");
335 }
336 else {
337 if (can_see) msg("The %s fell into a trap!", mname);
338 killed(mitem, FALSE, FALSE);
339 }
340 }
341
342 /* Move the cursor back onto the hero */
343 wmove(cw, hero.y, hero.x);
344
345 md_flushinp(); /* flush typeahead */
346
347 return(ch);
348 }
349
350 /*
351 * blue_light:
352 * magically light up a room (or level or make it dark)
353 */
354
355 bool
356 blue_light(blessed, cursed)
357 bool blessed, cursed;
358 {
359 register struct room *rp;
360 bool ret_val=FALSE; /* Whether or not affect is known */
361
362 rp = roomin(&hero); /* What room is hero in? */
363
364 /* Darken the room if the magic is cursed */
365 if (cursed) {
366 if ((rp == NULL) || !lit_room(rp)) msg(nothing);
367 else {
368 rp->r_flags |= ISDARK;
369 if (!lit_room(rp) && (levtype != OUTSIDE || !daytime))
370 msg("The %s suddenly goes dark.",
371 levtype == OUTSIDE ? "area" : "room");
372 else msg(nothing);
373 ret_val = TRUE;
374 }
375 }
376 else {
377 ret_val = TRUE;
378 if (rp && !lit_room(rp) &&
379 (levtype != OUTSIDE || !daytime)) {
380 addmsg("The %s is lit", levtype == OUTSIDE ? "area" : "room");
381 if (!terse)
382 addmsg(" by a %s blue light.",
383 blessed ? "bright" : "shimmering");
384 endmsg();
385 }
386 else if (winat(hero.y, hero.x) == PASSAGE)
387 msg("The corridor glows %sand then fades",
388 blessed ? "brightly " : "");
389 else {
390 ret_val = FALSE;
391 msg(nothing);
392 }
393 if (blessed) {
394 register int i; /* Index through rooms */
395
396 for (i=0; i<MAXROOMS; i++)
397 rooms[i].r_flags &= ~ISDARK;
398 }
399 else if (rp) rp->r_flags &= ~ISDARK;
400 }
401
402 /*
403 * Light the room and put the player back up
404 */
405 light(&hero);
406 mvwaddch(cw, hero.y, hero.x, PLAYER);
407 return(ret_val);
408 }
409
410 /*
411 * corr_move:
412 * Check to see that a move is legal. If so, return correct character.
413 * If not, if player came from a legal place, then try to turn him.
414 */
415
416 corr_move(dy, dx)
417 int dy, dx;
418 {
419 int legal=0; /* Number of legal alternatives */
420 register int y, x, /* Indexes though possible positions */
421 locy = 0, locx = 0; /* Hold delta of chosen location */
422
423 /* New position */
424 nh.y = hero.y + dy;
425 nh.x = hero.x + dx;
426
427 /* If it is a legal move, just return */
428 if (nh.x >= 0 && nh.x < COLS && nh.y > 0 && nh.y < LINES - 2) {
429
430 switch (winat(nh.y, nh.x)) {
431 case WALL:
432 case '|':
433 case '-':
434 break;
435 default:
436 if (diag_ok(&hero, &nh, &player))
437 return;
438 }
439 }
440
441 /* Check legal places surrounding the player -- ignore previous position */
442 for (y = hero.y - 1; y <= hero.y + 1; y++) {
443 if (y < 1 || y > LINES - 3)
444 continue;
445 for (x = hero.x - 1; x <= hero.x + 1; x++) {
446 /* Ignore borders of the screen */
447 if (x < 0 || x > COLS - 1)
448 continue;
449
450 /*
451 * Ignore where we came from, where we are, and where we couldn't go
452 */
453 if ((x == hero.x - dx && y == hero.y - dy) ||
454 (x == hero.x + dx && y == hero.y + dy) ||
455 (x == hero.x && y == hero.y))
456 continue;
457
458 switch (winat(y, x)) {
459 case WALL:
460 case '|':
461 case '-':
462 break;
463 default:
464 nh.y = y;
465 nh.x = x;
466 if (diag_ok(&hero, &nh, &player)) {
467 legal++;
468 locy = y - (hero.y - 1);
469 locx = x - (hero.x - 1);
470 }
471 }
472 }
473 }
474
475 /* If we have 2 or more legal moves, make no change */
476 if (legal != 1) {
477 return;
478 }
479
480 runch = Moves[locy][locx];
481
482 /*
483 * For mazes, pretend like it is the beginning of a new run at each turn
484 * in order to get the lighting correct.
485 */
486 if (levtype == MAZELEV) firstmove = TRUE;
487 return;
488 }
489
490 /*
491 * dip_it:
492 * Dip an object into a magic pool
493 */
494 dip_it()
495 {
496 reg struct linked_list *what;
497 reg struct object *ob;
498 reg struct trap *tp;
499 reg int wh, i;
500
501 tp = trap_at(hero.y,hero.x);
502 if (tp == NULL || tp->tr_type != POOL) {
503 msg("I see no shimmering pool here");
504 return;
505 }
506 if (tp->tr_flags & ISGONE) {
507 msg("This shimmering pool appears to have used once already");
508 return;
509 }
510 if ((what = get_item(pack, "dip", ALL)) == NULL) {
511 msg("");
512 after = FALSE;
513 return;
514 }
515 ob = OBJPTR(what);
516 mpos = 0;
517 if (ob == cur_armor ||
518 ob == cur_misc[WEAR_BOOTS] || ob == cur_misc[WEAR_JEWEL] ||
519 ob == cur_misc[WEAR_GAUNTLET]|| ob == cur_misc[WEAR_CLOAK] ||
520 ob == cur_misc[WEAR_BRACERS] || ob == cur_misc[WEAR_NECKLACE]||
521 ob == cur_ring[LEFT_1] || ob == cur_ring[LEFT_2] ||
522 ob == cur_ring[LEFT_3] || ob == cur_ring[LEFT_4] ||
523 ob == cur_ring[RIGHT_1] || ob == cur_ring[RIGHT_2] ||
524 ob == cur_ring[RIGHT_3] || ob == cur_ring[RIGHT_4]) {
525 msg("You'll have to take it off first.");
526 return;
527 }
528 tp->tr_flags |= ISGONE;
529 if (ob != NULL) {
530 wh = ob->o_which;
531 ob->o_flags |= ISKNOW;
532 i = rnd(100);
533 switch(ob->o_type) {
534 case WEAPON:
535 if(i < 50) { /* enchant weapon here */
536 if ((ob->o_flags & ISCURSED) == 0) {
537 ob->o_hplus += 1;
538 ob->o_dplus += 1;
539 }
540 else { /* weapon was prev cursed here */
541 ob->o_hplus = rnd(2);
542 ob->o_dplus = rnd(2);
543 }
544 ob->o_flags &= ~ISCURSED;
545 msg("The %s glows blue for a moment.",weaps[wh].w_name);
546 }
547 else if(i < 70) { /* curse weapon here */
548 if ((ob->o_flags & ISCURSED) == 0) {
549 ob->o_hplus = -(rnd(2)+1);
550 ob->o_dplus = -(rnd(2)+1);
551 }
552 else { /* if already cursed */
553 ob->o_hplus--;
554 ob->o_dplus--;
555 }
556 ob->o_flags |= ISCURSED;
557 msg("The %s glows red for a moment.",weaps[wh].w_name);
558 }
559 else
560 msg(nothing);
561 when ARMOR:
562 if (i < 50) { /* enchant armor */
563 if((ob->o_flags & ISCURSED) == 0)
564 ob->o_ac -= rnd(2) + 1;
565 else
566 ob->o_ac = -rnd(3)+ armors[wh].a_class;
567 ob->o_flags &= ~ISCURSED;
568 msg("The %s glows blue for a moment",armors[wh].a_name);
569 }
570 else if(i < 75){ /* curse armor */
571 if ((ob->o_flags & ISCURSED) == 0)
572 ob->o_ac = rnd(3)+ armors[wh].a_class;
573 else
574 ob->o_ac += rnd(2) + 1;
575 ob->o_flags |= ISCURSED;
576 msg("The %s glows red for a moment.",armors[wh].a_name);
577 }
578 else
579 msg(nothing);
580 when STICK: {
581 int j;
582 j = rnd(8) + 1;
583 if(i < 50) { /* add charges */
584 ob->o_charges += j;
585 ws_know[wh] = TRUE;
586 if (ob->o_flags & ISCURSED)
587 ob->o_flags &= ~ISCURSED;
588 sprintf(outstring,"The %s %s glows blue for a moment.",
589 ws_made[wh],ws_type[wh]);
590 msg(outstring);
591 }
592 else if(i < 65) { /* remove charges */
593 if ((ob->o_charges -= i) < 0)
594 ob->o_charges = 0;
595 ws_know[wh] = TRUE;
596 if (ob->o_flags & ISBLESSED)
597 ob->o_flags &= ~ISBLESSED;
598 else
599 ob->o_flags |= ISCURSED;
600 sprintf(outstring,"The %s %s glows red for a moment.",
601 ws_made[wh],ws_type[wh]);
602 msg(outstring);
603 }
604 else
605 msg(nothing);
606 }
607 when SCROLL:
608 s_know[wh] = TRUE;
609 msg("The '%s' scroll unfurls.",s_names[wh]);
610 when POTION:
611 p_know[wh] = TRUE;
612 msg("The %s potion bubbles for a moment.",p_colors[wh]);
613 when RING:
614 if(i < 50) { /* enchant ring */
615 if ((ob->o_flags & ISCURSED) == 0)
616 ob->o_ac += rnd(2) + 1;
617 else
618 ob->o_ac = rnd(2) + 1;
619 ob->o_flags &= ~ISCURSED;
620 }
621 else if(i < 80) { /* curse ring */
622 if ((ob->o_flags & ISCURSED) == 0)
623 ob->o_ac = -(rnd(2) + 1);
624 else
625 ob->o_ac -= (rnd(2) + 1);
626 ob->o_flags |= ISCURSED;
627 }
628 r_know[wh] = TRUE;
629 msg("The %s ring vibrates for a moment.",r_stones[wh]);
630 when MM:
631 m_know[wh] = TRUE;
632 switch (ob->o_which) {
633 case MM_BRACERS:
634 case MM_PROTECT:
635 if(i < 50) { /* enchant item */
636 if ((ob->o_flags & ISCURSED) == 0)
637 ob->o_ac += rnd(2) + 1;
638 else
639 ob->o_ac = rnd(2) + 1;
640 ob->o_flags &= ~ISCURSED;
641 }
642 else if(i < 80) { /* curse item */
643 if ((ob->o_flags & ISCURSED) == 0)
644 ob->o_ac = -(rnd(2) + 1);
645 else
646 ob->o_ac -= (rnd(2) + 1);
647 ob->o_flags |= ISCURSED;
648 }
649 msg("The item vibrates for a moment.");
650 when MM_CHOKE:
651 case MM_DISAPPEAR:
652 ob->o_ac = 0;
653 msg ("The dust dissolves in the pool!");
654 }
655 otherwise:
656 msg("The pool bubbles for a moment.");
657 }
658 updpack(FALSE);
659 }
660 else
661 msg(nothing);
662 }
663
664 /*
665 * do_move:
666 * Check to see that a move is legal. If it is handle the
667 * consequences (fighting, picking up, etc.)
668 */
669
670 do_move(dy, dx)
671 int dy, dx;
672 {
673 register struct room *rp, *orp;
674 register char ch;
675 coord old_hero;
676 int i, wasfirstmove;
677
678 wasfirstmove = firstmove;
679 firstmove = FALSE;
680 curprice = -1; /* if in trading post, we've moved off obj */
681 if (player.t_no_move) {
682 player.t_no_move--;
683 msg("You are still stuck in the bear trap");
684 return;
685 }
686 /*
687 * Do a confused move (maybe)
688 */
689 if ((on(player, ISHUH) && rnd(100) < 80) ||
690 (on(player, ISDANCE) && rnd(100) < 80) ||
691 (ISWEARING(R_DELUSION) && rnd(100) < 25))
692 nh = *rndmove(&player);
693 else {
694 nh.y = hero.y + dy;
695 nh.x = hero.x + dx;
696 }
697
698 /*
699 * Check if he tried to move off the screen or make an illegal
700 * diagonal move, and stop him if he did.
701 */
702 if (nh.x < 0 || nh.x > COLS-1 || nh.y < 1 || nh.y >= LINES - 2
703 || !diag_ok(&hero, &nh, &player))
704 {
705 after = running = FALSE;
706 return;
707 }
708 if (running && ce(hero, nh))
709 after = running = FALSE;
710 ch = CCHAR( winat(nh.y, nh.x) );
711
712 /* Take care of hero trying to move close to something frightening */
713 if (on(player, ISFLEE)) {
714 if (rnd(100) < 10) {
715 turn_off(player, ISFLEE);
716 msg("You regain your composure.");
717 }
718 else if (DISTANCE(nh.y, nh.x, player.t_dest->y, player.t_dest->x) <
719 DISTANCE(hero.y, hero.x, player.t_dest->y, player.t_dest->x))
720 return;
721 }
722
723 /* Take care of hero being held */
724 if (on(player, ISHELD) && !isalpha(ch))
725 {
726 msg("You are being held");
727 return;
728 }
729
730 /* assume he's not in a wall */
731 if (!isalpha(ch)) turn_off(player, ISINWALL);
732
733 switch(ch) {
734 case '|':
735 case '-':
736 if (levtype == OUTSIDE) {
737 hero = nh;
738 new_level(OUTSIDE);
739 return;
740 }
741 case WALL:
742 case SECRETDOOR:
743 if (off(player, CANINWALL) || running) {
744 after = running = FALSE;
745
746 /* Light if finishing run */
747 if (levtype == MAZELEV && lit_room(&rooms[0]))
748 look(FALSE, TRUE);
749
750 after = running = FALSE;
751
752 return;
753 }
754 turn_on(player, ISINWALL);
755 break;
756 case POOL:
757 if (levtype == OUTSIDE) {
758 lake_check(&nh);
759 running = FALSE;
760 break;
761 }
762 case MAZETRAP:
763 if (levtype == OUTSIDE) {
764 running = FALSE;
765 break;
766 }
767 case TRAPDOOR:
768 case TELTRAP:
769 case BEARTRAP:
770 case SLEEPTRAP:
771 case ARROWTRAP:
772 case DARTTRAP:
773 ch = be_trapped(&player, &nh);
774 if (ch == TRAPDOOR || ch == TELTRAP ||
775 pool_teleport || ch == MAZETRAP) {
776 pool_teleport = FALSE;
777 return;
778 }
779 break;
780 case GOLD:
781 case POTION:
782 case SCROLL:
783 case FOOD:
784 case WEAPON:
785 case ARMOR:
786 case RING:
787 case MM:
788 case RELIC:
789 case STICK:
790 running = FALSE;
791 take = ch;
792 break;
793 case DOOR:
794 case STAIRS:
795 running = FALSE;
796 break;
797 case POST:
798 running = FALSE;
799 new_level(POSTLEV);
800 return;
801 default:
802 break;
803 }
804
805 if (isalpha(ch)) { /* if its a monster then fight it */
806 running = FALSE;
807 i = 1;
808 if (player.t_ctype == C_FIGHTER)
809 i += pstats.s_lvl/10;
810 while (i--)
811 fight(&nh, cur_weapon, FALSE);
812 return;
813 }
814
815 /*
816 * if not fighting then move the hero
817 */
818 old_hero = hero; /* Save hero's old position */
819 hero = nh; /* Move the hero */
820 rp = roomin(&hero);
821 orp = roomin(&old_hero);
822
823 /* Unlight any possible cross-corridor */
824 if (levtype == MAZELEV) {
825 register bool call_light = FALSE;
826 register char wall_check;
827
828 if (wasfirstmove && lit_room(&rooms[0])) {
829 /* Are we moving out of a corridor? */
830 switch (runch) {
831 case 'h':
832 case 'l':
833 if (old_hero.y + 1 < LINES - 2) {
834 wall_check = CCHAR( winat(old_hero.y + 1, old_hero.x) );
835 if (!isrock(wall_check)) call_light = TRUE;
836 }
837 if (old_hero.y - 1 > 0) {
838 wall_check = CCHAR( winat(old_hero.y - 1, old_hero.x) );
839 if (!isrock(wall_check)) call_light = TRUE;
840 }
841 break;
842 case 'j':
843 case 'k':
844 if (old_hero.x + 1 < COLS) {
845 wall_check = CCHAR( winat(old_hero.y, old_hero.x + 1) );
846 if (!isrock(wall_check)) call_light = TRUE;
847 }
848 if (old_hero.x - 1 >= 0) {
849 wall_check = CCHAR( winat(old_hero.y, old_hero.x - 1) );
850 if (!isrock(wall_check)) call_light = TRUE;
851 }
852 break;
853 default:
854 call_light = TRUE;
855 }
856 player.t_oldpos = old_hero;
857 if (call_light) light(&old_hero);
858 }
859 }
860
861 else if (orp != NULL && rp == NULL) { /* Leaving a room -- darken it */
862 orp->r_flags |= FORCEDARK; /* Fake darkness */
863 light(&old_hero);
864 orp->r_flags &= ~FORCEDARK; /* Restore light state */
865 }
866 else if (rp != NULL && orp == NULL){/* Entering a room */
867 light(&hero);
868 }
869 ch = CCHAR( winat(old_hero.y, old_hero.x) );
870 wmove(cw, unc(old_hero));
871 waddch(cw, ch);
872 wmove(cw, unc(hero));
873 waddch(cw, PLAYER);
874 }
875
876 /*
877 * do_run:
878 * Start the hero running
879 */
880
881 do_run(ch)
882 char ch;
883 {
884 firstmove = TRUE;
885 running = TRUE;
886 after = FALSE;
887 runch = ch;
888 }
889
890 /*
891 * getdelta:
892 * Takes a movement character (eg. h, j, k, l) and returns the
893 * y and x delta corresponding to it in the remaining arguments.
894 * Returns TRUE if it could find it, FALSE otherwise.
895 */
896 bool
897 getdelta(match, dy, dx)
898 char match;
899 int *dy, *dx;
900 {
901 register y, x;
902
903 for (y = 0; y < 3; y++)
904 for (x = 0; x < 3; x++)
905 if (Moves[y][x] == match) {
906 *dy = y - 1;
907 *dx = x - 1;
908 return(TRUE);
909 }
910
911 return(FALSE);
912 }
913
914 /*
915 * isatrap:
916 * Returns TRUE if this character is some kind of trap
917 */
918 isatrap(ch)
919 reg char ch;
920 {
921 switch(ch) {
922 case DARTTRAP:
923 case TELTRAP:
924 case TRAPDOOR:
925 case ARROWTRAP:
926 case SLEEPTRAP:
927 case BEARTRAP: return(TRUE);
928 case MAZETRAP:
929 case POOL: return(levtype != OUTSIDE);
930 default: return(FALSE);
931 }
932 }
933
934 /*
935 * Called to illuminate a room.
936 * If it is dark, remove anything that might move.
937 */
938
939 light(cp)
940 coord *cp;
941 {
942 register struct room *rp;
943 register int j, k, x, y;
944 register char ch, rch, sch;
945 register struct linked_list *item;
946 int jlow, jhigh, klow, khigh; /* Boundaries of lit area */
947
948 if ((rp = roomin(cp)) != NULL) {
949 /*
950 * is he wearing ring of illumination?
951 */
952 if (&hero == cp && ISWEARING(R_LIGHT)) /* Must be hero's room */
953 rp->r_flags &= ~ISDARK;
954
955 /* If we are in a maze, don't look at the whole room (level) */
956 if (levtype == MAZELEV) {
957 int see_radius;
958
959 see_radius = 1;
960
961 /* If we are looking at the hero in a rock, broaden our sights */
962 if (&hero == cp || &player.t_oldpos == cp) {
963 ch = CCHAR( winat(hero.y, hero.x) );
964 if (isrock(ch)) see_radius = 2;
965 ch = CCHAR( winat(player.t_oldpos.y, player.t_oldpos.x) );
966 if (isrock(ch)) see_radius = 2;
967 }
968
969 jlow = max(0, cp->y - see_radius - rp->r_pos.y);
970 jhigh = min(rp->r_max.y, cp->y + see_radius + 1 - rp->r_pos.y);
971 klow = max(0, cp->x - see_radius - rp->r_pos.x);
972 khigh = min(rp->r_max.x, cp->x + see_radius + 1 - rp->r_pos.x);
973 }
974 else {
975 jlow = klow = 0;
976 jhigh = rp->r_max.y;
977 khigh = rp->r_max.x;
978 }
979 for (j = 0; j < rp->r_max.y; j++)
980 {
981 for (k = 0; k < rp->r_max.x; k++)
982 {
983 bool see_here = 0, see_before = 0;
984
985 /* Is this in the give area -- needed for maze */
986 if ((j < jlow || j >= jhigh) && (k < klow || k >= khigh))
987 continue;
988
989 y = rp->r_pos.y + j;
990 x = rp->r_pos.x + k;
991
992 /*
993 * If we are in a maze do not look at this area unless
994 * we can see it from where we are or where we last were
995 * (for erasing purposes).
996 */
997 if (levtype == MAZELEV) {
998 /* If we can't see it from here, could we see it before? */
999 if ((see_here = maze_view(y, x)) == FALSE) {
1000 coord savhero;
1001
1002 /* Could we see it from where we were? */
1003 savhero = hero;
1004 hero = player.t_oldpos;
1005 see_before = maze_view(y, x);
1006 hero = savhero;
1007
1008 if (!see_before) continue;
1009 }
1010 }
1011
1012 ch = show(y, x);
1013 wmove(cw, y, x);
1014 /*
1015 * Figure out how to display a secret door
1016 */
1017 if (ch == SECRETDOOR) {
1018 if (j == 0 || j == rp->r_max.y - 1)
1019 ch = '-';
1020 else
1021 ch = '|';
1022 }
1023 /* For monsters, if they were previously not seen and
1024 * now can be seen, or vice-versa, make sure that will
1025 * happen. This is for dark rooms as opposed to invisibility.
1026 *
1027 * Call winat() in the test because ch will not reveal
1028 * invisible monsters.
1029 */
1030 if (isalpha(winat(y, x))) {
1031 struct thing *tp; /* The monster */
1032
1033 item = wake_monster(y, x);
1034 tp = THINGPTR(item);
1035
1036 /* Previously not seen -- now can see it */
1037 if (tp->t_oldch == ' ' && cansee(tp->t_pos.y, tp->t_pos.x))
1038 tp->t_oldch = CCHAR( mvinch(y, x) );
1039
1040 /* Previously seen -- now can't see it */
1041 else if (!cansee(tp->t_pos.y, tp->t_pos.x) &&
1042 roomin(&tp->t_pos) != NULL)
1043 switch (tp->t_oldch) {
1044 /*
1045 * Only blank it out if it is in a room and not
1046 * the border (or other wall) of the room.
1047 */
1048 case DOOR:
1049 case SECRETDOOR:
1050 case '-':
1051 case '|':
1052 break;
1053
1054 otherwise:
1055 tp->t_oldch = ' ';
1056 }
1057 }
1058
1059 /*
1060 * If the room is a dark room, we might want to remove
1061 * monsters and the like from it (since they might
1062 * move).
1063 * A dark room.
1064 */
1065 if ((!lit_room(rp) && (levtype != OUTSIDE)) ||
1066 (levtype == OUTSIDE && !daytime) ||
1067 on(player, ISBLIND) ||
1068 (rp->r_flags & FORCEDARK) ||
1069 (levtype == MAZELEV && !see_here && see_before)) {
1070 sch = CCHAR( mvwinch(cw, y, x) ); /* What's seen */
1071 rch = CCHAR( mvinch(y, x) ); /* What's really there */
1072 switch (rch) {
1073 case DOOR:
1074 case SECRETDOOR:
1075 case STAIRS:
1076 case TRAPDOOR:
1077 case TELTRAP:
1078 case BEARTRAP:
1079 case SLEEPTRAP:
1080 case ARROWTRAP:
1081 case DARTTRAP:
1082 case MAZETRAP:
1083 case POOL:
1084 case POST:
1085 case '|':
1086 case '-':
1087 case WALL:
1088 if (isalpha(sch)) ch = rch;
1089 else if (sch != FLOOR) ch = sch;
1090 else ch = ' '; /* Hide undiscoverd things */
1091 when FLOOR:
1092 ch = ' ';
1093 otherwise:
1094 ch = ' ';
1095 }
1096 /* Take care of our magic bookkeeping. */
1097 switch (sch) {
1098 case MAGIC:
1099 case BMAGIC:
1100 case CMAGIC:
1101 ch = sch;
1102 }
1103 }
1104 mvwaddch(cw, y, x, ch);
1105 }
1106 }
1107 }
1108 }
1109
1110 /*
1111 * lit_room:
1112 * Called to see if the specified room is lit up or not.
1113 */
1114
1115 bool
1116 lit_room(rp)
1117 register struct room *rp;
1118 {
1119 register struct linked_list *fire_item;
1120 register struct thing *fire_creature;
1121
1122 if (!(rp->r_flags & ISDARK)) return(TRUE); /* A definitely lit room */
1123
1124 /* Is it lit by fire light? */
1125 if (rp->r_flags & HASFIRE) {
1126 switch (levtype) {
1127 case MAZELEV:
1128 /* See if a fire creature is in line of sight */
1129 for (fire_item = rp->r_fires; fire_item != NULL;
1130 fire_item = next(fire_item)) {
1131 fire_creature = THINGPTR(fire_item);
1132 if (maze_view(fire_creature->t_pos.y,
1133 fire_creature->t_pos.x)) return(TRUE);
1134 }
1135
1136 /* Couldn't find any in line-of-sight */
1137 return(FALSE);
1138
1139 /* We should probably do something special for the outside */
1140 otherwise:
1141 return TRUE;
1142 }
1143 }
1144 return(FALSE);
1145 }
1146
1147 /*
1148 * rndmove:
1149 * move in a random direction if the monster/person is confused
1150 */
1151
1152 coord *
1153 rndmove(who)
1154 struct thing *who;
1155 {
1156 register int x, y;
1157 register int ex, ey, nopen = 0;
1158 static coord ret; /* what we will be returning */
1159 static coord dest;
1160
1161 ret = who->t_pos;
1162 /*
1163 * Now go through the spaces surrounding the player and
1164 * set that place in the array to true if the space can be
1165 * moved into
1166 */
1167 ey = ret.y + 1;
1168 ex = ret.x + 1;
1169 for (y = who->t_pos.y - 1; y <= ey; y++)
1170 if (y > 0 && y < LINES - 2)
1171 for (x = who->t_pos.x - 1; x <= ex; x++)
1172 {
1173 if (x < 0 || x >= COLS)
1174 continue;
1175 if (step_ok(y, x, NOMONST, who) == TRUE)
1176 {
1177 dest.y = y;
1178 dest.x = x;
1179 if (!diag_ok(&who->t_pos, &dest, who))
1180 continue;
1181 if (rnd(++nopen) == 0)
1182 ret = dest;
1183 }
1184 }
1185 return &ret;
1186 }
1187
1188
1189
1190 /*
1191 * set_trap:
1192 * set a trap at (y, x) on screen.
1193 */
1194
1195 set_trap(tp, y, x)
1196 register struct thing *tp;
1197 register int y, x;
1198 {
1199 register bool is_player = (tp == &player);
1200 register char selection = rnd(7) + '1';
1201 register char ch = 0, och;
1202 int thief_bonus = 0;
1203 int s_dext;
1204
1205 switch (och = CCHAR( mvinch(y, x) )) {
1206 case WALL:
1207 case FLOOR:
1208 case PASSAGE:
1209 break;
1210 default:
1211 msg("The trap failed!");
1212 return;
1213 }
1214
1215 if (is_player && player.t_ctype == C_THIEF) thief_bonus = 30;
1216
1217 s_dext = (tp == &player) ? dex_compute() : tp->t_stats.s_dext;
1218
1219 if (ntraps >= MAXTRAPS || ++trap_tries >= MAXTRPTRY || levtype == POSTLEV ||
1220 rnd(80) >= (s_dext + tp->t_stats.s_lvl/2 + thief_bonus)) {
1221 if (is_player) msg("The trap failed!");
1222 return;
1223 }
1224
1225
1226 if (is_player) {
1227 int state = 0; /* 0 -> current screen, 1 -> prompt screen, 2 -> done */
1228
1229 msg("Which kind of trap do you wish to set? (* for a list): ");
1230 do {
1231 selection = tolower(readchar());
1232 switch (selection) {
1233 case '*':
1234 if (state != 1) {
1235 wclear(hw);
1236 touchwin(hw);
1237 mvwaddstr(hw, 2, 0, "[1] Trap Door\n[2] Bear Trap\n");
1238 waddstr(hw, "[3] Sleep Trap\n[4] Arrow Trap\n");
1239 waddstr(hw, "[5] Teleport Trap\n[6] Dart Trap\n");
1240 if (wizard) {
1241 waddstr(hw, "[7] Magic pool\n[8] Maze Trap\n");
1242 waddstr(hw, "[9] Trading Post\n");
1243 }
1244 mvwaddstr(hw, 0, 0, "Which kind of trap do you wish to set? ");
1245 draw(hw);
1246 state = 1; /* Now in prompt window */
1247 }
1248 break;
1249
1250 case ESCAPE:
1251 if (state == 1) {
1252 clearok(cw, TRUE); /* Set up for redraw */
1253 touchwin(cw);
1254 }
1255 msg("");
1256
1257 trap_tries--; /* Don't count this one */
1258 after = FALSE;
1259 return;
1260
1261 case '1':
1262 case '2':
1263 case '3':
1264 case '4':
1265 case '5':
1266 case '6':
1267 case '7':
1268 case '8':
1269 case '9':
1270 if (selection < '7' || wizard) {
1271 if (state == 1) { /* In prompt window */
1272 clearok(cw, TRUE); /* Set up for redraw */
1273 touchwin(cw);
1274 }
1275
1276 msg("");
1277
1278 /* Make sure there is a floor below us for trap doors */
1279 if (selection == '1' && level >= nfloors) {
1280 if (state == 1) draw(cw);
1281 msg("There is no level below this one.");
1282 return;
1283 }
1284 state = 2; /* Finished */
1285 break;
1286 }
1287
1288 /* Fall through for non-wizard, unusual trap case */
1289 default:
1290 if (state == 1) { /* In the prompt window */
1291 mvwaddstr(hw, 0, 0, "Please enter a selection between 1 and 6: ");
1292 draw(hw);
1293 }
1294 else { /* Normal window */
1295 mpos = 0;
1296 msg("Please enter a selection between 1 and 6: ");
1297 }
1298 }
1299 } while (state != 2);
1300 }
1301
1302 switch (selection) {
1303 case '1': ch = TRAPDOOR;
1304 when '2': ch = BEARTRAP;
1305 when '3': ch = SLEEPTRAP;
1306 when '4': ch = ARROWTRAP;
1307 when '5': ch = TELTRAP;
1308 when '6': ch = DARTTRAP;
1309 when '7': ch = POOL;
1310 when '8': ch = MAZETRAP;
1311 when '9': ch = POST;
1312 }
1313
1314 mvaddch(y, x, ch);
1315 traps[ntraps].tr_show = och;
1316 traps[ntraps].tr_type = ch;
1317 traps[ntraps].tr_pos.y = y;
1318 traps[ntraps].tr_pos.x = x;
1319 if (is_player)
1320 traps[ntraps].tr_flags = ISTHIEFSET;
1321 if (ch == POOL || ch == POST) {
1322 traps[ntraps].tr_flags |= ISFOUND;
1323 }
1324
1325 ntraps++;
1326 }
1327
1328 /*
1329 * show:
1330 * returns what a certain thing will display as to the un-initiated
1331 */
1332
1333 show(y, x)
1334 register int y, x;
1335 {
1336 register char ch = CCHAR( winat(y, x) );
1337 register struct linked_list *it;
1338 register struct thing *tp;
1339
1340 if (isatrap(ch)) {
1341 register struct trap *trp = trap_at(y, x);
1342
1343 return (trp->tr_flags & ISFOUND) ? ch : trp->tr_show;
1344 }
1345 else if (isalpha(ch)) {
1346 if ((it = find_mons(y, x)) == NULL) {
1347 msg("Can't find monster in show");
1348 return(mvwinch(stdscr, y, x));
1349 }
1350 tp = THINGPTR(it);
1351
1352 if (on(*tp, ISDISGUISE)) ch = tp->t_disguise; /* As a mimic */
1353
1354 /* Hide invisible creatures */
1355 else if (invisible(tp)) {
1356 /* We can't see surprise-type creatures through "see invisible" */
1357 if (off(player,CANSEE) || on(*tp,CANSURPRISE))
1358 ch = CCHAR( mvwinch(stdscr, y, x) ); /* Invisible */
1359 }
1360 else if (on(*tp, CANINWALL)) {
1361 if (isrock(mvwinch(stdscr, y, x))) ch = CCHAR( winch(stdscr) ); /* As Xorn */
1362 }
1363 }
1364 return ch;
1365 }
1366
1367
1368 /*
1369 * trap_at:
1370 * find the trap at (y,x) on screen.
1371 */
1372
1373 struct trap *
1374 trap_at(y, x)
1375 register int y, x;
1376 {
1377 register struct trap *tp, *ep;
1378
1379 ep = &traps[ntraps];
1380 for (tp = traps; tp < ep; tp++)
1381 if (tp->tr_pos.y == y && tp->tr_pos.x == x)
1382 break;
1383 if (tp == ep)
1384 debug((sprintf(prbuf, "Trap at %d,%d not in array", y, x), prbuf));
1385 return tp;
1386 }