move.c revision 1.6 1 /* $NetBSD: move.c,v 1.6 2003/08/07 09:37:38 agc Exp $ */
2
3 /*
4 * Copyright (c) 1988, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Timothy C. Stoehr.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 #include <sys/cdefs.h>
36 #ifndef lint
37 #if 0
38 static char sccsid[] = "@(#)move.c 8.1 (Berkeley) 5/31/93";
39 #else
40 __RCSID("$NetBSD: move.c,v 1.6 2003/08/07 09:37:38 agc Exp $");
41 #endif
42 #endif /* not lint */
43
44 /*
45 * move.c
46 *
47 * This source herein may be modified and/or distributed by anybody who
48 * so desires, with the following restrictions:
49 * 1.) No portion of this notice shall be removed.
50 * 2.) Credit shall not be taken for the creation of this source.
51 * 3.) This code is not to be traded, sold, or used for personal
52 * gain or profit.
53 *
54 */
55
56 #include "rogue.h"
57
58 short m_moves = 0;
59 boolean jump = 0;
60 const char *you_can_move_again = "you can move again";
61
62 int
63 one_move_rogue(dirch, pickup)
64 short dirch, pickup;
65 {
66 short row, col;
67 object *obj;
68 char desc[DCOLS];
69 short n, status, d;
70
71 row = rogue.row;
72 col = rogue.col;
73
74 if (confused) {
75 dirch = gr_dir();
76 }
77 (void) is_direction(dirch, &d);
78 get_dir_rc(d, &row, &col, 1);
79
80 if (!can_move(rogue.row, rogue.col, row, col)) {
81 return(MOVE_FAILED);
82 }
83 if (being_held || bear_trap) {
84 if (!(dungeon[row][col] & MONSTER)) {
85 if (being_held) {
86 message("you are being held", 1);
87 } else {
88 message("you are still stuck in the bear trap", 0);
89 (void) reg_move();
90 }
91 return(MOVE_FAILED);
92 }
93 }
94 if (r_teleport) {
95 if (rand_percent(R_TELE_PERCENT)) {
96 tele();
97 return(STOPPED_ON_SOMETHING);
98 }
99 }
100 if (dungeon[row][col] & MONSTER) {
101 rogue_hit(object_at(&level_monsters, row, col), 0);
102 (void) reg_move();
103 return(MOVE_FAILED);
104 }
105 if (dungeon[row][col] & DOOR) {
106 if (cur_room == PASSAGE) {
107 cur_room = get_room_number(row, col);
108 light_up_room(cur_room);
109 wake_room(cur_room, 1, row, col);
110 } else {
111 light_passage(row, col);
112 }
113 } else if ((dungeon[rogue.row][rogue.col] & DOOR) &&
114 (dungeon[row][col] & TUNNEL)) {
115 light_passage(row, col);
116 wake_room(cur_room, 0, rogue.row, rogue.col);
117 darken_room(cur_room);
118 cur_room = PASSAGE;
119 } else if (dungeon[row][col] & TUNNEL) {
120 light_passage(row, col);
121 }
122 mvaddch(rogue.row, rogue.col, get_dungeon_char(rogue.row, rogue.col));
123 mvaddch(row, col, rogue.fchar);
124
125 if (!jump) {
126 refresh();
127 }
128 rogue.row = row;
129 rogue.col = col;
130 if (dungeon[row][col] & OBJECT) {
131 if (levitate && pickup) {
132 return(STOPPED_ON_SOMETHING);
133 }
134 if (pickup && !levitate) {
135 if ((obj = pick_up(row, col, &status)) != NULL) {
136 get_desc(obj, desc);
137 if (obj->what_is == GOLD) {
138 free_object(obj);
139 goto NOT_IN_PACK;
140 }
141 } else if (!status) {
142 goto MVED;
143 } else {
144 goto MOVE_ON;
145 }
146 } else {
147 MOVE_ON:
148 obj = object_at(&level_objects, row, col);
149 (void) strcpy(desc, "moved onto ");
150 get_desc(obj, desc+11);
151 goto NOT_IN_PACK;
152 }
153 n = strlen(desc);
154 desc[n] = '(';
155 desc[n+1] = obj->ichar;
156 desc[n+2] = ')';
157 desc[n+3] = 0;
158 NOT_IN_PACK:
159 message(desc, 1);
160 (void) reg_move();
161 return(STOPPED_ON_SOMETHING);
162 }
163 if (dungeon[row][col] & (DOOR | STAIRS | TRAP)) {
164 if ((!levitate) && (dungeon[row][col] & TRAP)) {
165 trap_player(row, col);
166 }
167 (void) reg_move();
168 return(STOPPED_ON_SOMETHING);
169 }
170 MVED: if (reg_move()) { /* fainted from hunger */
171 return(STOPPED_ON_SOMETHING);
172 }
173 return((confused ? STOPPED_ON_SOMETHING : MOVED));
174 }
175
176 void
177 multiple_move_rogue(dirch)
178 short dirch;
179 {
180 short row, col;
181 short m;
182
183 switch(dirch) {
184 case '\010':
185 case '\012':
186 case '\013':
187 case '\014':
188 case '\031':
189 case '\025':
190 case '\016':
191 case '\002':
192 do {
193 row = rogue.row;
194 col = rogue.col;
195 if (((m = one_move_rogue((dirch + 96), 1)) == MOVE_FAILED) ||
196 (m == STOPPED_ON_SOMETHING) ||
197 interrupted) {
198 break;
199 }
200 } while (!next_to_something(row, col));
201 if ( (!interrupted) && passgo && (m == MOVE_FAILED) &&
202 (dungeon[rogue.row][rogue.col] & TUNNEL)) {
203 turn_passage(dirch + 96, 0);
204 }
205 break;
206 case 'H':
207 case 'J':
208 case 'K':
209 case 'L':
210 case 'B':
211 case 'Y':
212 case 'U':
213 case 'N':
214 while ((!interrupted) && (one_move_rogue((dirch + 32), 1) == MOVED)) ;
215
216 if ( (!interrupted) && passgo &&
217 (dungeon[rogue.row][rogue.col] & TUNNEL)) {
218 turn_passage(dirch + 32, 1);
219 }
220 break;
221 }
222 }
223
224 boolean
225 is_passable(row, col)
226 int row, col;
227 {
228 if ((row < MIN_ROW) || (row > (DROWS - 2)) || (col < 0) ||
229 (col > (DCOLS-1))) {
230 return(0);
231 }
232 if (dungeon[row][col] & HIDDEN) {
233 return((dungeon[row][col] & TRAP) ? 1 : 0);
234 }
235 return(dungeon[row][col] & (FLOOR | TUNNEL | DOOR | STAIRS | TRAP));
236 }
237
238 boolean
239 next_to_something(drow, dcol)
240 int drow, dcol;
241 {
242 short i, j, i_end, j_end, row, col;
243 short pass_count = 0;
244 unsigned short s;
245
246 if (confused) {
247 return(1);
248 }
249 if (blind) {
250 return(0);
251 }
252 i_end = (rogue.row < (DROWS-2)) ? 1 : 0;
253 j_end = (rogue.col < (DCOLS-1)) ? 1 : 0;
254
255 for (i = ((rogue.row > MIN_ROW) ? -1 : 0); i <= i_end; i++) {
256 for (j = ((rogue.col > 0) ? -1 : 0); j <= j_end; j++) {
257 if ((i == 0) && (j == 0)) {
258 continue;
259 }
260 if (((rogue.row+i) == drow) && ((rogue.col+j) == dcol)) {
261 continue;
262 }
263 row = rogue.row + i;
264 col = rogue.col + j;
265 s = dungeon[row][col];
266 if (s & HIDDEN) {
267 continue;
268 }
269 /* If the rogue used to be right, up, left, down, or right of
270 * row,col, and now isn't, then don't stop */
271 if (s & (MONSTER | OBJECT | STAIRS)) {
272 if (((row == drow) || (col == dcol)) &&
273 (!((row == rogue.row) || (col == rogue.col)))) {
274 continue;
275 }
276 return(1);
277 }
278 if (s & TRAP) {
279 if (!(s & HIDDEN)) {
280 if (((row == drow) || (col == dcol)) &&
281 (!((row == rogue.row) || (col == rogue.col)))) {
282 continue;
283 }
284 return(1);
285 }
286 }
287 if ((((i - j) == 1) || ((i - j) == -1)) && (s & TUNNEL)) {
288 if (++pass_count > 1) {
289 return(1);
290 }
291 }
292 if ((s & DOOR) && ((i == 0) || (j == 0))) {
293 return(1);
294 }
295 }
296 }
297 return(0);
298 }
299
300 boolean
301 can_move(row1, col1, row2, col2)
302 int row1, col1, row2, col2;
303 {
304 if (!is_passable(row2, col2)) {
305 return(0);
306 }
307 if ((row1 != row2) && (col1 != col2)) {
308 if ((dungeon[row1][col1] & DOOR) || (dungeon[row2][col2] & DOOR)) {
309 return(0);
310 }
311 if ((!dungeon[row1][col2]) || (!dungeon[row2][col1])) {
312 return(0);
313 }
314 }
315 return(1);
316 }
317
318 void
319 move_onto()
320 {
321 short ch, d;
322 boolean first_miss = 1;
323
324 while (!is_direction(ch = rgetchar(), &d)) {
325 sound_bell();
326 if (first_miss) {
327 message("direction? ", 0);
328 first_miss = 0;
329 }
330 }
331 check_message();
332 if (ch != CANCEL) {
333 (void) one_move_rogue(ch, 0);
334 }
335 }
336
337 boolean
338 is_direction(c, d)
339 short c;
340 short *d;
341 {
342 switch(c) {
343 case 'h':
344 *d = LEFT;
345 break;
346 case 'j':
347 *d = DOWN;
348 break;
349 case 'k':
350 *d = UPWARD;
351 break;
352 case 'l':
353 *d = RIGHT;
354 break;
355 case 'b':
356 *d = DOWNLEFT;
357 break;
358 case 'y':
359 *d = UPLEFT;
360 break;
361 case 'u':
362 *d = UPRIGHT;
363 break;
364 case 'n':
365 *d = DOWNRIGHT;
366 break;
367 case CANCEL:
368 break;
369 default:
370 return(0);
371 }
372 return(1);
373 }
374
375 boolean
376 check_hunger(msg_only)
377 boolean msg_only;
378 {
379 short i, n;
380 boolean fainted = 0;
381
382 if (rogue.moves_left == HUNGRY) {
383 (void) strcpy(hunger_str, "hungry");
384 message(hunger_str, 0);
385 print_stats(STAT_HUNGER);
386 }
387 if (rogue.moves_left == WEAK) {
388 (void) strcpy(hunger_str, "weak");
389 message(hunger_str, 1);
390 print_stats(STAT_HUNGER);
391 }
392 if (rogue.moves_left <= FAINT) {
393 if (rogue.moves_left == FAINT) {
394 (void) strcpy(hunger_str, "faint");
395 message(hunger_str, 1);
396 print_stats(STAT_HUNGER);
397 }
398 n = get_rand(0, (FAINT - rogue.moves_left));
399 if (n > 0) {
400 fainted = 1;
401 if (rand_percent(40)) {
402 rogue.moves_left++;
403 }
404 message("you faint", 1);
405 for (i = 0; i < n; i++) {
406 if (coin_toss()) {
407 mv_mons();
408 }
409 }
410 message(you_can_move_again, 1);
411 }
412 }
413 if (msg_only) {
414 return(fainted);
415 }
416 if (rogue.moves_left <= STARVE) {
417 killed_by((object *) 0, STARVATION);
418 }
419
420 switch(e_rings) {
421 /*case -2:
422 Subtract 0, i.e. do nothing.
423 break;*/
424 case -1:
425 rogue.moves_left -= (rogue.moves_left % 2);
426 break;
427 case 0:
428 rogue.moves_left--;
429 break;
430 case 1:
431 rogue.moves_left--;
432 (void) check_hunger(1);
433 rogue.moves_left -= (rogue.moves_left % 2);
434 break;
435 case 2:
436 rogue.moves_left--;
437 (void) check_hunger(1);
438 rogue.moves_left--;
439 break;
440 }
441 return(fainted);
442 }
443
444 boolean
445 reg_move()
446 {
447 boolean fainted;
448
449 if ((rogue.moves_left <= HUNGRY) || (cur_level >= max_level)) {
450 fainted = check_hunger(0);
451 } else {
452 fainted = 0;
453 }
454
455 mv_mons();
456
457 if (++m_moves >= 120) {
458 m_moves = 0;
459 wanderer();
460 }
461 if (halluc) {
462 if (!(--halluc)) {
463 unhallucinate();
464 } else {
465 hallucinate();
466 }
467 }
468 if (blind) {
469 if (!(--blind)) {
470 unblind();
471 }
472 }
473 if (confused) {
474 if (!(--confused)) {
475 unconfuse();
476 }
477 }
478 if (bear_trap) {
479 bear_trap--;
480 }
481 if (levitate) {
482 if (!(--levitate)) {
483 message("you float gently to the ground", 1);
484 if (dungeon[rogue.row][rogue.col] & TRAP) {
485 trap_player(rogue.row, rogue.col);
486 }
487 }
488 }
489 if (haste_self) {
490 if (!(--haste_self)) {
491 message("you feel yourself slowing down", 0);
492 }
493 }
494 heal();
495 if (auto_search > 0) {
496 search(auto_search, auto_search);
497 }
498 return(fainted);
499 }
500
501 void
502 rest(count)
503 int count;
504 {
505 int i;
506
507 interrupted = 0;
508
509 for (i = 0; i < count; i++) {
510 if (interrupted) {
511 break;
512 }
513 (void) reg_move();
514 }
515 }
516
517 char
518 gr_dir()
519 {
520 short d;
521
522 d = get_rand(1, 8);
523
524 switch(d) {
525 case 1:
526 d = 'j';
527 break;
528 case 2:
529 d = 'k';
530 break;
531 case 3:
532 d = 'l';
533 break;
534 case 4:
535 d = 'h';
536 break;
537 case 5:
538 d = 'y';
539 break;
540 case 6:
541 d = 'u';
542 break;
543 case 7:
544 d = 'b';
545 break;
546 case 8:
547 d = 'n';
548 break;
549 }
550 return(d);
551 }
552
553 void
554 heal()
555 {
556 static short heal_exp = -1, n, c = 0;
557 static boolean alt;
558
559 if (rogue.hp_current == rogue.hp_max) {
560 c = 0;
561 return;
562 }
563 if (rogue.exp != heal_exp) {
564 heal_exp = rogue.exp;
565
566 switch(heal_exp) {
567 case 1:
568 n = 20;
569 break;
570 case 2:
571 n = 18;
572 break;
573 case 3:
574 n = 17;
575 break;
576 case 4:
577 n = 14;
578 break;
579 case 5:
580 n = 13;
581 break;
582 case 6:
583 n = 10;
584 break;
585 case 7:
586 n = 9;
587 break;
588 case 8:
589 n = 8;
590 break;
591 case 9:
592 n = 7;
593 break;
594 case 10:
595 n = 4;
596 break;
597 case 11:
598 n = 3;
599 break;
600 case 12:
601 default:
602 n = 2;
603 }
604 }
605 if (++c >= n) {
606 c = 0;
607 rogue.hp_current++;
608 if ((alt = !alt) != 0) {
609 rogue.hp_current++;
610 }
611 if ((rogue.hp_current += regeneration) > rogue.hp_max) {
612 rogue.hp_current = rogue.hp_max;
613 }
614 print_stats(STAT_HP);
615 }
616 }
617
618 boolean
619 can_turn(nrow, ncol)
620 short nrow, ncol;
621 {
622 if ((dungeon[nrow][ncol] & TUNNEL) && is_passable(nrow, ncol)) {
623 return(1);
624 }
625 return(0);
626 }
627
628 void
629 turn_passage(dir, fast)
630 short dir;
631 boolean fast;
632 {
633 short crow = rogue.row, ccol = rogue.col, turns = 0;
634 short ndir = 0;
635
636 if ((dir != 'h') && can_turn(crow, ccol + 1)) {
637 turns++;
638 ndir = 'l';
639 }
640 if ((dir != 'l') && can_turn(crow, ccol - 1)) {
641 turns++;
642 ndir = 'h';
643 }
644 if ((dir != 'k') && can_turn(crow + 1, ccol)) {
645 turns++;
646 ndir = 'j';
647 }
648 if ((dir != 'j') && can_turn(crow - 1, ccol)) {
649 turns++;
650 ndir = 'k';
651 }
652 if (turns == 1) {
653 multiple_move_rogue(ndir - (fast ? 32 : 96));
654 }
655 }
656