diff --git a/src/pickup.c b/src/pickup.c index 0ca9dca13..7424f109e 100644 --- a/src/pickup.c +++ b/src/pickup.c @@ -42,7 +42,7 @@ staticfn int traditional_loot(boolean); staticfn int menu_loot(int, boolean); staticfn int tip_ok(struct obj *); 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 char in_or_out_menu(const char *, struct obj *, boolean, boolean, boolean, boolean); @@ -3607,10 +3607,25 @@ dotip(void) } else { for (cobj = svl.level.objects[cc.x][cc.y]; cobj; cobj = nobj) { + int target_count = 0; + boolean dum; /* argument placeholder, not actually used */ + char prompt_part2[BUFSZ]; + nobj = cobj->nexthere; if (!Is_container(cobj)) 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, doname, ansimpleoname, "container")); 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 * before choosing 'targetbox'. */ - targetbox = tipcontainer_gettarget(box, &cancelled); + targetbox = tipcontainer_gettarget(box, &cancelled, (int *) 0); if (cancelled) return; @@ -3876,16 +3891,17 @@ count_target_containers( staticfn struct obj * tipcontainer_gettarget( 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; - winid win; + winid win = WIN_ERR; anything any; - char buf[BUFSZ]; + char buf[BUFSZ], on_the_surface[BUFSZ]; menu_item *pick_list = (menu_item *) 0; struct obj dummyobj, *otmp; - boolean hands_available = TRUE, exclude_it; + boolean hands_available = TRUE, exclude_it, skip_targetmenu = FALSE; int clr = NO_COLOR; #if 0 /* [skip potential early return so that menu response is needed @@ -3899,58 +3915,88 @@ tipcontainer_gettarget( return (struct obj *) 0; } #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); - start_menu(win, MENU_BEHAVE_STANDARD); + dummyobj = cg.zeroobj; /* lint suppression; only its address + 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 */ - any = cg.zeroany; - any.a_obj = &dummyobj; - /* tip to floor does not require free hands */ - add_menu(win, &nul_glyphinfo, &any, '-', 0, ATR_NONE, clr, - /* [TODO? vary destination string depending on surface()] */ - "on the floor", MENU_ITEMFLAGS_SELECTED); - add_menu_str(win, ""); - - n_conts = 0; - for (otmp = gi.invent; otmp; otmp = otmp->nobj) { - if (otmp == box) - continue; - /* skip non-containers; bag of tricks passes Is_container() test, - only include it if it isn't known to be a bag of tricks */ - if (!Is_container(otmp) - || (otmp->otyp == BAG_OF_TRICKS && otmp->dknown - && objects[otmp->otyp].oc_name_known)) - continue; - if (!n_conts++) - hands_available = u_handsy(); /* might issue message */ - /* container-to-container tip requires free hands; - exclude container as possible target when known to be locked */ - exclude_it = !hands_available || (otmp->olocked && otmp->lknown); - any = cg.zeroany; - any.a_obj = !exclude_it ? otmp : 0; - Sprintf(buf, "%s%s", !exclude_it ? "" : " ", doname(otmp)); - tmpglyph = obj_to_glyph(otmp, rn2_on_display_rng); - 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); + n_conts = 0; + } + for (otmp = gi.invent; otmp; otmp = otmp->nobj) { + if (otmp == box) + continue; + /* skip non-containers; bag of tricks passes Is_container() test, + only include it if it isn't known to be a bag of tricks */ + if (!Is_container(otmp) + || (otmp->otyp == BAG_OF_TRICKS && otmp->dknown + && objects[otmp->otyp].oc_name_known)) + continue; + if (!n_conts++) + hands_available = u_handsy(); /* might issue message */ + /* container-to-container tip requires free hands; + exclude container as possible target when known to be locked */ + exclude_it = !hands_available || (otmp->olocked && otmp->lknown); + if (looppass == 0) { + if (!exclude_it) + count_tiptargets++; + } else { + any = cg.zeroany; + any.a_obj = !exclude_it ? otmp : 0; + Sprintf(buf, "%s%s", !exclude_it ? "" : " ", doname(otmp)); + tmpglyph = obj_to_glyph(otmp, rn2_on_display_rng); + 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)); - end_menu(win, buf); - n = select_menu(win, PICK_ONE, &pick_list); - destroy_nhwindow(win); - - otmp = 0; - if (pick_list) { - otmp = pick_list[0].item.a_obj; - /* PICK_ONE with a preselected item might return 2; - if so, choose the one that wasn't preselected */ - if (n > 1 && otmp == &dummyobj) - otmp = pick_list[1].item.a_obj; - if (otmp == &dummyobj) - otmp = 0; - free((genericptr_t) pick_list); + otmp = 0; + if (pick_list) { + otmp = pick_list[0].item.a_obj; + /* PICK_ONE with a preselected item might return 2; + if so, choose the one that wasn't preselected */ + if (n > 1 && otmp == &dummyobj) + otmp = pick_list[1].item.a_obj; + if (otmp == &dummyobj) + otmp = 0; + free((genericptr_t) pick_list); + } + } else { + otmp = 0; + n = 0; /* don't flag as having been cancelled */ } *cancelled = (boolean) (n == -1); return otmp;