This was fixed by adding "after = FALSE;" to the relevant cases in command(). Rogue V4 and V5 are not affected.
1397 lines
37 KiB
C
1397 lines
37 KiB
C
/*
|
|
command.c - Read and execute the user commands
|
|
|
|
UltraRogue: The Ultimate Adventure in the Dungeons of Doom
|
|
Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
|
|
All rights reserved.
|
|
|
|
Based on "Advanced Rogue"
|
|
Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
|
|
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 <stdlib.h>
|
|
#include <ctype.h>
|
|
#include "rogue.h"
|
|
|
|
/*
|
|
command()
|
|
Process the user commands
|
|
*/
|
|
|
|
void
|
|
command(void)
|
|
{
|
|
static char repcommand; /* Command to repeat if we are repeating */
|
|
static int fight_to_death; /* Flags if we are fighting to death */
|
|
static coord dir; /* Last direction specified */
|
|
|
|
#ifdef WIZARD
|
|
object *obj;
|
|
#endif
|
|
char ch;
|
|
int ntimes = 1; /* Number of player moves */
|
|
coord nullcoord;
|
|
|
|
nullcoord.x = nullcoord.y = 0;
|
|
|
|
if (on(player, CANFLY) && rnd(2))
|
|
ntimes++;
|
|
|
|
if (on(player, ISHASTE))
|
|
ntimes++;
|
|
|
|
if (fighting && att_bonus())
|
|
ntimes *= 2;
|
|
|
|
if (on(player, ISSLOW))
|
|
{
|
|
if (player.t_turn != TRUE)
|
|
ntimes--;
|
|
|
|
player.t_turn ^= TRUE;
|
|
}
|
|
|
|
if (ntimes == 0)
|
|
return;
|
|
|
|
while (ntimes--)
|
|
{
|
|
moving = FALSE;
|
|
|
|
/* If player is infested, take off a hit point */
|
|
|
|
if (on(player, HASINFEST) && !is_wearing(R_HEALTH))
|
|
{
|
|
if ((pstats.s_hpt -= infest_dam) <= 0)
|
|
{
|
|
death(D_INFESTATION);
|
|
return;
|
|
}
|
|
}
|
|
|
|
look(after);
|
|
|
|
if (!running)
|
|
door_stop = FALSE;
|
|
|
|
status(FALSE);
|
|
wmove(cw, hero.y, hero.x);
|
|
|
|
if (!((running || count) && jump))
|
|
wrefresh(cw); /* Draw screen */
|
|
|
|
take = 0;
|
|
after = TRUE;
|
|
|
|
/*
|
|
* Read command or continue run
|
|
*/
|
|
|
|
if (!no_command)
|
|
{
|
|
if (fighting)
|
|
{
|
|
ch = (fight_to_death) ? 'F' : 'f';
|
|
}
|
|
else if (running)
|
|
{
|
|
/*
|
|
* If in a corridor, if we are at a turn with
|
|
* only one way to go, turn that way.
|
|
*/
|
|
|
|
if ((winat(hero.y, hero.x) == PASSAGE) && off(player, ISHUH) &&
|
|
(off(player, ISBLIND)))
|
|
switch (runch)
|
|
{
|
|
case 'h': corr_move(0, -1); break;
|
|
case 'j': corr_move(1, 0); break;
|
|
case 'k': corr_move(-1, 0); break;
|
|
case 'l': corr_move(0, 1); break;
|
|
}
|
|
|
|
ch = runch;
|
|
}
|
|
else if (count)
|
|
ch = repcommand;
|
|
else
|
|
{
|
|
ch = readchar();
|
|
|
|
if (mpos != 0 && !running)
|
|
msg(""); /* Erase message if its there */
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ch = '.';
|
|
fighting = moving = FALSE;
|
|
}
|
|
|
|
if (no_command)
|
|
{
|
|
if (--no_command == 0)
|
|
msg("You can move again.");
|
|
}
|
|
else
|
|
{
|
|
|
|
/*
|
|
* check for prefixes
|
|
*/
|
|
|
|
if (isdigit(ch))
|
|
{
|
|
count = 0;
|
|
while (isdigit(ch))
|
|
{
|
|
count = count * 10 + (ch - '0');
|
|
ch = readcharw(cw);
|
|
}
|
|
repcommand = ch;
|
|
|
|
/*
|
|
* Preserve count for commands which can be
|
|
* repeated.
|
|
*/
|
|
|
|
switch(ch)
|
|
{
|
|
case 'h':
|
|
case 'j':
|
|
case 'k':
|
|
case 'l':
|
|
case 'y':
|
|
case 'u':
|
|
case 'b':
|
|
case 'n':
|
|
case 'H':
|
|
case 'J':
|
|
case 'K':
|
|
case 'L':
|
|
case 'Y':
|
|
case 'U':
|
|
case 'B':
|
|
case 'N':
|
|
case 'q':
|
|
case 'r':
|
|
case 's':
|
|
case 'm':
|
|
case 't':
|
|
case 'C':
|
|
case 'I':
|
|
case '.':
|
|
case 'z':
|
|
case 'p':
|
|
break;
|
|
default:
|
|
count = 0;
|
|
}
|
|
}
|
|
|
|
/* Save current direction */
|
|
|
|
if (!running) /* If running, it is already saved */
|
|
switch (ch)
|
|
{
|
|
case 'h':
|
|
case 'j':
|
|
case 'k':
|
|
case 'l':
|
|
case 'y':
|
|
case 'u':
|
|
case 'b':
|
|
case 'n':
|
|
runch = ch;
|
|
break;
|
|
case 'H':
|
|
case 'J':
|
|
case 'K':
|
|
case 'L':
|
|
case 'Y':
|
|
case 'U':
|
|
case 'B':
|
|
case 'N':
|
|
runch = (char) tolower(ch);
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* execute a command
|
|
*/
|
|
|
|
if (count && !running)
|
|
count--;
|
|
|
|
switch(ch)
|
|
{
|
|
/*
|
|
* Movement and combat commands
|
|
*/
|
|
|
|
case 'h': do_move(0,-1); break;
|
|
case 'j': do_move(1, 0); break;
|
|
case 'k': do_move(-1, 0); break;
|
|
case 'l': do_move(0, 1); break;
|
|
case 'y': do_move(-1, -1); break;
|
|
case 'u': do_move(-1, 1); break;
|
|
case 'b': do_move(1, -1); break;
|
|
case 'n': do_move(1, 1); break;
|
|
case 'H': do_run('h'); break;
|
|
case 'J': do_run('j'); break;
|
|
case 'K': do_run('k'); break;
|
|
case 'L': do_run('l'); break;
|
|
case 'Y': do_run('y'); break;
|
|
case 'U': do_run('u'); break;
|
|
case 'B': do_run('b'); break;
|
|
case 'N': do_run('n'); break;
|
|
case 'm':
|
|
moving = TRUE;
|
|
if (!get_dir())
|
|
{
|
|
after = FALSE;
|
|
break;
|
|
}
|
|
do_move(delta.y, delta.x);
|
|
break;
|
|
case 'F':
|
|
case 'f':
|
|
fight_to_death = (ch == 'F');
|
|
if (!fighting)
|
|
{
|
|
if (get_dir())
|
|
{
|
|
dir = delta;
|
|
beast = NULL;
|
|
}
|
|
else
|
|
{
|
|
after = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
do_fight(dir, (ch == 'F') ? TRUE : FALSE);
|
|
break;
|
|
case 't':
|
|
if (get_dir())
|
|
missile(delta.y, delta.x, get_item("throw", 0),
|
|
&player);
|
|
else
|
|
after = FALSE;
|
|
|
|
/*
|
|
* Informational commands - Do not do
|
|
* after daemons
|
|
*/
|
|
break;
|
|
|
|
case 0x7f: /* sometime generated by */
|
|
/* suspend/foreground */
|
|
case ESCAPE:
|
|
case ' ':
|
|
after = FALSE; /* do nothing */
|
|
break;
|
|
case 'Q':
|
|
after = FALSE;
|
|
quit();
|
|
break;
|
|
case 'i':
|
|
after = FALSE;
|
|
inventory(pack, '*');
|
|
break;
|
|
case 'I':
|
|
after = FALSE;
|
|
inventory(pack, 0);
|
|
break;
|
|
case '~':
|
|
after = FALSE;
|
|
next_exp_level(MESSAGE);
|
|
break;
|
|
case '>':
|
|
after = FALSE;
|
|
d_level();
|
|
break;
|
|
case '<':
|
|
after = FALSE;
|
|
u_level();
|
|
break;
|
|
case '?':
|
|
after = FALSE;
|
|
help();
|
|
break;
|
|
case '/':
|
|
after = FALSE;
|
|
identify();
|
|
break;
|
|
case 'v':
|
|
after = FALSE;
|
|
msg("UltraRogue Version %s.", release);
|
|
break;
|
|
case 'o':
|
|
after = FALSE;
|
|
option();
|
|
strcpy(fd_data[1].mi_name, fruit);
|
|
break;
|
|
case 12: /* ctrl-l */
|
|
case 18: /* ctrl-r */
|
|
after = FALSE;
|
|
clearok(cw, TRUE);
|
|
wrefresh(cw);
|
|
break;
|
|
case 16: /* ctrl-p */
|
|
{
|
|
int decrement = FALSE;
|
|
after = FALSE;
|
|
|
|
if (mpos == 0)
|
|
decrement = TRUE;
|
|
|
|
msg_index = (msg_index + 9) % 10;
|
|
msg(msgbuf[msg_index]);
|
|
if (decrement)
|
|
msg_index = (msg_index + 9) % 10;
|
|
}
|
|
break;
|
|
|
|
case 'S':
|
|
after = FALSE;
|
|
if (save_game())
|
|
{
|
|
wclear(cw);
|
|
wrefresh(cw);
|
|
endwin();
|
|
printf("\n");
|
|
exit(0);
|
|
}
|
|
break;
|
|
|
|
/*
|
|
* Other misc commands
|
|
*/
|
|
|
|
case '.': break; /* rest */
|
|
case ',': add_pack(NULL, NOMESSAGE); break;
|
|
case 'q': quaff(&player, -1, ISNORMAL); break;
|
|
case 'r': read_scroll(&player, -1, ISNORMAL); break;
|
|
case 'd': drop(NULL); break;
|
|
case '^': set_trap(&player, hero.y, hero.x); break;
|
|
case 'c': incant(&player, nullcoord); break;
|
|
case 'D': dip_it(); break;
|
|
case 'e': eat(); break;
|
|
case '=': listen(); break;
|
|
case 'A': apply(); break;
|
|
case 'w': wield(); break;
|
|
case 'W': wear(); break;
|
|
case 'T': take_off(); break;
|
|
case 'P': ring_on(); break;
|
|
case 'R': ring_off(); break;
|
|
case 'p': prayer(); break;
|
|
case 'C': after = FALSE; call(FALSE); break;
|
|
case 'M': after = FALSE; call(TRUE); break;
|
|
case 's': search(FALSE); break;
|
|
|
|
/*
|
|
* Directional commands - get_dir sets delta
|
|
*/
|
|
case 20: /* ctrl-t */
|
|
if (get_dir())
|
|
steal();
|
|
else
|
|
after = FALSE;
|
|
break;
|
|
|
|
case 'z':
|
|
if (get_dir())
|
|
do_zap(&player, -1, ISNORMAL);
|
|
else
|
|
after = FALSE;
|
|
break;
|
|
|
|
case 'a':
|
|
if (get_dir())
|
|
affect();
|
|
else
|
|
after = FALSE;
|
|
touchwin(cw);
|
|
break;
|
|
|
|
/*
|
|
* wizard commands
|
|
*/
|
|
|
|
#ifdef WIZARD
|
|
case 0x17: /* ctrl-w */
|
|
after = FALSE;
|
|
|
|
if (!wizard)
|
|
{
|
|
if (!canwizard)
|
|
{
|
|
msg("Illegal command '^W'.");
|
|
break;
|
|
}
|
|
|
|
if (passwd())
|
|
{
|
|
msg("Welcome, oh mighty wizard.");
|
|
wizard = waswizard = TRUE;
|
|
}
|
|
else
|
|
{
|
|
msg("Incorrect password.");
|
|
break;
|
|
}
|
|
}
|
|
|
|
msg("Wizard command: ");
|
|
mpos = 0;
|
|
ch = readchar();
|
|
|
|
switch (ch)
|
|
{
|
|
case 'v':
|
|
wiz_verbose = !wiz_verbose;
|
|
break;
|
|
|
|
case 'e':
|
|
wizard = FALSE;
|
|
msg("Not wizard any more.");
|
|
break;
|
|
|
|
case 's': activity(); break;
|
|
case 't': teleport(); break;
|
|
case 'm': overlay(mw, cw); break;
|
|
case 'f': overlay(stdscr, cw); break;
|
|
case 'i': inventory(lvl_obj, 0); break;
|
|
case 'c': buy_it('\0', ISNORMAL); break;
|
|
case 'I': whatis(NULL); break;
|
|
case 'F':
|
|
msg("food left: %d\tfood level: %d",
|
|
food_left,foodlev);
|
|
break;
|
|
case 'M':
|
|
creat_mons(&player, get_monster_number("create"),
|
|
MESSAGE);
|
|
break;
|
|
|
|
case 'r':
|
|
msg("rnd(4)%d, rnd(40)%d, rnd(100)%d",
|
|
rnd(4), rnd(40), rnd(100));
|
|
break;
|
|
|
|
case 'C':
|
|
obj = get_object(pack, "charge", STICK, NULL);
|
|
|
|
if (obj != NULL)
|
|
obj->o_charges = 10000;
|
|
|
|
break;
|
|
|
|
case 'w':
|
|
obj = get_object(pack, "price", 0, NULL);
|
|
|
|
if (obj != NULL)
|
|
msg("Worth %d.", get_worth(obj));
|
|
|
|
break;
|
|
|
|
case 'g':
|
|
{
|
|
int tlev;
|
|
|
|
prbuf[0] = '\0';
|
|
msg("Which level? ");
|
|
|
|
if (get_string(prbuf, cw) == NORM)
|
|
{
|
|
msg("");
|
|
|
|
if ((tlev = atoi(prbuf)) < 1)
|
|
msg("Illegal level.");
|
|
else if (tlev > 3000)
|
|
{
|
|
levtype = THRONE;
|
|
level = tlev - 3000;
|
|
}
|
|
else if (tlev > 2000)
|
|
{
|
|
levtype = MAZELEV;
|
|
level = tlev - 2000;
|
|
}
|
|
else if (tlev > 1000)
|
|
{
|
|
levtype = POSTLEV;
|
|
level = tlev - 1000;
|
|
}
|
|
else
|
|
{
|
|
levtype = NORMLEV;
|
|
level = tlev;
|
|
}
|
|
|
|
new_level(levtype,0);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 'o': make_omnipotent(); break;
|
|
|
|
case ESCAPE: /* Escape */
|
|
door_stop = FALSE;
|
|
|
|
count = 0;
|
|
after = FALSE;
|
|
break;
|
|
|
|
default:
|
|
msg("Illegal wizard command '%s', %d.",
|
|
unctrl(ch), ch);
|
|
count = 0;
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
msg("Illegal command '%s', %d.",
|
|
unctrl(ch), ch);
|
|
count = 0;
|
|
after = FALSE;
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* turn off flags if no longer needed
|
|
*/
|
|
if (!running)
|
|
door_stop = FALSE;
|
|
}
|
|
|
|
/*
|
|
* If he ran into something to take, let him pick it up.
|
|
*/
|
|
if (take != 0)
|
|
{
|
|
if (!moving)
|
|
pick_up(take);
|
|
else
|
|
show_floor();
|
|
}
|
|
if (!running)
|
|
door_stop = FALSE;
|
|
} /* end while */
|
|
}
|
|
|
|
|
|
void
|
|
do_after_effects(void)
|
|
{
|
|
int i;
|
|
|
|
/* Kick off the rest of the daemons and fuses */
|
|
|
|
look(FALSE);
|
|
do_daemons(AFTER);
|
|
do_fuses(AFTER);
|
|
|
|
/* Special abilities */
|
|
|
|
if ((player.t_ctype == C_THIEF || player.t_ctype == C_ASSASIN ||
|
|
player.t_ctype == C_NINJA || player.t_ctype == C_RANGER) &&
|
|
(rnd(100) < (2 * pstats.s_dext + 5 * pstats.s_lvl)))
|
|
search(TRUE);
|
|
|
|
for (i = 0; i < ring_value(R_SEARCH); i++)
|
|
search(FALSE);
|
|
|
|
if (is_wearing(R_TELEPORT) && rnd(50) < 2)
|
|
{
|
|
teleport();
|
|
|
|
if (off(player, ISCLEAR))
|
|
{
|
|
if (on(player, ISHUH))
|
|
lengthen_fuse(FUSE_UNCONFUSE, rnd(8) + HUHDURATION);
|
|
else
|
|
light_fuse(FUSE_UNCONFUSE, 0, rnd(8) + HUHDURATION, AFTER);
|
|
|
|
turn_on(player, ISHUH);
|
|
}
|
|
else
|
|
msg("You feel dizzy for a moment, but it quickly passes.");
|
|
}
|
|
|
|
/* accidents and general clumsiness */
|
|
|
|
if (fighting && rnd(50) == 0)
|
|
{
|
|
msg("You become tired of this nonsense.");
|
|
fighting = after = FALSE;
|
|
}
|
|
|
|
if (on(player, ISELECTRIC))
|
|
electrificate();
|
|
|
|
if (!fighting && (no_command == 0) && cur_weapon != NULL
|
|
&& rnd(on(player, STUMBLER) ? 399 : 9999) == 0
|
|
&& rnd(pstats.s_dext) <
|
|
2 - hitweight() + (on(player, STUMBLER) ? 4 : 0))
|
|
{
|
|
msg("You trip and stumble over your weapon.");
|
|
running = after = FALSE;
|
|
|
|
if (rnd(8) == 0 && (pstats.s_hpt -= roll(1, 10)) <= 0)
|
|
{
|
|
msg("You break your neck and die.");
|
|
death(D_FALL);
|
|
return;
|
|
}
|
|
else if (cur_weapon->o_flags & ISPOISON && rnd(4) == 0)
|
|
{
|
|
msg("You are cut by your %s!",
|
|
inv_name(cur_weapon, LOWERCASE));
|
|
|
|
if (player.t_ctype != C_PALADIN
|
|
&& !(player.t_ctype == C_NINJA &&
|
|
pstats.s_lvl > 12)
|
|
&& !save(VS_POISON))
|
|
{
|
|
if (pstats.s_hpt == 1)
|
|
{
|
|
msg("You die from the poison in the cut.");
|
|
death(D_POISON);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
msg("You feel very sick now.");
|
|
pstats.s_hpt /= 2;
|
|
chg_str(-2, FALSE, FALSE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Time to enforce weapon and armor restrictions */
|
|
if (rnd(9999) == 0)
|
|
{
|
|
if (((cur_weapon == NULL) ||
|
|
(wield_ok(&player, cur_weapon, NOMESSAGE)))
|
|
&& ((cur_armor == NULL) ||
|
|
(wear_ok(&player, cur_armor, NOMESSAGE))))
|
|
{
|
|
switch (player.t_ctype)
|
|
{
|
|
case C_CLERIC:
|
|
case C_DRUID:
|
|
case C_RANGER:
|
|
case C_PALADIN:
|
|
if (rnd(luck) != 0)
|
|
/* You better have done
|
|
* little wrong */
|
|
goto bad_cleric;
|
|
|
|
msg("You are enraptured by the renewed "
|
|
"power of your god.");
|
|
break;
|
|
|
|
case C_MAGICIAN:
|
|
case C_ILLUSION:
|
|
msg("You become in tune with the universe.");
|
|
break;
|
|
|
|
case C_THIEF:
|
|
case C_NINJA:
|
|
case C_ASSASIN:
|
|
msg("You become supernaly sensitive to your "
|
|
"surroundings.");
|
|
break;
|
|
|
|
case C_FIGHTER:
|
|
msg("You catch your second wind.");
|
|
break;
|
|
|
|
default:
|
|
msg("What a strange type you are!");
|
|
break;
|
|
}
|
|
pstats.s_hpt = max_stats.s_hpt += rnd(pstats.s_lvl) + 1;
|
|
pstats.s_power = max_stats.s_power += rnd(pstats.s_lvl) + 1;
|
|
}
|
|
else
|
|
{ /* he blew it - make him pay */
|
|
|
|
int death_cause = 0;
|
|
|
|
switch (player.t_ctype)
|
|
{
|
|
case C_CLERIC:
|
|
case C_DRUID:
|
|
case C_RANGER:
|
|
case C_PALADIN:
|
|
bad_cleric:
|
|
msg("Your god scourges you for your misdeeds.");
|
|
death_cause = D_GODWRATH;
|
|
break;
|
|
|
|
case C_MAGICIAN:
|
|
case C_ILLUSION:
|
|
msg("You short out your manna on the unfamiliar %s.",
|
|
(cur_armor != NULL ? "armor" : "weapon"));
|
|
|
|
death_cause = D_SPELLFUMBLE;
|
|
break;
|
|
|
|
case C_THIEF:
|
|
case C_NINJA:
|
|
case C_ASSASIN:
|
|
msg("You trip and fall because of the unfamiliar %s.",
|
|
(cur_armor != NULL ? "armor" : "weapon"));
|
|
death_cause = D_CLUMSY;
|
|
break;
|
|
|
|
case C_FIGHTER:
|
|
debug("Fighter getting raw deal?");
|
|
break;
|
|
|
|
default:
|
|
msg("What a strange type you are!");
|
|
break;
|
|
}
|
|
|
|
aggravate();
|
|
pstats.s_power /= 2;
|
|
pstats.s_hpt /= 2;
|
|
player.t_no_move++;
|
|
|
|
if ((pstats.s_hpt -= rnd(pstats.s_lvl)) <= 0)
|
|
{
|
|
death(death_cause);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (rnd(500000) == 0)
|
|
{
|
|
new_level(THRONE,0);
|
|
fighting = running = after = FALSE;
|
|
command();
|
|
}
|
|
}
|
|
|
|
void
|
|
make_omnipotent(void)
|
|
{
|
|
int i;
|
|
struct linked_list *item;
|
|
struct object *obj;
|
|
|
|
for (i = 0; i < 20; i++)
|
|
raise_level();
|
|
|
|
max_stats.s_hpt += 1000;
|
|
max_stats.s_power += 1000;
|
|
pstats.s_hpt = max_stats.s_hpt;
|
|
pstats.s_power = max_stats.s_power;
|
|
max_stats.s_str = pstats.s_str = 25;
|
|
max_stats.s_intel = pstats.s_intel = 25;
|
|
max_stats.s_wisdom = pstats.s_wisdom = 25;
|
|
max_stats.s_dext = pstats.s_dext = 25;
|
|
max_stats.s_const = pstats.s_const = 25;
|
|
|
|
if (cur_weapon == NULL || cur_weapon->o_which != CLAYMORE)
|
|
{
|
|
item = spec_item(WEAPON, CLAYMORE, 10, 10);
|
|
cur_weapon = OBJPTR(item);
|
|
cur_weapon->o_flags |= ISKNOW;
|
|
add_pack(item, NOMESSAGE);
|
|
}
|
|
|
|
/* and a kill-o-zap stick */
|
|
|
|
item = spec_item(STICK, WS_DISINTEGRATE, 10000, 0);
|
|
obj = OBJPTR(item);
|
|
obj->o_flags |= ISKNOW;
|
|
know_items[TYP_STICK][WS_DISINTEGRATE] = TRUE;
|
|
|
|
if (guess_items[TYP_STICK][WS_DISINTEGRATE])
|
|
{
|
|
ur_free(guess_items[TYP_STICK][WS_DISINTEGRATE]);
|
|
guess_items[TYP_STICK][WS_DISINTEGRATE] = NULL;
|
|
}
|
|
|
|
add_pack(item, NOMESSAGE);
|
|
|
|
/* and his suit of armor */
|
|
|
|
if (cur_armor == NULL ||
|
|
!(cur_armor->o_which == CRYSTAL_ARMOR ||
|
|
cur_armor->o_which == MITHRIL))
|
|
{
|
|
item = spec_item(ARMOR, CRYSTAL_ARMOR, 15, 0);
|
|
obj = OBJPTR(item);
|
|
obj->o_flags |= ISKNOW;
|
|
obj->o_weight =
|
|
(int) (armors[CRYSTAL_ARMOR].a_wght * 0.2);
|
|
cur_armor = obj;
|
|
add_pack(item, NOMESSAGE);
|
|
}
|
|
|
|
/* and some rings (have to put them on, for now) */
|
|
|
|
|
|
if (!is_wearing(R_SEARCH))
|
|
{
|
|
item = spec_item(RING, R_SEARCH, 0, 0);
|
|
obj = OBJPTR(item);
|
|
obj->o_flags |= ISKNOW;
|
|
know_items[TYP_RING][R_SEARCH] = TRUE;
|
|
|
|
if (guess_items[TYP_RING][R_SEARCH])
|
|
{
|
|
ur_free(guess_items[TYP_RING][R_SEARCH]);
|
|
guess_items[TYP_RING][R_SEARCH] = NULL;
|
|
}
|
|
|
|
add_pack(item, NOMESSAGE);
|
|
}
|
|
|
|
if (!is_wearing(R_PIETY))
|
|
{
|
|
item = spec_item(RING, R_PIETY, 0, 0);
|
|
obj = OBJPTR(item);
|
|
obj->o_flags |= ISKNOW;
|
|
know_items[TYP_RING][R_PIETY] = TRUE;
|
|
|
|
if (guess_items[TYP_RING][R_PIETY])
|
|
{
|
|
ur_free(guess_items[TYP_RING][R_PIETY]);
|
|
guess_items[TYP_RING][R_PIETY] = NULL;
|
|
}
|
|
|
|
add_pack(item, NOMESSAGE);
|
|
}
|
|
|
|
item = spec_item(SCROLL, S_ELECTRIFY, 0, 0);
|
|
obj = OBJPTR(item);
|
|
obj->o_flags |= ISKNOW;
|
|
know_items[TYP_SCROLL][S_ELECTRIFY] = TRUE;
|
|
|
|
if (guess_items[TYP_SCROLL][S_ELECTRIFY])
|
|
{
|
|
ur_free(guess_items[TYP_SCROLL][S_ELECTRIFY]);
|
|
guess_items[TYP_SCROLL][S_ELECTRIFY] = NULL;
|
|
}
|
|
|
|
add_pack(item, NOMESSAGE);
|
|
|
|
/* Spiff him up a bit */
|
|
quaff(&player, P_SHERO, ISBLESSED);
|
|
quaff(&player, P_CLEAR, ISBLESSED);
|
|
quaff(&player, P_FIRERESIST, ISBLESSED);
|
|
quaff(&player, P_TRUESEE, ISBLESSED);
|
|
quaff(&player, P_PHASE, ISBLESSED);
|
|
purse += 50000L;
|
|
updpack();
|
|
}
|
|
|
|
|
|
/*
|
|
quit()
|
|
Have player make certain, then exit.
|
|
*/
|
|
|
|
void
|
|
quit_handler(int sig)
|
|
{
|
|
if (signal(SIGINT, quit_handler) != quit_handler)
|
|
mpos = 0;
|
|
|
|
sig = 0;
|
|
|
|
quit();
|
|
}
|
|
|
|
void
|
|
quit(void)
|
|
{
|
|
msg("Really quit?");
|
|
|
|
wrefresh(cw);
|
|
|
|
if (readchar() == 'y')
|
|
{
|
|
clear();
|
|
wclear(cw);
|
|
wrefresh(cw);
|
|
move(LINES - 1, 0);
|
|
wrefresh(stdscr);
|
|
score(pstats.s_exp, pstats.s_lvl, CHICKEN, 0);
|
|
byebye();
|
|
}
|
|
else
|
|
{
|
|
signal(SIGINT, quit_handler);
|
|
wmove(cw, 0, 0);
|
|
wclrtoeol(cw);
|
|
status(FALSE);
|
|
wrefresh(cw);
|
|
mpos = 0;
|
|
count = 0;
|
|
fighting = running = 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
search()
|
|
Player gropes about him to find hidden things.
|
|
*/
|
|
|
|
void
|
|
search(int is_thief)
|
|
{
|
|
int x, y;
|
|
char ch;
|
|
|
|
/*
|
|
* Look all around the hero, if there is something hidden there, give
|
|
* him a chance to find it. If its found, display it.
|
|
*/
|
|
|
|
if (on(player, ISBLIND))
|
|
return;
|
|
|
|
for (x = hero.x - 1; x <= hero.x + 1; x++)
|
|
for (y = hero.y - 1; y <= hero.y + 1; y++)
|
|
{
|
|
ch = winat(y, x);
|
|
|
|
if (isatrap(ch))
|
|
{
|
|
static char trname[1024]; /* temp scratch space */
|
|
struct trap *tp;
|
|
struct room *rp;
|
|
|
|
if (isatrap( mvwinch(cw, y, x)))
|
|
continue;
|
|
|
|
tp = trap_at(y, x);
|
|
|
|
if ((tp->tr_flags & ISTHIEFSET) ||
|
|
(rnd(100) > 50 && !is_thief))
|
|
break;
|
|
|
|
rp = roomin(hero);
|
|
|
|
if (tp->tr_type == FIRETRAP && rp != NULL)
|
|
{
|
|
rp->r_flags &= ~ISDARK;
|
|
light(&hero);
|
|
}
|
|
|
|
tp->tr_flags |= ISFOUND;
|
|
mvwaddch(cw, y, x, ch);
|
|
count = 0;
|
|
running = FALSE;
|
|
msg(tr_name(tp->tr_type,trname));
|
|
}
|
|
else if (ch == SECRETDOOR)
|
|
{
|
|
if (rnd(100) < 20 && !is_thief)
|
|
{
|
|
mvaddch(y, x, DOOR);
|
|
count = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
help()
|
|
Give single character help, or the whole mess if he wants it
|
|
*/
|
|
|
|
void
|
|
help(void)
|
|
{
|
|
const struct h_list *strp = helpstr;
|
|
char helpch;
|
|
int cnt;
|
|
|
|
msg("Character you want help for (* for all): ");
|
|
helpch = readchar();
|
|
mpos = 0;
|
|
|
|
/*
|
|
* If its not a *, print the right help string or an error if he
|
|
* typed a funny character.
|
|
*/
|
|
|
|
if (helpch != '*')
|
|
{
|
|
wmove(cw, 0, 0);
|
|
|
|
while (strp->h_ch)
|
|
{
|
|
if (strp->h_desc == 0)
|
|
{
|
|
if (!wizard)
|
|
break;
|
|
else
|
|
{
|
|
strp++;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (strp->h_ch == helpch)
|
|
{
|
|
msg("%s%s", unctrl(strp->h_ch), strp->h_desc);
|
|
break;
|
|
}
|
|
strp++;
|
|
}
|
|
|
|
if (strp->h_ch != helpch)
|
|
msg("Unknown character '%s'.", unctrl(helpch));
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Here we print help for everything. Then wait before we return to
|
|
* command mode
|
|
*/
|
|
|
|
wclear(hw);
|
|
cnt = 0;
|
|
|
|
while (strp->h_ch)
|
|
{
|
|
if (strp->h_desc == 0)
|
|
{
|
|
if (!wizard)
|
|
break;
|
|
else
|
|
{
|
|
strp++;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
mvwaddstr(hw, cnt % 23, cnt > 22 ? 40 : 0, unctrl(strp->h_ch));
|
|
waddstr(hw, strp->h_desc);
|
|
strp++;
|
|
|
|
if (++cnt >= 46 && strp->h_ch && (strp->h_desc != NULL || wizard))
|
|
{
|
|
wmove(hw, LINES - 1, 0);
|
|
wprintw(hw, (char *) morestr);
|
|
wrefresh(hw);
|
|
wait_for(' ');
|
|
wclear(hw);
|
|
cnt = 0;
|
|
}
|
|
}
|
|
|
|
wmove(hw, LINES - 1, 0);
|
|
wprintw(hw, (char *) morestr);
|
|
wrefresh(hw);
|
|
wait_for(' ');
|
|
wclear(hw);
|
|
wrefresh(hw);
|
|
|
|
wmove(cw, 0, 0);
|
|
wclrtoeol(cw);
|
|
status(FALSE);
|
|
touchwin(cw);
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
identify()
|
|
Tell the player what a certain thing is.
|
|
*/
|
|
|
|
void
|
|
identify(void)
|
|
{
|
|
int ch;
|
|
char *str;
|
|
|
|
msg("What do you want identified? ");
|
|
mpos = 0;
|
|
|
|
if ((ch = readchar()) == ESCAPE)
|
|
{
|
|
msg("");
|
|
return;
|
|
}
|
|
|
|
if (isalpha(ch))
|
|
{
|
|
id_monst(ch);
|
|
return;
|
|
}
|
|
|
|
switch (ch)
|
|
{
|
|
case '|':
|
|
case '-': str = "wall of a room"; break;
|
|
case GOLD: str = "gold"; break;
|
|
case STAIRS: str = "passage leading down"; break;
|
|
case DOOR: str = "door"; break;
|
|
case FLOOR: str = "room floor"; break;
|
|
case VPLAYER: str = "The hero of the game ---> you"; break;
|
|
case IPLAYER: str = "you (but invisible)"; break;
|
|
case PASSAGE: str = "passage"; break;
|
|
case POST: str = "trading post"; break;
|
|
case POOL: str = "a shimmering pool"; break;
|
|
case TRAPDOOR: str = "trapdoor"; break;
|
|
case ARROWTRAP: str = "arrow trap"; break;
|
|
case SLEEPTRAP: str = "sleeping gas trap"; break;
|
|
case BEARTRAP: str = "bear trap"; break;
|
|
case TELTRAP: str = "teleport trap"; break;
|
|
case DARTTRAP: str = "dart trap"; break;
|
|
case MAZETRAP: str = "entrance to a maze"; break;
|
|
case FIRETRAP: str = "fire trap"; break;
|
|
case POISONTRAP: str = "poison pool trap"; break;
|
|
case LAIR: str = "monster lair entrance"; break;
|
|
case RUSTTRAP: str = "rust trap"; break;
|
|
case POTION: str = "potion"; break;
|
|
case SCROLL: str = "scroll"; break;
|
|
case FOOD: str = "food"; break;
|
|
case WEAPON: str = "weapon"; break;
|
|
case ' ': str = "solid rock"; break;
|
|
case ARMOR: str = "armor"; break;
|
|
case ARTIFACT: str = "an artifact from bygone ages"; break;
|
|
case RING: str = "ring"; break;
|
|
case STICK: str = "wand or staff"; break;
|
|
default: str = "unknown character"; break;
|
|
}
|
|
msg("'%s'; %s", unctrl(ch), str);
|
|
}
|
|
|
|
/*
|
|
d_level()
|
|
He wants to go down a level
|
|
*/
|
|
|
|
void
|
|
d_level(void)
|
|
{
|
|
int no_phase = FALSE;
|
|
|
|
if (mvinch(hero.y, hero.x) != STAIRS)
|
|
{
|
|
if (off(player, CANINWALL)) /* Must use stairs if can't phase */
|
|
{
|
|
msg("I see no way down.");
|
|
return;
|
|
}
|
|
|
|
extinguish_fuse(FUSE_UNPHASE);/*Using phase to go down gets rid of it*/
|
|
no_phase = TRUE;
|
|
}
|
|
|
|
if (is_wearing(R_LEVITATION) || on(player, CANFLY))
|
|
{
|
|
msg("You can't! You're floating in the air.");
|
|
return;
|
|
}
|
|
|
|
if (rnd(pstats.s_dext) < 3 * (2 - hitweight() +
|
|
(on(player, STUMBLER) ? 4 : 0)))
|
|
{
|
|
msg("You trip and fall down the stairs.");
|
|
|
|
if ((pstats.s_hpt -= roll(1, 10)) <= 0)
|
|
{
|
|
msg("You break your neck and die.");
|
|
death(D_FALL);
|
|
return;
|
|
}
|
|
}
|
|
|
|
level++;
|
|
new_level(NORMLEV,0);
|
|
|
|
if (no_phase)
|
|
unphase(NULL);
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
u_level()
|
|
He wants to go up a level
|
|
*/
|
|
|
|
void
|
|
u_level(void)
|
|
{
|
|
char ch = 0;
|
|
|
|
if (has_artifact && ((ch = CCHAR(mvinch(hero.y, hero.x))) == STAIRS ||
|
|
(on(player, CANINWALL)
|
|
&& (is_wearing(R_LEVITATION) || on(player, CANFLY)))))
|
|
{
|
|
if (--level == 0)
|
|
total_winner();
|
|
else if (rnd(wizard ? 3 : 15) == 0)
|
|
new_level(THRONE,0);
|
|
else
|
|
{
|
|
new_level(NORMLEV,0);
|
|
msg("You feel a wrenching sensation in your gut.");
|
|
}
|
|
|
|
if (on(player, CANINWALL) && ch != STAIRS)
|
|
{
|
|
extinguish_fuse(FUSE_UNPHASE);
|
|
unphase(NULL);
|
|
}
|
|
|
|
return;
|
|
}
|
|
else if (ch != STAIRS &&
|
|
!(on(player, CANINWALL) && (is_wearing(R_LEVITATION)
|
|
|| on(player, CANFLY))))
|
|
msg("I see no way up.");
|
|
else
|
|
msg("Your way is magically blocked.");
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
call()
|
|
allow a user to call a potion, scroll, or ring something
|
|
*/
|
|
|
|
void
|
|
call(int mark)
|
|
{
|
|
struct object *obj;
|
|
char *elsewise;
|
|
int item_type = numthings;
|
|
char **item_color = NULL;
|
|
|
|
if (mark)
|
|
obj = get_object(pack, "mark", 0, bff_markable);
|
|
else
|
|
obj = get_object(pack, "call", 0, bff_callable);
|
|
|
|
if (obj == NULL)
|
|
return;
|
|
|
|
switch (obj->o_type)
|
|
{
|
|
case RING:
|
|
item_type = TYP_RING;
|
|
item_color = r_stones;
|
|
break;
|
|
case POTION:
|
|
item_type = TYP_POTION;
|
|
item_color = p_colors;
|
|
break;
|
|
case SCROLL:
|
|
item_type = TYP_SCROLL;
|
|
item_color = s_names;
|
|
break;
|
|
case STICK:
|
|
item_type = TYP_STICK;
|
|
item_color = ws_made;
|
|
break;
|
|
default:
|
|
if (!mark)
|
|
{
|
|
msg("You can't call that anything.");
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (!mark && know_items[item_type][obj->o_which])
|
|
{
|
|
msg("That has already been identified.");
|
|
return;
|
|
}
|
|
|
|
if (mark)
|
|
{
|
|
if (obj->o_mark[0])
|
|
msg("Was marked \"%s\".", obj->o_mark);
|
|
|
|
msg("What do you want to mark it? ");
|
|
prbuf[0] = '\0';
|
|
}
|
|
else
|
|
{
|
|
elsewise = (guess_items[item_type][obj->o_which] != NULL ?
|
|
guess_items[item_type][obj->o_which] : item_color[obj->o_which]);
|
|
|
|
msg("Was called \"%s\".", elsewise);
|
|
msg("What do you want to call it? ");
|
|
|
|
if (guess_items[item_type][obj->o_which] != NULL)
|
|
ur_free(guess_items[item_type][obj->o_which]);
|
|
|
|
strcpy(prbuf, elsewise);
|
|
}
|
|
|
|
if (get_string(prbuf, cw) == NORM)
|
|
{
|
|
if (mark)
|
|
{
|
|
strncpy(obj->o_mark, prbuf, MARKLEN - 1);
|
|
obj->o_mark[MARKLEN - 1] = '\0';
|
|
}
|
|
else
|
|
{
|
|
guess_items[item_type][obj->o_which] = new_alloc(strlen(prbuf) + 1);
|
|
strcpy(guess_items[item_type][obj->o_which], prbuf);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
att_bonus()
|
|
bonus attacks for certain player classes
|
|
*/
|
|
|
|
int
|
|
att_bonus(void)
|
|
{
|
|
int bonus = FALSE;
|
|
|
|
if ((player.t_ctype == C_FIGHTER || player.t_ctype == C_PALADIN)
|
|
&& (pstats.s_lvl > 12 ||
|
|
(pstats.s_lvl > 6 && pstats.s_lvl < 13 && rnd(2))))
|
|
bonus = TRUE;
|
|
|
|
else if ((player.t_ctype == C_RANGER)
|
|
&& (pstats.s_lvl > 14 ||
|
|
(pstats.s_lvl > 7 && pstats.s_lvl < 15 && rnd(2))))
|
|
bonus = TRUE;
|
|
|
|
else if ((player.t_ctype == C_NINJA)
|
|
&& (pstats.s_lvl > 8 ||
|
|
(pstats.s_lvl > 4 && pstats.s_lvl < 9 && rnd(2))))
|
|
bonus = TRUE;
|
|
|
|
return(bonus);
|
|
}
|