add 'montelecontrol' option (wizard-mode only)

Add a new debugging option, 'montelecontrol', that allows a wizard-
mode player to choose a teleporting monster's destination.  If player
picks a bad spot, confirmation will be requested.  If accepted, the
spot will be used even though the consequences could be bad; that's
on the player.  If rejected, the destination will be assigned as if
no control had been attempted rather than try again.

The fuzzer isn't allowed to override a bad spot if it tries to pick
one.  That would probably trigger a sanity_check warning; the fuzzer
causes impossible warnings to behave as if panic, so accepting a bad
spot would just be fuzzer suicide.  It is allowed to randomly set the
option and maybe--though extremely unlikely--randomly pick a valid
controlled destination.
This commit is contained in:
PatR
2023-06-09 00:56:53 -07:00
parent 62eacb11c4
commit e475dca209
8 changed files with 77 additions and 2 deletions

View File

@@ -3564,6 +3564,17 @@ mnexto(struct monst *mtmp, unsigned int rlocflags)
deal_with_overcrowding(mtmp);
return;
}
/* wizard-mode player can choose destination by setting 'montelecontrol'
option; enexto()'s value for 'mm' will be the default; 'savemm' is
used to make sure player doesn't choose hero's location and then
answer 'y' to the 'override invalid spot' prompt */
if (iflags.mon_telecontrol) {
coord savemm = mm;
if (!control_mon_tele(mtmp, &mm, rlocflags, FALSE))
mm = savemm;
}
rloc_to_flag(mtmp, mm.x, mm.y, rlocflags);
return;
}
@@ -3595,6 +3606,7 @@ maybe_mnexto(struct monst *mtmp)
if (couldsee(mm.x, mm.y)
/* don't move grid bugs diagonally */
&& (diagok || mm.x == mtmp->mx || mm.y == mtmp->my)) {
/* [this doesn't honor the 'montelecontrol' option] */
rloc_to(mtmp, mm.x, mm.y);
return;
}
@@ -3658,6 +3670,7 @@ mnearto(
newx = mm.x;
newy = mm.y;
}
/* [this doesn't honor the 'montelecontrol' option] */
rloc_to_flag(mtmp, newx, newy, rlocflags);
if (move_other && othermon) {

View File

@@ -1735,6 +1735,16 @@ rloc(
goto found_xy;
}
/* wizard-mode player can choose destination by setting 'montelecontrol'
option; ignored if/when this is arrival of a migrating monster */
if (iflags.mon_telecontrol && mtmp->mx) {
cc.x = mtmp->mx, cc.y = mtmp->my;
if (control_mon_tele(mtmp, &cc, rlocflags, TRUE)) {
x = cc.x, y = cc.y;
goto found_xy;
}
}
/* this used to try randomly 1000 times, then fallback to left-to-right
top-to-bottom exhaustive check; now that the exhaustive check uses
randomized order, reduce the number of random attempts to 50;
@@ -1788,6 +1798,45 @@ rloc(
return TRUE;
}
/* let wizard-mode player choose a teleporting monster's destination */
boolean
control_mon_tele(
struct monst *mon,
coord *cc_p, /* input: default spot; output: player selected spot */
unsigned rlocflags,
boolean via_rloc)
{
char tcbuf[BUFSZ];
if (!isok(cc_p->x, cc_p->y)) {
cc_p->x = mon->mx, cc_p->y = mon->my;
if (!isok(cc_p->x, cc_p->y))
cc_p->x = u.ux, cc_p->y = u.uy;
}
if (!wizard || !iflags.mon_telecontrol)
return FALSE;
pline("Teleport %s @ <%d,%d> where?",
noit_mon_nam(mon), mon->mx, mon->my);
/* getpos '?' will show "Move the cursor to <where to teleport Foo>:" */
Sprintf(tcbuf, "where to teleport %s", noit_mon_nam(mon));
if (getpos(cc_p, FALSE, tcbuf) >= 0 && !u_at(cc_p->x, cc_p->y)) {
if (via_rloc
? rloc_pos_ok(cc_p->x, cc_p->y, mon)
: goodpos(cc_p->x, cc_p->y, mon, rlocflags))
return TRUE;
if (!iflags.debug_fuzzer) {
Sprintf(tcbuf, "<%d,%d> is not considered viable; force anyway?",
mon->mx, mon->my);
if (y_n(tcbuf) == 'y')
return TRUE;
}
}
pline("%s destination.", via_rloc ? "Picking random" : "Using derived");
return FALSE;
}
static void
mvault_tele(struct monst* mtmp)
{