kernel/extp{read,write}v: Change ioccnt from u_int to int.
[dragonfly.git] / games / rogue / move.c
blob2239e380f3aa250038e73d4bfdf14cfae78d2739
1 /*-
2 * Copyright (c) 1988, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Timothy C. Stoehr.
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. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
32 * @(#)move.c 8.1 (Berkeley) 5/31/93
33 * $FreeBSD: src/games/rogue/move.c,v 1.7 1999/11/30 03:49:24 billf Exp $
37 * move.c
39 * This source herein may be modified and/or distributed by anybody who
40 * so desires, with the following restrictions:
41 * 1.) No portion of this notice shall be removed.
42 * 2.) Credit shall not be taken for the creation of this source.
43 * 3.) This code is not to be traded, sold, or used for personal
44 * gain or profit.
48 #include "rogue.h"
50 short m_moves = 0;
51 boolean jump = 0;
52 const char you_can_move_again[] = "you can move again";
54 static boolean can_turn(short, short);
55 static boolean check_hunger(boolean);
56 static short gr_dir(void);
57 static void heal(void);
58 static boolean next_to_something(int, int);
59 static void turn_passage(short, boolean);
61 short
62 one_move_rogue(short dirch, short pickup)
64 short row, col;
65 object *obj;
66 char desc[DCOLS];
67 short n, status, d;
69 row = rogue.row;
70 col = rogue.col;
72 if (confused) {
73 dirch = gr_dir();
75 is_direction(dirch, &d);
76 get_dir_rc(d, &row, &col, 1);
78 if (!can_move(rogue.row, rogue.col, row, col)) {
79 return(MOVE_FAILED);
81 if (being_held || bear_trap) {
82 if (!(dungeon[row][col] & MONSTER)) {
83 if (being_held) {
84 message("you are being held", 1);
85 } else {
86 message("you are still stuck in the bear trap", 0);
87 reg_move();
89 return(MOVE_FAILED);
92 if (r_teleport) {
93 if (rand_percent(R_TELE_PERCENT)) {
94 tele();
95 return(STOPPED_ON_SOMETHING);
98 if (dungeon[row][col] & MONSTER) {
99 rogue_hit(object_at(&level_monsters, row, col), 0);
100 reg_move();
101 return(MOVE_FAILED);
103 if (dungeon[row][col] & DOOR) {
104 if (cur_room == PASSAGE) {
105 cur_room = get_room_number(row, col);
106 if (cur_room == NO_ROOM)
107 clean_up("one_move_rogue: door to nowhere");
108 light_up_room(cur_room);
109 wake_room(cur_room, 1, row, col);
110 } else {
111 light_passage(row, col);
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);
122 mvaddch(rogue.row, rogue.col, get_dungeon_char(rogue.row, rogue.col));
123 mvaddch(row, col, rogue.fchar);
125 if (!jump) {
126 refresh();
128 rogue.row = row;
129 rogue.col = col;
130 if (dungeon[row][col] & OBJECT) {
131 if (levitate && pickup) {
132 return(STOPPED_ON_SOMETHING);
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;
141 } else if (!status) {
142 goto MVED;
143 } else {
144 goto MOVE_ON;
146 } else {
147 MOVE_ON:
148 obj = object_at(&level_objects, row, col);
149 strcpy(desc, "moved onto ");
150 get_desc(obj, desc+11);
151 goto NOT_IN_PACK;
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 reg_move();
161 return(STOPPED_ON_SOMETHING);
163 if (dungeon[row][col] & (DOOR | STAIRS | TRAP)) {
164 if ((!levitate) && (dungeon[row][col] & TRAP)) {
165 trap_player(row, col);
167 reg_move();
168 return(STOPPED_ON_SOMETHING);
170 MVED: if (reg_move()) { /* fainted from hunger */
171 return(STOPPED_ON_SOMETHING);
173 return((confused ? STOPPED_ON_SOMETHING : MOVED));
176 void
177 multiple_move_rogue(short dirch)
179 short row, col;
180 short m;
182 switch(dirch) {
183 case '\010':
184 case '\012':
185 case '\013':
186 case '\014':
187 case '\031':
188 case '\025':
189 case '\016':
190 case '\002':
191 do {
192 row = rogue.row;
193 col = rogue.col;
194 if (((m = one_move_rogue((dirch + 96), 1)) == MOVE_FAILED) ||
195 (m == STOPPED_ON_SOMETHING) ||
196 interrupted) {
197 break;
199 } while (!next_to_something(row, col));
200 if ( (!interrupted) && passgo && (m == MOVE_FAILED) &&
201 (dungeon[rogue.row][rogue.col] & TUNNEL)) {
202 turn_passage(dirch + 96, 0);
204 break;
205 case 'H':
206 case 'J':
207 case 'K':
208 case 'L':
209 case 'B':
210 case 'Y':
211 case 'U':
212 case 'N':
213 while ((!interrupted) && (one_move_rogue((dirch + 32), 1) == MOVED))
216 if ( (!interrupted) && passgo &&
217 (dungeon[rogue.row][rogue.col] & TUNNEL)) {
218 turn_passage(dirch + 32, 1);
220 break;
224 boolean
225 is_passable(int row, int col)
227 if ((row < MIN_ROW) || (row > (DROWS - 2)) || (col < 0) ||
228 (col > (DCOLS-1))) {
229 return(0);
231 if (dungeon[row][col] & HIDDEN) {
232 return((dungeon[row][col] & TRAP) ? 1 : 0);
234 return(dungeon[row][col] & (FLOOR | TUNNEL | DOOR | STAIRS | TRAP));
237 static boolean
238 next_to_something(int drow, int dcol)
240 short i, j, i_end, j_end, row, col;
241 short pass_count = 0;
242 unsigned short s;
244 if (confused) {
245 return(1);
247 if (blind) {
248 return(0);
250 i_end = (rogue.row < (DROWS-2)) ? 1 : 0;
251 j_end = (rogue.col < (DCOLS-1)) ? 1 : 0;
253 for (i = ((rogue.row > MIN_ROW) ? -1 : 0); i <= i_end; i++) {
254 for (j = ((rogue.col > 0) ? -1 : 0); j <= j_end; j++) {
255 if ((i == 0) && (j == 0)) {
256 continue;
258 if (((rogue.row+i) == drow) && ((rogue.col+j) == dcol)) {
259 continue;
261 row = rogue.row + i;
262 col = rogue.col + j;
263 s = dungeon[row][col];
264 if (s & HIDDEN) {
265 continue;
267 /* If the rogue used to be right, up, left, down, or right of
268 * row,col, and now isn't, then don't stop */
269 if (s & (MONSTER | OBJECT | STAIRS)) {
270 if (((row == drow) || (col == dcol)) &&
271 (!((row == rogue.row) || (col == rogue.col)))) {
272 continue;
274 return(1);
276 if (s & TRAP) {
277 if (!(s & HIDDEN)) {
278 if (((row == drow) || (col == dcol)) &&
279 (!((row == rogue.row) || (col == rogue.col)))) {
280 continue;
282 return(1);
285 if ((((i - j) == 1) || ((i - j) == -1)) && (s & TUNNEL)) {
286 if (++pass_count > 1) {
287 return(1);
290 if ((s & DOOR) && ((i == 0) || (j == 0))) {
291 return(1);
295 return(0);
298 boolean
299 can_move(short row1, short col1, short row2, short col2)
301 if (!is_passable(row2, col2)) {
302 return(0);
304 if ((row1 != row2) && (col1 != col2)) {
305 if ((dungeon[row1][col1] & DOOR) || (dungeon[row2][col2] & DOOR)) {
306 return(0);
308 if ((!dungeon[row1][col2]) || (!dungeon[row2][col1])) {
309 return(0);
312 return(1);
315 void
316 move_onto(void)
318 short ch, d;
319 boolean first_miss = 1;
321 while (!is_direction(ch = rgetchar(), &d)) {
322 sound_bell();
323 if (first_miss) {
324 message("direction? ", 0);
325 first_miss = 0;
328 check_message();
329 if (ch != CANCEL) {
330 one_move_rogue(ch, 0);
334 boolean
335 is_direction(short c, short *d)
337 switch(c) {
338 case 'h':
339 *d = LEFT;
340 break;
341 case 'j':
342 *d = DOWN;
343 break;
344 case 'k':
345 *d = UPWARD;
346 break;
347 case 'l':
348 *d = RIGHT;
349 break;
350 case 'b':
351 *d = DOWNLEFT;
352 break;
353 case 'y':
354 *d = UPLEFT;
355 break;
356 case 'u':
357 *d = UPRIGHT;
358 break;
359 case 'n':
360 *d = DOWNRIGHT;
361 break;
362 case CANCEL:
363 break;
364 default:
365 return(0);
367 return(1);
370 static boolean
371 check_hunger(boolean msg_only)
373 short i, n;
374 boolean fainted = 0;
376 if (rogue.moves_left == HUNGRY) {
377 strcpy(hunger_str, "hungry");
378 message(hunger_str, 0);
379 print_stats(STAT_HUNGER);
381 if (rogue.moves_left == WEAK) {
382 strcpy(hunger_str, "weak");
383 message(hunger_str, 1);
384 print_stats(STAT_HUNGER);
386 if (rogue.moves_left <= FAINT) {
387 if (rogue.moves_left == FAINT) {
388 strcpy(hunger_str, "faint");
389 message(hunger_str, 1);
390 print_stats(STAT_HUNGER);
392 n = get_rand(0, (FAINT - rogue.moves_left));
393 if (n > 0) {
394 fainted = 1;
395 if (rand_percent(40)) {
396 rogue.moves_left++;
398 message("you faint", 1);
399 for (i = 0; i < n; i++) {
400 if (coin_toss()) {
401 mv_mons();
404 message(you_can_move_again, 1);
407 if (msg_only) {
408 return(fainted);
410 if (rogue.moves_left <= STARVE) {
411 killed_by(NULL, STARVATION);
414 switch(e_rings) {
415 case -1:
416 rogue.moves_left -= (rogue.moves_left % 2);
417 break;
418 case 0:
419 rogue.moves_left--;
420 break;
421 case 1:
422 rogue.moves_left--;
423 check_hunger(1);
424 rogue.moves_left -= (rogue.moves_left % 2);
425 break;
426 case 2:
427 rogue.moves_left--;
428 check_hunger(1);
429 rogue.moves_left--;
430 break;
432 return(fainted);
435 boolean
436 reg_move(void)
438 boolean fainted;
440 if ((rogue.moves_left <= HUNGRY) || (cur_level >= max_level)) {
441 fainted = check_hunger(0);
442 } else {
443 fainted = 0;
446 mv_mons();
448 if (++m_moves >= 120) {
449 m_moves = 0;
450 wanderer();
452 if (halluc) {
453 if (!(--halluc)) {
454 unhallucinate();
455 } else {
456 hallucinate();
459 if (blind) {
460 if (!(--blind)) {
461 unblind();
464 if (confused) {
465 if (!(--confused)) {
466 unconfuse();
469 if (bear_trap) {
470 bear_trap--;
472 if (levitate) {
473 if (!(--levitate)) {
474 message("you float gently to the ground", 1);
475 if (dungeon[rogue.row][rogue.col] & TRAP) {
476 trap_player(rogue.row, rogue.col);
480 if (haste_self) {
481 if (!(--haste_self)) {
482 message("you feel yourself slowing down", 0);
485 heal();
486 if (auto_search > 0) {
487 search(auto_search, auto_search);
489 return(fainted);
492 void
493 rest(int count)
495 int i;
497 interrupted = 0;
499 for (i = 0; i < count; i++) {
500 if (interrupted) {
501 break;
503 reg_move();
507 static short
508 gr_dir(void)
510 short d;
512 d = get_rand(1, 8);
514 switch(d) {
515 case 1:
516 d = 'j';
517 break;
518 case 2:
519 d = 'k';
520 break;
521 case 3:
522 d = 'l';
523 break;
524 case 4:
525 d = 'h';
526 break;
527 case 5:
528 d = 'y';
529 break;
530 case 6:
531 d = 'u';
532 break;
533 case 7:
534 d = 'b';
535 break;
536 case 8:
537 d = 'n';
538 break;
540 return(d);
543 static void
544 heal(void)
546 static short heal_exp = -1, n, c = 0;
547 static boolean alt;
549 if (rogue.hp_current == rogue.hp_max) {
550 c = 0;
551 return;
553 if (rogue.exp != heal_exp) {
554 heal_exp = rogue.exp;
556 switch(heal_exp) {
557 case 1:
558 n = 20;
559 break;
560 case 2:
561 n = 18;
562 break;
563 case 3:
564 n = 17;
565 break;
566 case 4:
567 n = 14;
568 break;
569 case 5:
570 n = 13;
571 break;
572 case 6:
573 n = 10;
574 break;
575 case 7:
576 n = 9;
577 break;
578 case 8:
579 n = 8;
580 break;
581 case 9:
582 n = 7;
583 break;
584 case 10:
585 n = 4;
586 break;
587 case 11:
588 n = 3;
589 break;
590 case 12:
591 default:
592 n = 2;
595 if (++c >= n) {
596 c = 0;
597 rogue.hp_current++;
598 if ((alt = !alt) != 0) {
599 rogue.hp_current++;
601 if ((rogue.hp_current += regeneration) > rogue.hp_max) {
602 rogue.hp_current = rogue.hp_max;
604 print_stats(STAT_HP);
608 static boolean
609 can_turn(short nrow, short ncol)
611 if ((dungeon[nrow][ncol] & TUNNEL) && is_passable(nrow, ncol)) {
612 return(1);
614 return(0);
617 static void
618 turn_passage(short dir, boolean fast)
620 short crow = rogue.row, ccol = rogue.col, turns = 0;
621 short ndir = 0;
623 if ((dir != 'h') && can_turn(crow, ccol + 1)) {
624 turns++;
625 ndir = 'l';
627 if ((dir != 'l') && can_turn(crow, ccol - 1)) {
628 turns++;
629 ndir = 'h';
631 if ((dir != 'k') && can_turn(crow + 1, ccol)) {
632 turns++;
633 ndir = 'j';
635 if ((dir != 'j') && can_turn(crow - 1, ccol)) {
636 turns++;
637 ndir = 'k';
639 if (turns == 1) {
640 multiple_move_rogue(ndir - (fast ? 32 : 96));