From 73a315dcfdb07527443f9a332a5624d55a76ee9b Mon Sep 17 00:00:00 2001 From: "nethack.rankin" Date: Sat, 21 Apr 2007 02:43:32 +0000 Subject: [PATCH] f-iring without ammo There was a suggestion in the newsgroup that if you use the 'f' command when your quiver is empty, that whatever missile you supply to the "what do you want to throw?" prompt be automatically put into the quiver. This implements that, and separates most of the common code from dothrow() and dofire() into a separate routine. A post-3.4.3 change to dothrow() to require hands for throwing wasn't propagated to dofire(). With the common routine, they're much less likely to get out of sync like that. This is going into the branch as well as the trunk because the hands checking mismatch was added there too. --- doc/fixes34.4 | 2 + src/dothrow.c | 109 +++++++++++++++++++++++++++----------------------- 2 files changed, 61 insertions(+), 50 deletions(-) diff --git a/doc/fixes34.4 b/doc/fixes34.4 index 8254a7353..84d0c58d4 100644 --- a/doc/fixes34.4 +++ b/doc/fixes34.4 @@ -387,6 +387,8 @@ intelligent pets will use keys to unlock doors destroyed drawbridge leaves some iron chains give feedback when a nearby monster grows into a stronger form familiars are now created without any starting inventory +using the 'f' command when quiver is empty will fill quiver if player selects + a stack of 2 or more items in response to the "what to throw?" prompt Platform- and/or Interface-Specific New Features diff --git a/src/dothrow.c b/src/dothrow.c index 42bf9fbba..fb7479b0b 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -7,6 +7,7 @@ #include "hack.h" STATIC_DCL int FDECL(throw_obj, (struct obj *,int)); +STATIC_DCL boolean FDECL(ok_to_throw, (int *)); STATIC_DCL void NDECL(autoquiver); STATIC_DCL int FDECL(gem_accept, (struct monst *, struct obj *)); STATIC_DCL void FDECL(tmiss, (struct obj *, struct monst *,BOOLEAN_P)); @@ -208,6 +209,28 @@ int shotlimit; return 1; } +/* common to dothrow() and dofire() */ +STATIC_OVL boolean +ok_to_throw(shotlimit_p) +int *shotlimit_p; /* (see dothrow()) */ +{ + /* kludge to work around parse()'s pre-decrement of `multi' */ + *shotlimit_p = (multi || save_cm) ? multi + 1 : 0; + multi = 0; /* reset; it's been used up */ + + if (notake(youmonst.data)) { + You("are physically incapable of throwing or shooting anything."); + return FALSE; + } else if (nohands(youmonst.data)) { + You_cant("throw or shoot without hands."); /* not body_part(HAND) */ + return FALSE; + /*[what about !freehand(), aside from cursed missile launcher?]*/ + } + if (check_capacity((char *)0)) return FALSE; + return TRUE; +} + +/* t command - throw */ int dothrow() { @@ -222,27 +245,16 @@ dothrow() * * Prior to 3.3.0, command ``3t'' meant ``t(shoot) t(shoot) t(shoot)'' * and took 3 turns. Now it means ``t(shoot at most 3 missiles)''. + * + * [3.5.0: shot count setup has been moved into ok_to_throw().] */ - /* kludge to work around parse()'s pre-decrement of `multi' */ - shotlimit = (multi || save_cm) ? multi + 1 : 0; - multi = 0; /* reset; it's been used up */ + if (!ok_to_throw(&shotlimit)) return 0; - if (notake(youmonst.data)) { - You("are physically incapable of throwing anything."); - return 0; - } else if (nohands(youmonst.data)) { - You_cant("throw without hands."); /* not `body_part(HAND)' */ - return 0; - /*[what about !freehand(), aside from cursed missile launcher?]*/ - } - - if(check_capacity((char *)0)) return(0); obj = getobj(uslinging() ? bullets : toss_objs, "throw"); /* it is also possible to throw food */ /* (or jewels, or iron balls... ) */ - if (!obj) return(0); - return throw_obj(obj, shotlimit); + return obj ? throw_obj(obj, shotlimit) : 0; } @@ -311,50 +323,47 @@ autoquiver() return; } - -/* Throw from the quiver */ +/* f command -- fire: throw from the quiver */ int dofire() { int shotlimit; - - if (notake(youmonst.data)) { - You("are physically incapable of doing that."); - return 0; - } - - if(check_capacity((char *)0)) return(0); - if (!uquiver) { - if (!flags.autoquiver) { - /* Don't automatically fill the quiver */ - You("have no ammunition readied!"); - return(dothrow()); - } - autoquiver(); - if (!uquiver) { - You("have nothing appropriate for your quiver!"); - return(dothrow()); - } else { - You("fill your quiver:"); - prinv((char *)0, uquiver, 0L); - } - } + struct obj *obj; /* - * Since some characters shoot multiple missiles at one time, - * allow user to specify a count prefix for 'f' or 't' to limit - * number of items thrown (to avoid possibly hitting something - * behind target after killing it, or perhaps to conserve ammo). + * Same as dothrow(), except we use quivered missile instead + * of asking what to throw/shoot. * - * The number specified can never increase the number of missiles. - * Using ``5f'' when the shooting skill (plus RNG) dictates launch - * of 3 projectiles will result in 3 being shot, not 5. + * If quiver is empty, we use autoquiver to fill it when the + * corresponding option is on. If the option is off or if + * autoquiver doesn't select anything, we ask what to throw. + * For the last, if player's response is a stack, we put + * that stack into quiver slot provided it's not wielded. */ - /* kludge to work around parse()'s pre-decrement of `multi' */ - shotlimit = (multi || save_cm) ? multi + 1 : 0; - multi = 0; /* reset; it's been used up */ + if (!ok_to_throw(&shotlimit)) return 0; - return throw_obj(uquiver, shotlimit); + if ((obj = uquiver) == 0) { + if (!flags.autoquiver) { + You("have no ammunition readied."); + } else { + autoquiver(); + if ((obj = uquiver) == 0) + You("have nothing appropriate for your quiver."); + } + /* if autoquiver is disabled or has failed, prompt for missile; + fill quiver with it if it's a stack that's not wielded */ + if (!obj) { + obj = getobj(uslinging() ? bullets : toss_objs, "throw"); + if (obj && obj->quan > 1L && !obj->owornmask && + /* Q command doesn't allow gold in quiver */ + obj->oclass != COIN_CLASS) + setuqwep(obj); /* demi-autoquiver */ + } + /* give feedback if quiver has now been filled */ + if (uquiver) prinv("You ready:", uquiver, 0L); + } + + return obj ? throw_obj(obj, shotlimit) : 0; } /* if in midst of multishot shooting/throwing, stop early */