1 /* $NetBSD: move.c,v 1.13 2011/05/23 23:01:17 joerg Exp $ */
4 * Copyright (c) 1988, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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
35 #include <sys/cdefs.h>
38 static char sccsid
[] = "@(#)move.c 8.1 (Berkeley) 5/31/93";
40 __RCSID("$NetBSD: move.c,v 1.13 2011/05/23 23:01:17 joerg Exp $");
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
60 const char you_can_move_again
[] = "you can move again";
62 static boolean
can_turn(short, short);
63 static boolean
check_hunger(boolean
);
64 static char gr_dir(void);
65 static void heal(void);
66 static boolean
next_to_something(int, int);
67 static void turn_passage(short, boolean
);
70 one_move_rogue(short dirch
, short pickup
)
75 short status
, d
= 0; /* XXX: GCC */
83 (void)is_direction(dirch
, &d
);
84 get_dir_rc(d
, &row
, &col
, 1);
86 if (!can_move(rogue
.row
, rogue
.col
, row
, col
)) {
89 if (being_held
|| bear_trap
) {
90 if (!(dungeon
[row
][col
] & MONSTER
)) {
92 messagef(1, "you are being held");
94 messagef(0, "you are still stuck in the bear trap");
101 if (rand_percent(R_TELE_PERCENT
)) {
103 return(STOPPED_ON_SOMETHING
);
106 if (dungeon
[row
][col
] & MONSTER
) {
107 rogue_hit(object_at(&level_monsters
, row
, col
), 0);
111 if (dungeon
[row
][col
] & DOOR
) {
112 if (cur_room
== PASSAGE
) {
113 cur_room
= get_room_number(row
, col
);
114 if (cur_room
== NO_ROOM
)
115 clean_up("one_move_rogue: door to nowhere");
116 light_up_room(cur_room
);
117 wake_room(cur_room
, 1, row
, col
);
119 light_passage(row
, col
);
121 } else if ((dungeon
[rogue
.row
][rogue
.col
] & DOOR
) &&
122 (dungeon
[row
][col
] & TUNNEL
)) {
123 light_passage(row
, col
);
124 wake_room(cur_room
, 0, rogue
.row
, rogue
.col
);
125 darken_room(cur_room
);
127 } else if (dungeon
[row
][col
] & TUNNEL
) {
128 light_passage(row
, col
);
130 mvaddch(rogue
.row
, rogue
.col
, get_dungeon_char(rogue
.row
, rogue
.col
));
131 mvaddch(row
, col
, rogue
.fchar
);
138 if (dungeon
[row
][col
] & OBJECT
) {
139 if (levitate
&& pickup
) {
140 return(STOPPED_ON_SOMETHING
);
142 if (pickup
&& !levitate
) {
143 if ((obj
= pick_up(row
, col
, &status
)) != NULL
) {
144 get_desc(obj
, desc
, sizeof(desc
));
145 if (obj
->what_is
== GOLD
) {
147 messagef(1, "%s", desc
);
150 } else if (!status
) {
157 obj
= object_at(&level_objects
, row
, col
);
158 get_desc(obj
, desc
, sizeof(desc
));
159 messagef(1, "moved onto %s", desc
);
162 messagef(1, "%s(%c)", desc
, obj
->ichar
);
165 return(STOPPED_ON_SOMETHING
);
167 if (dungeon
[row
][col
] & (DOOR
| STAIRS
| TRAP
)) {
168 if ((!levitate
) && (dungeon
[row
][col
] & TRAP
)) {
169 trap_player(row
, col
);
172 return(STOPPED_ON_SOMETHING
);
174 MVED
: if (reg_move()) { /* fainted from hunger */
175 return(STOPPED_ON_SOMETHING
);
177 return((confused
? STOPPED_ON_SOMETHING
: MOVED
));
181 multiple_move_rogue(short dirch
)
198 if (((m
= one_move_rogue((dirch
+ 96), 1)) == MOVE_FAILED
) ||
199 (m
== STOPPED_ON_SOMETHING
) ||
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);
217 while ((!interrupted
) && (one_move_rogue((dirch
+ 32), 1) == MOVED
))
220 if ( (!interrupted
) && passgo
&&
221 (dungeon
[rogue
.row
][rogue
.col
] & TUNNEL
)) {
222 turn_passage(dirch
+ 32, 1);
229 is_passable(int row
, int col
)
231 if ((row
< MIN_ROW
) || (row
> (DROWS
- 2)) || (col
< 0) ||
235 if (dungeon
[row
][col
] & HIDDEN
) {
236 return((dungeon
[row
][col
] & TRAP
) ? 1 : 0);
238 return(dungeon
[row
][col
] & (FLOOR
| TUNNEL
| DOOR
| STAIRS
| TRAP
));
242 next_to_something(int drow
, int dcol
)
244 short i
, j
, i_end
, j_end
, row
, col
;
245 short pass_count
= 0;
254 i_end
= (rogue
.row
< (DROWS
-2)) ? 1 : 0;
255 j_end
= (rogue
.col
< (DCOLS
-1)) ? 1 : 0;
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)) {
262 if (((rogue
.row
+i
) == drow
) && ((rogue
.col
+j
) == dcol
)) {
267 s
= dungeon
[row
][col
];
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
)))) {
282 if (((row
== drow
) || (col
== dcol
)) &&
283 (!((row
== rogue
.row
) || (col
== rogue
.col
)))) {
289 if ((((i
- j
) == 1) || ((i
- j
) == -1)) && (s
& TUNNEL
)) {
290 if (++pass_count
> 1) {
294 if ((s
& DOOR
) && ((i
== 0) || (j
== 0))) {
303 can_move(int row1
, int col1
, int row2
, int col2
)
305 if (!is_passable(row2
, col2
)) {
308 if ((row1
!= row2
) && (col1
!= col2
)) {
309 if ((dungeon
[row1
][col1
] & DOOR
) || (dungeon
[row2
][col2
] & DOOR
)) {
312 if ((!dungeon
[row1
][col2
]) || (!dungeon
[row2
][col1
])) {
323 boolean first_miss
= 1;
325 while (!is_direction(ch
= rgetchar(), &d
)) {
328 messagef(0, "direction? ");
334 (void)one_move_rogue(ch
, 0);
339 is_direction(short c
, short *d
)
375 check_hunger(boolean msg_only
)
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
);
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
);
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
);
396 n
= get_rand(0, (FAINT
- rogue
.moves_left
));
399 if (rand_percent(40)) {
402 messagef(1, "you faint");
403 for (i
= 0; i
< n
; i
++) {
408 messagef(1, "%s", you_can_move_again
);
414 if (rogue
.moves_left
<= STARVE
) {
415 killed_by(NULL
, STARVATION
);
420 Subtract 0, i.e. do nothing.
423 rogue
.moves_left
-= (rogue
.moves_left
% 2);
430 (void)check_hunger(1);
431 rogue
.moves_left
-= (rogue
.moves_left
% 2);
435 (void)check_hunger(1);
447 if ((rogue
.moves_left
<= HUNGRY
) || (cur_level
>= max_level
)) {
448 fainted
= check_hunger(0);
455 if (++m_moves
>= 120) {
481 messagef(1, "you float gently to the ground");
482 if (dungeon
[rogue
.row
][rogue
.col
] & TRAP
) {
483 trap_player(rogue
.row
, rogue
.col
);
488 if (!(--haste_self
)) {
489 messagef(0, "you feel yourself slowing down");
493 if (auto_search
> 0) {
494 search(auto_search
, auto_search
);
506 for (i
= 0; i
< count
; i
++) {
553 static short heal_exp
= -1, n
, c
= 0;
556 if (rogue
.hp_current
== rogue
.hp_max
) {
560 if (rogue
.exp
!= heal_exp
) {
561 heal_exp
= rogue
.exp
;
605 if ((alt
= !alt
) != 0) {
608 if ((rogue
.hp_current
+= regeneration
) > rogue
.hp_max
) {
609 rogue
.hp_current
= rogue
.hp_max
;
611 print_stats(STAT_HP
);
616 can_turn(short nrow
, short ncol
)
618 if ((dungeon
[nrow
][ncol
] & TUNNEL
) && is_passable(nrow
, ncol
)) {
625 turn_passage(short dir
, boolean fast
)
627 short crow
= rogue
.row
, ccol
= rogue
.col
, turns
= 0;
630 if ((dir
!= 'h') && can_turn(crow
, ccol
+ 1)) {
634 if ((dir
!= 'l') && can_turn(crow
, ccol
- 1)) {
638 if ((dir
!= 'k') && can_turn(crow
+ 1, ccol
)) {
642 if ((dir
!= 'j') && can_turn(crow
- 1, ccol
)) {
647 multiple_move_rogue(ndir
- (fast
? 32 : 96));