From: PatR Date: Sun, 22 May 2022 00:40:52 +0000 (-0700) Subject: add new #wizkill command X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=af55e3d027870557d0ca9003ac7f224afdd06d6c;p=nethack add new #wizkill command Add a way to get rid of specific monsters in wizard mode without fighting, zapping, &c. #wizkill command lets you kill creatures by picking them with getpos(). You can pick multiple monsters by targetting them one after another. You don't have to be able to see or sense them but if you target a spot that has no monster, the command ends. By default, the hero gets credit or blame as if having killed the targets but #wizkill can be preceded by 'm' prefix to treat their deaths as if they had been caused by a monster. --- 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);