]> git.cameronkatri.com Git - bsdgames-darwin.git/blob - rogue/move.c
Coverity CID 2788: If no room gets returned, don't try to place a monster.
[bsdgames-darwin.git] / rogue / move.c
1 /* $NetBSD: move.c,v 1.7 2006/03/30 04:19:38 jnemeth 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.7 2006/03/30 04:19:38 jnemeth 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 if (cur_room == NO_ROOM)
109 clean_up("one_move_rogue: door to nowhere");
110 light_up_room(cur_room);
111 wake_room(cur_room, 1, row, col);
112 } else {
113 light_passage(row, col);
114 }
115 } else if ((dungeon[rogue.row][rogue.col] & DOOR) &&
116 (dungeon[row][col] & TUNNEL)) {
117 light_passage(row, col);
118 wake_room(cur_room, 0, rogue.row, rogue.col);
119 darken_room(cur_room);
120 cur_room = PASSAGE;
121 } else if (dungeon[row][col] & TUNNEL) {
122 light_passage(row, col);
123 }
124 mvaddch(rogue.row, rogue.col, get_dungeon_char(rogue.row, rogue.col));
125 mvaddch(row, col, rogue.fchar);
126
127 if (!jump) {
128 refresh();
129 }
130 rogue.row = row;
131 rogue.col = col;
132 if (dungeon[row][col] & OBJECT) {
133 if (levitate && pickup) {
134 return(STOPPED_ON_SOMETHING);
135 }
136 if (pickup && !levitate) {
137 if ((obj = pick_up(row, col, &status)) != NULL) {
138 get_desc(obj, desc);
139 if (obj->what_is == GOLD) {
140 free_object(obj);
141 goto NOT_IN_PACK;
142 }
143 } else if (!status) {
144 goto MVED;
145 } else {
146 goto MOVE_ON;
147 }
148 } else {
149 MOVE_ON:
150 obj = object_at(&level_objects, row, col);
151 (void) strcpy(desc, "moved onto ");
152 get_desc(obj, desc+11);
153 goto NOT_IN_PACK;
154 }
155 n = strlen(desc);
156 desc[n] = '(';
157 desc[n+1] = obj->ichar;
158 desc[n+2] = ')';
159 desc[n+3] = 0;
160 NOT_IN_PACK:
161 message(desc, 1);
162 (void) reg_move();
163 return(STOPPED_ON_SOMETHING);
164 }
165 if (dungeon[row][col] & (DOOR | STAIRS | TRAP)) {
166 if ((!levitate) && (dungeon[row][col] & TRAP)) {
167 trap_player(row, col);
168 }
169 (void) reg_move();
170 return(STOPPED_ON_SOMETHING);
171 }
172 MVED: if (reg_move()) { /* fainted from hunger */
173 return(STOPPED_ON_SOMETHING);
174 }
175 return((confused ? STOPPED_ON_SOMETHING : MOVED));
176 }
177
178 void
179 multiple_move_rogue(dirch)
180 short dirch;
181 {
182 short row, col;
183 short m;
184
185 switch(dirch) {
186 case '\010':
187 case '\012':
188 case '\013':
189 case '\014':
190 case '\031':
191 case '\025':
192 case '\016':
193 case '\002':
194 do {
195 row = rogue.row;
196 col = rogue.col;
197 if (((m = one_move_rogue((dirch + 96), 1)) == MOVE_FAILED) ||
198 (m == STOPPED_ON_SOMETHING) ||
199 interrupted) {
200 break;
201 }
202 } while (!next_to_something(row, col));
203 if ( (!interrupted) && passgo && (m == MOVE_FAILED) &&
204 (dungeon[rogue.row][rogue.col] & TUNNEL)) {
205 turn_passage(dirch + 96, 0);
206 }
207 break;
208 case 'H':
209 case 'J':
210 case 'K':
211 case 'L':
212 case 'B':
213 case 'Y':
214 case 'U':
215 case 'N':
216 while ((!interrupted) && (one_move_rogue((dirch + 32), 1) == MOVED)) ;
217
218 if ( (!interrupted) && passgo &&
219 (dungeon[rogue.row][rogue.col] & TUNNEL)) {
220 turn_passage(dirch + 32, 1);
221 }
222 break;
223 }
224 }
225
226 boolean
227 is_passable(row, col)
228 int 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 boolean
241 next_to_something(drow, dcol)
242 int drow, dcol;
243 {
244 short i, j, i_end, j_end, row, col;
245 short pass_count = 0;
246 unsigned short s;
247
248 if (confused) {
249 return(1);
250 }
251 if (blind) {
252 return(0);
253 }
254 i_end = (rogue.row < (DROWS-2)) ? 1 : 0;
255 j_end = (rogue.col < (DCOLS-1)) ? 1 : 0;
256
257 for (i = ((rogue.row > MIN_ROW) ? -1 : 0); i <= i_end; i++) {
258 for (j = ((rogue.col > 0) ? -1 : 0); j <= j_end; j++) {
259 if ((i == 0) && (j == 0)) {
260 continue;
261 }
262 if (((rogue.row+i) == drow) && ((rogue.col+j) == dcol)) {
263 continue;
264 }
265 row = rogue.row + i;
266 col = rogue.col + j;
267 s = dungeon[row][col];
268 if (s & HIDDEN) {
269 continue;
270 }
271 /* If the rogue used to be right, up, left, down, or right of
272 * row,col, and now isn't, then don't stop */
273 if (s & (MONSTER | OBJECT | STAIRS)) {
274 if (((row == drow) || (col == dcol)) &&
275 (!((row == rogue.row) || (col == rogue.col)))) {
276 continue;
277 }
278 return(1);
279 }
280 if (s & TRAP) {
281 if (!(s & HIDDEN)) {
282 if (((row == drow) || (col == dcol)) &&
283 (!((row == rogue.row) || (col == rogue.col)))) {
284 continue;
285 }
286 return(1);
287 }
288 }
289 if ((((i - j) == 1) || ((i - j) == -1)) && (s & TUNNEL)) {
290 if (++pass_count > 1) {
291 return(1);
292 }
293 }
294 if ((s & DOOR) && ((i == 0) || (j == 0))) {
295 return(1);
296 }
297 }
298 }
299 return(0);
300 }
301
302 boolean
303 can_move(row1, col1, row2, col2)
304 int row1, col1, row2, col2;
305 {
306 if (!is_passable(row2, col2)) {
307 return(0);
308 }
309 if ((row1 != row2) && (col1 != col2)) {
310 if ((dungeon[row1][col1] & DOOR) || (dungeon[row2][col2] & DOOR)) {
311 return(0);
312 }
313 if ((!dungeon[row1][col2]) || (!dungeon[row2][col1])) {
314 return(0);
315 }
316 }
317 return(1);
318 }
319
320 void
321 move_onto()
322 {
323 short ch, d;
324 boolean first_miss = 1;
325
326 while (!is_direction(ch = rgetchar(), &d)) {
327 sound_bell();
328 if (first_miss) {
329 message("direction? ", 0);
330 first_miss = 0;
331 }
332 }
333 check_message();
334 if (ch != CANCEL) {
335 (void) one_move_rogue(ch, 0);
336 }
337 }
338
339 boolean
340 is_direction(c, d)
341 short c;
342 short *d;
343 {
344 switch(c) {
345 case 'h':
346 *d = LEFT;
347 break;
348 case 'j':
349 *d = DOWN;
350 break;
351 case 'k':
352 *d = UPWARD;
353 break;
354 case 'l':
355 *d = RIGHT;
356 break;
357 case 'b':
358 *d = DOWNLEFT;
359 break;
360 case 'y':
361 *d = UPLEFT;
362 break;
363 case 'u':
364 *d = UPRIGHT;
365 break;
366 case 'n':
367 *d = DOWNRIGHT;
368 break;
369 case CANCEL:
370 break;
371 default:
372 return(0);
373 }
374 return(1);
375 }
376
377 boolean
378 check_hunger(msg_only)
379 boolean msg_only;
380 {
381 short i, n;
382 boolean fainted = 0;
383
384 if (rogue.moves_left == HUNGRY) {
385 (void) strcpy(hunger_str, "hungry");
386 message(hunger_str, 0);
387 print_stats(STAT_HUNGER);
388 }
389 if (rogue.moves_left == WEAK) {
390 (void) strcpy(hunger_str, "weak");
391 message(hunger_str, 1);
392 print_stats(STAT_HUNGER);
393 }
394 if (rogue.moves_left <= FAINT) {
395 if (rogue.moves_left == FAINT) {
396 (void) strcpy(hunger_str, "faint");
397 message(hunger_str, 1);
398 print_stats(STAT_HUNGER);
399 }
400 n = get_rand(0, (FAINT - rogue.moves_left));
401 if (n > 0) {
402 fainted = 1;
403 if (rand_percent(40)) {
404 rogue.moves_left++;
405 }
406 message("you faint", 1);
407 for (i = 0; i < n; i++) {
408 if (coin_toss()) {
409 mv_mons();
410 }
411 }
412 message(you_can_move_again, 1);
413 }
414 }
415 if (msg_only) {
416 return(fainted);
417 }
418 if (rogue.moves_left <= STARVE) {
419 killed_by((object *) 0, STARVATION);
420 }
421
422 switch(e_rings) {
423 /*case -2:
424 Subtract 0, i.e. do nothing.
425 break;*/
426 case -1:
427 rogue.moves_left -= (rogue.moves_left % 2);
428 break;
429 case 0:
430 rogue.moves_left--;
431 break;
432 case 1:
433 rogue.moves_left--;
434 (void) check_hunger(1);
435 rogue.moves_left -= (rogue.moves_left % 2);
436 break;
437 case 2:
438 rogue.moves_left--;
439 (void) check_hunger(1);
440 rogue.moves_left--;
441 break;
442 }
443 return(fainted);
444 }
445
446 boolean
447 reg_move()
448 {
449 boolean fainted;
450
451 if ((rogue.moves_left <= HUNGRY) || (cur_level >= max_level)) {
452 fainted = check_hunger(0);
453 } else {
454 fainted = 0;
455 }
456
457 mv_mons();
458
459 if (++m_moves >= 120) {
460 m_moves = 0;
461 wanderer();
462 }
463 if (halluc) {
464 if (!(--halluc)) {
465 unhallucinate();
466 } else {
467 hallucinate();
468 }
469 }
470 if (blind) {
471 if (!(--blind)) {
472 unblind();
473 }
474 }
475 if (confused) {
476 if (!(--confused)) {
477 unconfuse();
478 }
479 }
480 if (bear_trap) {
481 bear_trap--;
482 }
483 if (levitate) {
484 if (!(--levitate)) {
485 message("you float gently to the ground", 1);
486 if (dungeon[rogue.row][rogue.col] & TRAP) {
487 trap_player(rogue.row, rogue.col);
488 }
489 }
490 }
491 if (haste_self) {
492 if (!(--haste_self)) {
493 message("you feel yourself slowing down", 0);
494 }
495 }
496 heal();
497 if (auto_search > 0) {
498 search(auto_search, auto_search);
499 }
500 return(fainted);
501 }
502
503 void
504 rest(count)
505 int count;
506 {
507 int i;
508
509 interrupted = 0;
510
511 for (i = 0; i < count; i++) {
512 if (interrupted) {
513 break;
514 }
515 (void) reg_move();
516 }
517 }
518
519 char
520 gr_dir()
521 {
522 short d;
523
524 d = get_rand(1, 8);
525
526 switch(d) {
527 case 1:
528 d = 'j';
529 break;
530 case 2:
531 d = 'k';
532 break;
533 case 3:
534 d = 'l';
535 break;
536 case 4:
537 d = 'h';
538 break;
539 case 5:
540 d = 'y';
541 break;
542 case 6:
543 d = 'u';
544 break;
545 case 7:
546 d = 'b';
547 break;
548 case 8:
549 d = 'n';
550 break;
551 }
552 return(d);
553 }
554
555 void
556 heal()
557 {
558 static short heal_exp = -1, n, c = 0;
559 static boolean alt;
560
561 if (rogue.hp_current == rogue.hp_max) {
562 c = 0;
563 return;
564 }
565 if (rogue.exp != heal_exp) {
566 heal_exp = rogue.exp;
567
568 switch(heal_exp) {
569 case 1:
570 n = 20;
571 break;
572 case 2:
573 n = 18;
574 break;
575 case 3:
576 n = 17;
577 break;
578 case 4:
579 n = 14;
580 break;
581 case 5:
582 n = 13;
583 break;
584 case 6:
585 n = 10;
586 break;
587 case 7:
588 n = 9;
589 break;
590 case 8:
591 n = 8;
592 break;
593 case 9:
594 n = 7;
595 break;
596 case 10:
597 n = 4;
598 break;
599 case 11:
600 n = 3;
601 break;
602 case 12:
603 default:
604 n = 2;
605 }
606 }
607 if (++c >= n) {
608 c = 0;
609 rogue.hp_current++;
610 if ((alt = !alt) != 0) {
611 rogue.hp_current++;
612 }
613 if ((rogue.hp_current += regeneration) > rogue.hp_max) {
614 rogue.hp_current = rogue.hp_max;
615 }
616 print_stats(STAT_HP);
617 }
618 }
619
620 boolean
621 can_turn(nrow, ncol)
622 short nrow, ncol;
623 {
624 if ((dungeon[nrow][ncol] & TUNNEL) && is_passable(nrow, ncol)) {
625 return(1);
626 }
627 return(0);
628 }
629
630 void
631 turn_passage(dir, fast)
632 short dir;
633 boolean fast;
634 {
635 short crow = rogue.row, ccol = rogue.col, turns = 0;
636 short ndir = 0;
637
638 if ((dir != 'h') && can_turn(crow, ccol + 1)) {
639 turns++;
640 ndir = 'l';
641 }
642 if ((dir != 'l') && can_turn(crow, ccol - 1)) {
643 turns++;
644 ndir = 'h';
645 }
646 if ((dir != 'k') && can_turn(crow + 1, ccol)) {
647 turns++;
648 ndir = 'j';
649 }
650 if ((dir != 'j') && can_turn(crow - 1, ccol)) {
651 turns++;
652 ndir = 'k';
653 }
654 if (turns == 1) {
655 multiple_move_rogue(ndir - (fast ? 32 : 96));
656 }
657 }