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