more queued commands

This attempts to make item-actions, #herecmd, and #therecmd be more
robust.  When rhack() or yn_function() take queued input off cmdq
and get something unexpected, discard the rest of the queue.

It also fixes the two crash cases that entrez reported.  There are
bound to be others though.

I think a lot of actions that can be executed by queued input are
going to need nomul(0) calls to handle repeat counts that should be
ended early if something unexpected happens or something expected
fails to happen.  But that clears cmdq so may be tricky to decide
where to use.
This commit is contained in:
PatR
2022-04-17 13:36:38 -07:00
parent ec4749914a
commit 54189e795b
2 changed files with 39 additions and 36 deletions

View File

@@ -3969,9 +3969,10 @@ reset_cmd_vars(boolean reset_cmdq)
void
rhack(char *cmd)
{
char queuedkeystroke[2];
int spkey = NHKF_ESC;
boolean bad_command, firsttime = (cmd == 0);
struct _cmd_queue *cmdq = NULL;
struct _cmd_queue cq, *cmdq = NULL;
const struct ext_func_tab *cmdq_ec = 0, *prefix_seen = 0;
boolean was_m_prefix = FALSE;
@@ -3983,19 +3984,16 @@ rhack(char *cmd)
#endif
if ((cmdq = cmdq_pop()) != 0) {
/* doing queued commands */
if (cmdq->typ == CMDQ_KEY) {
static char commandline[2];
if (!cmd)
cmd = commandline;
cmd[0] = cmdq->key;
cmd[1] = '\0';
} else if (cmdq->typ == CMDQ_EXTCMD) {
cmdq_ec = cmdq->ec_entry;
}
cq = *cmdq;
free(cmdq);
if (cmdq_ec)
if (cq.typ == CMDQ_EXTCMD && (cmdq_ec = cq.ec_entry) != 0)
goto do_cmdq_extcmd;
cmd = queuedkeystroke;
/* already handled a queued command (goto do_cmdq_extcmd);
if something other than a key is queued, we'll drop down
to the !*cmd handling which clears out the command-queue */
cmd[0] = (cq.typ == CMDQ_KEY) ? cq.key : '\0';
cmd[1] = '\0';
} else if (firsttime) {
cmd = parse();
/* parse() pushed a cmd but didn't return any key */
@@ -4003,21 +4001,17 @@ rhack(char *cmd)
goto got_prefix_input;
}
if (*cmd == g.Cmd.spkeys[NHKF_ESC]) {
/* if there's no command, there's nothing to do except reset */
if (!cmd || !*cmd || *cmd == (char) 0377
|| *cmd == g.Cmd.spkeys[NHKF_ESC]) {
if (!cmd || *cmd != g.Cmd.spkeys[NHKF_ESC])
nhbell();
reset_cmd_vars(TRUE);
return;
}
/* Special case of *cmd == ' ' handled better below */
if (!*cmd || *cmd == (char) 0377) {
nhbell();
reset_cmd_vars(TRUE);
return; /* probably we just had an interrupt */
}
/* handle most movement commands */
g.context.travel = g.context.travel1 = 0;
{
register const struct ext_func_tab *tlist;
int res, (*func)(void);
@@ -4117,7 +4111,7 @@ rhack(char *cmd)
} else if ((res & ECMD_TIME) != 0) {
g.context.move = TRUE;
} else { /* ECMD_OK */
reset_cmd_vars(FALSE);
reset_cmd_vars(g.multi < 0);
}
return;
}
@@ -4911,6 +4905,8 @@ there_cmd_menu(int x, int y, int mod)
cmdq_add_dir(dx, dy, 0);
break;
case MCMD_REMOVE_SADDLE:
/* m-prefix for #loot: skip any floor containers */
cmdq_add_ec(do_reqmenu);
cmdq_add_ec(doloot);
cmdq_add_dir(dx, dy, 0);
cmdq_add_key('y'); /* "Do you want to remove the saddle ..." */
@@ -4918,6 +4914,7 @@ there_cmd_menu(int x, int y, int mod)
case MCMD_APPLY_SADDLE:
{
struct obj *otmp = carrying(SADDLE);
if (otmp) {
cmdq_add_ec(doapply);
cmdq_add_key(otmp->invlet);
@@ -5466,7 +5463,7 @@ doclicklook(void)
char
yn_function(const char *query, const char *resp, char def)
{
char res, qbuf[QBUFSZ];
char res = '\033', qbuf[QBUFSZ];
struct _cmd_queue *cmdq = cmdq_pop();
#ifdef DUMPLOG
unsigned idx = g.saved_pline_index;
@@ -5484,8 +5481,11 @@ yn_function(const char *query, const char *resp, char def)
Strcpy(&qbuf[QBUFSZ - 1 - 3], "...");
query = qbuf;
}
if (cmdq && cmdq->typ == CMDQ_KEY) {
res = cmdq->key;
if (cmdq) {
if (cmdq->typ == CMDQ_KEY)
res = cmdq->key;
else
cmdq_clear(); /* 'res' is ESC */
} else {
res = (*windowprocs.win_yn_function)(query, resp, def);
}

View File

@@ -1817,8 +1817,9 @@ container_at(int x, int y, boolean countem)
}
static boolean
able_to_loot(int x, int y,
boolean looting) /* loot vs tip */
able_to_loot(
int x, int y,
boolean looting) /* loot vs tip */
{
const char *verb = looting ? "loot" : "tip";
struct trap *t = t_at(x, y);
@@ -2045,21 +2046,20 @@ doloot_core(void)
if (!get_adjacent_loc("Loot in what direction?",
"Invalid loot location", u.ux, u.uy, &cc))
return ECMD_OK;
if (u_at(cc.x, cc.y)) {
underfoot = TRUE;
if (container_at(cc.x, cc.y, FALSE))
goto lootcont;
} else
underfoot = FALSE;
underfoot = u_at(cc.x, cc.y);
if (underfoot && container_at(cc.x, cc.y, FALSE))
goto lootcont;
if (u.dz < 0) {
You("%s to loot on the %s.", dont_find_anything,
ceiling(cc.x, cc.y));
timepassed = 1;
return (timepassed ? ECMD_TIME : ECMD_OK);
return ECMD_TIME;
}
mtmp = m_at(cc.x, cc.y);
if (mtmp)
if (mtmp) {
timepassed = loot_mon(mtmp, &prev_inquiry, &prev_loot);
if (timepassed)
underfoot = 1; /* not true but skips dont_find_anything */
}
/* always use a turn when choosing a direction is impaired,
even if you've successfully targetted a saddled creature
and then answered "no" to the "remove its saddle?" prompt */
@@ -2201,6 +2201,9 @@ loot_mon(struct monst *mtmp, int *passed_info, boolean *prev_loot)
return 1;
}
extract_from_minvent(mtmp, otmp, TRUE, FALSE);
if (flags.verbose)
You("take %s off of %s.",
thesimpleoname(otmp), mon_nam(mtmp));
otmp = hold_another_object(otmp, "You drop %s!", doname(otmp),
(const char *) 0);
nhUse(otmp);