/*
* Hero movement commands
*
* @(#)move.c 9.0 (rdk) 7/17/84
*
* Super-Rogue
* Copyright (C) 1984 Robert D. Kindelberger
* All rights reserved.
*
* Based on "Rogue: Exploring the Dungeons of Doom"
* Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
#include <string.h>
#include <ctype.h>
#include "rogue.h"
#include "rogue.ext"
/*
* Used to hold the new hero position
*/
struct 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)
{
reg int ch;
reg struct room *rp;
firstmove = FALSE;
curprice = -1;
inpool = FALSE;
if (player.t_nomove > 0) {
player.t_nomove -= 1;
msg("You are still stuck in the bear trap.");
return;
}
/*
* Do a confused move (maybe)
*/
if ((rnd(100) < 80 && pl_on(ISHUH)) ||
(iswearing(R_DELUS) && rnd(100) < 25))
nh = *rndmove(&player);
else {
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 (!cordok(nh.y, nh.x) ||
(pl_off(ISETHER) && !diag_ok(&hero, &nh))) {
after = running = FALSE;
return;
}
if (running) {
ch = winat(nh.y, nh.x);
if (dead_end(ch)) {
reg int gox, goy, apsg, whichway;
gox = goy = apsg = 0;
if (dy == 0) {
ch = show(hero.y+1,hero.x);
if (ch == PASSAGE) {
apsg += 1;
goy = 1;
}
ch = show(hero.y-1,hero.x);
if (ch == PASSAGE) {
apsg += 1;
goy = -1;
}
}
else if (dx == 0) {
ch = show(hero.y,hero.x+1);
if (ch == PASSAGE) {
gox = 1;
apsg += 1;
}
ch = show(hero.y,hero.x-1);
if (ch == PASSAGE) {
gox = -1;
apsg += 1;
}
}
if (apsg != 1) {
running = after = FALSE;
return;
}
else { /* can still run here */
nh.y = hero.y + goy;
nh.x = hero.x + gox;
whichway = (goy + 1) * 3 + gox + 1;
switch(whichway) {
case 0: runch = 'y';
when 1: runch = 'k';
when 2: runch = 'u';
when 3: runch = 'h';
when 4: runch = '.'; /* shouldn't do */
when 5: runch = 'l';
when 6: runch = 'b';
when 7: runch = 'j';
when 8: runch = 'n';
}
}
}
}
if (running && ce(hero, nh))
after = running = FALSE;
ch = winat(nh.y, nh.x);
if (pl_on(ISHELD) && ch != 'F' && ch != 'd') {
msg("You are being held.");
return;
}
if (pl_off(ISETHER)) {
if (isatrap(ch)) {
ch = be_trapped(&nh, &player);
if (nlmove) {
nlmove = FALSE;
return;
}
else if (ch == POOL)
inpool = TRUE;
}
else if (dead_end(ch)) {
after = running = FALSE;
return;
}
else {
switch(ch) {
case GOLD: case POTION: case SCROLL:
case FOOD: case WEAPON: case ARMOR:
case RING: case AMULET: case STICK:
running = FALSE;
take = ch;
default:
if (illeg_ch(ch)) {
running = FALSE;
mvaddch(nh.y, nh.x, FLOOR);
teleport(rndspot, &player);
light(&nh);
msg("The spatial warp disappears !");
return;
}
}
}
}
rp = roomin(&nh);
if (ch == DOOR) { /* just stepped on a door */
running = FALSE;
if (rp != NULL && rf_on(rp, ISTREAS)) {
struct linked_list *item;
struct thing *tp;
for (item = mlist; item != NULL; item = next(item)) {
tp = THINGPTR(item);
if (tp->t_room == rp)
runto(&tp->t_pos, &hero);
}
}
}
else if (ch == STAIRS && pl_off(ISETHER))
running = FALSE;
else if (isalpha(ch) && pl_off(ISETHER)) {
running = FALSE;
fight(&nh, cur_weapon, FALSE);
return;
}
if (rp == NULL && player.t_room != NULL)
light(&hero); /* exiting a room */
else if (rp != NULL && player.t_room == NULL)
light(&nh); /* just entering a room */
if (pl_on(ISBLIND))
ch = ' ';
else
ch = player.t_oldch;
mvwaddch(cw, hero.y, hero.x, ch);
mvwaddch(cw, nh.y, nh.x, PLAYER);
hero = nh;
player.t_room = rp;
player.t_oldch = mvinch(hero.y, hero.x);
}
/*
* Called to illuminate a room.
* If it is dark, remove anything that might move.
*/
void
light(struct coord *cp)
{
reg struct room *rp;
reg int j, k, x, y;
reg char ch, rch;
reg struct linked_list *item;
rp = roomin(cp);
if (rp == NULL)
return;
if (pl_on(ISBLIND)) {
for (j = 0; j < rp->r_max.y; j += 1) {
for (k = 0; k < rp->r_max.x; k += 1) {
y = rp->r_pos.y + j;
x = rp->r_pos.x + k;
mvwaddch(cw, y, x, ' ');
}
}
look(FALSE);
return;
}
if (iswearing(R_LIGHT))
rp->r_flags &= ~ISDARK;
for (j = 0; j < rp->r_max.y; j += 1) {
for (k = 0; k < rp->r_max.x; k += 1) {
y = rp->r_pos.y + j;
x = rp->r_pos.x + k;
if (levtype == MAZELEV && !cansee(y, x))
continue;
ch = show(y, x);
wmove(cw, y, x);
/*
* Figure out how to display a secret door
*/
if (ch == SECRETDOOR) {
if (j == 0 || j == rp->r_max.y - 1)
ch = '-';
else
ch = '|';
}
if (isalpha(ch)) {
struct thing *mit;
item = wake_monster(y, x);
if (item == NULL) {
ch = FLOOR;
mvaddch(y, x, ch);
}
else {
mit = THINGPTR(item);
if (mit->t_oldch == ' ')
if (!rf_on(rp,ISDARK))
mit->t_oldch = mvinch(y, x);
if (levtype == MAZELEV)
ch = mvinch(y, x);
}
}
if (rf_on(rp,ISDARK)) {
rch = mvwinch(cw, y, x);
if (isatrap(rch)) {
ch = rch; /* if its a trap */
}
else { /* try other things */
switch (rch) {
case DOOR: case STAIRS: case '|':
case '-':
ch = rch;
otherwise:
ch = ' ';
}
}
}
mvwaddch(cw, y, x, ch);
}
}
}
/*
* show:
* returns what a certain thing will display as to the un-initiated
*/
char
show(int y, int x)
{
reg char ch = winat(y, x);
reg struct linked_list *it;
reg struct thing *tp;
reg struct trap *ta;
if (isatrap(ch)) {
if ((ta = trap_at(y, x)) == NULL)
return FLOOR;
if (iswearing(R_FTRAPS))
ta->tr_flags |= ISFOUND;
return ((ta->tr_flags & ISFOUND) ? ta->tr_type : FLOOR);
}
if (ch == SECRETDOOR && iswearing(R_FTRAPS)) {
mvaddch(y,x,DOOR);
return DOOR;
}
if ((it = find_mons(y, x)) != NULL) { /* maybe a monster */
tp = THINGPTR(it);
if (ch == 'M' || (tp->t_flags & ISINVIS)) {
if (ch == 'M')
ch = tp->t_disguise;
else if (pl_off(CANSEE)) {
if (ch == 's')
ch = ' '; /* shadows show as a blank */
else
ch = mvinch(y, x); /* hide invisibles */
}
}
}
return ch;
}
/*
* be_trapped:
* Hero or monster stepped on a trap.
*/
int
be_trapped(struct coord *tc, struct thing *th)
{
reg struct trap *trp;
reg int ch, ishero;
struct linked_list *mon;
char stuckee[35], seeit, sayso;
if ((trp = trap_at(tc->y, tc->x)) == NULL)
return 0;
ishero = (th == &player);
if (ishero) {
strcpy(stuckee, "You");
count = running = FALSE;
}
else {
sprintf(stuckee, "The %s", monsters[th->t_indx].m_name);
}
seeit = cansee(tc->y, tc->x);
if (seeit)
mvwaddch(cw, tc->y, tc->x, trp->tr_type);
trp->tr_flags |= ISFOUND;
sayso = TRUE;
switch (ch = trp->tr_type) {
case POST:
if (ishero) {
nlmove = TRUE;
new_level(POSTLEV);
}
else
goto goner;
when MAZETRAP:
if (ishero) {
nlmove = TRUE;
level += 1;
new_level(MAZELEV);
msg("You are surrounded by twisty passages!");
}
else
goto goner;
when TELTRAP:
nlmove = TRUE;
teleport(trp->tr_goto, th);
when TRAPDOOR:
if (ishero) {
level += 1;
new_level(NORMLEV);
}
else { /* monsters get lost */
goner:
ch = GONER;
}
nlmove = TRUE;
if (seeit && sayso)
msg("%s fell into a trap!", stuckee);
when BEARTRAP:
th->t_nomove += BEARTIME;
if (seeit) {
strcat(stuckee, (ishero ? " are" : " is"));
msg("%s caught in a bear trap.", stuckee);
}
when SLEEPTRAP:
if (ishero && pl_on(ISINVINC))
msg("You feel momentarily dizzy.");
else {
if (ishero)
th->t_nocmd += SLEEPTIME;
else
th->t_nomove += SLEEPTIME;
if (seeit)
msg("%s fall%s asleep in a strange white mist.",
stuckee, (ishero ? "":"s"));
}
when ARROWTRAP: {
int resist, ac;
struct stats *it;
stuckee[0] = tolower(stuckee[0]);
it = &th->t_stats;
if (ishero && cur_armor != NULL)
ac = cur_armor->o_ac;
else
ac = it->s_arm;
resist = ac + getpdex(it, FALSE);
if (ishero && pl_on(ISINVINC))
resist = -100; /* invincible is impossible to hit */
if (swing(3 + (level / 4), resist, 1)) {
if (seeit)
msg("%sAn arrow shot %s.", (ishero ? "Oh no! " : ""),
stuckee);
if (ishero)
chg_hpt(-roll(1,6),FALSE,K_ARROW);
else {
it->s_hpt -= roll(1,6);
if (it->s_hpt < 1) {
sayso = FALSE;
goto goner;
}
}
}
else {
struct linked_list *item;
struct object *arrow;
if (seeit)
msg("An arrow shoots past %s.", stuckee);
item = new_thing(FALSE, WEAPON, ARROW);
arrow = OBJPTR(item);
arrow->o_hplus = 3;
arrow->o_dplus = rnd(2);
arrow->o_count = 1;
arrow->o_pos = th->t_pos;
fall(item, FALSE);
}
}
when DARTTRAP: {
int resist, ac;
struct stats *it;
stuckee[0] = tolower(stuckee[0]);
it = &th->t_stats;
if (ishero && cur_armor != NULL)
ac = cur_armor->o_ac;
else
ac = it->s_arm;
resist = ac + getpdex(it, FALSE);
if (ishero && pl_on(ISINVINC))
resist = -100; /* invincible is impossible to hit */
if (swing(3 + (level / 4), resist, 0)) {
if (seeit)
msg("A small dart just hit %s.", stuckee);
if (ishero) {
if (!save(VS_POISON))
chg_abil(CON,-1,TRUE);
if (!iswearing(R_SUSTSTR))
chg_abil(STR,-1,TRUE);
chg_hpt(-roll(1, 4),FALSE,K_DART);
}
else {
if (!save_throw(VS_POISON, th))
it->s_ef.a_str -= 1;
it->s_hpt -= roll(1, 4);
if (it->s_hpt < 1) {
sayso = FALSE;
goto goner;
}
}
}
else if (seeit)
msg("A small dart whizzes by %s.", stuckee);
}
when POOL:
if (!ishero && rnd(100) < 10) {
if (seeit)
msg("The %s drowns !!", stuckee);
goto goner;
}
if ((trp->tr_flags & ISGONE) && rnd(100) < 10) {
nlmove = TRUE;
if (rnd(100) < 15)
teleport(rndspot, th); /* teleport away */
else if(rnd(100) < 15 && level > 2) {
level -= rnd(2) + 1;
new_level(NORMLEV);
msg("You here a faint groan from below.");
}
else if(rnd(100) < 40) {
level += rnd(4);
new_level(NORMLEV);
msg("You find yourself in strange surroundings.");
}
else if(rnd(100) < 6 && pl_off(ISINVINC)) {
msg("Oh no!!! You drown in the pool!!! --More--");
wait_for(cw, ' ');
death(K_POOL);
}
else
nlmove = FALSE;
}
}
flushinp(); /* flush typeahead */
return ch;
}
/*
* dip_it:
* Dip an object into a magic pool
*/
void
dip_it(void)
{
reg struct linked_list *what;
reg struct object *ob;
reg struct trap *tp;
reg int wh;
tp = trap_at(hero.y,hero.x);
if (tp == NULL || inpool == FALSE || (tp->tr_flags & ISGONE))
return;
if ((what = get_item("dip",0)) == NULL)
return;
ob = OBJPTR(what);
mpos = 0;
/*
* If hero is trying to dip an object OTHER than his
* current weapon, make sure that he could drop his
* current weapon
*/
if (ob != cur_weapon) {
if (cur_weapon != NULL && o_on(cur_weapon, ISCURSED)) {
msg("You are unable to release your weapon.");
after = FALSE;
return;
}
}
if (ob == cur_armor) {
msg("You have to take off your armor before you can dip it.");
after = FALSE;
return;
}
else if (ob == cur_ring[LEFT] || ob == cur_ring[RIGHT]) {
msg("You have to take that ring off before you can dip it.");
after = FALSE;
return;
}
wh = ob->o_which;
tp->tr_flags |= ISGONE;
if (ob != NULL && o_off(ob,ISPROT)) {
setoflg(ob,ISKNOW);
switch(ob->o_type) {
case WEAPON:
if(rnd(100) < 20) { /* enchant weapon here */
if (o_off(ob,ISCURSED)) {
ob->o_hplus += 1;
ob->o_dplus += 1;
}
else { /* weapon was prev cursed here */
ob->o_hplus = rnd(2);
ob->o_dplus = rnd(2);
}
resoflg(ob,ISCURSED);
}
else if(rnd(100) < 10) { /* curse weapon here */
if (o_off(ob,ISCURSED)) {
ob->o_hplus = -(rnd(2)+1);
ob->o_dplus = -(rnd(2)+1);
}
else { /* if already cursed */
ob->o_hplus--;
ob->o_dplus--;
}
setoflg(ob,ISCURSED);
}
msg("The %s glows for a moment.",w_magic[wh].mi_name);
when ARMOR:
if (rnd(100) < 30) { /* enchant armor */
if(o_off(ob,ISCURSED))
ob->o_ac -= rnd(2) + 1;
else
ob->o_ac = -rnd(3)+ armors[wh].a_class;
resoflg(ob,ISCURSED);
}
else if(rnd(100) < 15){ /* curse armor */
if (o_off(ob,ISCURSED))
ob->o_ac = rnd(3)+ armors[wh].a_class;
else
ob->o_ac += rnd(2) + 1;
setoflg(ob,ISCURSED);
}
msg("The %s glows for a moment.",a_magic[wh].mi_name);
when STICK: {
int i;
struct rod *rd;
i = rnd(8) + 1;
if(rnd(100) < 25) /* add charges */
ob->o_charges += i;
else if(rnd(100) < 10) { /* remove charges */
if ((ob->o_charges -= i) < 0)
ob->o_charges = 0;
}
ws_know[wh] = TRUE;
rd = &ws_stuff[wh];
msg("The %s %s glows for a moment.",rd->ws_made,rd->ws_type);
}
when SCROLL:
s_know[wh] = TRUE;
msg("The '%s' scroll unfurls.",s_names[wh]);
when POTION:
p_know[wh] = TRUE;
msg("The %s potion bubbles for a moment.",p_colors[wh]);
when RING:
r_know[wh] = TRUE;
if (magring(ob)) {
if(rnd(100) < 25) { /* enchant ring */
if (o_off(ob,ISCURSED))
ob->o_ac += rnd(2) + 1;
else
ob->o_ac = rnd(2) + 1;
resoflg(ob,ISCURSED);
}
else if(rnd(100) < 10) { /* curse ring */
if (o_off(ob,ISCURSED))
ob->o_ac = -(rnd(2) + 1);
else
ob->o_ac -= (rnd(2) + 1);
setoflg(ob,ISCURSED);
}
}
msg("The %s ring vibrates for a moment.",r_stones[wh]);
otherwise:
msg("The pool bubbles for a moment.");
}
}
cur_weapon = ob; /* hero has to weild item to dip it */
}
/*
* trap_at:
* Find the trap at (y,x) on screen.
*/
struct trap *
trap_at(int y, int x)
{
reg struct trap *tp, *ep;
ep = &traps[ntraps];
for (tp = traps; tp < ep; tp += 1)
if (tp->tr_pos.y == y && tp->tr_pos.x == x)
break;
if (tp >= ep)
tp = NULL;
return tp;
}
/*
* rndmove:
* move in a random direction if the monster/person is confused
*/
struct coord *
rndmove(struct thing *who)
{
reg int x, y, ex, ey, ch;
int nopen = 0;
struct linked_list *item;
static struct coord ret; /* what we will be returning */
static struct coord dest;
ret = who->t_pos;
/*
* Now go through the spaces surrounding the player and
* set that place in the array to true if the space can be
* moved into
*/
ey = ret.y + 1;
ex = ret.x + 1;
for (y = who->t_pos.y - 1; y <= ey; y += 1) {
for (x = who->t_pos.x - 1; x <= ex; x += 1) {
if (!cordok(y, x))
continue;
ch = winat(y, x);
if (step_ok(ch)) {
dest.y = y;
dest.x = x;
if (!diag_ok(&who->t_pos, &dest))
continue;
if (ch == SCROLL && who != &player) {
/*
* check for scare monster scrolls
*/
item = find_obj(y, x);
if (item != NULL && (OBJPTR(item))->o_which == S_SCARE)
continue;
}
if (rnd(++nopen) == 0)
ret = dest;
}
}
}
return &ret;
}
/*
* isatrap:
* Returns TRUE if this character is some kind of trap
*/
bool
isatrap(char ch)
{
switch(ch) {
case POST:
case DARTTRAP:
case POOL:
case TELTRAP:
case TRAPDOOR:
case ARROWTRAP:
case SLEEPTRAP:
case BEARTRAP:
case MAZETRAP:
return TRUE;
default:
return FALSE;
}
}