From 97928335ae7c46435336d9daf179d12617be8ccb Mon Sep 17 00:00:00 2001 From: "nethack.rankin" Date: Fri, 25 May 2007 02:01:54 +0000 Subject: [PATCH] C/#name menu, calling old discoveries [1 of 2] (trunk only) Implement 's menu-mode for #name, primarily because it is the natural place to add [re]naming entries in the discoveries list, something that was requested in the newsgroup ten or so years ago. The latter allows changing the type name of something which has previously been named and is no longer being carried. This also makes the C command become a synonym for #name or vice versa; one or the other could now be reassigned to something else. #name What do you want to name? a - a monster b - a particular object in inventory c - a type of object in inventory d - a type of object on discoveries list Menu group accelerators provide unseen alternate choices: C for monster, y for individual object, n for object type (and d for discoveries, but that's only interesting if inventory is empty so that usual b & c are omitted and discoveries entry moves up to b). These alternates allow `#name y' and `#name n' to work the same as before, for users who have trouble retraining their fingers. Using C to name a monster now takes an extra keystroke, but using `C C' for it could make that be less annoying. --- include/extern.h | 5 ++- src/cmd.c | 13 +++--- src/do_name.c | 113 +++++++++++++++++++++++++++++++++-------------- src/invent.c | 1 + src/o_init.c | 82 +++++++++++++++++++++++++++++++--- 5 files changed, 168 insertions(+), 46 deletions(-) diff --git a/include/extern.h b/include/extern.h index d15118c6d..fbbaea8ee 100644 --- a/include/extern.h +++ b/include/extern.h @@ -365,9 +365,9 @@ E void FDECL(new_oname, (struct obj *,int)); E void FDECL(free_oname, (struct obj *)); E const char *FDECL(safe_oname, (struct obj *)); E struct monst *FDECL(christen_monst, (struct monst *,const char *)); -E int NDECL(do_mname); E struct obj *FDECL(oname, (struct obj *,const char *)); -E int NDECL(ddocall); +E boolean FDECL(objtyp_is_callable, (int)); +E int NDECL(docallcmd); E void FDECL(docall, (struct obj *)); E const char *NDECL(rndghostname); E char *FDECL(x_monnam, (struct monst *,int,const char *,int,BOOLEAN_P)); @@ -1513,6 +1513,7 @@ E void FDECL(restnames, (int)); E void FDECL(discover_object, (int,BOOLEAN_P,BOOLEAN_P)); E void FDECL(undiscover_object, (int)); E int NDECL(dodiscovered); +E void NDECL(rename_disco); /* ### objects.c ### */ diff --git a/src/cmd.c b/src/cmd.c index d31f2ce52..68c2a7d9b 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -42,8 +42,7 @@ extern int NDECL(dodown); /**/ extern int NDECL(doup); /**/ extern int NDECL(donull); /**/ extern int NDECL(dowipe); /**/ -extern int NDECL(do_mname); /**/ -extern int NDECL(ddocall); /**/ +extern int NDECL(docallcnd); /**/ extern int NDECL(dotakeoff); /**/ extern int NDECL(doremring); /**/ extern int NDECL(dowear); /**/ @@ -1646,7 +1645,7 @@ static const struct func_tab cmdlist[] = { {M('a'), TRUE, doorganize}, /* 'b', 'B' : go sw */ {'c', FALSE, doclose}, - {'C', TRUE, do_mname}, + {'C', TRUE, docallcmd}, {M('c'), TRUE, dotalk}, {'d', FALSE, dodrop}, {'D', FALSE, doddrop}, @@ -1671,9 +1670,9 @@ static const struct func_tab cmdlist[] = { {M('l'), FALSE, doloot}, /* 'n' prefixes a count if number_pad is on */ {M('m'), TRUE, domonability}, - {'N', TRUE, ddocall}, /* if number_pad is on */ - {M('n'), TRUE, ddocall}, - {M('N'), TRUE, ddocall}, + {'N', TRUE, docallcmd}, /* if number_pad is on */ + {M('n'), TRUE, docallcmd}, + {M('N'), TRUE, docallcmd}, {'o', FALSE, doopen}, {'O', TRUE, doset}, {M('o'), FALSE, dosacrifice}, @@ -1753,7 +1752,7 @@ struct ext_func_tab extcmdlist[] = { {"jump", "jump to a location", dojump, FALSE}, {"loot", "loot a box on the floor", doloot, FALSE}, {"monster", "use a monster's special ability", domonability, TRUE}, - {"name", "name an item or type of object", ddocall, TRUE}, + {"name", "name an item or type of object", docallcmd, TRUE}, {"offer", "offer a sacrifice to the gods", dosacrifice, FALSE}, #ifdef DUNGEON_OVERVIEW {"overview", "show an overview of the dungeon", dooverview, TRUE}, diff --git a/src/do_name.c b/src/do_name.c index 885e69554..e57126c32 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -1,12 +1,13 @@ -/* SCCS Id: @(#)do_name.c 3.5 2006/05/22 */ +/* SCCS Id: @(#)do_name.c 3.5 2007/05/12 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" -STATIC_DCL void FDECL(do_oname, (struct obj *)); -STATIC_DCL void FDECL(getpos_help, (BOOLEAN_P,const char *)); STATIC_DCL char *NDECL(nextmbuf); +STATIC_DCL void FDECL(getpos_help, (BOOLEAN_P,const char *)); +STATIC_DCL void NDECL(do_mname); +STATIC_DCL void FDECL(do_oname, (struct obj *)); extern const char what_is_an_unknown_object[]; /* from pager.c */ @@ -305,7 +306,8 @@ const char *name; return mtmp; } -int +/* allow player to assign a name to some chosen monster */ +STATIC_OVL void do_mname() { char buf[BUFSZ], monnambuf[BUFSZ]; @@ -316,13 +318,13 @@ do_mname() if (Hallucination) { You("would never recognize it anyway."); - return 0; + return; } cc.x = u.ux; cc.y = u.uy; if (getpos(&cc, FALSE, "the monster you want to name") < 0 || (cx = cc.x) < 0) - return 0; + return; cy = cc.y; if (cx == u.ux && cy == u.uy) { @@ -336,7 +338,7 @@ do_mname() (flags.female ? "beautiful" : "handsome") : "ugly", plname); - return(0); + return; #ifdef STEED } #endif @@ -349,13 +351,13 @@ do_mname() || mtmp->m_ap_type == M_AP_OBJECT || (mtmp->minvis && !See_invisible)))) { pline("I see no monster there."); - return(0); + return; } /* special case similar to the one in lookat() */ Sprintf(qbuf, "What do you want to call %s?", distant_monnam(mtmp, ARTICLE_THE, monnambuf)); getlin(qbuf,buf); - if(!*buf || *buf == '\033') return(0); + if (!*buf || *buf == '\033') return; /* strip leading and trailing spaces; unnames monster if all spaces */ (void)mungspaces(buf); @@ -372,7 +374,6 @@ do_mname() pline("%s will not accept the name %s.", upstart(monnambuf), buf); else (void) christen_monst(mtmp, buf); - return(0); } /* @@ -459,34 +460,70 @@ static NEARDATA const char callable[] = { SCROLL_CLASS, POTION_CLASS, WAND_CLASS, RING_CLASS, AMULET_CLASS, GEM_CLASS, SPBOOK_CLASS, ARMOR_CLASS, TOOL_CLASS, 0 }; -int -ddocall() +boolean +objtyp_is_callable(i) +int i; { - register struct obj *obj; -#ifdef REDO - char ch; -#endif - char allowall[2]; + return (boolean)(objects[i].oc_uname || + (OBJ_DESCR(objects[i]) && + index(callable, objects[i].oc_class))); +} - switch( -#ifdef REDO - ch = +/* C and #name commands - player can name monster or object or type of obj */ +int +docallcmd() +{ + struct obj *obj; + winid win; + anything any; + menu_item *pick_list = 0; + char ch, allowall[2]; + + win = create_nhwindow(NHW_MENU); + start_menu(win); + any = zeroany; + any.a_char = 'm'; /* entry 'a', group accelator 'C' */ + add_menu(win, NO_GLYPH, &any, 0, 'C', ATR_NONE, + "a monster", MENU_UNSELECTED); + if (invent) { + /* we use y and n as accelerators so that we can accept user's + response keyed to old "name an individual object?" prompt */ + any.a_char = 'i'; /* entry 'b', group accelator 'y' */ + add_menu(win, NO_GLYPH, &any, 0, 'y', ATR_NONE, + "a particular object in inventory", MENU_UNSELECTED); + any.a_char = 'o'; /* entry 'c', group accelator 'n' */ + add_menu(win, NO_GLYPH, &any, 0, 'n', ATR_NONE, + "a type of object in inventory", MENU_UNSELECTED); + } + any.a_char = 'd'; /* entry 'd' (or 'b'), group accelator 'd' */ + add_menu(win, NO_GLYPH, &any, 0, any.a_char, ATR_NONE, + "a type of object on discoveries list", MENU_UNSELECTED); +#if 0 + any.a_char = 'f'; /* entry 'e' (or 'c'), group accelator 'f' */ + add_menu(win, NO_GLYPH, &any, 0, any.a_char, ATR_NONE, + "a type of object upon the floor", MENU_UNSELECTED); #endif - ynq("Name an individual object?")) { + end_menu(win, "What do you want to name?"); + if (select_menu(win, PICK_ONE, &pick_list) > 0) { + ch = pick_list[0].item.a_char; + free((genericptr_t)pick_list); + } else + ch = 'q'; + destroy_nhwindow(win); + + switch (ch) { + default: case 'q': break; - case 'y': -#ifdef REDO - savech(ch); -#endif + case 'm': /* name a visible monster */ + do_mname(); + break; + case 'i': /* name an individual object in inventory */ allowall[0] = ALL_CLASSES; allowall[1] = '\0'; obj = getobj(allowall, "name"); if(obj) do_oname(obj); break; - default : -#ifdef REDO - savech(ch); -#endif + case 'o': /* name a type of object in inventory */ obj = getobj(callable, "call"); if (obj) { /* behave as if examining it in inventory; @@ -495,12 +532,24 @@ ddocall() (void) xname(obj); if (!obj->dknown) { - You("would never recognize another one."); - return 0; + You("would never recognize another one."); +#if 0 + } else if (!objtyp_is_callable(obj->otyp)) { + You("know those as well as you ever will."); +#endif + } else { + docall(obj); } - docall(obj); } break; + case 'd': /* name a type of object on the discoveries list */ + rename_disco(); + break; +#if 0 + case 'f': /* name a type of object visible on the floor */ + /* [not implemented] */ + break; +#endif } return 0; } diff --git a/src/invent.c b/src/invent.c index a34c7445a..0d1475a28 100644 --- a/src/invent.c +++ b/src/invent.c @@ -971,6 +971,7 @@ register const char *let,*word; (otmp->otyp != HORN_OF_PLENTY || !otmp->dknown || !objects[HORN_OF_PLENTY].oc_name_known)) || (!strcmp(word, "charge") && !is_chargeable(otmp)) + || (!strcmp(word, "call") && !objtyp_is_callable(otyp)) ) foo--; /* ugly check for unworn armor that can't be worn */ diff --git a/src/o_init.c b/src/o_init.c index d019ef23b..79cd1c3f0 100644 --- a/src/o_init.c +++ b/src/o_init.c @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)o_init.c 3.5 2005/11/14 */ +/* SCCS Id: @(#)o_init.c 3.5 2007/05/21 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -407,10 +407,9 @@ int dodiscovered() /* free after Robert Viduya */ { register int i, dis; - int ct = 0; - char *s, oclass, prev_class, classes[MAXOCLASSES]; + int ct = 0; + char *s, oclass, prev_class, classes[MAXOCLASSES], buf[BUFSZ]; winid tmpwin; - char buf[BUFSZ]; tmpwin = create_nhwindow(NHW_MENU); putstr(tmpwin, 0, "Discoveries"); @@ -442,7 +441,7 @@ dodiscovered() /* free after Robert Viduya */ prev_class = oclass + 1; /* forced different from oclass */ for (i = bases[(int)oclass]; i < NUM_OBJECTS && objects[i].oc_class == oclass; i++) { - if ((dis = disco[i]) && interesting_to_discover(dis)) { + if ((dis = disco[i]) != 0 && interesting_to_discover(dis)) { ct++; if (oclass != prev_class) { putstr(tmpwin, iflags.menu_headings, let_to_name(oclass, FALSE)); @@ -463,4 +462,77 @@ dodiscovered() /* free after Robert Viduya */ return 0; } +/* put up nameable subset of discoveries list as a menu */ +void +rename_disco() +{ + register int i, dis; + int ct = 0, mn = 0, sl; + char *s, oclass, prev_class; + winid tmpwin; + anything any; + menu_item *selected = 0; + + any = zeroany; + tmpwin = create_nhwindow(NHW_MENU); + start_menu(tmpwin); + + /* + * Skip the "unique objects" section (each will appear within its + * regular class if it is nameable) and the artifacts section. + * We assume that classes omitted from packorder aren't nameable + * so we skip venom too. + */ + + /* for each class, show discoveries in that class */ + for (s = flags.inv_order; *s; s++) { + oclass = *s; + prev_class = oclass + 1; /* forced different from oclass */ + for (i = bases[(int)oclass]; + i < NUM_OBJECTS && objects[i].oc_class == oclass; i++) { + dis = disco[i]; + if (!dis || !interesting_to_discover(dis)) continue; + ct++; + if (!objtyp_is_callable(dis)) continue; + mn++; + + if (oclass != prev_class) { + any.a_int = 0; + add_menu(tmpwin, NO_GLYPH, &any, ' ', iflags.menu_headings, + ATR_NONE, let_to_name(oclass, FALSE), MENU_UNSELECTED); + prev_class = oclass; + } + any.a_int = dis; + add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, + obj_typename(dis), MENU_UNSELECTED); + } + } + if (ct == 0) { + You("haven't discovered anything yet..."); + } else if (mn == 0) { + pline("None of your discoveries can be assigned names..."); + } else { + end_menu(tmpwin, "Pick an object type to name"); + dis = STRANGE_OBJECT; + sl = select_menu(tmpwin, PICK_ONE, &selected); + if (sl > 0) { + dis = selected[0].item.a_int; + free((genericptr_t)selected); + } + if (dis != STRANGE_OBJECT) { + struct obj odummy; + + odummy = zeroobj; + odummy.otyp = dis; + odummy.oclass = objects[dis].oc_class; + odummy.quan = 1L; + odummy.known = !objects[dis].oc_uses_known; + odummy.dknown = 1; + docall(&odummy); + } + } + destroy_nhwindow(tmpwin); + return; +} + /*o_init.c*/