]> git.cameronkatri.com Git - bsdgames-darwin.git/blob - rogue/move.c
Comprehensive (or at least extensive) string handling cleanup for rogue.
[bsdgames-darwin.git] / rogue / move.c
1 /* $NetBSD: move.c,v 1.9 2007/12/27 23:53:00 dholland 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.9 2007/12/27 23:53:00 dholland 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 status, d = 0; /* XXX: GCC */
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 messagef(1, "you are being held");
87 } else {
88 messagef(0, "you are still stuck in the bear trap");
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, sizeof(desc));
139 if (obj->what_is == GOLD) {
140 free_object(obj);
141 messagef(1, "%s", desc);
142 goto NOT_IN_PACK;
143 }
144 } else if (!status) {
145 goto MVED;
146 } else {
147 goto MOVE_ON;
148 }
149 } else {
150 MOVE_ON:
151 obj = object_at(&level_objects, row, col);
152 get_desc(obj, desc, sizeof(desc));
153 messagef(1, "moved onto %s", desc);
154 goto NOT_IN_PACK;
155 }
156 messagef(1, "%s(%c)", desc, obj->ichar);
157 NOT_IN_PACK:
158 (void) reg_move();
159 return(STOPPED_ON_SOMETHING);
160 }
161 if (dungeon[row][col] & (DOOR | STAIRS | TRAP)) {
162 if ((!levitate) && (dungeon[row][col] & TRAP)) {
163 trap_player(row, col);
164 }
165 (void) reg_move();
166 return(STOPPED_ON_SOMETHING);
167 }
168 MVED: if (reg_move()) { /* fainted from hunger */
169 return(STOPPED_ON_SOMETHING);
170 }
171 return((confused ? STOPPED_ON_SOMETHING : MOVED));
172 }
173
174 void
175 multiple_move_rogue(dirch)
176 short dirch;
177 {
178 short row, col;
179 short m;
180
181 switch(dirch) {
182 case '\010':
183 case '\012':
184 case '\013':
185 case '\014':
186 case '\031':
187 case '\025':
188 case '\016':
189 case '\002':
190 do {
191 row = rogue.row;
192 col = rogue.col;
193 if (((m = one_move_rogue((dirch + 96), 1)) == MOVE_FAILED) ||
194 (m == STOPPED_ON_SOMETHING) ||
195 interrupted) {
196 break;
197 }
198 } while (!next_to_something(row, col));
199 if ( (!interrupted) && passgo && (m == MOVE_FAILED) &&
200 (dungeon[rogue.row][rogue.col] & TUNNEL)) {
201 turn_passage(dirch + 96, 0);
202 }
203 break;
204 case 'H':
205 case 'J':
206 case 'K':
207 case 'L':
208 case 'B':
209 case 'Y':
210 case 'U':
211 case 'N':
212 while ((!interrupted) && (one_move_rogue((dirch + 32), 1) == MOVED)) ;
213
214 if ( (!interrupted) && passgo &&
215 (dungeon[rogue.row][rogue.col] & TUNNEL)) {
216 turn_passage(dirch + 32, 1);
217 }
218 break;
219 }
220 }
221
222 boolean
223 is_passable(row, col)
224 int row, col;
225 {
226 if ((row < MIN_ROW) || (row > (DROWS - 2)) || (col < 0) ||
227 (col > (DCOLS-1))) {
228 return(0);
229 }
230 if (dungeon[row][col] & HIDDEN) {
231 return((dungeon[row][col] & TRAP) ? 1 : 0);
232 }
233 return(dungeon[row][col] & (FLOOR | TUNNEL | DOOR | STAIRS | TRAP));
234 }
235
236 boolean
237 next_to_something(drow, dcol)
238 int drow, dcol;
239 {
240 short i, j, i_end, j_end, row, col;
241 short pass_count = 0;
242 unsigned short s;
243
244 if (confused) {
245 return(1);
246 }
247 if (blind) {
248 return(0);
249 }
250 i_end = (rogue.row < (DROWS-2)) ? 1 : 0;
251 j_end = (rogue.col < (DCOLS-1)) ? 1 : 0;
252
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;
257 }
258 if (((rogue.row+i) == drow) && ((rogue.col+j) == dcol)) {
259 continue;
260 }
261 row = rogue.row + i;
262 col = rogue.col + j;
263 s = dungeon[row][col];
264 if (s & HIDDEN) {
265 continue;
266 }
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;
273 }
274 return(1);
275 }
276 if (s & TRAP) {
277 if (!(s & HIDDEN)) {
278 if (((row == drow) || (col == dcol)) &&
279 (!((row == rogue.row) || (col == rogue.col)))) {
280 continue;
281 }
282 return(1);
283 }
284 }
285 if ((((i - j) == 1) || ((i - j) == -1)) && (s & TUNNEL)) {
286 if (++pass_count > 1) {
287 return(1);
288 }
289 }
290 if ((s & DOOR) && ((i == 0) || (j == 0))) {
291 return(1);
292 }
293 }
294 }
295 return(0);
296 }
297
298 boolean
299 can_move(row1, col1, row2, col2)
300 int row1, col1, row2, col2;
301 {
302 if (!is_passable(row2, col2)) {
303 return(0);
304 }
305 if ((row1 != row2) && (col1 != col2)) {
306 if ((dungeon[row1][col1] & DOOR) || (dungeon[row2][col2] & DOOR)) {
307 return(0);
308 }
309 if ((!dungeon[row1][col2]) || (!dungeon[row2][col1])) {
310 return(0);
311 }
312 }
313 return(1);
314 }
315
316 void
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 messagef(0, "direction? ");
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 short i, n;
378 boolean fainted = 0;
379
380 if (rogue.moves_left == HUNGRY) {
381 (void) strlcpy(hunger_str, "hungry", sizeof(hunger_str));
382 messagef(0, "%s", hunger_str);
383 print_stats(STAT_HUNGER);
384 }
385 if (rogue.moves_left == WEAK) {
386 (void) strlcpy(hunger_str, "weak", sizeof(hunger_str));
387 messagef(1, "%s", hunger_str);
388 print_stats(STAT_HUNGER);
389 }
390 if (rogue.moves_left <= FAINT) {
391 if (rogue.moves_left == FAINT) {
392 (void) strlcpy(hunger_str, "faint", sizeof(hunger_str));
393 messagef(1, "%s", hunger_str);
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 messagef(1, "you faint");
403 for (i = 0; i < n; i++) {
404 if (coin_toss()) {
405 mv_mons();
406 }
407 }
408 messagef(1, you_can_move_again);
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 messagef(1, "you float gently to the ground");
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 messagef(0, "you feel yourself slowing down");
490 }
491 }
492 heal();
493 if (auto_search > 0) {
494 search(auto_search, auto_search);
495 }
496 return(fainted);
497 }
498
499 void
500 rest(count)
501 int count;
502 {
503 int i;
504
505 interrupted = 0;
506
507 for (i = 0; i < count; i++) {
508 if (interrupted) {
509 break;
510 }
511 (void) reg_move();
512 }
513 }
514
515 char
516 gr_dir()
517 {
518 short d;
519
520 d = get_rand(1, 8);
521
522 switch(d) {
523 case 1:
524 d = 'j';
525 break;
526 case 2:
527 d = 'k';
528 break;
529 case 3:
530 d = 'l';
531 break;
532 case 4:
533 d = 'h';
534 break;
535 case 5:
536 d = 'y';
537 break;
538 case 6:
539 d = 'u';
540 break;
541 case 7:
542 d = 'b';
543 break;
544 case 8:
545 d = 'n';
546 break;
547 }
548 return(d);
549 }
550
551 void
552 heal()
553 {
554 static short heal_exp = -1, n, c = 0;
555 static boolean alt;
556
557 if (rogue.hp_current == rogue.hp_max) {
558 c = 0;
559 return;
560 }
561 if (rogue.exp != heal_exp) {
562 heal_exp = rogue.exp;
563
564 switch(heal_exp) {
565 case 1:
566 n = 20;
567 break;
568 case 2:
569 n = 18;
570 break;
571 case 3:
572 n = 17;
573 break;
574 case 4:
575 n = 14;
576 break;
577 case 5:
578 n = 13;
579 break;
580 case 6:
581 n = 10;
582 break;
583 case 7:
584 n = 9;
585 break;
586 case 8:
587 n = 8;
588 break;
589 case 9:
590 n = 7;
591 break;
592 case 10:
593 n = 4;
594 break;
595 case 11:
596 n = 3;
597 break;
598 case 12:
599 default:
600 n = 2;
601 }
602 }
603 if (++c >= n) {
604 c = 0;
605 rogue.hp_current++;
606 if ((alt = !alt) != 0) {
607 rogue.hp_current++;
608 }
609 if ((rogue.hp_current += regeneration) > rogue.hp_max) {
610 rogue.hp_current = rogue.hp_max;
611 }
612 print_stats(STAT_HP);
613 }
614 }
615
616 boolean
617 can_turn(nrow, ncol)
618 short nrow, ncol;
619 {
620 if ((dungeon[nrow][ncol] & TUNNEL) && is_passable(nrow, ncol)) {
621 return(1);
622 }
623 return(0);
624 }
625
626 void
627 turn_passage(dir, fast)
628 short dir;
629 boolean fast;
630 {
631 short crow = rogue.row, ccol = rogue.col, turns = 0;
632 short ndir = 0;
633
634 if ((dir != 'h') && can_turn(crow, ccol + 1)) {
635 turns++;
636 ndir = 'l';
637 }
638 if ((dir != 'l') && can_turn(crow, ccol - 1)) {
639 turns++;
640 ndir = 'h';
641 }
642 if ((dir != 'k') && can_turn(crow + 1, ccol)) {
643 turns++;
644 ndir = 'j';
645 }
646 if ((dir != 'j') && can_turn(crow - 1, ccol)) {
647 turns++;
648 ndir = 'k';
649 }
650 if (turns == 1) {
651 multiple_move_rogue(ndir - (fast ? 32 : 96));
652 }
653 }