mirror of https://github.com/nealey/rogue
401 lines
7.5 KiB
C
401 lines
7.5 KiB
C
|
/*
|
||
|
* Hero movement commands
|
||
|
*
|
||
|
* @(#)master.c 4.49 (Berkeley) 02/05/99
|
||
|
*/
|
||
|
|
||
|
#include <curses.h>
|
||
|
#include <ctype.h>
|
||
|
#include "netprot.h"
|
||
|
|
||
|
/*
|
||
|
* Used to hold the new Hero position
|
||
|
*/
|
||
|
|
||
|
coord nh;
|
||
|
|
||
|
/*
|
||
|
* do_run:
|
||
|
* Start the hero running
|
||
|
*/
|
||
|
void
|
||
|
do_run(char ch)
|
||
|
{
|
||
|
Running = TRUE;
|
||
|
After = FALSE;
|
||
|
Runch = ch;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* do_move:
|
||
|
* Check to see that a move is legal. If it is handle the
|
||
|
* consequences (fighting, picking up, etc.)
|
||
|
*/
|
||
|
void
|
||
|
do_move(int dy, int dx)
|
||
|
{
|
||
|
char ch, fl;
|
||
|
|
||
|
Firstmove = FALSE;
|
||
|
if (No_move)
|
||
|
{
|
||
|
No_move--;
|
||
|
msg("you are still stuck in the bear trap");
|
||
|
return;
|
||
|
}
|
||
|
/*
|
||
|
* Do a confused move (maybe)
|
||
|
*/
|
||
|
if (on(Player, ISHUH) && rnd(5) != 0)
|
||
|
{
|
||
|
nh = *rndmove(&Player);
|
||
|
if (ce(nh, Hero))
|
||
|
{
|
||
|
After = FALSE;
|
||
|
Running = FALSE;
|
||
|
To_death = FALSE;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
over:
|
||
|
nh.y = Hero.y + dy;
|
||
|
nh.x = Hero.x + dx;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Check if he tried to move off the screen or make an illegal
|
||
|
* diagonal move, and stop him if he did.
|
||
|
*/
|
||
|
if (nh.x < 0 || nh.x >= NUMCOLS || nh.y <= 0 || nh.y >= NUMLINES - 1)
|
||
|
goto hit_bound;
|
||
|
if (!diag_ok(&Hero, &nh))
|
||
|
{
|
||
|
After = FALSE;
|
||
|
Running = FALSE;
|
||
|
return;
|
||
|
}
|
||
|
if (Running && ce(Hero, nh))
|
||
|
After = Running = FALSE;
|
||
|
fl = flat(nh.y, nh.x);
|
||
|
ch = winat(nh.y, nh.x);
|
||
|
if (!(fl & F_REAL) && ch == FLOOR)
|
||
|
{
|
||
|
if (!on(Player, ISLEVIT))
|
||
|
{
|
||
|
chat(nh.y, nh.x) = ch = TRAP;
|
||
|
flat(nh.y, nh.x) |= F_REAL;
|
||
|
}
|
||
|
}
|
||
|
else if (on(Player, ISHELD) && ch != 'F')
|
||
|
{
|
||
|
msg("you are being held");
|
||
|
return;
|
||
|
}
|
||
|
switch (ch)
|
||
|
{
|
||
|
case ' ':
|
||
|
case '|':
|
||
|
case '-':
|
||
|
hit_bound:
|
||
|
if (Passgo && Running && (Proom->r_flags & ISGONE)
|
||
|
&& !on(Player, ISBLIND))
|
||
|
{
|
||
|
bool b1, b2;
|
||
|
|
||
|
switch (Runch)
|
||
|
{
|
||
|
case 'h':
|
||
|
case 'l':
|
||
|
b1 = (Hero.y != 1 && turn_ok(Hero.y - 1, Hero.x));
|
||
|
b2 = (Hero.y != NUMLINES - 2 && turn_ok(Hero.y + 1, Hero.x));
|
||
|
if (!(b1 ^ b2))
|
||
|
break;
|
||
|
if (b1)
|
||
|
{
|
||
|
Runch = 'k';
|
||
|
dy = -1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Runch = 'j';
|
||
|
dy = 1;
|
||
|
}
|
||
|
dx = 0;
|
||
|
turnref();
|
||
|
goto over;
|
||
|
case 'j':
|
||
|
case 'k':
|
||
|
b1 = (Hero.x != 0 && turn_ok(Hero.y, Hero.x - 1));
|
||
|
b2 = (Hero.x != NUMCOLS - 1 && turn_ok(Hero.y, Hero.x + 1));
|
||
|
if (!(b1 ^ b2))
|
||
|
break;
|
||
|
if (b1)
|
||
|
{
|
||
|
Runch = 'h';
|
||
|
dx = -1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Runch = 'l';
|
||
|
dx = 1;
|
||
|
}
|
||
|
dy = 0;
|
||
|
turnref();
|
||
|
goto over;
|
||
|
}
|
||
|
}
|
||
|
Running = FALSE;
|
||
|
After = FALSE;
|
||
|
break;
|
||
|
case DOOR:
|
||
|
Running = FALSE;
|
||
|
if (flat(Hero.y, Hero.x) & F_PASS)
|
||
|
enter_room(&nh);
|
||
|
goto move_stuff;
|
||
|
case TRAP:
|
||
|
ch = be_trapped(&nh);
|
||
|
if (ch == T_DOOR || ch == T_TELEP)
|
||
|
return;
|
||
|
goto move_stuff;
|
||
|
case PASSAGE:
|
||
|
/*
|
||
|
* when you're in a corridor, you don't know if you're in
|
||
|
* a maze room or not, and there ain't no way to find out
|
||
|
* if you're leaving a maze room, so it is necessary to
|
||
|
* always recalculate Proom.
|
||
|
*/
|
||
|
Proom = roomin(&Hero);
|
||
|
goto move_stuff;
|
||
|
case FLOOR:
|
||
|
if (!(fl & F_REAL))
|
||
|
be_trapped(&Hero);
|
||
|
goto move_stuff;
|
||
|
case STAIRS:
|
||
|
Seenstairs = TRUE;
|
||
|
/* FALLTHROUGH */
|
||
|
default:
|
||
|
Running = FALSE;
|
||
|
if (isupper(ch) || moat(nh.y, nh.x))
|
||
|
fight(&nh, Cur_weapon, FALSE);
|
||
|
else
|
||
|
{
|
||
|
if (ch != STAIRS)
|
||
|
Take = ch;
|
||
|
move_stuff:
|
||
|
mvaddch(Hero.y, Hero.x, floor_at());
|
||
|
if ((fl & F_PASS) && chat(Oldpos.y, Oldpos.x) == DOOR)
|
||
|
leave_room(&nh);
|
||
|
Hero = nh;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* turn_ok:
|
||
|
* Decide whether it is legal to turn onto the given space
|
||
|
*/
|
||
|
bool
|
||
|
turn_ok(int y, int x)
|
||
|
{
|
||
|
PLACE *pp;
|
||
|
|
||
|
pp = INDEX(y, x);
|
||
|
return (pp->p_ch == DOOR
|
||
|
|| (pp->p_flags & (F_REAL|F_PASS)) == (F_REAL|F_PASS));
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* turnref:
|
||
|
* Decide whether to refresh at a passage turning or not
|
||
|
*/
|
||
|
void
|
||
|
turnref(void)
|
||
|
{
|
||
|
PLACE *pp;
|
||
|
|
||
|
pp = INDEX(Hero.y, Hero.x);
|
||
|
if (!(pp->p_flags & F_SEEN))
|
||
|
{
|
||
|
if (Jump)
|
||
|
{
|
||
|
leaveok(stdscr, TRUE);
|
||
|
refresh();
|
||
|
leaveok(stdscr, FALSE);
|
||
|
}
|
||
|
pp->p_flags |= F_SEEN;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* door_open:
|
||
|
* Called to illuminate a room. If it is dark, remove anything
|
||
|
* that might move.
|
||
|
*/
|
||
|
void
|
||
|
door_open(struct room *rp)
|
||
|
{
|
||
|
THING *mp;
|
||
|
int y, x;
|
||
|
|
||
|
if (!(rp->r_flags & ISGONE))
|
||
|
for (y = rp->r_pos.y; y < rp->r_pos.y + rp->r_max.y; y++)
|
||
|
for (x = rp->r_pos.x; x < rp->r_pos.x + rp->r_max.x; x++)
|
||
|
if (isupper(winat(y, x)))
|
||
|
wake_monster(y, x);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* be_trapped:
|
||
|
* The guy stepped on a trap.... Make him pay.
|
||
|
*/
|
||
|
char
|
||
|
be_trapped(coord *tc)
|
||
|
{
|
||
|
PLACE *pp;
|
||
|
THING *arrow;
|
||
|
char tr;
|
||
|
|
||
|
if (on(Player, ISLEVIT))
|
||
|
return T_RUST; /* anything that's not a door or teleport */
|
||
|
Running = FALSE;
|
||
|
Count = FALSE;
|
||
|
pp = INDEX(tc->y, tc->x);
|
||
|
pp->p_ch = TRAP;
|
||
|
tr = pp->p_flags & F_TMASK;
|
||
|
pp->p_flags |= F_SEEN;
|
||
|
switch (tr)
|
||
|
{
|
||
|
when T_DOOR:
|
||
|
Level++;
|
||
|
new_level();
|
||
|
msg("you fell into a trap!");
|
||
|
when T_BEAR:
|
||
|
No_move += BEARTIME;
|
||
|
msg("you are caught in a bear trap");
|
||
|
when T_SLEEP:
|
||
|
No_command += SLEEPTIME;
|
||
|
Player.t_flags &= ~ISRUN;
|
||
|
msg("a strange white mist envelops you and you fall asleep");
|
||
|
when T_ARROW:
|
||
|
if (swing(Pstats.s_lvl - 1, Pstats.s_arm, 1))
|
||
|
{
|
||
|
Pstats.s_hpt -= roll(1, 6);
|
||
|
if (Pstats.s_hpt <= 0)
|
||
|
{
|
||
|
msg("an arrow killed you");
|
||
|
death('a');
|
||
|
}
|
||
|
else
|
||
|
msg("oh no! An arrow shot you");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
arrow = new_item();
|
||
|
init_weapon(arrow, ARROW);
|
||
|
arrow->o_count = 1;
|
||
|
arrow->o_pos = Hero;
|
||
|
fall(arrow, FALSE);
|
||
|
msg("an arrow shoots past you");
|
||
|
}
|
||
|
when T_TELEP:
|
||
|
/*
|
||
|
* since the hero's leaving, look() won't put a TRAP
|
||
|
* down for us, so we have to do it ourself
|
||
|
*/
|
||
|
teleport();
|
||
|
mvaddch(tc->y, tc->x, TRAP);
|
||
|
when T_DART:
|
||
|
if (!swing(Pstats.s_lvl+1, Pstats.s_arm, 1))
|
||
|
msg("a small dart whizzes by your ear and vanishes");
|
||
|
else
|
||
|
{
|
||
|
Pstats.s_hpt -= roll(1, 4);
|
||
|
if (Pstats.s_hpt <= 0)
|
||
|
{
|
||
|
msg("a poisoned dart killed you");
|
||
|
death('d');
|
||
|
}
|
||
|
if (!ISWEARING(R_SUSTSTR) && !save(VS_POISON))
|
||
|
chg_str(-1);
|
||
|
msg("a small dart just hit you in the shoulder");
|
||
|
}
|
||
|
when T_RUST:
|
||
|
msg("a gush of water hits you on the head");
|
||
|
rust_armor(Cur_armor);
|
||
|
}
|
||
|
flush_type();
|
||
|
return tr;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* rndmove:
|
||
|
* Move in a random direction if the monster/person is confused
|
||
|
*/
|
||
|
coord *
|
||
|
rndmove(THING *who)
|
||
|
{
|
||
|
THING *obj;
|
||
|
int x, y;
|
||
|
char ch;
|
||
|
coord ret; /* what we will be returning */
|
||
|
|
||
|
y = ret.y = who->t_pos.y + rnd(3) - 1;
|
||
|
x = ret.x = who->t_pos.x + rnd(3) - 1;
|
||
|
/*
|
||
|
* Now check to see if that's a legal move. If not, don't move.
|
||
|
* (I.e., bump into the wall or whatever)
|
||
|
*/
|
||
|
if (y == who->t_pos.y && x == who->t_pos.x)
|
||
|
return &ret;
|
||
|
if (!diag_ok(&who->t_pos, &ret))
|
||
|
goto bad;
|
||
|
else
|
||
|
{
|
||
|
ch = winat(y, x);
|
||
|
if (!step_ok(ch))
|
||
|
goto bad;
|
||
|
if (ch == SCROLL)
|
||
|
{
|
||
|
for (obj = Lvl_obj; obj != NULL; obj = next(obj))
|
||
|
if (y == obj->o_pos.y && x == obj->o_pos.x)
|
||
|
break;
|
||
|
if (obj != NULL && obj->o_which == S_SCARE)
|
||
|
goto bad;
|
||
|
}
|
||
|
}
|
||
|
return &ret;
|
||
|
|
||
|
bad:
|
||
|
ret = who->t_pos;
|
||
|
return &ret;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* rust_armor:
|
||
|
* Rust the given armor, if it is a legal kind to rust, and we
|
||
|
* aren't wearing a magic ring.
|
||
|
*/
|
||
|
void
|
||
|
rust_armor(THING *arm)
|
||
|
{
|
||
|
if (arm == NULL || arm->o_type != ARMOR || arm->o_which == LEATHER ||
|
||
|
arm->o_arm >= 9)
|
||
|
return;
|
||
|
|
||
|
if ((arm->o_flags & ISPROT) || ISWEARING(R_SUSTARM))
|
||
|
{
|
||
|
if (!To_death)
|
||
|
msg("the rust vanishes instantly");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
arm->o_arm++;
|
||
|
if (!Terse)
|
||
|
msg("your armor appears to be weaker now. Oh my!");
|
||
|
else
|
||
|
msg("your armor weakens");
|
||
|
}
|
||
|
}
|