aboutsummaryrefslogtreecommitdiff
path: root/rogue/move.c
diff options
context:
space:
mode:
authorB. Watson <yalhcru@gmail.com>2015-05-07 16:32:32 -0400
committerB. Watson <yalhcru@gmail.com>2015-05-07 16:32:32 -0400
commit013ac7742311556022304e8b30ca170d48b3a016 (patch)
tree53faa33e75991363f1a6dcc7edc83a66b70e6995 /rogue/move.c
downloadbsd-games-extra-013ac7742311556022304e8b30ca170d48b3a016.tar.gz
initial commit
Diffstat (limited to 'rogue/move.c')
-rw-r--r--rogue/move.c649
1 files changed, 649 insertions, 0 deletions
diff --git a/rogue/move.c b/rogue/move.c
new file mode 100644
index 0000000..8378654
--- /dev/null
+++ b/rogue/move.c
@@ -0,0 +1,649 @@
+/* $NetBSD: move.c,v 1.13 2011/05/23 23:01:17 joerg Exp $ */
+
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Timothy C. Stoehr.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)move.c 8.1 (Berkeley) 5/31/93";
+#else
+__RCSID("$NetBSD: move.c,v 1.13 2011/05/23 23:01:17 joerg Exp $");
+#endif
+#endif /* not lint */
+
+/*
+ * move.c
+ *
+ * This source herein may be modified and/or distributed by anybody who
+ * so desires, with the following restrictions:
+ * 1.) No portion of this notice shall be removed.
+ * 2.) Credit shall not be taken for the creation of this source.
+ * 3.) This code is not to be traded, sold, or used for personal
+ * gain or profit.
+ *
+ */
+
+#include "rogue.h"
+
+short m_moves = 0;
+boolean jump = 0;
+const char you_can_move_again[] = "you can move again";
+
+static boolean can_turn(short, short);
+static boolean check_hunger(boolean);
+static char gr_dir(void);
+static void heal(void);
+static boolean next_to_something(int, int);
+static void turn_passage(short, boolean);
+
+int
+one_move_rogue(short dirch, short pickup)
+{
+ short row, col;
+ object *obj;
+ char desc[DCOLS];
+ short status, d = 0; /* XXX: GCC */
+
+ row = rogue.row;
+ col = rogue.col;
+
+ if (confused) {
+ dirch = gr_dir();
+ }
+ (void)is_direction(dirch, &d);
+ get_dir_rc(d, &row, &col, 1);
+
+ if (!can_move(rogue.row, rogue.col, row, col)) {
+ return(MOVE_FAILED);
+ }
+ if (being_held || bear_trap) {
+ if (!(dungeon[row][col] & MONSTER)) {
+ if (being_held) {
+ messagef(1, "you are being held");
+ } else {
+ messagef(0, "you are still stuck in the bear trap");
+ (void)reg_move();
+ }
+ return(MOVE_FAILED);
+ }
+ }
+ if (r_teleport) {
+ if (rand_percent(R_TELE_PERCENT)) {
+ tele();
+ return(STOPPED_ON_SOMETHING);
+ }
+ }
+ if (dungeon[row][col] & MONSTER) {
+ rogue_hit(object_at(&level_monsters, row, col), 0);
+ (void)reg_move();
+ return(MOVE_FAILED);
+ }
+ if (dungeon[row][col] & DOOR) {
+ if (cur_room == PASSAGE) {
+ cur_room = get_room_number(row, col);
+ if (cur_room == NO_ROOM)
+ clean_up("one_move_rogue: door to nowhere");
+ light_up_room(cur_room);
+ wake_room(cur_room, 1, row, col);
+ } else {
+ light_passage(row, col);
+ }
+ } else if ((dungeon[rogue.row][rogue.col] & DOOR) &&
+ (dungeon[row][col] & TUNNEL)) {
+ light_passage(row, col);
+ wake_room(cur_room, 0, rogue.row, rogue.col);
+ darken_room(cur_room);
+ cur_room = PASSAGE;
+ } else if (dungeon[row][col] & TUNNEL) {
+ light_passage(row, col);
+ }
+ mvaddch(rogue.row, rogue.col, get_dungeon_char(rogue.row, rogue.col));
+ mvaddch(row, col, rogue.fchar);
+
+ if (!jump) {
+ refresh();
+ }
+ rogue.row = row;
+ rogue.col = col;
+ if (dungeon[row][col] & OBJECT) {
+ if (levitate && pickup) {
+ return(STOPPED_ON_SOMETHING);
+ }
+ if (pickup && !levitate) {
+ if ((obj = pick_up(row, col, &status)) != NULL) {
+ get_desc(obj, desc, sizeof(desc));
+ if (obj->what_is == GOLD) {
+ free_object(obj);
+ messagef(1, "%s", desc);
+ goto NOT_IN_PACK;
+ }
+ } else if (!status) {
+ goto MVED;
+ } else {
+ goto MOVE_ON;
+ }
+ } else {
+MOVE_ON:
+ obj = object_at(&level_objects, row, col);
+ get_desc(obj, desc, sizeof(desc));
+ messagef(1, "moved onto %s", desc);
+ goto NOT_IN_PACK;
+ }
+ messagef(1, "%s(%c)", desc, obj->ichar);
+NOT_IN_PACK:
+ (void)reg_move();
+ return(STOPPED_ON_SOMETHING);
+ }
+ if (dungeon[row][col] & (DOOR | STAIRS | TRAP)) {
+ if ((!levitate) && (dungeon[row][col] & TRAP)) {
+ trap_player(row, col);
+ }
+ (void)reg_move();
+ return(STOPPED_ON_SOMETHING);
+ }
+MVED: if (reg_move()) { /* fainted from hunger */
+ return(STOPPED_ON_SOMETHING);
+ }
+ return((confused ? STOPPED_ON_SOMETHING : MOVED));
+}
+
+void
+multiple_move_rogue(short dirch)
+{
+ short row, col;
+ short m;
+
+ switch(dirch) {
+ case '\010':
+ case '\012':
+ case '\013':
+ case '\014':
+ case '\031':
+ case '\025':
+ case '\016':
+ case '\002':
+ do {
+ row = rogue.row;
+ col = rogue.col;
+ if (((m = one_move_rogue((dirch + 96), 1)) == MOVE_FAILED) ||
+ (m == STOPPED_ON_SOMETHING) ||
+ interrupted) {
+ break;
+ }
+ } while (!next_to_something(row, col));
+ if ( (!interrupted) && passgo && (m == MOVE_FAILED) &&
+ (dungeon[rogue.row][rogue.col] & TUNNEL)) {
+ turn_passage(dirch + 96, 0);
+ }
+ break;
+ case 'H':
+ case 'J':
+ case 'K':
+ case 'L':
+ case 'B':
+ case 'Y':
+ case 'U':
+ case 'N':
+ while ((!interrupted) && (one_move_rogue((dirch + 32), 1) == MOVED))
+ ;
+
+ if ( (!interrupted) && passgo &&
+ (dungeon[rogue.row][rogue.col] & TUNNEL)) {
+ turn_passage(dirch + 32, 1);
+ }
+ break;
+ }
+}
+
+boolean
+is_passable(int row, int col)
+{
+ if ((row < MIN_ROW) || (row > (DROWS - 2)) || (col < 0) ||
+ (col > (DCOLS-1))) {
+ return(0);
+ }
+ if (dungeon[row][col] & HIDDEN) {
+ return((dungeon[row][col] & TRAP) ? 1 : 0);
+ }
+ return(dungeon[row][col] & (FLOOR | TUNNEL | DOOR | STAIRS | TRAP));
+}
+
+static boolean
+next_to_something(int drow, int dcol)
+{
+ short i, j, i_end, j_end, row, col;
+ short pass_count = 0;
+ unsigned short s;
+
+ if (confused) {
+ return(1);
+ }
+ if (blind) {
+ return(0);
+ }
+ i_end = (rogue.row < (DROWS-2)) ? 1 : 0;
+ j_end = (rogue.col < (DCOLS-1)) ? 1 : 0;
+
+ for (i = ((rogue.row > MIN_ROW) ? -1 : 0); i <= i_end; i++) {
+ for (j = ((rogue.col > 0) ? -1 : 0); j <= j_end; j++) {
+ if ((i == 0) && (j == 0)) {
+ continue;
+ }
+ if (((rogue.row+i) == drow) && ((rogue.col+j) == dcol)) {
+ continue;
+ }
+ row = rogue.row + i;
+ col = rogue.col + j;
+ s = dungeon[row][col];
+ if (s & HIDDEN) {
+ continue;
+ }
+ /* If the rogue used to be right, up, left, down, or right of
+ * row,col, and now isn't, then don't stop */
+ if (s & (MONSTER | OBJECT | STAIRS)) {
+ if (((row == drow) || (col == dcol)) &&
+ (!((row == rogue.row) || (col == rogue.col)))) {
+ continue;
+ }
+ return(1);
+ }
+ if (s & TRAP) {
+ if (!(s & HIDDEN)) {
+ if (((row == drow) || (col == dcol)) &&
+ (!((row == rogue.row) || (col == rogue.col)))) {
+ continue;
+ }
+ return(1);
+ }
+ }
+ if ((((i - j) == 1) || ((i - j) == -1)) && (s & TUNNEL)) {
+ if (++pass_count > 1) {
+ return(1);
+ }
+ }
+ if ((s & DOOR) && ((i == 0) || (j == 0))) {
+ return(1);
+ }
+ }
+ }
+ return(0);
+}
+
+boolean
+can_move(int row1, int col1, int row2, int col2)
+{
+ if (!is_passable(row2, col2)) {
+ return(0);
+ }
+ if ((row1 != row2) && (col1 != col2)) {
+ if ((dungeon[row1][col1] & DOOR) || (dungeon[row2][col2] & DOOR)) {
+ return(0);
+ }
+ if ((!dungeon[row1][col2]) || (!dungeon[row2][col1])) {
+ return(0);
+ }
+ }
+ return(1);
+}
+
+void
+move_onto(void)
+{
+ short ch, d;
+ boolean first_miss = 1;
+
+ while (!is_direction(ch = rgetchar(), &d)) {
+ sound_bell();
+ if (first_miss) {
+ messagef(0, "direction? ");
+ first_miss = 0;
+ }
+ }
+ check_message();
+ if (ch != CANCEL) {
+ (void)one_move_rogue(ch, 0);
+ }
+}
+
+boolean
+is_direction(short c, short *d)
+{
+ switch(c) {
+ case 'h':
+ *d = LEFT;
+ break;
+ case 'j':
+ *d = DOWN;
+ break;
+ case 'k':
+ *d = UPWARD;
+ break;
+ case 'l':
+ *d = RIGHT;
+ break;
+ case 'b':
+ *d = DOWNLEFT;
+ break;
+ case 'y':
+ *d = UPLEFT;
+ break;
+ case 'u':
+ *d = UPRIGHT;
+ break;
+ case 'n':
+ *d = DOWNRIGHT;
+ break;
+ case CANCEL:
+ break;
+ default:
+ return(0);
+ }
+ return(1);
+}
+
+static boolean
+check_hunger(boolean msg_only)
+{
+ short i, n;
+ boolean fainted = 0;
+
+ if (rogue.moves_left == HUNGRY) {
+ (void)strlcpy(hunger_str, "hungry", sizeof(hunger_str));
+ messagef(0, "%s", hunger_str);
+ print_stats(STAT_HUNGER);
+ }
+ if (rogue.moves_left == WEAK) {
+ (void)strlcpy(hunger_str, "weak", sizeof(hunger_str));
+ messagef(1, "%s", hunger_str);
+ print_stats(STAT_HUNGER);
+ }
+ if (rogue.moves_left <= FAINT) {
+ if (rogue.moves_left == FAINT) {
+ (void)strlcpy(hunger_str, "faint", sizeof(hunger_str));
+ messagef(1, "%s", hunger_str);
+ print_stats(STAT_HUNGER);
+ }
+ n = get_rand(0, (FAINT - rogue.moves_left));
+ if (n > 0) {
+ fainted = 1;
+ if (rand_percent(40)) {
+ rogue.moves_left++;
+ }
+ messagef(1, "you faint");
+ for (i = 0; i < n; i++) {
+ if (coin_toss()) {
+ mv_mons();
+ }
+ }
+ messagef(1, "%s", you_can_move_again);
+ }
+ }
+ if (msg_only) {
+ return(fainted);
+ }
+ if (rogue.moves_left <= STARVE) {
+ killed_by(NULL, STARVATION);
+ }
+
+ switch(e_rings) {
+ /*case -2:
+ Subtract 0, i.e. do nothing.
+ break;*/
+ case -1:
+ rogue.moves_left -= (rogue.moves_left % 2);
+ break;
+ case 0:
+ rogue.moves_left--;
+ break;
+ case 1:
+ rogue.moves_left--;
+ (void)check_hunger(1);
+ rogue.moves_left -= (rogue.moves_left % 2);
+ break;
+ case 2:
+ rogue.moves_left--;
+ (void)check_hunger(1);
+ rogue.moves_left--;
+ break;
+ }
+ return(fainted);
+}
+
+boolean
+reg_move(void)
+{
+ boolean fainted;
+
+ if ((rogue.moves_left <= HUNGRY) || (cur_level >= max_level)) {
+ fainted = check_hunger(0);
+ } else {
+ fainted = 0;
+ }
+
+ mv_mons();
+
+ if (++m_moves >= 120) {
+ m_moves = 0;
+ wanderer();
+ }
+ if (halluc) {
+ if (!(--halluc)) {
+ unhallucinate();
+ } else {
+ hallucinate();
+ }
+ }
+ if (blind) {
+ if (!(--blind)) {
+ unblind();
+ }
+ }
+ if (confused) {
+ if (!(--confused)) {
+ unconfuse();
+ }
+ }
+ if (bear_trap) {
+ bear_trap--;
+ }
+ if (levitate) {
+ if (!(--levitate)) {
+ messagef(1, "you float gently to the ground");
+ if (dungeon[rogue.row][rogue.col] & TRAP) {
+ trap_player(rogue.row, rogue.col);
+ }
+ }
+ }
+ if (haste_self) {
+ if (!(--haste_self)) {
+ messagef(0, "you feel yourself slowing down");
+ }
+ }
+ heal();
+ if (auto_search > 0) {
+ search(auto_search, auto_search);
+ }
+ return(fainted);
+}
+
+void
+rest(int count)
+{
+ int i;
+
+ interrupted = 0;
+
+ for (i = 0; i < count; i++) {
+ if (interrupted) {
+ break;
+ }
+ (void)reg_move();
+ }
+}
+
+static char
+gr_dir(void)
+{
+ short d;
+
+ d = get_rand(1, 8);
+
+ switch(d) {
+ case 1:
+ d = 'j';
+ break;
+ case 2:
+ d = 'k';
+ break;
+ case 3:
+ d = 'l';
+ break;
+ case 4:
+ d = 'h';
+ break;
+ case 5:
+ d = 'y';
+ break;
+ case 6:
+ d = 'u';
+ break;
+ case 7:
+ d = 'b';
+ break;
+ case 8:
+ d = 'n';
+ break;
+ }
+ return(d);
+}
+
+static void
+heal(void)
+{
+ static short heal_exp = -1, n, c = 0;
+ static boolean alt;
+
+ if (rogue.hp_current == rogue.hp_max) {
+ c = 0;
+ return;
+ }
+ if (rogue.exp != heal_exp) {
+ heal_exp = rogue.exp;
+
+ switch(heal_exp) {
+ case 1:
+ n = 20;
+ break;
+ case 2:
+ n = 18;
+ break;
+ case 3:
+ n = 17;
+ break;
+ case 4:
+ n = 14;
+ break;
+ case 5:
+ n = 13;
+ break;
+ case 6:
+ n = 10;
+ break;
+ case 7:
+ n = 9;
+ break;
+ case 8:
+ n = 8;
+ break;
+ case 9:
+ n = 7;
+ break;
+ case 10:
+ n = 4;
+ break;
+ case 11:
+ n = 3;
+ break;
+ case 12:
+ default:
+ n = 2;
+ }
+ }
+ if (++c >= n) {
+ c = 0;
+ rogue.hp_current++;
+ if ((alt = !alt) != 0) {
+ rogue.hp_current++;
+ }
+ if ((rogue.hp_current += regeneration) > rogue.hp_max) {
+ rogue.hp_current = rogue.hp_max;
+ }
+ print_stats(STAT_HP);
+ }
+}
+
+static boolean
+can_turn(short nrow, short ncol)
+{
+ if ((dungeon[nrow][ncol] & TUNNEL) && is_passable(nrow, ncol)) {
+ return(1);
+ }
+ return(0);
+}
+
+static void
+turn_passage(short dir, boolean fast)
+{
+ short crow = rogue.row, ccol = rogue.col, turns = 0;
+ short ndir = 0;
+
+ if ((dir != 'h') && can_turn(crow, ccol + 1)) {
+ turns++;
+ ndir = 'l';
+ }
+ if ((dir != 'l') && can_turn(crow, ccol - 1)) {
+ turns++;
+ ndir = 'h';
+ }
+ if ((dir != 'k') && can_turn(crow + 1, ccol)) {
+ turns++;
+ ndir = 'j';
+ }
+ if ((dir != 'j') && can_turn(crow - 1, ccol)) {
+ turns++;
+ ndir = 'k';
+ }
+ if (turns == 1) {
+ multiple_move_rogue(ndir - (fast ? 32 : 96));
+ }
+}