This was fixed by adding "after = FALSE;" to the relevant cases in command(). Rogue V4 and V5 are not affected.
1330 lines
46 KiB
C
1330 lines
46 KiB
C
/*
|
|
command.c - Read and execute the user commands
|
|
|
|
XRogue: Expeditions into the Dungeons of Doom
|
|
Copyright (C) 1991 Robert Pietkivitch
|
|
All rights reserved.
|
|
|
|
Based on "Advanced Rogue"
|
|
Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T
|
|
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 <curses.h>
|
|
#include <ctype.h>
|
|
#include <signal.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "mach_dep.h"
|
|
#include "rogue.h"
|
|
|
|
void display(void);
|
|
void d_level(void);
|
|
void u_level(void);
|
|
void shell(void);
|
|
void nameit(void);
|
|
void namemonst(void);
|
|
void count_gold(void);
|
|
|
|
/*
|
|
* command:
|
|
* Process the user commands
|
|
*/
|
|
|
|
void
|
|
command(void)
|
|
{
|
|
unsigned int ch;
|
|
struct linked_list *item;
|
|
unsigned int countch = 0, direction = 0, newcount = FALSE;
|
|
int segment = 1;
|
|
int monst_limit, monst_current;
|
|
|
|
monst_limit = monst_current = 1;
|
|
while (playing) {
|
|
/*
|
|
* Let the daemons start up, but only do them once a round
|
|
* (round = 10 segments).
|
|
*/
|
|
if (segment >= 10) {
|
|
do_daemons(BEFORE);
|
|
do_fuses(BEFORE);
|
|
}
|
|
|
|
after = TRUE;
|
|
do {
|
|
/* One more tick of the clock. */
|
|
if (segment >= 10 && after && (++turns % DAYLENGTH) == 0) {
|
|
daytime ^= TRUE;
|
|
if (levtype == OUTSIDE) {
|
|
if (daytime) msg("A bright star flares above the horizon.");
|
|
else msg("The bright star travels beyond the horizon.");
|
|
}
|
|
light(&hero);
|
|
}
|
|
|
|
/*
|
|
* Don't bother with these updates unless the player's going
|
|
* to do something.
|
|
*/
|
|
if (player.t_action == A_NIL && player.t_no_move <= 1) {
|
|
look(after, FALSE);
|
|
lastscore = purse;
|
|
wmove(cw, hero.y, hero.x);
|
|
if (!((running || count) && jump)) {
|
|
status(FALSE);
|
|
}
|
|
}
|
|
|
|
/* Draw the screen */
|
|
if (!((running || count) && jump)) {
|
|
wmove(cw, hero.y, hero.x);
|
|
draw(cw);
|
|
}
|
|
|
|
after = TRUE;
|
|
|
|
/*
|
|
* Read command or continue run
|
|
*/
|
|
if (--player.t_no_move <= 0) {
|
|
take = 0; /* Nothing here to start with */
|
|
player.t_no_move = 0; /* Be sure we don't go too negative */
|
|
if (!running) door_stop = FALSE;
|
|
|
|
/* Was the player being held? */
|
|
if (player.t_action == A_FREEZE) {
|
|
player.t_action = A_NIL;
|
|
msg("You can move again.");
|
|
}
|
|
|
|
if (player.t_action != A_NIL) ch = player.t_action;
|
|
else if (running) {
|
|
char scratch;
|
|
|
|
/* If in a corridor or maze, if we are at a turn with
|
|
* only one way to go, turn that way.
|
|
*/
|
|
scratch = winat(hero.y, hero.x) & A_CHARTEXT;
|
|
if ((scratch==PASSAGE||scratch==DOOR||levtype==MAZELEV) &&
|
|
off(player, ISHUH) &&
|
|
off(player, ISBLIND)) {
|
|
int y, x;
|
|
if (getdelta(runch, &y, &x) == TRUE) {
|
|
corr_move(y, x);
|
|
}
|
|
}
|
|
ch = runch;
|
|
}
|
|
else if (count) ch = countch;
|
|
else {
|
|
ch = wgetch(cw);
|
|
if (mpos != 0 && !running) /* Erase message if its there */
|
|
msg("");
|
|
}
|
|
|
|
/*
|
|
* check for prefixes
|
|
*/
|
|
if (isascii(ch) && isdigit(ch))
|
|
{
|
|
count = 0;
|
|
newcount = TRUE;
|
|
while (isascii(ch) && isdigit(ch))
|
|
{
|
|
count = count * 10 + (ch - '0');
|
|
ch = wgetch(cw);
|
|
}
|
|
countch = ch;
|
|
/*
|
|
* turn off count for commands which don't make sense
|
|
* to repeat
|
|
*/
|
|
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 C_SEARCH: case '.':
|
|
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':
|
|
case 'H': case 'J': case 'K': case 'L':
|
|
case 'Y': case 'U': case 'B': case 'N':
|
|
runch = tolower(ch);
|
|
}
|
|
}
|
|
|
|
/* Perform the action */
|
|
switch (ch) {
|
|
case 'f':
|
|
if (!on(player, ISBLIND))
|
|
{
|
|
door_stop = TRUE;
|
|
firstmove = TRUE;
|
|
}
|
|
if (count && !newcount)
|
|
ch = direction;
|
|
else
|
|
ch = wgetch(cw);
|
|
switch (ch)
|
|
{
|
|
case 'h': case 'j': case 'k': case 'l':
|
|
case 'y': case 'u': case 'b': case 'n':
|
|
ch = toupper(ch);
|
|
}
|
|
direction = ch;
|
|
}
|
|
newcount = FALSE;
|
|
|
|
/*
|
|
* execute a command
|
|
*/
|
|
if (count && !running && player.t_action == A_NIL)
|
|
count--;
|
|
|
|
switch (ch) {
|
|
case '!' : shell(); break;
|
|
case KEY_LEFT : do_move(0, -1);
|
|
when KEY_DOWN : do_move(1, 0);
|
|
when KEY_UP : do_move(-1, 0);
|
|
when KEY_RIGHT : do_move(0, 1);
|
|
when KEY_HOME : do_move(-1, -1);
|
|
when KEY_A1 : do_move(-1, -1);
|
|
when KEY_PPAGE : do_move(-1, 1);
|
|
when KEY_A3 : do_move(-1, 1);
|
|
when KEY_END : do_move(1, -1);
|
|
when KEY_C1 : do_move(1, -1);
|
|
when KEY_NPAGE : do_move(1, 1);
|
|
when KEY_C3 : do_move(1, 1);
|
|
#ifdef CTL_RIGHT
|
|
when CTL_RIGHT : do_run('l');
|
|
when CTL_LEFT : do_run('h');
|
|
when CTL_UP : do_run('k');
|
|
when CTL_DOWN : do_run('j');
|
|
when CTL_HOME : do_run('y');
|
|
when CTL_PGUP : do_run('u');
|
|
when CTL_END : do_run('b');
|
|
when CTL_PGDN : do_run('n');
|
|
#endif
|
|
when 'h' : do_move(0, -1);
|
|
when 'j' : do_move(1, 0);
|
|
when 'k' : do_move(-1, 0);
|
|
when 'l' : do_move(0, 1);
|
|
when 'y' : do_move(-1, -1);
|
|
when 'u' : do_move(-1, 1);
|
|
when 'b' : do_move(1, -1);
|
|
when 'n' : do_move(1, 1);
|
|
when 'H' : do_run('h');
|
|
when 'J' : do_run('j');
|
|
when 'K' : do_run('k');
|
|
when 'L' : do_run('l');
|
|
when 'Y' : do_run('y');
|
|
when 'U' : do_run('u');
|
|
when 'B' : do_run('b');
|
|
when 'N' : do_run('n');
|
|
when A_ATTACK:
|
|
/* Is our attackee still there? */
|
|
if (isalpha(winat(player.t_newpos.y,
|
|
player.t_newpos.x))) {
|
|
/* Our friend is still here */
|
|
player.t_action = A_NIL;
|
|
fight(&player.t_newpos, cur_weapon, FALSE);
|
|
}
|
|
else { /* Our monster has moved */
|
|
player.t_action = A_NIL;
|
|
}
|
|
when A_PICKUP:
|
|
player.t_action = A_NIL;
|
|
if (add_pack((struct linked_list *)NULL, FALSE)) {
|
|
char tch;
|
|
tch = mvwinch(stdscr, hero.y, hero.x) & A_CHARTEXT;
|
|
if (tch != FLOOR && tch != PASSAGE) {
|
|
player.t_action = A_PICKUP; /*get more */
|
|
player.t_no_move += 2 * movement(&player);
|
|
}
|
|
}
|
|
when A_THROW:
|
|
if (player.t_action == A_NIL) {
|
|
item = get_item(pack, "throw", ALL, FALSE, FALSE);
|
|
if (item != NULL && get_dir(&player.t_newpos)) {
|
|
player.t_action = A_THROW;
|
|
player.t_using = item;
|
|
player.t_no_move = 2 * movement(&player);
|
|
}
|
|
else
|
|
after = FALSE;
|
|
}
|
|
else {
|
|
missile(player.t_newpos.y, player.t_newpos.x,
|
|
player.t_using, &player);
|
|
player.t_action = A_NIL;
|
|
player.t_using = 0;
|
|
}
|
|
when 'a' :
|
|
if (player.t_action == A_NIL) {
|
|
if (get_dir(&player.t_newpos)) {
|
|
player.t_action = 'a';
|
|
player.t_no_move = 1 + movement(&player);
|
|
}
|
|
else
|
|
after = FALSE;
|
|
}
|
|
else {
|
|
affect();
|
|
player.t_action = A_NIL;
|
|
}
|
|
when 'A' : choose_qst();
|
|
when 'F' : /* frighten a monster */
|
|
if (player.t_action == A_NIL) {
|
|
player.t_action = 'F';
|
|
player.t_no_move = 2*movement(&player);
|
|
}
|
|
else {
|
|
after = FALSE;
|
|
player.t_action = A_NIL;
|
|
fright(NULL);
|
|
}
|
|
when 'g' : /* Give command: give slime-molds to monsters */
|
|
if (player.t_action == A_NIL) {
|
|
player.t_action = 'g';
|
|
player.t_no_move = 2*movement(&player);
|
|
}
|
|
else {
|
|
after = FALSE;
|
|
player.t_action = A_NIL;
|
|
give(NULL);
|
|
}
|
|
when 'G' :
|
|
if (player.t_action == A_NIL) {
|
|
player.t_action = 'G';
|
|
player.t_no_move = movement(&player);
|
|
}
|
|
else {
|
|
player.t_action = A_NIL;
|
|
gsense();
|
|
}
|
|
when 'i' : after = FALSE; inventory(pack, ALL);
|
|
when 'I' : after = FALSE; picky_inven();
|
|
when 'm' :
|
|
after = FALSE;
|
|
nameitem((struct linked_list *)NULL, TRUE);
|
|
when 'o' : option();
|
|
when 'O' : msg("Charactor type: %s Quest item: %s", char_class[char_type].name, rel_magic[quest_item].mi_name);
|
|
when ',' :
|
|
case 'P' :
|
|
if (levtype != POSTLEV) {
|
|
/* We charge 2 movement units per item */
|
|
player.t_no_move =
|
|
2 * grab(hero.y, hero.x) * movement(&player);
|
|
}
|
|
else {
|
|
/* Let's quote the wise guy a price */
|
|
buy_it();
|
|
after = FALSE;
|
|
}
|
|
when 'Q' : after = FALSE; quit(0);
|
|
when 'S' :
|
|
after = FALSE;
|
|
if (save_game())
|
|
exit_game(EXIT_CLS | EXIT_ENDWIN);
|
|
when 'v' : after = FALSE;
|
|
msg("Advanced xrogue, Version %s ", release);
|
|
when 'X' : /* trap sense */
|
|
after = FALSE;
|
|
if (player.t_action == A_NIL) {
|
|
player.t_action = 'X';
|
|
player.t_no_move = movement(&player);
|
|
}
|
|
else {
|
|
xsense();
|
|
player.t_action = A_NIL;
|
|
}
|
|
when '.' :
|
|
case KEY_B2 :
|
|
player.t_no_move = movement(&player); /* Rest */
|
|
player.t_action = A_NIL;
|
|
when ' ' : after = FALSE; /* Do Nothing */
|
|
when '>' : after = FALSE; d_level();
|
|
when '<' : after = FALSE; u_level();
|
|
when '=' : after = FALSE; display();
|
|
when '?' : after = FALSE; help();
|
|
|
|
/* no character descriptions yet until updated (help.c) */
|
|
/* when '\\' : after = FALSE; ident_hero(); */
|
|
when '\\' : msg("Charon (the Boatman) looks at you... ");
|
|
|
|
when '/' : after = FALSE; identify('\0');
|
|
when C_COUNT : count_gold();
|
|
when C_DIP : dip_it();
|
|
when C_DROP : player.t_action = C_DROP;
|
|
drop((struct linked_list *)NULL);
|
|
when C_EAT : eat();
|
|
when C_QUAFF : quaff(-1, 0, 0, TRUE);
|
|
when C_READ : read_scroll(-1, 0, TRUE);
|
|
when C_SETTRAP : set_trap(&player, hero.y, hero.x);
|
|
when C_SEARCH :
|
|
if (player.t_action == A_NIL) {
|
|
player.t_action = C_SEARCH;
|
|
player.t_no_move = 2 + movement(&player);
|
|
}
|
|
else {
|
|
search(FALSE, FALSE);
|
|
player.t_action = A_NIL;
|
|
}
|
|
when C_TAKEOFF : take_off();
|
|
when C_USE : use_mm(-1);
|
|
when C_WEAR : wear();
|
|
when C_WIELD : wield();
|
|
when C_ZAP : if (!player_zap(0, FALSE)) after=FALSE;
|
|
when C_CAST : cast();
|
|
when C_CHANT : chant();
|
|
when C_PRAY : pray();
|
|
when CTRL('B') : msg("Current score: %d",
|
|
pstats.s_exp + (long) purse);
|
|
when CTRL('E') : msg("Current food level: %d(2000)",
|
|
food_left);
|
|
when CTRL('L') : after = FALSE; clearok(curscr, TRUE);
|
|
touchwin(cw);
|
|
when CTRL('N') : after = FALSE; nameit();
|
|
when CTRL('O') : after = FALSE; opt_player();
|
|
when CTRL('R') : after = FALSE; msg(huh);
|
|
when CTRL('T') :
|
|
if (player.t_action == A_NIL) {
|
|
if (get_dir(&player.t_newpos)) {
|
|
player.t_action = CTRL('T');
|
|
player.t_no_move = 2 * movement(&player);
|
|
}
|
|
else
|
|
after = FALSE;
|
|
}
|
|
else {
|
|
steal();
|
|
player.t_action = A_NIL;
|
|
}
|
|
when ESC : /* Escape */
|
|
door_stop = FALSE;
|
|
count = 0;
|
|
after = FALSE;
|
|
when '#':
|
|
if (levtype == POSTLEV) /* buy something */
|
|
buy_it();
|
|
after = FALSE;
|
|
when '$':
|
|
if (levtype == POSTLEV) /* price something */
|
|
price_it();
|
|
after = FALSE;
|
|
when '%':
|
|
if (levtype == POSTLEV) /* sell something */
|
|
sell_it();
|
|
after = FALSE;
|
|
when '+': /* instant karma! */
|
|
switch (rnd(100)) {
|
|
case 0: msg("You waste some time. ");
|
|
when 5: msg("An oak tree in the garden. ");
|
|
when 10: msg("Character is what you become in the dark. ");
|
|
when 15: msg("May you live all the days of your life. ");
|
|
when 20: msg("A hero is no braver than an ordinary man, but he is brave five minutes longer. ");
|
|
when 25: msg("Get down! ");
|
|
when 30: msg("Go back to sleep. ");
|
|
when 35: msg("Be here now. ");
|
|
when 40: msg("Choose the rock that feels right to you. ");
|
|
when 45: msg("Wait... ");
|
|
when 50: msg("You take a break (yawn)... ");
|
|
when 55: msg("Without danger there is no pleasure. ");
|
|
when 60: msg("Define meaningless? ");
|
|
when 65: msg("Don't push your luck! ");
|
|
when 70: msg("Gung ho. ");
|
|
when 75: msg("You are inside a computer. ");
|
|
when 80: msg("Directive is now required... ");
|
|
when 85: msg("Charon (the Boatman) awaits you... ");
|
|
when 95: msg(nothing);
|
|
otherwise: msg("");
|
|
}
|
|
after = FALSE;
|
|
when CTRL('P') :
|
|
#ifdef WIZARD
|
|
after = FALSE;
|
|
if (wizard)
|
|
{
|
|
wizard = FALSE;
|
|
trader = 0;
|
|
msg("Not wizard any more");
|
|
}
|
|
else
|
|
{
|
|
if (waswizard || passwd())
|
|
{
|
|
msg("Welcome, O Mighty Wizard! ");
|
|
wizard = waswizard = TRUE;
|
|
}
|
|
else
|
|
msg("Sorry");
|
|
}
|
|
#else
|
|
msg("Sorry");
|
|
#endif
|
|
|
|
otherwise :
|
|
after = FALSE;
|
|
if (wizard) switch (ch) {
|
|
case 'M' : create_obj(TRUE, 0, 0);
|
|
when 'V' : msg("vlevel = %d turns = %d",
|
|
vlevel, turns);
|
|
when CTRL('A') : activity();
|
|
when CTRL('C') : do_teleport();
|
|
when CTRL('D') : level++;
|
|
take_with();
|
|
new_level(NORMLEV);
|
|
when CTRL('F') : overlay(stdscr,cw);
|
|
when CTRL('G') :
|
|
{
|
|
item=get_item(pack,"charge",STICK,FALSE,FALSE);
|
|
if (item != NULL) {
|
|
(OBJPTR(item))->o_charges=10000;
|
|
}
|
|
}
|
|
when CTRL('H') :
|
|
{
|
|
register int i, j;
|
|
register struct object *obj;
|
|
|
|
for (i = 0; i < 9; i++)
|
|
raise_level();
|
|
/*
|
|
* Give the rogue a sword
|
|
*/
|
|
if (cur_weapon==NULL || cur_weapon->o_type !=
|
|
RELIC) {
|
|
if (player.t_ctype == C_THIEF ||
|
|
player.t_ctype == C_ASSASSIN ||
|
|
player.t_ctype == C_MONK)
|
|
item = spec_item(WEAPON, BASWORD, 20, 20);
|
|
else
|
|
item = spec_item(WEAPON,TWOSWORD, 20, 20);
|
|
if (add_pack(item, TRUE))
|
|
{
|
|
cur_weapon = OBJPTR(item);
|
|
(OBJPTR(item))->o_flags |= (ISKNOW|ISPROT);
|
|
}
|
|
else
|
|
o_discard(item);
|
|
/*
|
|
* And his suit of armor
|
|
*/
|
|
if (player.t_ctype == C_THIEF ||
|
|
player.t_ctype == C_ASSASSIN ||
|
|
player.t_ctype == C_MONK)
|
|
j = PADDED_ARMOR;
|
|
else
|
|
j = PLATE_ARMOR;
|
|
item = spec_item(ARMOR, j, 20, 0);
|
|
obj = OBJPTR(item);
|
|
obj->o_flags |= (ISKNOW | ISPROT);
|
|
obj->o_weight = armors[j].a_wght;
|
|
if (add_pack(item, TRUE))
|
|
cur_armor = obj;
|
|
else
|
|
o_discard(item);
|
|
}
|
|
purse += 20000;
|
|
}
|
|
when CTRL('I') : inventory(lvl_obj, ALL);
|
|
when CTRL('J') : teleport();
|
|
when CTRL('K') : whatis((struct linked_list *)NULL);
|
|
when CTRL('W') : wanderer();
|
|
when CTRL('X') : overlay(mw,cw);
|
|
when CTRL('Y') : msg("food left: %d\tfood level: %d",
|
|
food_left, foodlev);
|
|
otherwise :
|
|
msg("Illegal wizard command '%s'.", unctrl(ch));
|
|
count = 0;
|
|
}
|
|
else
|
|
{
|
|
msg("Illegal command '%s'.", unctrl(ch));
|
|
count = 0;
|
|
after = FALSE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If he ran into something to take, let him pick it up.
|
|
* unless it's a trading post
|
|
*/
|
|
if (auto_pickup && take != 0 && levtype != POSTLEV) {
|
|
/* get ready to pick it up */
|
|
player.t_action = A_PICKUP;
|
|
player.t_no_move += 2 * movement(&player);
|
|
}
|
|
}
|
|
|
|
/* If he was fighting, let's stop (for now) */
|
|
if (player.t_quiet < 0) player.t_quiet = 0;
|
|
|
|
if (!running)
|
|
door_stop = FALSE;
|
|
|
|
if (after && segment >= 10) {
|
|
/*
|
|
* Kick off the rest if the daemons and fuses
|
|
*/
|
|
|
|
/*
|
|
* If player is infested, take off a hit point
|
|
*/
|
|
if (on(player, HASINFEST)) {
|
|
pstats.s_hpt -= infest_dam;
|
|
if (pstats.s_hpt == 50 || pstats.s_hpt == 25)
|
|
msg("You feel yourself withering away... ");
|
|
if (pstats.s_hpt < 1) {
|
|
msg("You die a festering mass. --More--");
|
|
wait_for(' ');
|
|
pstats.s_hpt = -1;
|
|
death(D_INFESTATION);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* The eye of Vecna is a constant drain on the player
|
|
*/
|
|
if (cur_relic[EYE_VECNA]) {
|
|
pstats.s_hpt -= 1;
|
|
if (pstats.s_hpt == 50 || pstats.s_hpt == 25)
|
|
msg("You feel Vecna's eye looking about. ");
|
|
if (pstats.s_hpt <= 10 && pstats.s_hpt >= 3)
|
|
msg("Vecna's eye moves about very quickly. ");
|
|
if (pstats.s_hpt < 1) {
|
|
msg("Vecna's curse is upon you! --More--");
|
|
wait_for(' ');
|
|
pstats.s_hpt = -1;
|
|
death(D_RELIC);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* if player has body rot then take off three hits
|
|
*/
|
|
if (on(player, DOROT)) {
|
|
pstats.s_hpt -= rnd(3)+1;
|
|
if (pstats.s_hpt == 50 || pstats.s_hpt == 25)
|
|
msg("Something really begins to stink and smell! ");
|
|
if (pstats.s_hpt < 1) {
|
|
msg("You keel over with rot. --More--");
|
|
wait_for(' ');
|
|
pstats.s_hpt = -1;
|
|
death(D_ROT);
|
|
}
|
|
}
|
|
do_daemons(AFTER);
|
|
do_fuses(AFTER);
|
|
}
|
|
} while (after == FALSE);
|
|
|
|
/* Make the monsters go */
|
|
if (--monst_current <= 0)
|
|
monst_current = monst_limit = runners(monst_limit);
|
|
|
|
if (++segment > 10) segment = 1;
|
|
reap(); /* bury all the dead monsters */
|
|
}
|
|
}
|
|
|
|
/*
|
|
* display
|
|
* tell the player what is at a certain coordinates assuming
|
|
* it can be seen.
|
|
*/
|
|
void
|
|
display(void)
|
|
{
|
|
coord c;
|
|
struct linked_list *item;
|
|
struct thing *tp;
|
|
int what;
|
|
|
|
msg("What do you want to display (* for help)?");
|
|
c = get_coordinates();
|
|
mpos = 0;
|
|
if (!cansee(c.y, c.x)) {
|
|
msg("You can't see what is there.");
|
|
return;
|
|
}
|
|
what = mvwinch(cw, c.y, c.x);
|
|
if (isalpha(what)) {
|
|
item = find_mons(c.y, c.x);
|
|
tp = THINGPTR(item);
|
|
msg("%s", monster_name(tp));
|
|
return;
|
|
}
|
|
if ((item = find_obj(c.y, c.x)) != NULL) {
|
|
msg("%s", inv_name(OBJPTR(item), FALSE));
|
|
return;
|
|
}
|
|
identify(what);
|
|
}
|
|
|
|
/*
|
|
* quit:
|
|
* Have player make certain, then exit.
|
|
*/
|
|
|
|
/*UNUSED*/
|
|
void
|
|
quit(int sig)
|
|
{
|
|
register int oy, ox;
|
|
|
|
NOOP(sig);
|
|
|
|
/*
|
|
* Reset the signal in case we got here via an interrupt
|
|
*/
|
|
|
|
if (signal(SIGINT, quit) != quit)
|
|
mpos = 0;
|
|
|
|
getyx(cw, oy, ox);
|
|
if (level < 1) { /* if not down in the dungeon proper; exit the game */
|
|
wclear(hw);
|
|
wmove(hw, lines-1, 0);
|
|
draw(hw);
|
|
wmove(hw, 12, 30);
|
|
wprintw(hw, "Good-bye!");
|
|
draw(hw);
|
|
exit_game(EXIT_ENDWIN);
|
|
}
|
|
msg("Really quit? <yes or no> "); /* otherwise ask about quitting */
|
|
draw(cw);
|
|
prbuf[0] = '\0';
|
|
if ((get_str(prbuf, msgw) == NORM) && strcmp(prbuf, "yes") == 0) {
|
|
clear();
|
|
move(lines-1, 0);
|
|
draw(stdscr);
|
|
writelog(pstats.s_exp + (long) purse, CHICKEN, 0);
|
|
score(pstats.s_exp + (long) purse, CHICKEN, 0);
|
|
exit_game(EXIT_ENDWIN);
|
|
}
|
|
else {
|
|
signal(SIGINT, quit);
|
|
wmove(msgw, 0, 0);
|
|
wclrtoeol(msgw);
|
|
draw(msgw);
|
|
status(FALSE);
|
|
wmove(cw, oy, ox);
|
|
draw(cw);
|
|
mpos = 0;
|
|
count = 0;
|
|
running = FALSE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* bugkill:
|
|
* killed by a program bug instead of voluntarily.
|
|
*/
|
|
|
|
void
|
|
bugkill(int sig)
|
|
{
|
|
signal(sig, quit); /* If we get it again, give up */
|
|
if (levtype == OUTSIDE) {
|
|
msg("Oh no! You walk right into a flying swarm of nasty little bugs!! ");
|
|
msg("One of them penetrates your brain!!! --More--");
|
|
}
|
|
else {
|
|
msg("Charon (the Boatman) has finally come for you... --More--");
|
|
}
|
|
wait_for(' ');
|
|
pstats.s_hpt = -1;
|
|
death(D_SIGNAL); /* Killed by a bug */
|
|
}
|
|
|
|
/*
|
|
* search:
|
|
* Player gropes about him to find hidden things.
|
|
*/
|
|
|
|
void
|
|
search(bool is_thief, bool door_chime)
|
|
{
|
|
register int x, y;
|
|
register char ch, /* The trap or door character */
|
|
sch; /* Trap or door character (as seen on screen) */
|
|
register unsigned char mch; /* Monster, if a monster is on the trap or door */
|
|
register struct linked_list *item;
|
|
register struct thing *mp; /* Status on surrounding monster */
|
|
|
|
/*
|
|
* 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++)
|
|
{
|
|
if (y==hero.y && x==hero.x)
|
|
continue;
|
|
|
|
if (x < 0 || y < 0 || x >= cols || y >= lines)
|
|
continue;
|
|
|
|
/* Mch and ch will be the same unless there is a monster here */
|
|
mch = winat(y, x) & A_CHARTEXT;
|
|
ch = mvwinch(stdscr, y, x) & A_CHARTEXT;
|
|
sch = mvwinch(cw, y, x) & A_CHARTEXT; /* What's on the screen */
|
|
|
|
if (door_chime == FALSE && isatrap(ch)) {
|
|
register struct trap *tp;
|
|
|
|
/* Is there a monster on the trap? */
|
|
if (mch != ch && (item = find_mons(y, x)) != NULL) {
|
|
mp = THINGPTR(item);
|
|
if (sch == mch) sch = mp->t_oldch;
|
|
}
|
|
else mp = NULL;
|
|
|
|
/*
|
|
* is this one found already?
|
|
*/
|
|
if (isatrap(sch))
|
|
continue; /* give him chance for other traps */
|
|
tp = trap_at(y, x);
|
|
/*
|
|
* if the thief set it then don't display it.
|
|
* if its not a thief he has 50/50 shot
|
|
*/
|
|
if((tp->tr_flags&ISTHIEFSET) || (!is_thief && rnd(100)>50))
|
|
continue; /* give him chance for other traps */
|
|
tp->tr_flags |= ISFOUND;
|
|
|
|
/* Let's update the screen */
|
|
if (mp != NULL && mvwinch(cw, y, x) == mch)
|
|
mp->t_oldch = ch; /* Will change when monst moves */
|
|
else mvwaddch(cw, y, x, ch);
|
|
|
|
count = 0;
|
|
running = FALSE;
|
|
|
|
/* Stop what we were doing */
|
|
player.t_no_move = movement(&player);
|
|
player.t_action = A_NIL;
|
|
player.t_using = NULL;
|
|
|
|
if (fight_flush) flushinp();
|
|
msg(tr_name(tp->tr_type));
|
|
}
|
|
else if (ch == SECRETDOOR) {
|
|
if (door_chime == TRUE || (!is_thief && rnd(100) < 20)) {
|
|
struct room *rp;
|
|
coord cp;
|
|
|
|
/* Is there a monster on the door? */
|
|
if (mch != ch && (item = find_mons(y, x)) != NULL) {
|
|
mp = THINGPTR(item);
|
|
|
|
/* Screen will change when monster moves */
|
|
if (sch == mch) mp->t_oldch = ch;
|
|
}
|
|
mvaddch(y, x, DOOR);
|
|
count = 0;
|
|
/*
|
|
* if its the entrance to a treasure room, wake it up
|
|
*/
|
|
cp.y = y;
|
|
cp.x = x;
|
|
rp = roomin(&cp);
|
|
if (rp->r_flags & ISTREAS)
|
|
wake_room(rp);
|
|
|
|
/* Make sure we don't shoot into the room */
|
|
if (door_chime == FALSE) {
|
|
count = 0;
|
|
running = FALSE;
|
|
|
|
/* Stop what we were doing */
|
|
player.t_no_move = movement(&player);
|
|
player.t_action = A_NIL;
|
|
player.t_using = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* d_level:
|
|
* He wants to go down a level
|
|
*/
|
|
|
|
void
|
|
d_level(void)
|
|
{
|
|
bool no_phase=FALSE;
|
|
char position = winat(hero.y, hero.x) & A_CHARTEXT;
|
|
int au;
|
|
|
|
|
|
/* If we are on a trading post, go to a trading post level. */
|
|
if (position == POST) {
|
|
take_with(); /* Take charmed monsters with you while shopping */
|
|
new_level(POSTLEV);
|
|
return;
|
|
}
|
|
|
|
/* Dive for gold */
|
|
if (position == POOL) {
|
|
if (rnd(300) < 2) {
|
|
msg("Oh no!!! You drown in the pool!!! --More--");
|
|
pstats.s_hpt = -1;
|
|
wait_for(' ');
|
|
death(D_DROWN);
|
|
}
|
|
else if (rnd(125) < 25) {
|
|
au = rnd(350) + (level * 10);
|
|
msg("You dive under the water momentarily.. ");
|
|
msg("You found %d gold pieces! ", au);
|
|
purse = purse + au;
|
|
return;
|
|
}
|
|
else return; /* doesn't happen all of the time */
|
|
}
|
|
|
|
/* Going down traps is hazardous */
|
|
switch (position) {
|
|
case WORMHOLE:
|
|
case TRAPDOOR:
|
|
case MAZETRAP:
|
|
case DARTTRAP:
|
|
case SLEEPTRAP:
|
|
case ARROWTRAP:
|
|
case BEARTRAP:
|
|
case TELTRAP:
|
|
msg ("You find yourself in some sort of quicksand!? ");
|
|
msg ("Hey! There are rock maggots in here!! ");
|
|
player.t_no_move += movement(&player) * FREEZETIME;
|
|
player.t_action = A_FREEZE;
|
|
msg("You can't move. "); /* spare monks */
|
|
if (!ISWEARING(R_HEALTH) && player.t_ctype != C_MONK) {
|
|
turn_on(player, DOROT);
|
|
msg("You feel your skin starting to rot and peel away!! ");
|
|
}
|
|
return;
|
|
}
|
|
|
|
/* If we are at a top-level trading post, we probably can't go down */
|
|
if (levtype == POSTLEV && level == 0 && position != STAIRS) {
|
|
msg("I see no way down.");
|
|
return;
|
|
}
|
|
|
|
if (winat(hero.y, hero.x) != STAIRS) {
|
|
if (off(player, CANINWALL) || /* Must use stairs if can't phase */
|
|
(levtype == OUTSIDE && rnd(100) < 90)) {
|
|
msg("I see no way down.");
|
|
return;
|
|
}
|
|
if (levtype == OUTSIDE) {
|
|
level++;
|
|
take_with();
|
|
new_level(NORMLEV);
|
|
if (no_phase) unphase();
|
|
return;
|
|
}
|
|
|
|
/* Is there any dungeon left below? */
|
|
if (level >= nfloors) {
|
|
msg("There is only solid rock below.");
|
|
return;
|
|
}
|
|
|
|
extinguish(unphase); /* Using phase to go down gets rid of it */
|
|
no_phase = TRUE;
|
|
}
|
|
|
|
/* Is this the bottom? */
|
|
if (level >= nfloors) {
|
|
msg("The stairway only goes up.");
|
|
return;
|
|
}
|
|
|
|
level++;
|
|
take_with();
|
|
new_level(NORMLEV);
|
|
if (no_phase) unphase();
|
|
}
|
|
|
|
/*
|
|
* u_level:
|
|
* He wants to go up a level
|
|
*/
|
|
|
|
void
|
|
u_level(void)
|
|
{
|
|
bool no_phase = FALSE;
|
|
register struct linked_list *item;
|
|
char position = winat(hero.y, hero.x) & A_CHARTEXT;
|
|
struct thing *tp;
|
|
struct object *obj;
|
|
|
|
/* You can go up into the outside if standing on top of a worm hole */
|
|
if (position == WORMHOLE) {
|
|
prev_max = 1000;
|
|
level--;
|
|
if (level <= 0) level = 1;
|
|
if (wizard) addmsg("Going up through a worm hole. ");
|
|
take_with();
|
|
new_level(OUTSIDE);
|
|
msg("You find yourself in strange surroundings... ");
|
|
return;
|
|
}
|
|
|
|
if (winat(hero.y, hero.x) != STAIRS) {
|
|
if (off(player, CANINWALL)) { /* Must use stairs if can't phase */
|
|
msg("I see no way up.");
|
|
return;
|
|
}
|
|
|
|
extinguish(unphase);
|
|
no_phase = TRUE;
|
|
}
|
|
|
|
if (position != STAIRS) return;
|
|
|
|
if (level == 0 || levtype == OUTSIDE) {
|
|
msg("The stairway only goes down.");
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* does he have the item he was quested to get?
|
|
*/
|
|
if (level == 1) {
|
|
for (item = pack; item != NULL; item = next(item)) {
|
|
obj = OBJPTR(item);
|
|
if (obj->o_type == RELIC && obj->o_which == quest_item)
|
|
total_winner();
|
|
}
|
|
}
|
|
/*
|
|
* check to see if he trapped a UNIQUE, If he did then put it back
|
|
* in the monster table for next time
|
|
*/
|
|
for (item = tlist; item != NULL; item = next(item)) {
|
|
tp = THINGPTR(item);
|
|
if (on(*tp, ISUNIQUE))
|
|
monsters[tp->t_index].m_normal = TRUE;
|
|
}
|
|
t_free_list(tlist); /* Monsters that fell below are long gone! */
|
|
|
|
if (levtype != POSTLEV)
|
|
level--;
|
|
if (level > 0) {
|
|
take_with();
|
|
new_level(NORMLEV);
|
|
}
|
|
else if (cur_max > level) {
|
|
prev_max = 1000; /* flag used in n_level.c */
|
|
level--;
|
|
if (level <= 0) level = 1;
|
|
if (wizard) msg("Going up: cur_max=%d level=%d. ", cur_max, level);
|
|
take_with();
|
|
new_level(OUTSIDE); /* Leaving the dungeon for outside */
|
|
msg("You emerge into the %s. ", daytime ? "eerie light" : "dark night");
|
|
return;
|
|
}
|
|
else {
|
|
prev_max = 1; /* flag used in n_level.c */
|
|
level = -1; /* Indicate that we are new to the outside */
|
|
if (wizard) msg("Going up: cur_max=%d level=%d. ", cur_max, level);
|
|
take_with();
|
|
new_level(OUTSIDE);
|
|
msg("You emerge into the %s. ", daytime ? "eerie light" : "dark night");
|
|
return;
|
|
}
|
|
|
|
if (no_phase) unphase();
|
|
}
|
|
|
|
/*
|
|
* Let him escape for a while
|
|
*/
|
|
|
|
void
|
|
shell(void)
|
|
{
|
|
/*
|
|
* Set the terminal back to original mode
|
|
*/
|
|
wclear(hw);
|
|
wmove(hw, lines-1, 0);
|
|
draw(hw);
|
|
endwin();
|
|
in_shell = TRUE;
|
|
fflush(stdout);
|
|
|
|
md_shellescape();
|
|
|
|
printf("%s", retstr);
|
|
fflush(stdout);
|
|
noecho();
|
|
crmode();
|
|
in_shell = FALSE;
|
|
wait_for('\n');
|
|
restscr(cw);
|
|
}
|
|
|
|
/*
|
|
* see what we want to name -- an item or a monster.
|
|
*/
|
|
void
|
|
nameit(void)
|
|
{
|
|
char answer;
|
|
|
|
msg("Name monster or item (m or i)? ");
|
|
answer = wgetch(cw);
|
|
mpos = 0;
|
|
|
|
while (answer != 'm' && answer != 'i' && answer != ESC) {
|
|
mpos = 0;
|
|
msg("Please specify m or i, for monster or item - ");
|
|
answer = wgetch(cw);
|
|
}
|
|
|
|
switch (answer) {
|
|
case 'm': namemonst();
|
|
when 'i': nameitem((struct linked_list *)NULL, FALSE);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* allow a user to call a potion, scroll, or ring something
|
|
*/
|
|
|
|
void
|
|
nameitem(struct linked_list *item, bool mark)
|
|
{
|
|
register struct object *obj;
|
|
register char **guess = NULL, *elsewise = NULL;
|
|
register bool *know;
|
|
|
|
if (item == NULL) {
|
|
if (mark) item = get_item(pack, "mark", ALL, FALSE, FALSE);
|
|
else item = get_item(pack, "name", CALLABLE, FALSE, FALSE);
|
|
if (item == NULL) return;
|
|
}
|
|
/*
|
|
* Make certain that it is somethings that we want to wear
|
|
*/
|
|
obj = OBJPTR(item);
|
|
switch (obj->o_type)
|
|
{
|
|
case RING:
|
|
guess = r_guess;
|
|
know = r_know;
|
|
elsewise = (r_guess[obj->o_which] != NULL ?
|
|
r_guess[obj->o_which] : r_stones[obj->o_which]);
|
|
when POTION:
|
|
guess = p_guess;
|
|
know = p_know;
|
|
elsewise = (p_guess[obj->o_which] != NULL ?
|
|
p_guess[obj->o_which] : p_colors[obj->o_which]);
|
|
when SCROLL:
|
|
guess = s_guess;
|
|
know = s_know;
|
|
elsewise = (s_guess[obj->o_which] != NULL ?
|
|
s_guess[obj->o_which] : s_names[obj->o_which]);
|
|
when STICK:
|
|
guess = ws_guess;
|
|
know = ws_know;
|
|
elsewise = (ws_guess[obj->o_which] != NULL ?
|
|
ws_guess[obj->o_which] : ws_made[obj->o_which]);
|
|
when MM:
|
|
guess = m_guess;
|
|
know = m_know;
|
|
elsewise = (m_guess[obj->o_which] != NULL ?
|
|
m_guess[obj->o_which] : "nothing");
|
|
otherwise:
|
|
if (!mark) {
|
|
msg("You can't call that anything.");
|
|
return;
|
|
}
|
|
else know = (bool *) 0;
|
|
}
|
|
if ((obj->o_flags & ISPOST) || (know && know[obj->o_which] && !mark)) {
|
|
msg("That has already been identified.");
|
|
return;
|
|
}
|
|
if (mark) {
|
|
if (obj->o_mark[0]) {
|
|
addmsg(terse ? "M" : "Was m");
|
|
msg("arked \"%s\"", obj->o_mark);
|
|
}
|
|
msg(terse ? "Mark it: " : "What do you want to mark it? ");
|
|
prbuf[0] = '\0';
|
|
}
|
|
else {
|
|
if (elsewise) {
|
|
addmsg(terse ? "N" : "Was n");
|
|
msg("amed \"%s\"", elsewise);
|
|
strcpy(prbuf, elsewise);
|
|
}
|
|
else prbuf[0] = '\0';
|
|
msg(terse ? "Name it: " : "What do you want to name it? ");
|
|
}
|
|
if (get_str(prbuf, msgw) == NORM) {
|
|
if (mark) {
|
|
strncpy((char *)obj->o_mark, prbuf, MARKLEN-1);
|
|
obj->o_mark[MARKLEN-1] = '\0';
|
|
}
|
|
else if (prbuf[0] != '\0') {
|
|
if (guess[obj->o_which] != NULL)
|
|
free(guess[obj->o_which]);
|
|
guess[obj->o_which] = new((unsigned int) strlen(prbuf) + 1);
|
|
strcpy(guess[obj->o_which], prbuf);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Name a monster */
|
|
|
|
void
|
|
namemonst(void)
|
|
{
|
|
register struct thing *tp;
|
|
struct linked_list *item;
|
|
coord c;
|
|
|
|
/* Find the monster */
|
|
msg("Choose the monster (* for help)");
|
|
c = get_coordinates();
|
|
|
|
/* Make sure we can see it and that it is a monster. */
|
|
mpos = 0;
|
|
if (!cansee(c.y, c.x)) {
|
|
msg("You can't see what is there.");
|
|
return;
|
|
}
|
|
|
|
if (isalpha(mvwinch(cw, c.y, c.x))) {
|
|
item = find_mons(c.y, c.x);
|
|
if (item != NULL) {
|
|
tp = THINGPTR(item);
|
|
if (tp->t_name == NULL)
|
|
strcpy(prbuf, monsters[tp->t_index].m_name);
|
|
else
|
|
strcpy(prbuf, tp->t_name);
|
|
|
|
addmsg(terse ? "N" : "Was n");
|
|
msg("amed \"%s\"", prbuf);
|
|
msg(terse ? "Name it: " : "What do you want to name it? ");
|
|
|
|
if (get_str(prbuf, msgw) == NORM) {
|
|
if (prbuf[0] != '\0') {
|
|
if (tp->t_name != NULL)
|
|
free(tp->t_name);
|
|
tp->t_name = new((unsigned int) strlen(prbuf) + 1);
|
|
strcpy(tp->t_name, prbuf);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
msg("There is no monster there to name.");
|
|
}
|
|
|
|
void
|
|
count_gold(void)
|
|
{
|
|
if (player.t_action != C_COUNT) {
|
|
msg("You take a break to count your money.. ");
|
|
player.t_using = NULL;
|
|
player.t_action = C_COUNT; /* We are counting */
|
|
if (purse > 500000) msg("This may take some time... 10, 20, 30...");
|
|
player.t_no_move = (purse/75000 + 1) * movement(&player);
|
|
return;
|
|
}
|
|
if (purse > 10000)
|
|
msg("You have %ld pieces of gold. ", purse);
|
|
else if (purse == 1)
|
|
msg("You have 1 piece of gold. ");
|
|
else
|
|
msg("You have %ld gold pieces. ", purse);
|
|
player.t_action = A_NIL;
|
|
}
|
|
|
|
/*
|
|
* Teleport somewhere, anywhere...
|
|
*/
|
|
|
|
void
|
|
do_teleport(void)
|
|
{
|
|
int tlev;
|
|
prbuf[0] = '\0';
|
|
msg("To which level do you wish to teleport? ");
|
|
if(get_str(prbuf,msgw) == NORM) {
|
|
tlev = atoi(prbuf);
|
|
if (quest_item == ALTERAN_CARD || wizard) {
|
|
if (wizard && (tlev < 1 || tlev > LEVEL)) { /* wizard */
|
|
mpos = 0;
|
|
msg("The power of teleportation does have its limitations. ");
|
|
return;
|
|
}
|
|
else if (!wizard && (tlev < 10 || tlev > LEVEL)) {
|
|
mpos = 0;
|
|
msg("The power of teleportation does have its limitations. ");
|
|
return;
|
|
}
|
|
else if (tlev >= LEVEL-100 && tlev < LEVEL-50) {
|
|
levtype = OUTSIDE;
|
|
level = LEVEL-100;
|
|
prev_max = 1000; /* a flag for going outside */
|
|
}
|
|
else if (tlev >= LEVEL-150 && tlev < LEVEL-100) {
|
|
levtype = MAZELEV;
|
|
level = LEVEL-150;
|
|
}
|
|
else if (tlev >= LEVEL-200 && tlev < LEVEL-150) {
|
|
levtype = POSTLEV;
|
|
level = LEVEL-200;
|
|
}
|
|
else {
|
|
levtype = NORMLEV;
|
|
level = tlev;
|
|
}
|
|
}
|
|
else if (tlev < 40 || tlev > 399) { /* not quest item or wizard */
|
|
mpos = 0;
|
|
msg("The power of teleportation does have its limitations. ");
|
|
return;
|
|
}
|
|
else {
|
|
levtype = NORMLEV;
|
|
level = tlev;
|
|
}
|
|
|
|
/* okay, now send him off */
|
|
cur_max = level; /* deepest he's been */
|
|
new_level(levtype);
|
|
}
|
|
}
|
|
|