diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index 80aa63355..80f5aedae 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -1709,6 +1709,10 @@ Default key is \(oq\(haI\(cq. Set one or more intrinsic attributes. Autocompletes. Debug mode only. +.lp "#wizkill " +Remove monsters from play by just pointing at them. +Autocompletes. +Debug mode only. .lp #wizlevelport Teleport to another level. Autocompletes. diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index 27cc137e7..51e808236 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -1837,6 +1837,11 @@ Set one or more intrinsic attributes. Autocompletes. Debug mode only. %.lp +\item[\tb{\#wizkill}] +Remove monsters from play by just pointing at them. +Autocompletes. +Debug mode only. +%.lp \item[\tb{\#wizlevelport}] Teleport to another level. Autocompletes. diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 5bb014b5d..1b2457c1a 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1641,6 +1641,7 @@ display detected door traps and chest traps as trapped doors and trapped if built with DEBUG enabled and running in wizard mode, starting play with DEBUGFILES=seethru in environment makes clouds on the Plane of Air, water on Plane of Water, and fumaroles on Plane of Fire be transparent +add wizard mode #wizkill command to remove monster(s) from play Platform- and/or Interface-Specific New Features diff --git a/src/cmd.c b/src/cmd.c index 642c4e3d8..1809e61cd 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -114,6 +114,7 @@ static int wiz_where(void); static int wiz_detect(void); static int wiz_panic(void); static int wiz_polyself(void); +static int wiz_kill(void); static int wiz_load_lua(void); static int wiz_level_tele(void); static int wiz_level_change(void); @@ -1155,6 +1156,68 @@ wiz_detect(void) return ECMD_OK; } +/* the #wizkill command - pick targets and reduce them to 0HP; + by default, the hero is credited/blamed; use 'm' prefix to avoid that */ +static int +wiz_kill() +{ + struct monst *mtmp; + coord cc; + int ans; + char c, qbuf[QBUFSZ]; + const char *prompt = "Pick first monster to slay"; + boolean save_verbose = flags.verbose; + + cc.x = u.ux, cc.y = u.uy; + for (;;) { + pline("%s:", prompt); + prompt = "Next monster"; + + flags.verbose = FALSE; + ans = getpos(&cc, TRUE, "a monster"); + flags.verbose = save_verbose; + if (ans < 0 || cc.x < 1) + break; + + mtmp = 0; + if (u_at(cc.x, cc.y)) { + if (u.usteed) { + Sprintf(qbuf, "Kill %.110s?", mon_nam(u.usteed)); + if ((c = ynq(qbuf)) == 'q') + break; + if (c == 'y') + mtmp = u.usteed; + } + if (!mtmp) { + Sprintf(qbuf, "%s?", Role_if(PM_SAMURAI) ? "Perform seppuku" + : "Commit suicide"); + if (paranoid_query(TRUE, qbuf)) { + Sprintf(g.killer.name, "%s own player", uhis()); + g.killer.format = KILLED_BY; + done(DIED); + } + break; + } + } else { + mtmp = m_at(cc.x, cc.y); + } + + if (mtmp) { + /* we don't require that monster be seen or sensed but when it + isn't, death message will be "You kill it" or "It is killed" */ + if (!iflags.menu_requested) + killed(mtmp); /* normal case: hero is credited/blamed */ + else + monkilled(mtmp, "", AD_PHYS); /* 'm'-prefix */ + } else { + There("is no monster there."); + break; + } + } + /* distinction between ECMD_CANCEL and ECMD_OK is unimportant here */ + return ECMD_OK; /* no time elapses */ +} + /* the #wizloadlua command - load an arbitrary lua file */ static int wiz_load_lua(void) @@ -1166,7 +1229,7 @@ wiz_load_lua(void) buf[0] = '\0'; getlin("Load which lua file?", buf); if (buf[0] == '\033' || buf[0] == '\0') - return 0; + return ECMD_CANCEL; if (!strchr(buf, '.')) strcat(buf, ".lua"); (void) load_lua(buf, &sbi); @@ -1185,7 +1248,7 @@ wiz_load_splua(void) buf[0] = '\0'; getlin("Load which des lua file?", buf); if (buf[0] == '\033' || buf[0] == '\0') - return 0; + return ECMD_CANCEL; if (!strchr(buf, '.')) strcat(buf, ".lua"); @@ -1303,7 +1366,7 @@ wiz_telekinesis(void) pline("Pick a monster to hurtle."); do { ans = getpos(&cc, TRUE, "a monster"); - if (ans < 0 || cc.x < 0) + if (ans < 0 || cc.x < 1) return ECMD_CANCEL; if ((((mtmp = m_at(cc.x, cc.y)) != 0) && canspotmon(mtmp)) @@ -2524,6 +2587,9 @@ struct ext_func_tab extcmdlist[] = { wiz_identify, IFBURIED | WIZMODECMD, NULL }, { '\0', "wizintrinsic", "set an intrinsic", wiz_intrinsic, IFBURIED | AUTOCOMPLETE | WIZMODECMD, NULL }, + { '\0', "wizkill", "slay a monster", + wiz_kill, (IFBURIED | AUTOCOMPLETE | WIZMODECMD + | CMD_M_PREFIX | NOFUZZERCMD), NULL }, { C('v'), "wizlevelport", "teleport to another level", wiz_level_tele, IFBURIED | WIZMODECMD | CMD_M_PREFIX, NULL }, { '\0', "wizloaddes", "load and execute a des-file lua script", diff --git a/src/do_name.c b/src/do_name.c index c7e5a5c02..bf927d851 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -136,6 +136,8 @@ getpos_help(boolean force, const char *goal) visctrl(g.Cmd.spkeys[NHKF_GETPOS_MON_PREV]), GLOC_MONS); } + if (goal && !strcmp(goal, "a monster")) + goto skip_non_mons; if (!iflags.terrainmode || (iflags.terrainmode & TER_OBJ) != 0) { getpos_help_keyxhelp(tmpwin, visctrl(g.Cmd.spkeys[NHKF_GETPOS_OBJ_NEXT]), @@ -195,6 +197,7 @@ getpos_help(boolean force, const char *goal) : "(Reset 'whatis_coord' option to omit coordinates from '%s' text.)", visctrl(g.Cmd.spkeys[NHKF_GETPOS_AUTODESC])); } + skip_non_mons: /* disgusting hack; the alternate selection characters work for any getpos call, but only matter for dowhatis (and doquickwhatis) */ doing_what_is = (goal == what_is_an_unknown_object);