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