some tipping fixes

- adjust the surface name in prompts (resolves a TODO in the code).
- be more player-friendly with the prompting, and don't prompt a
second time if the floor/surface is the only tip-destination, as
that can be annoyng and viewed as unnecessary. Instead, include
that information in the first decision prompt.

Resolves #1537
This commit is contained in:
nhmall
2026-05-24 00:01:50 -04:00
parent 7025945d2a
commit 05371dd481
+102 -56
View File
@@ -42,7 +42,7 @@ staticfn int traditional_loot(boolean);
staticfn int menu_loot(int, boolean); staticfn int menu_loot(int, boolean);
staticfn int tip_ok(struct obj *); staticfn int tip_ok(struct obj *);
staticfn int choose_tip_container_menu(void); staticfn int choose_tip_container_menu(void);
staticfn struct obj *tipcontainer_gettarget(struct obj *, boolean *); staticfn struct obj *tipcontainer_gettarget(struct obj *, boolean *, int *);
staticfn int tipcontainer_checks(struct obj *, struct obj *, boolean); staticfn int tipcontainer_checks(struct obj *, struct obj *, boolean);
staticfn char in_or_out_menu(const char *, struct obj *, boolean, boolean, staticfn char in_or_out_menu(const char *, struct obj *, boolean, boolean,
boolean, boolean); boolean, boolean);
@@ -3607,10 +3607,25 @@ dotip(void)
} else { } else {
for (cobj = svl.level.objects[cc.x][cc.y]; cobj; for (cobj = svl.level.objects[cc.x][cc.y]; cobj;
cobj = nobj) { cobj = nobj) {
int target_count = 0;
boolean dum; /* argument placeholder, not actually used */
char prompt_part2[BUFSZ];
nobj = cobj->nexthere; nobj = cobj->nexthere;
if (!Is_container(cobj)) if (!Is_container(cobj))
continue; continue;
c = ynq(safe_qbuf(qbuf, "There is ", " here, tip it?", /*
* Calling tipcontainer_gettarget with a non-zero int ptr
* as the 3rd argument just obtains the count of elligible
* tip targets. No menu is displayed and no tip-target pick
* is carried out.
*/
(void) tipcontainer_gettarget(cobj, &dum, &target_count);
Sprintf(prompt_part2, " here, tip it%s%s?",
(target_count == 0) ? " onto the " : "",
(target_count == 0) ? surface(cobj->ox, cobj->oy)
: "");
c = ynq(safe_qbuf(qbuf, "There is ", prompt_part2,
cobj, cobj,
doname, ansimpleoname, "container")); doname, ansimpleoname, "container"));
if (c == 'q') if (c == 'q')
@@ -3709,7 +3724,7 @@ tipcontainer(struct obj *box) /* or bag */
* if 'box' is known to be empty or known to be locked, give up * if 'box' is known to be empty or known to be locked, give up
* before choosing 'targetbox'. * before choosing 'targetbox'.
*/ */
targetbox = tipcontainer_gettarget(box, &cancelled); targetbox = tipcontainer_gettarget(box, &cancelled, (int *) 0);
if (cancelled) if (cancelled)
return; return;
@@ -3876,16 +3891,17 @@ count_target_containers(
staticfn struct obj * staticfn struct obj *
tipcontainer_gettarget( tipcontainer_gettarget(
struct obj *box, struct obj *box,
boolean *cancelled) boolean *cancelled,
int *only_count_targets)
{ {
int n, n_conts, tmpglyph; int n, n_conts = 0, tmpglyph, looppass, count_tiptargets = 0;
glyph_info tmpglyphinfo; glyph_info tmpglyphinfo;
winid win; winid win = WIN_ERR;
anything any; anything any;
char buf[BUFSZ]; char buf[BUFSZ], on_the_surface[BUFSZ];
menu_item *pick_list = (menu_item *) 0; menu_item *pick_list = (menu_item *) 0;
struct obj dummyobj, *otmp; struct obj dummyobj, *otmp;
boolean hands_available = TRUE, exclude_it; boolean hands_available = TRUE, exclude_it, skip_targetmenu = FALSE;
int clr = NO_COLOR; int clr = NO_COLOR;
#if 0 /* [skip potential early return so that menu response is needed #if 0 /* [skip potential early return so that menu response is needed
@@ -3899,58 +3915,88 @@ tipcontainer_gettarget(
return (struct obj *) 0; return (struct obj *) 0;
} }
#endif #endif
/*
* looppass 0 : count the elligible drop targets
* looppass 1 : if there are elligible tip targets, besides the floor,
* then build and present a menu of those targets, including
* the floor.
*/
for (looppass = 0; looppass < 2; looppass++) {
if (looppass == 1) {
if (only_count_targets) {
*only_count_targets = count_tiptargets;
skip_targetmenu = TRUE;
break;
}
if (count_tiptargets == 0) {
/* nothing but the floor */
skip_targetmenu = TRUE;
break;
}
win = create_nhwindow(NHW_MENU);
start_menu(win, MENU_BEHAVE_STANDARD);
win = create_nhwindow(NHW_MENU); dummyobj = cg.zeroobj; /* lint suppression; only its address
start_menu(win, MENU_BEHAVE_STANDARD); matters */
any = cg.zeroany;
any.a_obj = &dummyobj;
/* tip to floor does not require free hands */
Sprintf(on_the_surface, "on the %s", surface(u.ux, u.uy));
add_menu(win, &nul_glyphinfo, &any, '-', 0, ATR_NONE, clr,
on_the_surface, MENU_ITEMFLAGS_SELECTED);
add_menu_str(win, "");
dummyobj = cg.zeroobj; /* lint suppression; only its address matters */ n_conts = 0;
any = cg.zeroany; }
any.a_obj = &dummyobj; for (otmp = gi.invent; otmp; otmp = otmp->nobj) {
/* tip to floor does not require free hands */ if (otmp == box)
add_menu(win, &nul_glyphinfo, &any, '-', 0, ATR_NONE, clr, continue;
/* [TODO? vary destination string depending on surface()] */ /* skip non-containers; bag of tricks passes Is_container() test,
"on the floor", MENU_ITEMFLAGS_SELECTED); only include it if it isn't known to be a bag of tricks */
add_menu_str(win, ""); if (!Is_container(otmp)
|| (otmp->otyp == BAG_OF_TRICKS && otmp->dknown
n_conts = 0; && objects[otmp->otyp].oc_name_known))
for (otmp = gi.invent; otmp; otmp = otmp->nobj) { continue;
if (otmp == box) if (!n_conts++)
continue; hands_available = u_handsy(); /* might issue message */
/* skip non-containers; bag of tricks passes Is_container() test, /* container-to-container tip requires free hands;
only include it if it isn't known to be a bag of tricks */ exclude container as possible target when known to be locked */
if (!Is_container(otmp) exclude_it = !hands_available || (otmp->olocked && otmp->lknown);
|| (otmp->otyp == BAG_OF_TRICKS && otmp->dknown if (looppass == 0) {
&& objects[otmp->otyp].oc_name_known)) if (!exclude_it)
continue; count_tiptargets++;
if (!n_conts++) } else {
hands_available = u_handsy(); /* might issue message */ any = cg.zeroany;
/* container-to-container tip requires free hands; any.a_obj = !exclude_it ? otmp : 0;
exclude container as possible target when known to be locked */ Sprintf(buf, "%s%s", !exclude_it ? "" : " ", doname(otmp));
exclude_it = !hands_available || (otmp->olocked && otmp->lknown); tmpglyph = obj_to_glyph(otmp, rn2_on_display_rng);
any = cg.zeroany; map_glyphinfo(0, 0, tmpglyph, 0U, &tmpglyphinfo);
any.a_obj = !exclude_it ? otmp : 0; add_menu(win, &tmpglyphinfo, &any,
Sprintf(buf, "%s%s", !exclude_it ? "" : " ", doname(otmp)); !exclude_it ? otmp->invlet : 0, 0, ATR_NONE, clr,
tmpglyph = obj_to_glyph(otmp, rn2_on_display_rng); buf, MENU_ITEMFLAGS_NONE);
map_glyphinfo(0, 0, tmpglyph, 0U, &tmpglyphinfo); }
add_menu(win, &tmpglyphinfo, &any, !exclude_it ? otmp->invlet : 0, 0, }
ATR_NONE, clr, buf, MENU_ITEMFLAGS_NONE);
} }
if (!skip_targetmenu) {
Sprintf(buf, "Where to tip the contents of %s", doname(box));
end_menu(win, buf);
n = select_menu(win, PICK_ONE, &pick_list);
destroy_nhwindow(win);
Sprintf(buf, "Where to tip the contents of %s", doname(box)); otmp = 0;
end_menu(win, buf); if (pick_list) {
n = select_menu(win, PICK_ONE, &pick_list); otmp = pick_list[0].item.a_obj;
destroy_nhwindow(win); /* PICK_ONE with a preselected item might return 2;
if so, choose the one that wasn't preselected */
otmp = 0; if (n > 1 && otmp == &dummyobj)
if (pick_list) { otmp = pick_list[1].item.a_obj;
otmp = pick_list[0].item.a_obj; if (otmp == &dummyobj)
/* PICK_ONE with a preselected item might return 2; otmp = 0;
if so, choose the one that wasn't preselected */ free((genericptr_t) pick_list);
if (n > 1 && otmp == &dummyobj) }
otmp = pick_list[1].item.a_obj; } else {
if (otmp == &dummyobj) otmp = 0;
otmp = 0; n = 0; /* don't flag as having been cancelled */
free((genericptr_t) pick_list);
} }
*cancelled = (boolean) (n == -1); *cancelled = (boolean) (n == -1);
return otmp; return otmp;