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