diff --git a/include/extern.h b/include/extern.h index e372f52ff..40de54078 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1240,6 +1240,10 @@ extern boolean pmatchi(const char *, const char *) NONNULLPTRS; extern boolean pmatchz(const char *, const char *) NONNULLPTRS; */ +/* ### iactions.c ### */ + +extern int itemactions(struct obj *otmp) NONNULLARG1; + /* ### insight.c ### */ extern int doattributes(void); diff --git a/include/hack.h b/include/hack.h index e91df8365..7163bf6a4 100644 --- a/include/hack.h +++ b/include/hack.h @@ -571,6 +571,11 @@ enum hunger_state_types { STARVED = 6 }; +/* fake inventory letters, not 'a'..'z' or 'A'..'Z' */ +#define NOINVSYM '#' /* overflow because all 52 letters are in use */ +#define CONTAINED_SYM '>' /* designator for inside a container */ +#define HANDS_SYM '-' /* hands|fingers|self depending on context */ + /* inventory counts (slots in tty parlance) * a...zA..Z invlet_basic (52) * $a...zA..Z# 2 special additions diff --git a/src/iactions.c b/src/iactions.c new file mode 100644 index 000000000..ca00a2be6 --- /dev/null +++ b/src/iactions.c @@ -0,0 +1,716 @@ +/* NetHack 3.7 iactions.c $NHDT-Date: 1762680996 2025/11/09 01:36:36 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.543 $ */ +/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ +/*-Copyright (c) Pasi Kallinen, 2026. */ +/* NetHack may be freely redistributed. See license for details. */ + +#include "hack.h" + +staticfn boolean item_naming_classification(struct obj *, char *, char *); +staticfn int item_reading_classification(struct obj *, char *); +staticfn void ia_addmenu(winid, int, char, const char *); +staticfn void itemactions_pushkeys(struct obj *, int); + +enum item_action_actions { + IA_NONE = 0, + IA_UNWIELD, /* hack for 'w-' */ + IA_APPLY_OBJ, /* 'a' */ + IA_DIP_OBJ, /* 'a' on a potion == dip */ + IA_NAME_OBJ, /* 'c' name individual item */ + IA_NAME_OTYP, /* 'C' name item's type */ + IA_DROP_OBJ, /* 'd' */ + IA_EAT_OBJ, /* 'e' */ + IA_ENGRAVE_OBJ, /* 'E' */ + IA_FIRE_OBJ, /* 'f' */ + IA_ADJUST_OBJ, /* 'i' #adjust inventory letter */ + IA_ADJUST_STACK, /* 'I' #adjust with count to split stack */ + IA_SACRIFICE, /* 'O' offer sacrifice */ + IA_BUY_OBJ, /* 'p' pay shopkeeper */ + IA_QUAFF_OBJ, + IA_QUIVER_OBJ, + IA_READ_OBJ, + IA_RUB_OBJ, + IA_THROW_OBJ, + IA_TAKEOFF_OBJ, + IA_TIP_CONTAINER, + IA_INVOKE_OBJ, + IA_WIELD_OBJ, + IA_WEAR_OBJ, + IA_SWAPWEAPON, + IA_TWOWEAPON, + IA_ZAP_OBJ, + IA_WHATIS_OBJ, /* '/' specify inventory object */ +}; + +/* construct text for the menu entries for IA_NAME_OBJ and IA_NAME_OTYP */ +staticfn boolean +item_naming_classification( + struct obj *obj, + char *onamebuf, + char *ocallbuf) +{ + static const char + Name[] = "Name", + Rename[] = "Rename or un-name", + Call[] = "Call", + /* "re-call" seems a bit weird, but "recall" and + "rename" don't fit for changing a type name */ + Recall[] = "Re-call or un-call"; + + onamebuf[0] = ocallbuf[0] = '\0'; + if (name_ok(obj) == GETOBJ_SUGGEST) { + Sprintf(onamebuf, "%s %s %s", + (!has_oname(obj) || !*ONAME(obj)) ? Name : Rename, + the_unique_obj(obj) ? "the" + : !is_plural(obj) ? "this specific" + : "this stack of", /*"these",*/ + simpleonames(obj)); + } + if (call_ok(obj) == GETOBJ_SUGGEST) { + char *callname = simpleonames(obj); + + /* prefix known unique item with "the", make all other types plural */ + if (the_unique_obj(obj)) /* treats unID'd fake amulets as if real */ + callname = the(callname); + else if (!is_plural(obj)) + callname = makeplural(callname); + Sprintf(ocallbuf, "%s the type for %s", + (!objects[obj->otyp].oc_uname + || !*objects[obj->otyp].oc_uname) ? Call : Recall, + callname); + } + return (*onamebuf || *ocallbuf) ? TRUE : FALSE; +} + +/* construct text for the menu entries for IA_READ_OBJ */ +staticfn int +item_reading_classification(struct obj *obj, char *outbuf) +{ + int otyp = obj->otyp, res = IA_READ_OBJ; + + *outbuf = '\0'; + if (otyp == FORTUNE_COOKIE) { + Strcpy(outbuf, "Read the message inside this cookie"); + } else if (otyp == T_SHIRT) { + Strcpy(outbuf, "Read the slogan on the shirt"); + } else if (otyp == ALCHEMY_SMOCK) { + Strcpy(outbuf, "Read the slogan on the apron"); + } else if (otyp == HAWAIIAN_SHIRT) { + Strcpy(outbuf, "Look at the pattern on the shirt"); + } else if (obj->oclass == SCROLL_CLASS) { + const char *magic = ((obj->dknown +#ifdef MAIL_STRUCTURES + && otyp != SCR_MAIL +#endif + && (otyp != SCR_BLANK_PAPER + || !objects[otyp].oc_name_known)) + ? " to activate its magic" : ""); + + Sprintf(outbuf, "Read this scroll%s", magic); + } else if (obj->oclass == SPBOOK_CLASS) { + boolean novel = (otyp == SPE_NOVEL), + blank = (otyp == SPE_BLANK_PAPER + && objects[otyp].oc_name_known), + tome = (otyp == SPE_BOOK_OF_THE_DEAD + && objects[otyp].oc_name_known); + + Sprintf(outbuf, "%s this %s", + (novel || blank) ? "Read" : tome ? "Examine" : "Study", + novel ? simpleonames(obj) /* "novel" or "paperback book" */ + : tome ? "tome" : "spellbook"); + } else { + res = IA_NONE; + } + return res; +} + +staticfn void +ia_addmenu(winid win, int act, char let, const char *txt) +{ + anything any; + int clr = NO_COLOR; + + any = cg.zeroany; + any.a_int = act; + add_menu(win, &nul_glyphinfo, &any, let, 0, + ATR_NONE, clr, txt, MENU_ITEMFLAGS_NONE); +} + +/* set up a command to execute on a specific item next */ +staticfn void +itemactions_pushkeys(struct obj *otmp, int act) +{ + switch (act) { + default: + impossible("Unknown item action %d", act); + break; + case IA_NONE: + break; + case IA_UNWIELD: + cmdq_add_ec(CQ_CANNED, (otmp == uwep) ? dowield + : (otmp == uswapwep) ? remarm_swapwep + : (otmp == uquiver) ? dowieldquiver + : donull); /* can't happen */ + cmdq_add_key(CQ_CANNED, HANDS_SYM); + break; + case IA_APPLY_OBJ: + cmdq_add_ec(CQ_CANNED, doapply); + cmdq_add_key(CQ_CANNED, otmp->invlet); + break; + case IA_DIP_OBJ: + /* #altdip instead of normal #dip - takes potion to dip into + first (the inventory item instigating this) and item to + be dipped second, also ignores floor features such as + fountain/sink so we don't need to force m-prefix here */ + cmdq_add_ec(CQ_CANNED, dip_into); + cmdq_add_key(CQ_CANNED, otmp->invlet); + break; + case IA_NAME_OBJ: + case IA_NAME_OTYP: + cmdq_add_ec(CQ_CANNED, docallcmd); + cmdq_add_key(CQ_CANNED, (act == IA_NAME_OBJ) ? 'i' : 'o'); + cmdq_add_key(CQ_CANNED, otmp->invlet); + break; + case IA_DROP_OBJ: + cmdq_add_ec(CQ_CANNED, dodrop); + cmdq_add_key(CQ_CANNED, otmp->invlet); + break; + case IA_EAT_OBJ: + /* start with m-prefix; for #eat, it means ignore floor food + if present and eat food from invent */ + cmdq_add_ec(CQ_CANNED, do_reqmenu); + cmdq_add_ec(CQ_CANNED, doeat); + cmdq_add_key(CQ_CANNED, otmp->invlet); + break; + case IA_ENGRAVE_OBJ: + cmdq_add_ec(CQ_CANNED, doengrave); + cmdq_add_key(CQ_CANNED, otmp->invlet); + break; + case IA_FIRE_OBJ: + cmdq_add_ec(CQ_CANNED, dofire); + break; + case IA_ADJUST_OBJ: + cmdq_add_ec(CQ_CANNED, doorganize); /* #adjust */ + cmdq_add_key(CQ_CANNED, otmp->invlet); + break; + case IA_ADJUST_STACK: + cmdq_add_ec(CQ_CANNED, adjust_split); /* #altadjust */ + cmdq_add_key(CQ_CANNED, otmp->invlet); + break; + case IA_SACRIFICE: + cmdq_add_ec(CQ_CANNED, dosacrifice); + cmdq_add_key(CQ_CANNED, otmp->invlet); + break; + case IA_BUY_OBJ: + cmdq_add_ec(CQ_CANNED, dopay); + cmdq_add_key(CQ_CANNED, otmp->invlet); + break; + case IA_QUAFF_OBJ: + /* start with m-prefix; for #quaff, it means ignore fountain + or sink if present and drink a potion from invent */ + cmdq_add_ec(CQ_CANNED, do_reqmenu); + cmdq_add_ec(CQ_CANNED, dodrink); + cmdq_add_key(CQ_CANNED, otmp->invlet); + break; + case IA_QUIVER_OBJ: + cmdq_add_ec(CQ_CANNED, dowieldquiver); + cmdq_add_key(CQ_CANNED, otmp->invlet); + break; + case IA_READ_OBJ: + cmdq_add_ec(CQ_CANNED, doread); + cmdq_add_key(CQ_CANNED, otmp->invlet); + break; + case IA_RUB_OBJ: + cmdq_add_ec(CQ_CANNED, dorub); + cmdq_add_key(CQ_CANNED, otmp->invlet); + break; + case IA_THROW_OBJ: + cmdq_add_ec(CQ_CANNED, dothrow); + cmdq_add_key(CQ_CANNED, otmp->invlet); + break; + case IA_TAKEOFF_OBJ: + cmdq_add_ec(CQ_CANNED, ia_dotakeoff); /* #altdotakeoff */ + cmdq_add_key(CQ_CANNED, otmp->invlet); + break; + case IA_TIP_CONTAINER: + /* start with m-prefix to skip floor containers; + for menustyle:Traditional when more than one floor container + is present, player will get a #tip menu and have to pick + the "tip something being carried" choice, then this item + will be already chosen from inventory; suboptimal but + possibly an acceptable tradeoff since combining item actions + with use of traditional ggetobj() is an unlikely scenario */ + cmdq_add_ec(CQ_CANNED, do_reqmenu); + cmdq_add_ec(CQ_CANNED, dotip); + cmdq_add_key(CQ_CANNED, otmp->invlet); + break; + case IA_INVOKE_OBJ: + cmdq_add_ec(CQ_CANNED, doinvoke); + cmdq_add_key(CQ_CANNED, otmp->invlet); + break; + case IA_WIELD_OBJ: + cmdq_add_ec(CQ_CANNED, dowield); + cmdq_add_key(CQ_CANNED, otmp->invlet); + break; + case IA_WEAR_OBJ: + cmdq_add_ec(CQ_CANNED, dowear); + cmdq_add_key(CQ_CANNED, otmp->invlet); + break; + case IA_SWAPWEAPON: + cmdq_add_ec(CQ_CANNED, doswapweapon); + break; + case IA_TWOWEAPON: + cmdq_add_ec(CQ_CANNED, dotwoweapon); + break; + case IA_ZAP_OBJ: + cmdq_add_ec(CQ_CANNED, dozap); + cmdq_add_key(CQ_CANNED, otmp->invlet); + break; + case IA_WHATIS_OBJ: + cmdq_add_ec(CQ_CANNED, dowhatis); /* "/" command */ + cmdq_add_key(CQ_CANNED, 'i'); /* "i" == item from inventory */ + cmdq_add_key(CQ_CANNED, otmp->invlet); + break; + } +} + +/* Show menu of possible actions hero could do with item otmp */ +int +itemactions(struct obj *otmp) +{ + int n, act = IA_NONE; + winid win; + char buf[BUFSZ], buf2[BUFSZ]; + menu_item *selected; + struct monst *mtmp; + const char *light = otmp->lamplit ? "Extinguish" : "Light"; + boolean already_worn = (otmp->owornmask & (W_ARMOR | W_ACCESSORY)) != 0; + + win = create_nhwindow(NHW_MENU); + start_menu(win, MENU_BEHAVE_STANDARD); + + /* -: unwield; picking current weapon offers an opportunity for 'w-' + to wield bare/gloved hands; likewise for 'Q-' with quivered item(s) */ + if (otmp == uwep || otmp == uswapwep || otmp == uquiver) { + const char *verb = (otmp == uquiver) ? "Quiver" : "Wield", + *action = (otmp == uquiver) ? "un-ready" : "un-wield", + *which = is_plural(otmp) ? "these" : "this", + *what = ((otmp->oclass == WEAPON_CLASS || is_weptool(otmp)) + ? "weapon" : "item"); + /* + * TODO: if uwep is ammo, tell player that to shoot instead of toss, + * the corresponding launcher must be wielded; + */ + Sprintf(buf, "%s '%c' to %s %s %s", + verb, HANDS_SYM, action, which, + is_plural(otmp) ? makeplural(what) : what); + ia_addmenu(win, IA_UNWIELD, '-', buf); + } + + /* a: apply */ + if (otmp->oclass == COIN_CLASS) + ia_addmenu(win, IA_APPLY_OBJ, 'a', "Flip a coin"); + else if (otmp->otyp == CREAM_PIE) + ia_addmenu(win, IA_APPLY_OBJ, 'a', + "Hit yourself with this cream pie"); + else if (otmp->otyp == BULLWHIP) + ia_addmenu(win, IA_APPLY_OBJ, 'a', "Lash out with this whip"); + else if (otmp->otyp == GRAPPLING_HOOK) + ia_addmenu(win, IA_APPLY_OBJ, 'a', + "Grapple something with this hook"); + else if (otmp->otyp == BAG_OF_TRICKS && objects[otmp->otyp].oc_name_known) + /* bag of tricks skips this unless discovered */ + ia_addmenu(win, IA_APPLY_OBJ, 'a', "Reach into this bag"); + else if (Is_container(otmp)) + /* bag of tricks gets here only if not yet discovered */ + ia_addmenu(win, IA_APPLY_OBJ, 'a', "Open this container"); + else if (otmp->otyp == CAN_OF_GREASE) + ia_addmenu(win, IA_APPLY_OBJ, 'a', "Use the can to grease an item"); + else if (otmp->otyp == LOCK_PICK + || otmp->otyp == CREDIT_CARD + || otmp->otyp == SKELETON_KEY) + ia_addmenu(win, IA_APPLY_OBJ, 'a', "Use this tool to pick a lock"); + else if (otmp->otyp == TINNING_KIT) + ia_addmenu(win, IA_APPLY_OBJ, 'a', "Use this kit to tin a corpse"); + else if (otmp->otyp == LEASH) + ia_addmenu(win, IA_APPLY_OBJ, 'a', "Tie a pet to this leash"); + else if (otmp->otyp == SADDLE) + ia_addmenu(win, IA_APPLY_OBJ, 'a', "Place this saddle on a pet"); + else if (otmp->otyp == MAGIC_WHISTLE + || otmp->otyp == TIN_WHISTLE) + ia_addmenu(win, IA_APPLY_OBJ, 'a', "Blow this whistle"); + else if (otmp->otyp == EUCALYPTUS_LEAF) + ia_addmenu(win, IA_APPLY_OBJ, 'a', "Use this leaf as a whistle"); + else if (otmp->otyp == STETHOSCOPE) + ia_addmenu(win, IA_APPLY_OBJ, 'a', "Listen through the stethoscope"); + else if (otmp->otyp == MIRROR) + ia_addmenu(win, IA_APPLY_OBJ, 'a', "Show something its reflection"); + else if (otmp->otyp == BELL || otmp->otyp == BELL_OF_OPENING) + ia_addmenu(win, IA_APPLY_OBJ, 'a', "Ring the bell"); + else if (otmp->otyp == CANDELABRUM_OF_INVOCATION) { + Sprintf(buf, "%s the candelabrum", light); + ia_addmenu(win, IA_APPLY_OBJ, 'a', buf); + } else if (otmp->otyp == WAX_CANDLE || otmp->otyp == TALLOW_CANDLE) { + boolean multiple = (otmp->quan == 1L) ? FALSE : TRUE; + const char *s = multiple ? "these" : "this"; + struct obj *o = carrying(CANDELABRUM_OF_INVOCATION); + + if (o && o->spe < 7) + Sprintf(buf, "Attach %s to your candelabrum, or %s %s", s, + !otmp->lamplit ? "light" : "extinguish", /* [lowercase] */ + multiple ? "them" : "it"); + else + Sprintf(buf, "%s %s %s", light, s, simpleonames(otmp)); + ia_addmenu(win, IA_APPLY_OBJ, 'a', buf); + } else if (otmp->otyp == OIL_LAMP || otmp->otyp == MAGIC_LAMP + || otmp->otyp == BRASS_LANTERN) { + Sprintf(buf, "%s this light source", light); + ia_addmenu(win, IA_APPLY_OBJ, 'a', buf); + } else if (otmp->otyp == POT_OIL && objects[otmp->otyp].oc_name_known) { + Sprintf(buf, "%s this oil", light); + ia_addmenu(win, IA_APPLY_OBJ, 'a', buf); + } else if (otmp->oclass == POTION_CLASS) { + /* FIXME? this should probably be moved to 'D' rather than be 'a' */ + Sprintf(buf, "Dip something into %s potion%s", + is_plural(otmp) ? "one of these" : "this", plur(otmp->quan)); + ia_addmenu(win, IA_DIP_OBJ, 'a', buf); + } else if (otmp->otyp == EXPENSIVE_CAMERA) + ia_addmenu(win, IA_APPLY_OBJ, 'a', "Take a photograph"); + else if (otmp->otyp == TOWEL) + ia_addmenu(win, IA_APPLY_OBJ, 'a', + "Clean yourself off with this towel"); + else if (otmp->otyp == CRYSTAL_BALL) + ia_addmenu(win, IA_APPLY_OBJ, 'a', "Peer into this crystal ball"); + else if (otmp->otyp == MAGIC_MARKER) + ia_addmenu(win, IA_APPLY_OBJ, 'a', + "Write on something with this marker"); + else if (otmp->otyp == FIGURINE) + ia_addmenu(win, IA_APPLY_OBJ, 'a', "Make this figurine transform"); + else if (otmp->otyp == UNICORN_HORN) + ia_addmenu(win, IA_APPLY_OBJ, 'a', "Use this unicorn horn"); + else if (otmp->otyp == HORN_OF_PLENTY + && objects[otmp->otyp].oc_name_known) + ia_addmenu(win, IA_APPLY_OBJ, 'a', "Blow into the horn of plenty"); + else if (otmp->otyp >= WOODEN_FLUTE && otmp->otyp <= DRUM_OF_EARTHQUAKE) + ia_addmenu(win, IA_APPLY_OBJ, 'a', "Play this musical instrument"); + else if (otmp->otyp == LAND_MINE || otmp->otyp == BEARTRAP) + ia_addmenu(win, IA_APPLY_OBJ, 'a', "Arm this trap"); + else if (otmp->otyp == PICK_AXE || otmp->otyp == DWARVISH_MATTOCK) + ia_addmenu(win, IA_APPLY_OBJ, 'a', "Dig with this digging tool"); + else if (otmp->oclass == WAND_CLASS) + ia_addmenu(win, IA_APPLY_OBJ, 'a', "Break this wand"); + + /* 'c', 'C' - call an item or its type something */ + if (item_naming_classification(otmp, buf, buf2)) { + if (*buf) + ia_addmenu(win, IA_NAME_OBJ, 'c', buf); + if (*buf2) + ia_addmenu(win, IA_NAME_OTYP, 'C', buf2); + } + + /* d: drop item, works on everything except worn items; those will + always have a takeoff/remove choice so we don't have to worry + about the menu maybe being empty when 'd' is suppressed */ + if (!already_worn) { + Sprintf(buf, "Drop this %s", (otmp->quan > 1L) ? "stack" : "item"); + ia_addmenu(win, IA_DROP_OBJ, 'd', buf); + } + + /* e: eat item */ + if (otmp->otyp == TIN) { + Sprintf(buf, "Open %s%s and eat the contents", + (otmp->quan > 1L) ? "one of these tins" : "this tin", + (otmp->otyp == TIN && uwep && uwep->otyp == TIN_OPENER) + ? " with your tin opener" : ""); + ia_addmenu(win, IA_EAT_OBJ, 'e', buf); + } else if (is_edible(otmp)) { + Sprintf(buf, "Eat %s", (otmp->quan > 1L) ? "one of these" : "this"); + ia_addmenu(win, IA_EAT_OBJ, 'e', buf); + } + + /* E: engrave with item */ + if (otmp->otyp == TOWEL) { + ia_addmenu(win, IA_ENGRAVE_OBJ, 'E', + "Wipe the floor with this towel"); + } else if (otmp->otyp == MAGIC_MARKER) { + ia_addmenu(win, IA_ENGRAVE_OBJ, 'E', + "Scribble graffiti on the floor"); + } else if (otmp->oclass == WEAPON_CLASS || otmp->oclass == WAND_CLASS + || otmp->oclass == GEM_CLASS || otmp->oclass == RING_CLASS) { + Sprintf(buf, "%s on the %s with %s", + (is_blade(otmp) || otmp->oclass == WAND_CLASS + || ((otmp->oclass == GEM_CLASS || otmp->oclass == RING_CLASS) + && objects[otmp->otyp].oc_tough)) ? "Engrave" : "Write", + surface(u.ux, u.uy), + (otmp->quan > 1L) ? "one of these items" : "this item"); + ia_addmenu(win, IA_ENGRAVE_OBJ, 'E', buf); + } + + /* f: fire quivered ammo */ + if (otmp == uquiver) { + boolean shoot = ammo_and_launcher(otmp, uwep); + + /* FIXME: see the multi-shot FIXME about "one of" for 't: throw' */ + Sprintf(buf, "%s %s", shoot ? "Shoot" : "Throw", + (otmp->quan > 1L) ? "one of these" : "this"); + if (shoot) { + assert(uwep != NULL); + Sprintf(eos(buf), " with your wielded %s", simpleonames(uwep)); + } + ia_addmenu(win, IA_FIRE_OBJ, 'f', buf); + } + + /* i: #adjust inventory letter; gold can't be adjusted unless there + is some in a slot other than '$' (which shouldn't be possible) */ + if (otmp->oclass != COIN_CLASS || check_invent_gold("item-action")) + ia_addmenu(win, IA_ADJUST_OBJ, 'i', + "Adjust inventory by assigning new letter"); + /* I: #adjust inventory item by splitting its stack */ + if (otmp->quan > 1L && otmp->oclass != COIN_CLASS) + ia_addmenu(win, IA_ADJUST_STACK, 'I', + "Adjust inventory by splitting this stack"); + + /* O: offer sacrifice */ + if (IS_ALTAR(levl[u.ux][u.uy].typ) && !u.uswallow) { + /* FIXME: this doesn't match #offer's likely candidates, which don't + include corpses on Astral and don't include amulets off Astral */ + if (otmp->otyp == CORPSE) + ia_addmenu(win, IA_SACRIFICE, 'O', + "Offer this corpse as a sacrifice at this altar"); + else if (otmp->otyp == AMULET_OF_YENDOR + || otmp->otyp == FAKE_AMULET_OF_YENDOR) + ia_addmenu(win, IA_SACRIFICE, 'O', + "Offer this amulet as a sacrifice at this altar"); + } + + /* p: pay for unpaid utems */ + if (otmp->unpaid + /* FIXME: should also handle player owned container (so not + flagged 'unpaid') holding shop owned items */ + && (mtmp = shop_keeper(*in_rooms(u.ux, u.uy, SHOPBASE))) != 0 + && inhishop(mtmp)) { + Sprintf(buf, "Buy this unpaid %s", + (otmp->quan > 1L) ? "stack" : "item"); + ia_addmenu(win, IA_BUY_OBJ, 'p', buf); + } + + /* P: put on accessory */ + if (!already_worn) { + /* if 'otmp' is worn, we'll skip 'P' and show 'R' below; + if not worn, we show 'P - Put on this ' if + the slot is available, or 'P - '; for the latter, + 'P' will fail but we don't want to omit the choice because + item actions can be used to learn commands */ + *buf = '\0'; + if (otmp->oclass == AMULET_CLASS) { + Strcpy(buf, !uamul ? "Put this amulet on" + : "[already wearing an amulet]"); + } else if (otmp->oclass == RING_CLASS || otmp->otyp == MEAT_RING) { + if (!uleft || !uright) + Strcpy(buf, "Put this ring on"); + else + Sprintf(buf, "[both ring %s in use]", + makeplural(body_part(FINGER))); + } else if (otmp->otyp == BLINDFOLD || otmp->otyp == TOWEL + || otmp->otyp == LENSES) { + if (ublindf) + Strcpy(buf, "[already wearing eyewear]"); + else if (otmp->otyp == LENSES) + Strcpy(buf, "Put these lenses on"); + else + Sprintf(buf, "Put this on%s", + (otmp->otyp == TOWEL) ? " to blindfold yourself" : ""); + } + if (*buf) + ia_addmenu(win, IA_WEAR_OBJ, 'P', buf); + } + + /* q: drink item */ + if (otmp->oclass == POTION_CLASS) { + Sprintf(buf, "Quaff (drink) %s", + (otmp->quan > 1L) ? "one of these potions" : "this potion"); + ia_addmenu(win, IA_QUAFF_OBJ, 'q', buf); + } + + /* Q: quiver throwable item */ + if ((otmp->oclass == GEM_CLASS || otmp->oclass == WEAPON_CLASS) + && otmp != uquiver) { + Sprintf(buf, "Quiver this %s for easy %s with \'f\'ire", + (otmp->quan > 1L) ? "stack" : "item", + ammo_and_launcher(otmp, uwep) ? "shooting" : "throwing"); + ia_addmenu(win, IA_QUIVER_OBJ, 'Q', buf); + } + + /* r: read item */ + if (item_reading_classification(otmp, buf) == IA_READ_OBJ) + ia_addmenu(win, IA_READ_OBJ, 'r', buf); + + /* R: remove accessory or rub item */ + if (otmp->owornmask & W_ACCESSORY) { + Sprintf(buf, "Remove this %s", + (otmp->owornmask & W_AMUL) ? "amulet" + : (otmp->owornmask & W_RING) ? "ring" + : (otmp->owornmask & W_TOOL) ? "eyewear" + : "accessory"); /* catchall -- can't happen */ + ia_addmenu(win, IA_TAKEOFF_OBJ, 'R', buf); + } + if (otmp->otyp == OIL_LAMP || otmp->otyp == MAGIC_LAMP + || otmp->otyp == BRASS_LANTERN) { + Sprintf(buf, "Rub this %s", simpleonames(otmp)); + ia_addmenu(win, IA_RUB_OBJ, 'R', buf); + } else if (otmp->oclass == GEM_CLASS && is_graystone(otmp)) + ia_addmenu(win, IA_RUB_OBJ, 'R', "Rub something on this stone"); + + /* t: throw item */ + if (!already_worn) { + boolean shoot = ammo_and_launcher(otmp, uwep); + + /* + * FIXME: + * 'one of these' should be changed to 'some of these' when there + * is the possibility of a multi-shot volley but we don't have + * any way to determine that except by actually calculating the + * volley count and that could randomly yield 1 here and 2..N + * while throwing or vice versa. + */ + Sprintf(buf, "%s %s%s", shoot ? "Shoot" : "Throw", + (otmp->quan == 1L) ? "this item" + : (otmp->otyp == GOLD_PIECE) ? "them" + : "one of these", + /* if otmp is quivered, we've already listed + 'f - shoot|throw this item' as a choice; + if 't' is duplicating that, say so ('t' and 'f' + behavior differs for throwing a stack of gold) */ + (otmp == uquiver && (otmp->otyp != GOLD_PIECE + || otmp->quan == 1L)) + ? " (same as 'f')" : ""); + ia_addmenu(win, IA_THROW_OBJ, 't', buf); + } + + /* T: take off armor, tip carried container */ + if (otmp->owornmask & W_ARMOR) + ia_addmenu(win, IA_TAKEOFF_OBJ, 'T', "Take off this armor"); + if ((Is_container(otmp) && (Has_contents(otmp) || !otmp->cknown)) + || (otmp->otyp == HORN_OF_PLENTY && (otmp->spe > 0 || !otmp->known))) + ia_addmenu(win, IA_TIP_CONTAINER, 'T', + "Tip all the contents out of this container"); + + /* V: invoke */ + if ((otmp->otyp == FAKE_AMULET_OF_YENDOR && !otmp->known) + || otmp->oartifact || objects[otmp->otyp].oc_unique + /* non-artifact crystal balls don't have any unique power but + the #invoke command lists them as likely candidates */ + || otmp->otyp == CRYSTAL_BALL) + ia_addmenu(win, IA_INVOKE_OBJ, 'V', + "Try to invoke a unique power of this object"); + + /* w: wield, hold in hands, works on everything but with different + advice text; not mentioned for things that are already wielded */ + if (otmp == uwep || cantwield(gy.youmonst.data)) { + ; /* either already wielded or can't wield anything; skip 'w' */ + } else if (otmp->oclass == WEAPON_CLASS || is_weptool(otmp) + || is_wet_towel(otmp) || otmp->otyp == HEAVY_IRON_BALL) { + Sprintf(buf, "Wield this %s as your weapon", + (otmp->quan > 1L) ? "stack" : "item"); + ia_addmenu(win, IA_WIELD_OBJ, 'w', buf); + } else if (otmp->otyp == TIN_OPENER) { + ia_addmenu(win, IA_WIELD_OBJ, 'w', + "Wield the tin opener to easily open tins"); + } else if (!already_worn) { + /* originally this was using "hold this item in your hands" but + there's no concept of "holding an item", plus it unwields + whatever item you already have wielded so use "wield this item" */ + Sprintf(buf, "Wield this %s in your %s", + (otmp->quan > 1L) ? "stack" : "item", + /* only two-handed weapons and unicorn horns care about + pluralizing "hand" and they won't reach here, but plural + sounds better when poly'd into something with "claw" */ + makeplural(body_part(HAND))); + ia_addmenu(win, IA_WIELD_OBJ, 'w', buf); + } + + /* W: wear armor */ + if (!already_worn) { + if (otmp->oclass == ARMOR_CLASS) { + /* if 'otmp' is worn we skip 'W' (and show 'T' above instead); + if it isn't, we either show "W - wear this" if otmp's slot + isn't populated, or "W - [already wearing ]"; + for the latter, picking 'W' will fail but we don't want to + omit 'W' in this situation */ + long Wmask = armcat_to_wornmask(objects[otmp->otyp].oc_armcat); + struct obj *o = wearmask_to_obj(Wmask); + + if (!o) + Strcpy(buf, "Wear this armor"); + else + Sprintf(buf, "[already wearing %s]", an(armor_simple_name(o))); + + ia_addmenu(win, IA_WEAR_OBJ, 'W', buf); + } + } + + /* x: Swap main and readied weapon */ + if (otmp == uwep && uswapwep) + ia_addmenu(win, IA_SWAPWEAPON, 'x', + "Swap this with your alternate weapon"); + else if (otmp == uwep) + ia_addmenu(win, IA_SWAPWEAPON, 'x', + "Ready this as an alternate weapon"); + else if (otmp == uswapwep) + ia_addmenu(win, IA_SWAPWEAPON, 'x', + "Swap this with your main weapon"); + + /* this is based on TWOWEAPOK() in wield.c; we don't call can_two_weapon() + because it is very verbose; attempting to two-weapon might be rejected + but we screen out most reasons for rejection before offering it as a + choice */ +#define MAYBETWOWEAPON(obj) \ + ((((obj)->oclass == WEAPON_CLASS) \ + ? !(is_launcher(obj) || is_ammo(obj) || is_missile(obj)) \ + : is_weptool(obj)) \ + && !bimanual(obj)) + + /* X: Toggle two-weapon mode on or off */ + if ((otmp == uwep || otmp == uswapwep) + /* if already two-weaponing, no special checks needed to toggle off */ + && (u.twoweap + /* but if not, try to filter most "you can't do that" here */ + || (could_twoweap(gy.youmonst.data) && !uarms + && uwep && MAYBETWOWEAPON(uwep) + && uswapwep && MAYBETWOWEAPON(uswapwep)))) { + Sprintf(buf, "Toggle two-weapon combat %s", u.twoweap ? "off" : "on"); + ia_addmenu(win, IA_TWOWEAPON, 'X', buf); + } + +#undef MAYBETWOWEAPON + + /* z: Zap wand */ + if (otmp->oclass == WAND_CLASS) + ia_addmenu(win, IA_ZAP_OBJ, 'z', + "Zap this wand to release its magic"); + + /* ?: Look up an item in the game's database */ + if (ia_checkfile(otmp)) { + Sprintf(buf, "Look up information about %s", + (otmp->quan > 1L) ? "these" : "this"); + ia_addmenu(win, IA_WHATIS_OBJ, '/', buf); + } + + Sprintf(buf, "Do what with %s?", the(cxname(otmp))); + end_menu(win, buf); + + n = select_menu(win, PICK_ONE, &selected); + + if (n > 0) { + act = selected[0].item.a_int; + free((genericptr_t) selected); + + itemactions_pushkeys(otmp, act); + } + destroy_nhwindow(win); + + /* finish the 'i' command: no time elapses and cancelling without + selecting an action doesn't matter */ + return ECMD_OK; +} + +/*iactions.c*/ diff --git a/src/invent.c b/src/invent.c index 523250197..713bd7d7a 100644 --- a/src/invent.c +++ b/src/invent.c @@ -5,11 +5,6 @@ #include "hack.h" -/* fake inventory letters, not 'a'..'z' or 'A'..'Z' */ -#define NOINVSYM '#' /* overflow because all 52 letters are in use */ -#define CONTAINED_SYM '>' /* designator for inside a container */ -#define HANDS_SYM '-' /* hands|fingers|self depending on context */ - staticfn void inuse_classify(Loot *, struct obj *); staticfn char *loot_xname(struct obj *); staticfn int invletter_value(char); @@ -43,11 +38,6 @@ staticfn int adjust_ok(struct obj *); staticfn int adjust_gold_ok(struct obj *); staticfn int doorganize_core(struct obj *); staticfn char obj_to_let(struct obj *); -staticfn boolean item_naming_classification(struct obj *, char *, char *); -staticfn int item_reading_classification(struct obj *, char *); -staticfn void ia_addmenu(winid, int, char, const char *); -staticfn void itemactions_pushkeys(struct obj *, int); -staticfn int itemactions(struct obj *); staticfn int dispinv_with_action(char *, boolean, const char *); /* enum and structs are defined in wintype.h */ @@ -2965,708 +2955,6 @@ xprname( RESTORE_WARNING_FORMAT_NONLITERAL -enum item_action_actions { - IA_NONE = 0, - IA_UNWIELD, /* hack for 'w-' */ - IA_APPLY_OBJ, /* 'a' */ - IA_DIP_OBJ, /* 'a' on a potion == dip */ - IA_NAME_OBJ, /* 'c' name individual item */ - IA_NAME_OTYP, /* 'C' name item's type */ - IA_DROP_OBJ, /* 'd' */ - IA_EAT_OBJ, /* 'e' */ - IA_ENGRAVE_OBJ, /* 'E' */ - IA_FIRE_OBJ, /* 'f' */ - IA_ADJUST_OBJ, /* 'i' #adjust inventory letter */ - IA_ADJUST_STACK, /* 'I' #adjust with count to split stack */ - IA_SACRIFICE, /* 'O' offer sacrifice */ - IA_BUY_OBJ, /* 'p' pay shopkeeper */ - IA_QUAFF_OBJ, - IA_QUIVER_OBJ, - IA_READ_OBJ, - IA_RUB_OBJ, - IA_THROW_OBJ, - IA_TAKEOFF_OBJ, - IA_TIP_CONTAINER, - IA_INVOKE_OBJ, - IA_WIELD_OBJ, - IA_WEAR_OBJ, - IA_SWAPWEAPON, - IA_TWOWEAPON, - IA_ZAP_OBJ, - IA_WHATIS_OBJ, /* '/' specify inventory object */ -}; - -/* construct text for the menu entries for IA_NAME_OBJ and IA_NAME_OTYP */ -staticfn boolean -item_naming_classification( - struct obj *obj, - char *onamebuf, - char *ocallbuf) -{ - static const char - Name[] = "Name", - Rename[] = "Rename or un-name", - Call[] = "Call", - /* "re-call" seems a bit weird, but "recall" and - "rename" don't fit for changing a type name */ - Recall[] = "Re-call or un-call"; - - onamebuf[0] = ocallbuf[0] = '\0'; - if (name_ok(obj) == GETOBJ_SUGGEST) { - Sprintf(onamebuf, "%s %s %s", - (!has_oname(obj) || !*ONAME(obj)) ? Name : Rename, - the_unique_obj(obj) ? "the" - : !is_plural(obj) ? "this specific" - : "this stack of", /*"these",*/ - simpleonames(obj)); - } - if (call_ok(obj) == GETOBJ_SUGGEST) { - char *callname = simpleonames(obj); - - /* prefix known unique item with "the", make all other types plural */ - if (the_unique_obj(obj)) /* treats unID'd fake amulets as if real */ - callname = the(callname); - else if (!is_plural(obj)) - callname = makeplural(callname); - Sprintf(ocallbuf, "%s the type for %s", - (!objects[obj->otyp].oc_uname - || !*objects[obj->otyp].oc_uname) ? Call : Recall, - callname); - } - return (*onamebuf || *ocallbuf) ? TRUE : FALSE; -} - -/* construct text for the menu entries for IA_READ_OBJ */ -staticfn int -item_reading_classification(struct obj *obj, char *outbuf) -{ - int otyp = obj->otyp, res = IA_READ_OBJ; - - *outbuf = '\0'; - if (otyp == FORTUNE_COOKIE) { - Strcpy(outbuf, "Read the message inside this cookie"); - } else if (otyp == T_SHIRT) { - Strcpy(outbuf, "Read the slogan on the shirt"); - } else if (otyp == ALCHEMY_SMOCK) { - Strcpy(outbuf, "Read the slogan on the apron"); - } else if (otyp == HAWAIIAN_SHIRT) { - Strcpy(outbuf, "Look at the pattern on the shirt"); - } else if (obj->oclass == SCROLL_CLASS) { - const char *magic = ((obj->dknown -#ifdef MAIL_STRUCTURES - && otyp != SCR_MAIL -#endif - && (otyp != SCR_BLANK_PAPER - || !objects[otyp].oc_name_known)) - ? " to activate its magic" : ""); - - Sprintf(outbuf, "Read this scroll%s", magic); - } else if (obj->oclass == SPBOOK_CLASS) { - boolean novel = (otyp == SPE_NOVEL), - blank = (otyp == SPE_BLANK_PAPER - && objects[otyp].oc_name_known), - tome = (otyp == SPE_BOOK_OF_THE_DEAD - && objects[otyp].oc_name_known); - - Sprintf(outbuf, "%s this %s", - (novel || blank) ? "Read" : tome ? "Examine" : "Study", - novel ? simpleonames(obj) /* "novel" or "paperback book" */ - : tome ? "tome" : "spellbook"); - } else { - res = IA_NONE; - } - return res; -} - -staticfn void -ia_addmenu(winid win, int act, char let, const char *txt) -{ - anything any; - int clr = NO_COLOR; - - any = cg.zeroany; - any.a_int = act; - add_menu(win, &nul_glyphinfo, &any, let, 0, - ATR_NONE, clr, txt, MENU_ITEMFLAGS_NONE); -} - -/* set up a command to execute on a specific item next */ -staticfn void -itemactions_pushkeys(struct obj *otmp, int act) -{ - switch (act) { - default: - impossible("Unknown item action %d", act); - break; - case IA_NONE: - break; - case IA_UNWIELD: - cmdq_add_ec(CQ_CANNED, (otmp == uwep) ? dowield - : (otmp == uswapwep) ? remarm_swapwep - : (otmp == uquiver) ? dowieldquiver - : donull); /* can't happen */ - cmdq_add_key(CQ_CANNED, HANDS_SYM); - break; - case IA_APPLY_OBJ: - cmdq_add_ec(CQ_CANNED, doapply); - cmdq_add_key(CQ_CANNED, otmp->invlet); - break; - case IA_DIP_OBJ: - /* #altdip instead of normal #dip - takes potion to dip into - first (the inventory item instigating this) and item to - be dipped second, also ignores floor features such as - fountain/sink so we don't need to force m-prefix here */ - cmdq_add_ec(CQ_CANNED, dip_into); - cmdq_add_key(CQ_CANNED, otmp->invlet); - break; - case IA_NAME_OBJ: - case IA_NAME_OTYP: - cmdq_add_ec(CQ_CANNED, docallcmd); - cmdq_add_key(CQ_CANNED, (act == IA_NAME_OBJ) ? 'i' : 'o'); - cmdq_add_key(CQ_CANNED, otmp->invlet); - break; - case IA_DROP_OBJ: - cmdq_add_ec(CQ_CANNED, dodrop); - cmdq_add_key(CQ_CANNED, otmp->invlet); - break; - case IA_EAT_OBJ: - /* start with m-prefix; for #eat, it means ignore floor food - if present and eat food from invent */ - cmdq_add_ec(CQ_CANNED, do_reqmenu); - cmdq_add_ec(CQ_CANNED, doeat); - cmdq_add_key(CQ_CANNED, otmp->invlet); - break; - case IA_ENGRAVE_OBJ: - cmdq_add_ec(CQ_CANNED, doengrave); - cmdq_add_key(CQ_CANNED, otmp->invlet); - break; - case IA_FIRE_OBJ: - cmdq_add_ec(CQ_CANNED, dofire); - break; - case IA_ADJUST_OBJ: - cmdq_add_ec(CQ_CANNED, doorganize); /* #adjust */ - cmdq_add_key(CQ_CANNED, otmp->invlet); - break; - case IA_ADJUST_STACK: - cmdq_add_ec(CQ_CANNED, adjust_split); /* #altadjust */ - cmdq_add_key(CQ_CANNED, otmp->invlet); - break; - case IA_SACRIFICE: - cmdq_add_ec(CQ_CANNED, dosacrifice); - cmdq_add_key(CQ_CANNED, otmp->invlet); - break; - case IA_BUY_OBJ: - cmdq_add_ec(CQ_CANNED, dopay); - cmdq_add_key(CQ_CANNED, otmp->invlet); - break; - case IA_QUAFF_OBJ: - /* start with m-prefix; for #quaff, it means ignore fountain - or sink if present and drink a potion from invent */ - cmdq_add_ec(CQ_CANNED, do_reqmenu); - cmdq_add_ec(CQ_CANNED, dodrink); - cmdq_add_key(CQ_CANNED, otmp->invlet); - break; - case IA_QUIVER_OBJ: - cmdq_add_ec(CQ_CANNED, dowieldquiver); - cmdq_add_key(CQ_CANNED, otmp->invlet); - break; - case IA_READ_OBJ: - cmdq_add_ec(CQ_CANNED, doread); - cmdq_add_key(CQ_CANNED, otmp->invlet); - break; - case IA_RUB_OBJ: - cmdq_add_ec(CQ_CANNED, dorub); - cmdq_add_key(CQ_CANNED, otmp->invlet); - break; - case IA_THROW_OBJ: - cmdq_add_ec(CQ_CANNED, dothrow); - cmdq_add_key(CQ_CANNED, otmp->invlet); - break; - case IA_TAKEOFF_OBJ: - cmdq_add_ec(CQ_CANNED, ia_dotakeoff); /* #altdotakeoff */ - cmdq_add_key(CQ_CANNED, otmp->invlet); - break; - case IA_TIP_CONTAINER: - /* start with m-prefix to skip floor containers; - for menustyle:Traditional when more than one floor container - is present, player will get a #tip menu and have to pick - the "tip something being carried" choice, then this item - will be already chosen from inventory; suboptimal but - possibly an acceptable tradeoff since combining item actions - with use of traditional ggetobj() is an unlikely scenario */ - cmdq_add_ec(CQ_CANNED, do_reqmenu); - cmdq_add_ec(CQ_CANNED, dotip); - cmdq_add_key(CQ_CANNED, otmp->invlet); - break; - case IA_INVOKE_OBJ: - cmdq_add_ec(CQ_CANNED, doinvoke); - cmdq_add_key(CQ_CANNED, otmp->invlet); - break; - case IA_WIELD_OBJ: - cmdq_add_ec(CQ_CANNED, dowield); - cmdq_add_key(CQ_CANNED, otmp->invlet); - break; - case IA_WEAR_OBJ: - cmdq_add_ec(CQ_CANNED, dowear); - cmdq_add_key(CQ_CANNED, otmp->invlet); - break; - case IA_SWAPWEAPON: - cmdq_add_ec(CQ_CANNED, doswapweapon); - break; - case IA_TWOWEAPON: - cmdq_add_ec(CQ_CANNED, dotwoweapon); - break; - case IA_ZAP_OBJ: - cmdq_add_ec(CQ_CANNED, dozap); - cmdq_add_key(CQ_CANNED, otmp->invlet); - break; - case IA_WHATIS_OBJ: - cmdq_add_ec(CQ_CANNED, dowhatis); /* "/" command */ - cmdq_add_key(CQ_CANNED, 'i'); /* "i" == item from inventory */ - cmdq_add_key(CQ_CANNED, otmp->invlet); - break; - } -} - -/* Show menu of possible actions hero could do with item otmp */ -staticfn int -itemactions(struct obj *otmp) -{ - int n, act = IA_NONE; - winid win; - char buf[BUFSZ], buf2[BUFSZ]; - menu_item *selected; - struct monst *mtmp; - const char *light = otmp->lamplit ? "Extinguish" : "Light"; - boolean already_worn = (otmp->owornmask & (W_ARMOR | W_ACCESSORY)) != 0; - - win = create_nhwindow(NHW_MENU); - start_menu(win, MENU_BEHAVE_STANDARD); - - /* -: unwield; picking current weapon offers an opportunity for 'w-' - to wield bare/gloved hands; likewise for 'Q-' with quivered item(s) */ - if (otmp == uwep || otmp == uswapwep || otmp == uquiver) { - const char *verb = (otmp == uquiver) ? "Quiver" : "Wield", - *action = (otmp == uquiver) ? "un-ready" : "un-wield", - *which = is_plural(otmp) ? "these" : "this", - *what = ((otmp->oclass == WEAPON_CLASS || is_weptool(otmp)) - ? "weapon" : "item"); - /* - * TODO: if uwep is ammo, tell player that to shoot instead of toss, - * the corresponding launcher must be wielded; - */ - Sprintf(buf, "%s '%c' to %s %s %s", - verb, HANDS_SYM, action, which, - is_plural(otmp) ? makeplural(what) : what); - ia_addmenu(win, IA_UNWIELD, '-', buf); - } - - /* a: apply */ - if (otmp->oclass == COIN_CLASS) - ia_addmenu(win, IA_APPLY_OBJ, 'a', "Flip a coin"); - else if (otmp->otyp == CREAM_PIE) - ia_addmenu(win, IA_APPLY_OBJ, 'a', - "Hit yourself with this cream pie"); - else if (otmp->otyp == BULLWHIP) - ia_addmenu(win, IA_APPLY_OBJ, 'a', "Lash out with this whip"); - else if (otmp->otyp == GRAPPLING_HOOK) - ia_addmenu(win, IA_APPLY_OBJ, 'a', - "Grapple something with this hook"); - else if (otmp->otyp == BAG_OF_TRICKS && objects[otmp->otyp].oc_name_known) - /* bag of tricks skips this unless discovered */ - ia_addmenu(win, IA_APPLY_OBJ, 'a', "Reach into this bag"); - else if (Is_container(otmp)) - /* bag of tricks gets here only if not yet discovered */ - ia_addmenu(win, IA_APPLY_OBJ, 'a', "Open this container"); - else if (otmp->otyp == CAN_OF_GREASE) - ia_addmenu(win, IA_APPLY_OBJ, 'a', "Use the can to grease an item"); - else if (otmp->otyp == LOCK_PICK - || otmp->otyp == CREDIT_CARD - || otmp->otyp == SKELETON_KEY) - ia_addmenu(win, IA_APPLY_OBJ, 'a', "Use this tool to pick a lock"); - else if (otmp->otyp == TINNING_KIT) - ia_addmenu(win, IA_APPLY_OBJ, 'a', "Use this kit to tin a corpse"); - else if (otmp->otyp == LEASH) - ia_addmenu(win, IA_APPLY_OBJ, 'a', "Tie a pet to this leash"); - else if (otmp->otyp == SADDLE) - ia_addmenu(win, IA_APPLY_OBJ, 'a', "Place this saddle on a pet"); - else if (otmp->otyp == MAGIC_WHISTLE - || otmp->otyp == TIN_WHISTLE) - ia_addmenu(win, IA_APPLY_OBJ, 'a', "Blow this whistle"); - else if (otmp->otyp == EUCALYPTUS_LEAF) - ia_addmenu(win, IA_APPLY_OBJ, 'a', "Use this leaf as a whistle"); - else if (otmp->otyp == STETHOSCOPE) - ia_addmenu(win, IA_APPLY_OBJ, 'a', "Listen through the stethoscope"); - else if (otmp->otyp == MIRROR) - ia_addmenu(win, IA_APPLY_OBJ, 'a', "Show something its reflection"); - else if (otmp->otyp == BELL || otmp->otyp == BELL_OF_OPENING) - ia_addmenu(win, IA_APPLY_OBJ, 'a', "Ring the bell"); - else if (otmp->otyp == CANDELABRUM_OF_INVOCATION) { - Sprintf(buf, "%s the candelabrum", light); - ia_addmenu(win, IA_APPLY_OBJ, 'a', buf); - } else if (otmp->otyp == WAX_CANDLE || otmp->otyp == TALLOW_CANDLE) { - boolean multiple = (otmp->quan == 1L) ? FALSE : TRUE; - const char *s = multiple ? "these" : "this"; - struct obj *o = carrying(CANDELABRUM_OF_INVOCATION); - - if (o && o->spe < 7) - Sprintf(buf, "Attach %s to your candelabrum, or %s %s", s, - !otmp->lamplit ? "light" : "extinguish", /* [lowercase] */ - multiple ? "them" : "it"); - else - Sprintf(buf, "%s %s %s", light, s, simpleonames(otmp)); - ia_addmenu(win, IA_APPLY_OBJ, 'a', buf); - } else if (otmp->otyp == OIL_LAMP || otmp->otyp == MAGIC_LAMP - || otmp->otyp == BRASS_LANTERN) { - Sprintf(buf, "%s this light source", light); - ia_addmenu(win, IA_APPLY_OBJ, 'a', buf); - } else if (otmp->otyp == POT_OIL && objects[otmp->otyp].oc_name_known) { - Sprintf(buf, "%s this oil", light); - ia_addmenu(win, IA_APPLY_OBJ, 'a', buf); - } else if (otmp->oclass == POTION_CLASS) { - /* FIXME? this should probably be moved to 'D' rather than be 'a' */ - Sprintf(buf, "Dip something into %s potion%s", - is_plural(otmp) ? "one of these" : "this", plur(otmp->quan)); - ia_addmenu(win, IA_DIP_OBJ, 'a', buf); - } else if (otmp->otyp == EXPENSIVE_CAMERA) - ia_addmenu(win, IA_APPLY_OBJ, 'a', "Take a photograph"); - else if (otmp->otyp == TOWEL) - ia_addmenu(win, IA_APPLY_OBJ, 'a', - "Clean yourself off with this towel"); - else if (otmp->otyp == CRYSTAL_BALL) - ia_addmenu(win, IA_APPLY_OBJ, 'a', "Peer into this crystal ball"); - else if (otmp->otyp == MAGIC_MARKER) - ia_addmenu(win, IA_APPLY_OBJ, 'a', - "Write on something with this marker"); - else if (otmp->otyp == FIGURINE) - ia_addmenu(win, IA_APPLY_OBJ, 'a', "Make this figurine transform"); - else if (otmp->otyp == UNICORN_HORN) - ia_addmenu(win, IA_APPLY_OBJ, 'a', "Use this unicorn horn"); - else if (otmp->otyp == HORN_OF_PLENTY - && objects[otmp->otyp].oc_name_known) - ia_addmenu(win, IA_APPLY_OBJ, 'a', "Blow into the horn of plenty"); - else if (otmp->otyp >= WOODEN_FLUTE && otmp->otyp <= DRUM_OF_EARTHQUAKE) - ia_addmenu(win, IA_APPLY_OBJ, 'a', "Play this musical instrument"); - else if (otmp->otyp == LAND_MINE || otmp->otyp == BEARTRAP) - ia_addmenu(win, IA_APPLY_OBJ, 'a', "Arm this trap"); - else if (otmp->otyp == PICK_AXE || otmp->otyp == DWARVISH_MATTOCK) - ia_addmenu(win, IA_APPLY_OBJ, 'a', "Dig with this digging tool"); - else if (otmp->oclass == WAND_CLASS) - ia_addmenu(win, IA_APPLY_OBJ, 'a', "Break this wand"); - - /* 'c', 'C' - call an item or its type something */ - if (item_naming_classification(otmp, buf, buf2)) { - if (*buf) - ia_addmenu(win, IA_NAME_OBJ, 'c', buf); - if (*buf2) - ia_addmenu(win, IA_NAME_OTYP, 'C', buf2); - } - - /* d: drop item, works on everything except worn items; those will - always have a takeoff/remove choice so we don't have to worry - about the menu maybe being empty when 'd' is suppressed */ - if (!already_worn) { - Sprintf(buf, "Drop this %s", (otmp->quan > 1L) ? "stack" : "item"); - ia_addmenu(win, IA_DROP_OBJ, 'd', buf); - } - - /* e: eat item */ - if (otmp->otyp == TIN) { - Sprintf(buf, "Open %s%s and eat the contents", - (otmp->quan > 1L) ? "one of these tins" : "this tin", - (otmp->otyp == TIN && uwep && uwep->otyp == TIN_OPENER) - ? " with your tin opener" : ""); - ia_addmenu(win, IA_EAT_OBJ, 'e', buf); - } else if (is_edible(otmp)) { - Sprintf(buf, "Eat %s", (otmp->quan > 1L) ? "one of these" : "this"); - ia_addmenu(win, IA_EAT_OBJ, 'e', buf); - } - - /* E: engrave with item */ - if (otmp->otyp == TOWEL) { - ia_addmenu(win, IA_ENGRAVE_OBJ, 'E', - "Wipe the floor with this towel"); - } else if (otmp->otyp == MAGIC_MARKER) { - ia_addmenu(win, IA_ENGRAVE_OBJ, 'E', - "Scribble graffiti on the floor"); - } else if (otmp->oclass == WEAPON_CLASS || otmp->oclass == WAND_CLASS - || otmp->oclass == GEM_CLASS || otmp->oclass == RING_CLASS) { - Sprintf(buf, "%s on the %s with %s", - (is_blade(otmp) || otmp->oclass == WAND_CLASS - || ((otmp->oclass == GEM_CLASS || otmp->oclass == RING_CLASS) - && objects[otmp->otyp].oc_tough)) ? "Engrave" : "Write", - surface(u.ux, u.uy), - (otmp->quan > 1L) ? "one of these items" : "this item"); - ia_addmenu(win, IA_ENGRAVE_OBJ, 'E', buf); - } - - /* f: fire quivered ammo */ - if (otmp == uquiver) { - boolean shoot = ammo_and_launcher(otmp, uwep); - - /* FIXME: see the multi-shot FIXME about "one of" for 't: throw' */ - Sprintf(buf, "%s %s", shoot ? "Shoot" : "Throw", - (otmp->quan > 1L) ? "one of these" : "this"); - if (shoot) { - assert(uwep != NULL); - Sprintf(eos(buf), " with your wielded %s", simpleonames(uwep)); - } - ia_addmenu(win, IA_FIRE_OBJ, 'f', buf); - } - - /* i: #adjust inventory letter; gold can't be adjusted unless there - is some in a slot other than '$' (which shouldn't be possible) */ - if (otmp->oclass != COIN_CLASS || check_invent_gold("item-action")) - ia_addmenu(win, IA_ADJUST_OBJ, 'i', - "Adjust inventory by assigning new letter"); - /* I: #adjust inventory item by splitting its stack */ - if (otmp->quan > 1L && otmp->oclass != COIN_CLASS) - ia_addmenu(win, IA_ADJUST_STACK, 'I', - "Adjust inventory by splitting this stack"); - - /* O: offer sacrifice */ - if (IS_ALTAR(levl[u.ux][u.uy].typ) && !u.uswallow) { - /* FIXME: this doesn't match #offer's likely candidates, which don't - include corpses on Astral and don't include amulets off Astral */ - if (otmp->otyp == CORPSE) - ia_addmenu(win, IA_SACRIFICE, 'O', - "Offer this corpse as a sacrifice at this altar"); - else if (otmp->otyp == AMULET_OF_YENDOR - || otmp->otyp == FAKE_AMULET_OF_YENDOR) - ia_addmenu(win, IA_SACRIFICE, 'O', - "Offer this amulet as a sacrifice at this altar"); - } - - /* p: pay for unpaid utems */ - if (otmp->unpaid - /* FIXME: should also handle player owned container (so not - flagged 'unpaid') holding shop owned items */ - && (mtmp = shop_keeper(*in_rooms(u.ux, u.uy, SHOPBASE))) != 0 - && inhishop(mtmp)) { - Sprintf(buf, "Buy this unpaid %s", - (otmp->quan > 1L) ? "stack" : "item"); - ia_addmenu(win, IA_BUY_OBJ, 'p', buf); - } - - /* P: put on accessory */ - if (!already_worn) { - /* if 'otmp' is worn, we'll skip 'P' and show 'R' below; - if not worn, we show 'P - Put on this ' if - the slot is available, or 'P - '; for the latter, - 'P' will fail but we don't want to omit the choice because - item actions can be used to learn commands */ - *buf = '\0'; - if (otmp->oclass == AMULET_CLASS) { - Strcpy(buf, !uamul ? "Put this amulet on" - : "[already wearing an amulet]"); - } else if (otmp->oclass == RING_CLASS || otmp->otyp == MEAT_RING) { - if (!uleft || !uright) - Strcpy(buf, "Put this ring on"); - else - Sprintf(buf, "[both ring %s in use]", - makeplural(body_part(FINGER))); - } else if (otmp->otyp == BLINDFOLD || otmp->otyp == TOWEL - || otmp->otyp == LENSES) { - if (ublindf) - Strcpy(buf, "[already wearing eyewear]"); - else if (otmp->otyp == LENSES) - Strcpy(buf, "Put these lenses on"); - else - Sprintf(buf, "Put this on%s", - (otmp->otyp == TOWEL) ? " to blindfold yourself" : ""); - } - if (*buf) - ia_addmenu(win, IA_WEAR_OBJ, 'P', buf); - } - - /* q: drink item */ - if (otmp->oclass == POTION_CLASS) { - Sprintf(buf, "Quaff (drink) %s", - (otmp->quan > 1L) ? "one of these potions" : "this potion"); - ia_addmenu(win, IA_QUAFF_OBJ, 'q', buf); - } - - /* Q: quiver throwable item */ - if ((otmp->oclass == GEM_CLASS || otmp->oclass == WEAPON_CLASS) - && otmp != uquiver) { - Sprintf(buf, "Quiver this %s for easy %s with \'f\'ire", - (otmp->quan > 1L) ? "stack" : "item", - ammo_and_launcher(otmp, uwep) ? "shooting" : "throwing"); - ia_addmenu(win, IA_QUIVER_OBJ, 'Q', buf); - } - - /* r: read item */ - if (item_reading_classification(otmp, buf) == IA_READ_OBJ) - ia_addmenu(win, IA_READ_OBJ, 'r', buf); - - /* R: remove accessory or rub item */ - if (otmp->owornmask & W_ACCESSORY) { - Sprintf(buf, "Remove this %s", - (otmp->owornmask & W_AMUL) ? "amulet" - : (otmp->owornmask & W_RING) ? "ring" - : (otmp->owornmask & W_TOOL) ? "eyewear" - : "accessory"); /* catchall -- can't happen */ - ia_addmenu(win, IA_TAKEOFF_OBJ, 'R', buf); - } - if (otmp->otyp == OIL_LAMP || otmp->otyp == MAGIC_LAMP - || otmp->otyp == BRASS_LANTERN) { - Sprintf(buf, "Rub this %s", simpleonames(otmp)); - ia_addmenu(win, IA_RUB_OBJ, 'R', buf); - } else if (otmp->oclass == GEM_CLASS && is_graystone(otmp)) - ia_addmenu(win, IA_RUB_OBJ, 'R', "Rub something on this stone"); - - /* t: throw item */ - if (!already_worn) { - boolean shoot = ammo_and_launcher(otmp, uwep); - - /* - * FIXME: - * 'one of these' should be changed to 'some of these' when there - * is the possibility of a multi-shot volley but we don't have - * any way to determine that except by actually calculating the - * volley count and that could randomly yield 1 here and 2..N - * while throwing or vice versa. - */ - Sprintf(buf, "%s %s%s", shoot ? "Shoot" : "Throw", - (otmp->quan == 1L) ? "this item" - : (otmp->otyp == GOLD_PIECE) ? "them" - : "one of these", - /* if otmp is quivered, we've already listed - 'f - shoot|throw this item' as a choice; - if 't' is duplicating that, say so ('t' and 'f' - behavior differs for throwing a stack of gold) */ - (otmp == uquiver && (otmp->otyp != GOLD_PIECE - || otmp->quan == 1L)) - ? " (same as 'f')" : ""); - ia_addmenu(win, IA_THROW_OBJ, 't', buf); - } - - /* T: take off armor, tip carried container */ - if (otmp->owornmask & W_ARMOR) - ia_addmenu(win, IA_TAKEOFF_OBJ, 'T', "Take off this armor"); - if ((Is_container(otmp) && (Has_contents(otmp) || !otmp->cknown)) - || (otmp->otyp == HORN_OF_PLENTY && (otmp->spe > 0 || !otmp->known))) - ia_addmenu(win, IA_TIP_CONTAINER, 'T', - "Tip all the contents out of this container"); - - /* V: invoke */ - if ((otmp->otyp == FAKE_AMULET_OF_YENDOR && !otmp->known) - || otmp->oartifact || objects[otmp->otyp].oc_unique - /* non-artifact crystal balls don't have any unique power but - the #invoke command lists them as likely candidates */ - || otmp->otyp == CRYSTAL_BALL) - ia_addmenu(win, IA_INVOKE_OBJ, 'V', - "Try to invoke a unique power of this object"); - - /* w: wield, hold in hands, works on everything but with different - advice text; not mentioned for things that are already wielded */ - if (otmp == uwep || cantwield(gy.youmonst.data)) { - ; /* either already wielded or can't wield anything; skip 'w' */ - } else if (otmp->oclass == WEAPON_CLASS || is_weptool(otmp) - || is_wet_towel(otmp) || otmp->otyp == HEAVY_IRON_BALL) { - Sprintf(buf, "Wield this %s as your weapon", - (otmp->quan > 1L) ? "stack" : "item"); - ia_addmenu(win, IA_WIELD_OBJ, 'w', buf); - } else if (otmp->otyp == TIN_OPENER) { - ia_addmenu(win, IA_WIELD_OBJ, 'w', - "Wield the tin opener to easily open tins"); - } else if (!already_worn) { - /* originally this was using "hold this item in your hands" but - there's no concept of "holding an item", plus it unwields - whatever item you already have wielded so use "wield this item" */ - Sprintf(buf, "Wield this %s in your %s", - (otmp->quan > 1L) ? "stack" : "item", - /* only two-handed weapons and unicorn horns care about - pluralizing "hand" and they won't reach here, but plural - sounds better when poly'd into something with "claw" */ - makeplural(body_part(HAND))); - ia_addmenu(win, IA_WIELD_OBJ, 'w', buf); - } - - /* W: wear armor */ - if (!already_worn) { - if (otmp->oclass == ARMOR_CLASS) { - /* if 'otmp' is worn we skip 'W' (and show 'T' above instead); - if it isn't, we either show "W - wear this" if otmp's slot - isn't populated, or "W - [already wearing ]"; - for the latter, picking 'W' will fail but we don't want to - omit 'W' in this situation */ - long Wmask = armcat_to_wornmask(objects[otmp->otyp].oc_armcat); - struct obj *o = wearmask_to_obj(Wmask); - - if (!o) - Strcpy(buf, "Wear this armor"); - else - Sprintf(buf, "[already wearing %s]", an(armor_simple_name(o))); - - ia_addmenu(win, IA_WEAR_OBJ, 'W', buf); - } - } - - /* x: Swap main and readied weapon */ - if (otmp == uwep && uswapwep) - ia_addmenu(win, IA_SWAPWEAPON, 'x', - "Swap this with your alternate weapon"); - else if (otmp == uwep) - ia_addmenu(win, IA_SWAPWEAPON, 'x', - "Ready this as an alternate weapon"); - else if (otmp == uswapwep) - ia_addmenu(win, IA_SWAPWEAPON, 'x', - "Swap this with your main weapon"); - - /* this is based on TWOWEAPOK() in wield.c; we don't call can_two_weapon() - because it is very verbose; attempting to two-weapon might be rejected - but we screen out most reasons for rejection before offering it as a - choice */ -#define MAYBETWOWEAPON(obj) \ - ((((obj)->oclass == WEAPON_CLASS) \ - ? !(is_launcher(obj) || is_ammo(obj) || is_missile(obj)) \ - : is_weptool(obj)) \ - && !bimanual(obj)) - - /* X: Toggle two-weapon mode on or off */ - if ((otmp == uwep || otmp == uswapwep) - /* if already two-weaponing, no special checks needed to toggle off */ - && (u.twoweap - /* but if not, try to filter most "you can't do that" here */ - || (could_twoweap(gy.youmonst.data) && !uarms - && uwep && MAYBETWOWEAPON(uwep) - && uswapwep && MAYBETWOWEAPON(uswapwep)))) { - Sprintf(buf, "Toggle two-weapon combat %s", u.twoweap ? "off" : "on"); - ia_addmenu(win, IA_TWOWEAPON, 'X', buf); - } - -#undef MAYBETWOWEAPON - - /* z: Zap wand */ - if (otmp->oclass == WAND_CLASS) - ia_addmenu(win, IA_ZAP_OBJ, 'z', - "Zap this wand to release its magic"); - - /* ?: Look up an item in the game's database */ - if (ia_checkfile(otmp)) { - Sprintf(buf, "Look up information about %s", - (otmp->quan > 1L) ? "these" : "this"); - ia_addmenu(win, IA_WHATIS_OBJ, '/', buf); - } - - Sprintf(buf, "Do what with %s?", the(cxname(otmp))); - end_menu(win, buf); - - n = select_menu(win, PICK_ONE, &selected); - - if (n > 0) { - act = selected[0].item.a_int; - free((genericptr_t) selected); - - itemactions_pushkeys(otmp, act); - } - destroy_nhwindow(win); - - /* finish the 'i' command: no time elapses and cancelling without - selecting an action doesn't matter */ - return ECMD_OK; -} /* show some or all of inventory while allowing the picking of an item in order to preform context-sensitive item action on it; always returns 'ok'; diff --git a/sys/msdos/Makefile.GCC b/sys/msdos/Makefile.GCC index 8ae2be4dc..bdf4391e3 100644 --- a/sys/msdos/Makefile.GCC +++ b/sys/msdos/Makefile.GCC @@ -296,7 +296,7 @@ VOBJ22 = $(O)topl.o $(O)topten.o $(O)trap.o $(O)u_init.o $(O)uhitm.o VOBJ23 = $(O)utf8map.o $(O)vault.o $(O)track.o $(O)vision.o $(O)weapon.o VOBJ24 = $(O)were.o $(O)wield.o $(O)windows.o $(O)wintty.o $(O)wizard.o VOBJ25 = $(O)wizcmds.o $(O)worm.o $(O)worn.o $(O)write.o $(O)zap.o -VOBJ26 = $(O)light.o $(O)dlb.o $(REGEX) +VOBJ26 = $(O)light.o $(O)dlb.o $(O)iactions.o $(REGEX) SOBJ = $(O)msdos.o $(O)pcsys.o $(O)tty.o $(O)unix.o \ $(O)video.o $(O)vidtxt.o $(O)pckeys.o @@ -1399,6 +1399,7 @@ $(TARGETPFX)files.o: files.c $(HACK_H) ../include/dlb.h ../include/wintty.h \ $(TARGETPFX)fountain.o: fountain.c $(HACK_H) $(TARGETPFX)hack.o: hack.c $(HACK_H) $(TARGETPFX)hacklib.o: hacklib.c $(HACK_H) +$(TARGETPFX)iactions.o: iactions.c $(HACK_H) $(TARGETPFX)insight.o: insight.c $(HACK_H) $(TARGETPFX)invent.o: invent.c $(HACK_H) $(TARGETPFX)isaac64.o: isaac64.c $(CONFIG_H) ../include/isaac64.h diff --git a/sys/unix/Makefile.src b/sys/unix/Makefile.src index e5a30e3c1..81a6b72a6 100644 --- a/sys/unix/Makefile.src +++ b/sys/unix/Makefile.src @@ -519,7 +519,7 @@ HACKCSRC = allmain.c alloc.c apply.c artifact.c attrib.c ball.c bones.c \ dlb.c do.c do_name.c do_wear.c dog.c dogmove.c dokick.c dothrow.c \ drawing.c dungeon.c eat.c end.c engrave.c exper.c explode.c \ extralev.c files.c fountain.c hack.c hacklib.c \ - getpos.c glyphs.c insight.c invent.c isaac64.c light.c \ + getpos.c glyphs.c iactions.c insight.c invent.c isaac64.c light.c \ lock.c mail.c makemon.c mcastu.c mdlib.c mhitm.c \ mhitu.c minion.c mklev.c mkmap.c mkmaze.c mkobj.c mkroom.c mon.c \ mondata.c monmove.c monst.c mplayer.c mthrowu.c muse.c music.c \ @@ -601,6 +601,7 @@ HOBJ = $(TARGETPFX)allmain.o $(TARGETPFX)alloc.o \ $(TARGETPFX)engrave.o $(TARGETPFX)exper.o $(TARGETPFX)explode.o \ $(TARGETPFX)extralev.o $(TARGETPFX)files.o $(TARGETPFX)fountain.o \ $(TARGETPFX)getpos.o $(TARGETPFX)glyphs.o $(TARGETPFX)hack.o \ + $(TARGETPFX)iactions.o \ $(TARGETPFX)insight.o $(TARGETPFX)invent.o $(TARGETPFX)isaac64.o \ $(TARGETPFX)light.o $(TARGETPFX)lock.o $(TARGETPFX)mail.o \ $(TARGETPFX)makemon.o $(TARGETPFX)mcastu.o $(TARGETPFX)mdlib.o \ @@ -1176,6 +1177,7 @@ $(TARGETPFX)getpos.o: getpos.c $(HACK_H) $(TARGETPFX)glyphs.o: glyphs.c $(HACK_H) $(TARGETPFX)hack.o: hack.c $(HACK_H) $(TARGETPFX)hacklib.o: hacklib.c $(HACK_H) +$(TARGETPFX)iactions.o: iactions.c $(HACK_H) $(TARGETPFX)insight.o: insight.c $(HACK_H) $(TARGETPFX)invent.o: invent.c $(HACK_H) $(TARGETPFX)isaac64.o: isaac64.c $(CONFIG_H) ../include/isaac64.h diff --git a/sys/vms/Makefile.src b/sys/vms/Makefile.src index dee166f8e..9cf3f465f 100644 --- a/sys/vms/Makefile.src +++ b/sys/vms/Makefile.src @@ -151,7 +151,7 @@ HACKCSRC = allmain.c alloc.c apply.c artifact.c attrib.c ball.c bones.c \ dig.c display.c dlb.c do.c do_name.c do_wear.c dog.c dogmove.c dokick.c \ dothrow.c drawing.c dungeon.c eat.c end.c engrave.c exper.c \ explode.c extralev.c files.c fountain.c getpos.c glyphs.c hack.c \ - hacklib.c insight.c invent.c light.c lock.c \ + hacklib.c iactions.c insight.c invent.c light.c lock.c \ mail.c makemon.c mcastu.c mhitm.c mhitu.c minion.c \ mklev.c mkmap.c mkmaze.c mkobj.c mkroom.c mon.c mondata.c \ monmove.c monst.c mplayer.c mthrowu.c muse.c music.c o_init.c \ @@ -200,7 +200,7 @@ HOBJ1 = allmain.obj,alloc.obj,apply.obj,artifact.obj,attrib.obj, \ HOBJ2 = dog.obj,dogmove.obj,dokick.obj,dothrow.obj,drawing.obj, \ dungeon.obj,eat.obj,end.obj,engrave.obj,exper.obj,explode.obj, \ extralev.obj,files.obj,fountain.obj,getpos.obj,glyphs.obj,hack.obj, \ - hacklib.obj,insight.obj,invent.obj + hacklib.obj,iactions.obj,insight.obj,invent.obj HOBJ3 = light.obj,lock.obj,mail.obj,makemon.obj,mcastu.obj, \ mhitm.obj,mhitu.obj,minion.obj,mklev.obj,mkmap.obj,mkmaze.obj, \ mkobj.obj,mkroom.obj,mon.obj,mondata.obj,monmove.obj @@ -529,6 +529,7 @@ files.obj : files.c $(HACK_H) $(INC)dlb.h $(INC)wintty.h #zlib.h fountain.obj : fountain.c $(HACK_H) hack.obj : hack.c $(HACK_H) hacklib.obj : hacklib.c $(HACK_H) +iactions.obj : iactions.c $(HACK_H) insight.obj : insight.c $(HACK_H) invent.obj : invent.c $(HACK_H) light.obj : light.c $(HACK_H) diff --git a/sys/vms/Makefile_src.vms b/sys/vms/Makefile_src.vms index 937200a20..56b35aa58 100644 --- a/sys/vms/Makefile_src.vms +++ b/sys/vms/Makefile_src.vms @@ -130,7 +130,7 @@ HACKFILES := allmain alloc apply artifact attrib ball bones botl \ sp_lev spell stairs steal steed strutil symbols sys teleport \ timeout topten track trap u_init utf8map \ uhitm vault version vision weapon were wield \ - windows wizard wizcmds worm worn write zap + windows wizard wizcmds worm worn write zap iactions # the date file DATEFILES = date @@ -735,6 +735,7 @@ $(TARGETPFX)getpos.obj: getpos.c $(HACK_H) $(TARGETPFX)glyphs.obj: glyphs.c $(HACK_H) $(TARGETPFX)hack.obj: hack.c $(HACK_H) $(TARGETPFX)hacklib.obj: hacklib.c $(HACK_H) +$(TARGETPFX)iactions.obj: iactions.c $(HACK_H) $(TARGETPFX)insight.obj: insight.c $(HACK_H) $(TARGETPFX)invent.obj: invent.c $(HACK_H) $(TARGETPFX)isaac64.obj: isaac64.c $(CONFIG_H) $(INCL)isaac64.h diff --git a/sys/vms/vmsbuild.com b/sys/vms/vmsbuild.com index e34309fce..3749ffe04 100755 --- a/sys/vms/vmsbuild.com +++ b/sys/vms/vmsbuild.com @@ -425,7 +425,7 @@ $ c_list = "allmain,apply,artifact,attrib,ball,bones,botl,calendar,cmd" - + ",do_wear,dog,dogmove,dokick,dungeon,eat,end,engrave,exper,explode" - + ",extralev,files,fountain,getpos,glyphs" $ gosub compile_list -$ c_list = "hack,hacklib,insight,invent,light,lock,mail,makemon" - +$ c_list = "hack,hacklib,iactions,insight,invent,light,lock,mail,makemon" - + ",mcastu,mdlib,mhitm,mhitu,minion,mklev,mkmap,mkmaze" - + ",mkobj,mkroom,mon,mondata,monmove,mplayer,mthrowu,muse" - + ",music" diff --git a/sys/windows/GNUmakefile b/sys/windows/GNUmakefile index c964d780c..6f282c632 100644 --- a/sys/windows/GNUmakefile +++ b/sys/windows/GNUmakefile @@ -1232,7 +1232,7 @@ COREOBJS = $(addsuffix .o, allmain alloc apply artifact attrib ball bones botl \ dbridge decl detect dig display dlb do do_name do_wear \ dog dogmove dokick dothrow drawing dungeon \ eat end engrave exper explode extralev files fountain \ - getpos glyphs hack insight invent isaac64 light lock \ + getpos glyphs hack iactions insight invent isaac64 light lock \ mail makemon mcastu mdlib mhitm mhitu minion mklev mkmap mkmaze mkobj mkroom \ mon mondata monmove monst mplayer mthrowu muse music \ nhlobj nhlsel nhlua windsound o_init objects objnam options \ diff --git a/sys/windows/Makefile.nmake b/sys/windows/Makefile.nmake index e50f9fb21..faa637986 100644 --- a/sys/windows/Makefile.nmake +++ b/sys/windows/Makefile.nmake @@ -659,6 +659,7 @@ HACKCSRC = \ $(SRC)drawing.c $(SRC)dungeon.c $(SRC)eat.c $(SRC)end.c \ $(SRC)engrave.c $(SRC)exper.c $(SRC)explode.c $(SRC)files.c \ $(SRC)fountain.c $(SRC)getpos.c $(SRC)glyphs.c $(SRC)hack.c \ + $(SRC)iactions.c \ $(SRC)insight.c $(SRC)invent.c $(SRC)isaac64.c $(SRC)light.c \ $(SRC)lock.c $(SRC)mail.c $(SRC)makemon.c $(SRC)mcastu.c \ $(SRC)mdlib.c $(SRC)mhitm.c $(SRC)mhitu.c $(SRC)minion.c \ @@ -862,6 +863,7 @@ COREOBJTTY = \ $(OTTY)drawing.o $(OTTY)dungeon.o $(OTTY)eat.o $(OTTY)end.o \ $(OTTY)engrave.o $(OTTY)exper.o $(OTTY)explode.o $(OTTY)extralev.o \ $(OTTY)files.o $(OTTY)fountain.o $(OTTY)getpos.o $(OTTY)glyphs.o \ + $(OTTY)iactions.o \ $(OTTY)hack.o $(OTTY)insight.o $(OTTY)invent.o $(OTTY)isaac64.o \ $(OTTY)light.o $(OTTY)lock.o $(OTTY)mail.o $(OTTY)makemon.o \ $(OTTY)mcastu.o $(OTTY)mhitm.o $(OTTY)mhitu.o $(OTTY)minion.o \ @@ -925,6 +927,7 @@ COREOBJGUI = \ $(OGUI)drawing.o $(OGUI)dungeon.o $(OGUI)eat.o $(OGUI)end.o \ $(OGUI)engrave.o $(OGUI)exper.o $(OGUI)explode.o $(OGUI)extralev.o \ $(OGUI)files.o $(OGUI)fountain.o $(OGUI)getpos.o $(OGUI)glyphs.o \ + $(OGUI)iactions.o \ $(OGUI)hack.o $(OGUI)insight.o $(OGUI)invent.o $(OGUI)isaac64.o \ $(OGUI)light.o $(OGUI)lock.o $(OGUI)mail.o $(OGUI)makemon.o \ $(OGUI)mcastu.o $(OGUI)mhitm.o $(OGUI)mhitu.o $(OGUI)minion.o \ @@ -3257,6 +3260,7 @@ $(OTTY)getpos.o: getpos.c $(HACK_H) $(OTTY)glyphs.o: glyphs.c $(HACK_H) $(OTTY)hack.o: hack.c $(HACK_H) $(OTTY)hacklib.o: hacklib.c $(HACK_H) +$(OTTY)iactions.o: iactions.c $(HACK_H) $(OTTY)insight.o: insight.c $(HACK_H) $(OTTY)invent.o: invent.c $(HACK_H) $(OTTY)isaac64.o: isaac64.c $(CONFIG_H) $(INCL)isaac64.h @@ -3636,6 +3640,7 @@ $(OGUI)getpos.o: getpos.c $(HACK_H) $(OGUI)glyphs.o: glyphs.c $(HACK_H) $(OGUI)hack.o: hack.c $(HACK_H) $(OGUI)hacklib.o: hacklib.c $(HACK_H) +$(OGUI)iactions.o: iactions.c $(HACK_H) $(OGUI)insight.o: insight.c $(HACK_H) $(OGUI)invent.o: invent.c $(HACK_H) $(OGUI)isaac64.o: isaac64.c $(CONFIG_H) $(INCL)isaac64.h diff --git a/sys/windows/vs/NetHack/NetHack.vcxproj b/sys/windows/vs/NetHack/NetHack.vcxproj index d2ca44c61..5df071e6c 100644 --- a/sys/windows/vs/NetHack/NetHack.vcxproj +++ b/sys/windows/vs/NetHack/NetHack.vcxproj @@ -125,6 +125,7 @@ + diff --git a/sys/windows/vs/NetHackW/NetHackW.vcxproj b/sys/windows/vs/NetHackW/NetHackW.vcxproj index a3d74baa4..df43cdd0c 100644 --- a/sys/windows/vs/NetHackW/NetHackW.vcxproj +++ b/sys/windows/vs/NetHackW/NetHackW.vcxproj @@ -146,6 +146,7 @@ +